summaryrefslogtreecommitdiff
path: root/src/generate.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/generate.cc')
-rw-r--r--src/generate.cc8698
1 files changed, 8698 insertions, 0 deletions
diff --git a/src/generate.cc b/src/generate.cc
new file mode 100644
index 00000000..b5733682
--- /dev/null
+++ b/src/generate.cc
@@ -0,0 +1,8698 @@
+/*
+ * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
+ *
+ * This software may be copied and distributed for educational, research, and
+ * not for profit purposes provided that this copyright and statement are
+ * included in all such copies.
+ */
+
+#include "generate.hpp"
+
+#include "artifact_type.hpp"
+#include "cave.hpp"
+#include "cave_type.hpp"
+#include "dungeon_info_type.hpp"
+#include "feature_type.hpp"
+#include "hook_build_room1_in.hpp"
+#include "hooks.hpp"
+#include "init1.hpp"
+#include "levels.hpp"
+#include "loadsave.hpp"
+#include "monster2.hpp"
+#include "monster_race.hpp"
+#include "monster_type.hpp"
+#include "object2.hpp"
+#include "object_kind.hpp"
+#include "options.hpp"
+#include "player_type.hpp"
+#include "randart.hpp"
+#include "spells1.hpp"
+#include "tables.hpp"
+#include "town_type.hpp"
+#include "traps.hpp"
+#include "util.hpp"
+#include "variable.hpp"
+#include "vault_type.hpp"
+#include "wild.hpp"
+#include "wilderness_map.hpp"
+#include "z-rand.hpp"
+
+#include <cassert>
+#include <memory>
+#include <vector>
+
+#define SAFE_MAX_ATTEMPTS 5000
+
+/*
+ * Note that Level generation is *not* an important bottleneck,
+ * though it can be annoyingly slow on older machines... Thus
+ * we emphasize "simplicity" and "correctness" over "speed".
+ *
+ * This entire file is only needed for generating levels.
+ * This may allow smart compilers to only load it when needed.
+ *
+ * Consider the "v_info.txt" file for vault generation.
+ *
+ * In this file, we use the "special" granite and perma-wall sub-types,
+ * where "basic" is normal, "inner" is inside a room, "outer" is the
+ * outer wall of a room, and "solid" is the outer wall of the dungeon
+ * or any walls that may not be pierced by corridors. Thus the only
+ * wall type that may be pierced by a corridor is the "outer granite"
+ * type. The "basic granite" type yields the "actual" corridors.
+ *
+ * Note that we use the special "solid" granite wall type to prevent
+ * multiple corridors from piercing a wall in two adjacent locations,
+ * which would be messy, and we use the special "outer" granite wall
+ * to indicate which walls "surround" rooms, and may thus be "pierced"
+ * by corridors entering or leaving the room.
+ *
+ * Note that a tunnel which attempts to leave a room near the "edge"
+ * of the dungeon in a direction toward that edge will cause "silly"
+ * wall piercings, but will have no permanently incorrect effects,
+ * as long as the tunnel can *eventually* exit from another side.
+ * And note that the wall may not come back into the room by the
+ * hole it left through, so it must bend to the left or right and
+ * then optionally re-enter the room (at least 2 grids away). This
+ * is not a problem since every room that is large enough to block
+ * the passage of tunnels is also large enough to allow the tunnel
+ * to pierce the room itself several times.
+ *
+ * Note that no two corridors may enter a room through adjacent grids,
+ * they must either share an entryway or else use entryways at least
+ * two grids apart. This prevents "large" (or "silly") doorways.
+ *
+ * To create rooms in the dungeon, we first divide the dungeon up
+ * into "blocks" of 11x11 grids each, and require that all rooms
+ * occupy a rectangular group of blocks. As long as each room type
+ * reserves a sufficient number of blocks, the room building routines
+ * will not need to check bounds. Note that most of the normal rooms
+ * actually only use 23x11 grids, and so reserve 33x11 grids.
+ *
+ * Note that the use of 11x11 blocks (instead of the old 33x11 blocks)
+ * allows more variability in the horizontal placement of rooms, and
+ * at the same time has the disadvantage that some rooms (two thirds
+ * of the normal rooms) may be "split" by panel boundaries. This can
+ * induce a situation where a player is in a room and part of the room
+ * is off the screen. It may be annoying enough to go back to 33x11
+ * blocks to prevent this visual situation.
+ *
+ * Note that the dungeon generation routines are much different (2.7.5)
+ * and perhaps "DUN_ROOMS" should be less than 50.
+ *
+ * XXX XXX XXX Note that it is possible to create a room which is only
+ * connected to itself, because the "tunnel generation" code allows a
+ * tunnel to leave a room, wander around, and then re-enter the room.
+ *
+ * XXX XXX XXX Note that it is possible to create a set of rooms which
+ * are only connected to other rooms in that set, since there is nothing
+ * explicit in the code to prevent this from happening. But this is less
+ * likely than the "isolated room" problem, because each room attempts to
+ * connect to another room, in a giant cycle, thus requiring at least two
+ * bizarre occurances to create an isolated section of the dungeon.
+ *
+ * Note that (2.7.9) monster pits have been split into monster "nests"
+ * and monster "pits". The "nests" have a collection of monsters of a
+ * given type strewn randomly around the room (jelly, animal, or undead),
+ * while the "pits" have a collection of monsters of a given type placed
+ * around the room in an organized manner (orc, troll, giant, dragon, or
+ * demon). Note that both "nests" and "pits" are now "level dependant",
+ * and both make 16 "expensive" calls to the "get_mon_num()" function.
+ *
+ * Note that the cave grid flags changed in a rather drastic manner
+ * for Angband 2.8.0 (and 2.7.9+), in particular, dungeon terrain
+ * features, such as doors and stairs and traps and rubble and walls,
+ * are all handled as a set of 64 possible "terrain features", and
+ * not as "fake" objects (440-479) as in pre-2.8.0 versions.
+ *
+ * The 64 new "dungeon features" will also be used for "visual display"
+ * but we must be careful not to allow, for example, the user to display
+ * hidden traps in a different way from floors, or secret doors in a way
+ * different from granite walls, or even permanent granite in a different
+ * way from granite. XXX XXX XXX
+ */
+
+
+/*
+ * Dungeon generation values
+ */
+#define DUN_ROOMS 50 /* Number of rooms to attempt */
+#define DUN_UNUSUAL 194 /* Level/chance of unusual room (was 200) */
+#define DUN_DEST 18 /* 1/chance of having a destroyed level */
+#define SMALL_LEVEL 6 /* 1/chance of smaller size (3->6) */
+#define EMPTY_LEVEL 15 /* 1/chance of being 'empty' (15)*/
+#define DARK_EMPTY 5 /* 1/chance of arena level NOT being lit (2)*/
+#define XTRA_MAGIC 10 /* 1/chance of having a level with more magic (10)*/
+#define DUN_WILD_VAULT 50 /* Chance of finding a wilderness vault. */
+#define DUN_WAT_RNG 2 /* Width of rivers */
+#define DUN_WAT_CHG 50 /* 1 in 50 chance of junction in river */
+#define DUN_CAVERN 30 /* 1/chance of having a cavern level */
+
+/*
+ * Dungeon tunnel generation values
+ */
+#define DUN_TUN_RND 10 /* Chance of random direction */
+#define DUN_TUN_CHG 30 /* Chance of changing direction */
+#define DUN_TUN_CON 15 /* Chance of extra tunneling */
+#define DUN_TUN_PEN 25 /* Chance of doors at room entrances */
+#define DUN_TUN_JCT 90 /* Chance of doors at tunnel junctions */
+
+/*
+ * Dungeon streamer generation values
+ */
+#define DUN_STR_DEN 5 /* Density of streamers */
+#define DUN_STR_RNG 2 /* Width of streamers */
+#define DUN_STR_MAG 3 /* Number of magma streamers */
+#define DUN_STR_MC 90 /* 1/chance of treasure per magma */
+#define DUN_STR_QUA 2 /* Number of quartz streamers */
+#define DUN_STR_QC 40 /* 1/chance of treasure per quartz */
+#define DUN_STR_SAN 1 /* Number of sand streamers */
+#define DUN_STR_SC 10 /* 1/chance of treasure per sandwall */
+#define DUN_STR_WLW 1 /* Width of lava & water streamers -KMW- */
+#define DUN_STR_DWLW 8 /* Density of water & lava streams -KMW- */
+
+
+/*
+ * Dungeon treausre allocation values
+ */
+#define DUN_AMT_ROOM 9 /* Amount of objects for rooms */
+#define DUN_AMT_ITEM 3 /* Amount of objects for rooms/corridors */
+#define DUN_AMT_GOLD 3 /* Amount of treasure for rooms/corridors */
+#define DUN_AMT_ALTAR 1 /* Amount of altars */
+#define DUN_AMT_BETWEEN 2 /* Amount of between gates */
+#define DUN_AMT_FOUNTAIN 1 /* Amount of fountains */
+
+/*
+ * Hack -- Dungeon allocation "places"
+ */
+#define ALLOC_SET_CORR 1 /* Hallway */
+#define ALLOC_SET_ROOM 2 /* Room */
+#define ALLOC_SET_BOTH 3 /* Anywhere */
+
+/*
+ * Hack -- Dungeon allocation "types"
+ */
+#define ALLOC_TYP_RUBBLE 1 /* Rubble */
+#define ALLOC_TYP_TRAP 3 /* Trap */
+#define ALLOC_TYP_GOLD 4 /* Gold */
+#define ALLOC_TYP_OBJECT 5 /* Object */
+#define ALLOC_TYP_ALTAR 6 /* Altar */
+#define ALLOC_TYP_BETWEEN 7 /* Between */
+#define ALLOC_TYP_FOUNTAIN 8 /* Fountain */
+
+
+/*
+ * The "size" of a "generation block" in grids
+ */
+#define BLOCK_HGT 11
+#define BLOCK_WID 11
+
+/*
+ * Maximum numbers of rooms along each axis (currently 6x6)
+ */
+#define MAX_ROOMS_ROW (MAX_HGT / BLOCK_HGT)
+#define MAX_ROOMS_COL (MAX_WID / BLOCK_WID)
+
+
+/*
+ * Bounds on some arrays used in the "dun_data" structure.
+ * These bounds are checked, though usually this is a formality.
+ */
+#define CENT_MAX 100
+#define DOOR_MAX 200
+#define WALL_MAX 500
+#define TUNN_MAX 900
+
+
+/*
+ * Maximal number of room types
+ */
+#define ROOM_MAX 12
+
+
+
+/*
+ * Simple structure to hold a map location
+ */
+
+
+typedef struct coord coord;
+
+struct coord
+{
+ byte y;
+ byte x;
+};
+
+
+/*
+ * Room type information
+ */
+
+typedef struct room_data room_data;
+
+struct room_data
+{
+ /* Required size in blocks */
+ s16b dy1, dy2, dx1, dx2;
+
+ /* Hack -- minimum level */
+ s16b level;
+};
+
+
+/*
+ * Structure to hold all "dungeon generation" data
+ */
+
+typedef struct dun_data dun_data;
+
+struct dun_data
+{
+ /* Array of centers of rooms */
+ int cent_n;
+ coord cent[CENT_MAX];
+
+ /* Array of possible door locations */
+ int door_n;
+ coord door[DOOR_MAX];
+
+ /* Array of wall piercing locations */
+ int wall_n;
+ coord wall[WALL_MAX];
+
+ /* Array of tunnel grids */
+ int tunn_n;
+ coord tunn[TUNN_MAX];
+
+ /* Number of blocks along each axis */
+ int row_rooms;
+ int col_rooms;
+
+ /* Array of which blocks are used */
+ bool_ room_map[MAX_ROOMS_ROW][MAX_ROOMS_COL];
+
+ /* Hack -- there is a pit/nest on this level */
+ bool_ crowded;
+};
+
+/*
+ * Level generator type
+ */
+
+typedef struct level_generator_type level_generator_type;
+struct level_generator_type
+{
+ cptr name;
+ bool_ (*generator)();
+
+ struct level_generator_type *next;
+};
+
+static level_generator_type *level_generators = NULL;
+
+/*
+ * Add a new generator
+ */
+void add_level_generator(cptr name, bool_ (*generator)())
+{
+ assert(name != nullptr);
+
+ level_generator_type *g = new level_generator_type;
+
+ g->name = strdup(name);
+ g->generator = generator;
+
+ g->next = level_generators;
+ level_generators = g;
+}
+
+
+/*
+ * Dungeon generation data -- see "cave_gen()"
+ */
+static dun_data *dun;
+
+/*
+ * ???
+ */
+static int template_race;
+
+
+
+/*
+ * Array of room types depths
+ */
+static s16b roomdep[] =
+{
+ 0, /* 0 = Nothing */
+ 1, /* 1 = Simple (33x11) */
+ 1, /* 2 = Overlapping (33x11) */
+ 3, /* 3 = Crossed (33x11) */
+ 3, /* 4 = Large (33x11) */
+ 5, /* 5 = Monster nest (33x11) */
+ 5, /* 6 = Monster pit (33x11) */
+ 5, /* 7 = Lesser vault (33x22) */
+ 10, /* 8 = Greater vault (66x44) */
+ 1, /* 9 = Circular rooms (22x22) */
+ 3, /* 10 = Fractal cave (42x24) */
+ 10, /* 11 = Random vault (44x22) */
+ 10, /* 12 = Crypts (22x22) */
+};
+
+
+/*
+ * Always picks a correct direction
+ */
+static void correct_dir(int *rdir, int *cdir, int y1, int x1, int y2, int x2)
+{
+ /* Extract vertical and horizontal directions */
+ *rdir = (y1 == y2) ? 0 : (y1 < y2) ? 1 : -1;
+ *cdir = (x1 == x2) ? 0 : (x1 < x2) ? 1 : -1;
+
+ /* Never move diagonally */
+ if (*rdir && *cdir)
+ {
+ if (rand_int(100) < 50)
+ {
+ *rdir = 0;
+ }
+ else
+ {
+ *cdir = 0;
+ }
+ }
+}
+
+
+/*
+ * Pick a random direction
+ */
+static void rand_dir(int *rdir, int *cdir)
+{
+ /* Pick a random direction */
+ int i = rand_int(4);
+
+ /* Extract the dy/dx components */
+ *rdir = ddy_ddd[i];
+ *cdir = ddx_ddd[i];
+}
+
+
+/*
+ * Convert existing terrain type to "up stairs"
+ */
+static void place_up_stairs(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Create up stairs */
+ if ((rand_int(3) != 0) || (dungeon_flags2 & DF2_NO_SHAFT))
+ {
+ cave_set_feat(y, x, FEAT_LESS);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_SHAFT_UP);
+ }
+
+ c_ptr->special = 0;
+}
+
+
+/*
+ * Convert existing terrain type to "down stairs" with dungeon changing.
+ */
+static void place_magical_stairs(int y, int x, byte next)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Create up stairs */
+ cave_set_feat(y, x, FEAT_MORE);
+ c_ptr->special = next;
+}
+
+
+/*
+ * Convert existing terrain type to "down stairs"
+ */
+static void place_down_stairs(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /*
+ * Create down stairs
+ * All thoses tests are necesary because a shaft can jump up to 4 levels
+ */
+ if ((dun_level + 4 > d_info[dungeon_type].maxdepth) ||
+ (rand_int(3) != 0) || (dungeon_flags2 & DF2_NO_SHAFT))
+ {
+ cave_set_feat(y, x, FEAT_MORE);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_SHAFT_DOWN);
+ }
+
+ c_ptr->special = 0;
+}
+
+
+/*
+ * Helper function for place_new_way. Determine if y, x is one of
+ * floor features of the current dungeon
+ */
+static bool_ is_safe_floor(int y, int x)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+ byte feat = cave[y][x].feat;
+
+ /* One of the legal floor types */
+ if (feat == d_ptr->floor1) return (TRUE);
+ if (feat == d_ptr->floor2) return (TRUE);
+ if (feat == d_ptr->floor3) return (TRUE);
+
+ /* Assume non-floor */
+ return (FALSE);
+}
+
+
+/*
+ * Place a way to next / previoous level on flat places
+ */
+void place_new_way(int *y, int *x)
+{
+ int xx, yy;
+ int x0, x1, x2;
+ int y0, y1, y2;
+ cave_type *c_ptr;
+ bool_ ok;
+ int i, way_n;
+ byte way_x[MAX_WID], way_y[MAX_WID];
+
+
+ /* Find valid location XXX XXX XXX */
+ while (TRUE)
+ {
+ /* A way on vertical edge */
+ if (rand_int(cur_hgt + cur_wid) < cur_hgt)
+ {
+ /* Pick a random grid */
+ yy = *y = rand_int(cur_hgt - 2) + 1;
+ xx = *x = 1 + (rand_int(2) * (cur_wid - 3));
+
+ /* Pick a direction */
+ if (xx == 1)
+ {
+ /* Left */
+ x0 = + 1;
+ y0 = 0;
+
+ /* Sides */
+ x1 = 0;
+ y1 = -1;
+ x2 = 0;
+ y2 = + 1;
+ }
+ else
+ {
+ /* Right */
+ x0 = -1;
+ y0 = 0;
+
+ /* Sides */
+ x1 = 0;
+ y1 = -1;
+ x2 = 0;
+ y2 = + 1;
+ }
+ }
+
+ /* A way on horizontal edge */
+ else
+ {
+ /* Pick a random grid */
+ xx = *x = rand_int(cur_wid - 2) + 1;
+ yy = *y = 1 + (rand_int(2) * (cur_hgt - 3));
+
+ /* Pick a direction */
+ if (yy == 1)
+ {
+ /* Down */
+ x0 = 0;
+ y0 = + 1;
+
+ /* Sides */
+ x1 = -1;
+ y1 = 0;
+ x2 = + 1;
+ y2 = 0;
+ }
+ else
+ {
+ /* Up */
+ x0 = 0;
+ y0 = -1;
+
+ /* Sides */
+ x1 = -1;
+ y1 = 0;
+ x2 = + 1;
+ y2 = 0;
+ }
+ }
+
+
+ /* Look at the starting location */
+ c_ptr = &cave[yy][xx];
+
+ /* Reject locations inside vaults */
+ if (c_ptr->info & (CAVE_ICKY)) continue;
+
+ /* Reject permanent features */
+ if ((f_info[c_ptr->feat].flags1 & (FF1_PERMANENT)) &&
+ (f_info[c_ptr->feat].flags1 & (FF1_FLOOR))) continue;
+
+ /* Reject room walls */
+ if ((c_ptr->info & (CAVE_ROOM)) &&
+ (c_ptr->feat == feat_wall_outer)) continue;
+
+ /* Look at a neighbouring edge */
+ c_ptr = &cave[yy + y1][xx + x1];
+
+ /* Reject two adjacent ways */
+ if ((c_ptr->feat == FEAT_WAY_MORE) ||
+ (c_ptr->feat == FEAT_WAY_LESS)) continue;
+
+ /* Look at the other neighbouring edge */
+ c_ptr = &cave[yy + y2][xx + x2];
+
+ /* Reject two adjacent ways */
+ if ((c_ptr->feat == FEAT_WAY_MORE) ||
+ (c_ptr->feat == FEAT_WAY_LESS)) continue;
+
+ /* Look ahead */
+ c_ptr = &cave[yy + y0][xx + x0];
+
+ /* Reject two adjacent ways -- relatively rare, but this can happen */
+ if ((c_ptr->feat == FEAT_WAY_MORE) ||
+ (c_ptr->feat == FEAT_WAY_LESS)) continue;
+
+
+ /* Reset counter */
+ way_n = 0;
+
+ /* Assume bad location */
+ ok = FALSE;
+
+ /* Check if it connects to current dungeon */
+ while (in_bounds(yy, xx))
+ {
+ /* Check grids ahead */
+ if (is_safe_floor(yy + y0, xx + x0)) ok = TRUE;
+
+ /* Check side grids */
+ if (is_safe_floor(yy + y1, xx + x1)) ok = TRUE;
+ if (is_safe_floor(yy + y2, xx + x2)) ok = TRUE;
+
+ /* Connected */
+ if (ok) break;
+
+ /* Access grid (ahead) */
+ c_ptr = &cave[yy + y0][xx + x0];
+
+ /* Avoid opening vaults */
+ if (c_ptr->feat == FEAT_PERM_OUTER)
+ {
+ /* Comment this out if you find any problems... */
+ ok = TRUE;
+
+ break;
+ }
+
+ /* Paranoia */
+ if (c_ptr->feat == FEAT_PERM_SOLID) break;
+
+ /*
+ * Hack -- Avoid digging room corner
+ *
+ * CAVEAT: Can't handle situations like this:
+ *
+ * .....########
+ * .....########
+ * ######.....>#
+ * #############
+ * .....#
+ * .....#
+ */
+ if (c_ptr->info & (CAVE_ROOM))
+ {
+ cave_type *c1_ptr = &cave[yy + y0 + y1][xx + x0 + x1];
+ cave_type *c2_ptr = &cave[yy + y0 + y2][xx + x0 + x2];
+
+ /* Bend the way */
+ if ((c1_ptr->info & (CAVE_ROOM)) &&
+ !(c2_ptr->info & (CAVE_ROOM)))
+ {
+ way_x[way_n] = xx + x1;
+ way_y[way_n] = yy + y1;
+ way_n++;
+ way_x[way_n] = xx + x1 + x0;
+ way_y[way_n] = yy + y1 + y0;
+ way_n++;
+ }
+
+ /* Bend the way -- the other direction */
+ else if ((c2_ptr->info & (CAVE_ROOM)) &&
+ !(c1_ptr->info & (CAVE_ROOM)))
+ {
+ way_x[way_n] = xx + x2;
+ way_y[way_n] = yy + y2;
+ way_n++;
+ way_x[way_n] = xx + x2 + x0;
+ way_y[way_n] = yy + y2 + y0;
+ way_n++;
+ }
+
+ else
+ {
+ way_x[way_n] = xx + x0;
+ way_y[way_n] = yy + y0;
+ way_n++;
+ }
+
+ ok = TRUE;
+ break;
+ }
+
+ /* Remember the location */
+ way_x[way_n] = xx + x0;
+ way_y[way_n] = yy + y0;
+ way_n++;
+
+ /* Advance */
+ xx += x0;
+ yy += y0;
+ }
+
+ /* Accept connected corridor */
+ if (ok) break;
+
+ /* Try again, until valid location is found */
+ }
+
+
+ /* Actually dig a corridor connecting the way to dungeon */
+ for (i = 0; i < way_n; i++)
+ {
+ /* Dig */
+ place_floor(way_y[i], way_x[i]);
+ }
+}
+
+
+/*
+ * Returns random co-ordinates for player/monster/object
+ */
+bool_ new_player_spot(int branch)
+{
+ int y, x;
+ int max_attempts = 5000;
+
+ /* Place the player */
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ place_new_way(&y, &x);
+ }
+ else
+ {
+ while (max_attempts--)
+ {
+ /* Pick a legal spot */
+ y = rand_range(1, cur_hgt - 2);
+ x = rand_range(1, cur_wid - 2);
+
+ /* Must be a "naked" floor grid */
+ if (!cave_naked_bold(y, x)) continue;
+
+ /* Refuse to start on anti-teleport grids */
+ if (cave[y][x].info & (CAVE_ICKY)) continue;
+
+ /* Done */
+ break;
+
+ }
+ }
+
+ /* Should be -1, actually if we failed... */
+ if (max_attempts < 1) return (FALSE);
+
+
+ /* Save the new player grid */
+ p_ptr->py = y;
+ p_ptr->px = x;
+
+ /* XXX XXX XXX */
+ if (dungeon_stair && !(dungeon_flags2 & DF2_NO_STAIR) && dun_level &&
+ (!is_quest(dun_level) || (old_dun_level < dun_level)) && !branch)
+ {
+ if (old_dun_level < dun_level)
+ {
+ place_up_stairs(p_ptr->py , p_ptr->px);
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_WAY_LESS);
+ }
+ }
+ else
+ {
+ place_down_stairs(p_ptr->py , p_ptr->px);
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ cave_set_feat(p_ptr->py, p_ptr->px, FEAT_WAY_MORE);
+ }
+ }
+ }
+
+ return (TRUE);
+}
+
+
+
+/*
+ * Count the number of walls adjacent to the given grid.
+ *
+ * Note -- Assumes "in_bounds(y, x)"
+ *
+ * We count only granite walls and permanent walls.
+ */
+static int next_to_walls(int y, int x)
+{
+ int k = 0;
+
+ if (f_info[cave[y + 1][x].feat].flags1 & FF1_WALL) k++;
+ if (f_info[cave[y - 1][x].feat].flags1 & FF1_WALL) k++;
+ if (f_info[cave[y][x + 1].feat].flags1 & FF1_WALL) k++;
+ if (f_info[cave[y][x - 1].feat].flags1 & FF1_WALL) k++;
+
+ return (k);
+}
+
+
+
+/*
+ * Convert existing terrain type to rubble
+ */
+static void place_rubble(int y, int x)
+{
+ /* Create rubble */
+ cave_set_feat(y, x, FEAT_RUBBLE);
+}
+
+
+/*
+ * Place an altar at the given location
+ */
+static void place_altar(int y, int x)
+{
+ if (magik(10))
+ cave_set_feat(y, x, 164);
+}
+
+
+/*
+ * Place a fountain at the given location
+ */
+static void place_fountain(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+ int svals[SV_POTION_LAST + SV_POTION2_LAST + 1], maxsval = 0, k;
+
+ /* List of usable svals */
+ for (k = 1; k < max_k_idx; k++)
+ {
+ object_kind *k_ptr = &k_info[k];
+
+ if (((k_ptr->tval == TV_POTION) || (k_ptr->tval == TV_POTION2)) &&
+ (k_ptr->level <= dun_level) && (k_ptr->flags4 & TR4_FOUNTAIN))
+ {
+ if (k_ptr->tval == TV_POTION2) svals[maxsval] = k_ptr->sval + SV_POTION_LAST;
+ else svals[maxsval] = k_ptr->sval;
+ maxsval++;
+ }
+ }
+
+ if (maxsval == 0) return;
+
+ /* Place the fountain */
+ if (randint(100) < 30)
+ {
+ cave_set_feat(y, x, FEAT_EMPTY_FOUNTAIN);
+ c_ptr->special2 = 0;
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_FOUNTAIN);
+ c_ptr->special2 = damroll(3, 4);
+ }
+
+ c_ptr->special = svals[rand_int(maxsval)];
+}
+
+
+/*
+ * Place a between gate at the given location
+ */
+static void place_between(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x], *c1_ptr;
+ int gx, gy;
+
+ while (TRUE)
+ {
+ /* Location */
+ gy = rand_int(cur_hgt);
+ gx = rand_int(cur_wid);
+
+ /* Require "naked" floor grid */
+ if (cave_naked_bold(gy, gx)) break;
+ }
+
+ /* Access the target grid */
+ c1_ptr = &cave[gy][gx];
+
+ /* Place a pair of between gates */
+ cave_set_feat(y, x, FEAT_BETWEEN);
+ c_ptr->special = gx + (gy << 8);
+ cave_set_feat(gy, gx, FEAT_BETWEEN);
+ c1_ptr->special = x + (y << 8);
+}
+
+
+/*
+ * Place an up/down staircase at given location
+ */
+static void place_random_stairs(int y, int x)
+{
+ /* Paranoia */
+ if (!cave_clean_bold(y, x)) return;
+
+ /* Choose a staircase */
+ if (!dun_level)
+ {
+ place_down_stairs(y, x);
+ }
+ else if (is_quest(dun_level) && (dun_level > 1))
+ {
+ place_up_stairs(y, x);
+ }
+ else if (dun_level >= d_info[dungeon_type].maxdepth)
+ {
+ if (d_info[dungeon_type].next)
+ {
+ place_magical_stairs(y, x, d_info[dungeon_type].next);
+ }
+ else
+ {
+ place_up_stairs(y, x);
+ }
+ }
+ else if (rand_int(100) < 50)
+ {
+ place_down_stairs(y, x);
+ }
+ else
+ {
+ place_up_stairs(y, x);
+ }
+}
+
+
+/*
+ * Place a locked door at the given location
+ */
+static void place_locked_door(int y, int x)
+{
+ /* Create locked door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + randint(7));
+}
+
+
+/*
+ * Place a secret door at the given location
+ */
+static void place_secret_door(int y, int x)
+{
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Vaults */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ c_ptr->mimic = FEAT_WALL_INNER;
+ }
+
+ /* Ordinary room -- use current outer or inner wall */
+ else if (c_ptr->info & CAVE_ROOM)
+ {
+ /* Determine if it's inner or outer XXX XXX XXX */
+ if ((cave[y - 1][x].info & CAVE_ROOM) &&
+ (cave[y + 1][x].info & CAVE_ROOM) &&
+ (cave[y][x - 1].info & CAVE_ROOM) &&
+ (cave[y][x + 1].info & CAVE_ROOM))
+ {
+ c_ptr->mimic = feat_wall_inner;
+ }
+ else
+ {
+ c_ptr->mimic = feat_wall_outer;
+ }
+ }
+ else
+ {
+ c_ptr->mimic = fill_type[rand_int(100)];
+ }
+
+ /* Create secret door */
+ cave_set_feat(y, x, FEAT_SECRET);
+}
+
+
+/*
+ * Place a random type of door at the given location
+ */
+static void place_random_door(int y, int x)
+{
+ int tmp;
+
+ /* Choose an object */
+ tmp = rand_int(1000);
+
+ /* Open doors (300/1000) */
+ if (tmp < 300)
+ {
+ /* Create open door */
+ cave_set_feat(y, x, FEAT_OPEN);
+ }
+
+ /* Broken doors (100/1000) */
+ else if (tmp < 400)
+ {
+ /* Create broken door */
+ cave_set_feat(y, x, FEAT_BROKEN);
+ }
+
+ /* Secret doors (200/1000) */
+ else if (tmp < 600)
+ {
+ /* Create secret door */
+ place_secret_door(y, x);
+ }
+
+ /* Closed doors (300/1000) */
+ else if (tmp < 900)
+ {
+ /* Create closed door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
+ }
+
+ /* Locked doors (99/1000) */
+ else if (tmp < 999)
+ {
+ /* Create locked door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + randint(7));
+ }
+
+ /* Stuck doors (1/1000) */
+ else
+ {
+ /* Create jammed door */
+ cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x08 + rand_int(8));
+ }
+}
+
+
+
+/*
+ * Places some staircases near walls
+ */
+static void alloc_stairs(int feat, int num, int walls, int branch)
+{
+ int y, x, i, j, cnt;
+
+ /* Place "num" stairs */
+ for (cnt = 0, i = 0; i < num || (cnt < 1 && num > 1); i++)
+ {
+ /* Try several times, then decrease "walls" */
+ for (j = 0; j <= SAFE_MAX_ATTEMPTS; j++)
+ {
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ place_new_way(&y, &x);
+ }
+ else
+ {
+ /* Pick a random grid */
+ y = rand_int(cur_hgt);
+ x = rand_int(cur_wid);
+
+ /* Require "naked" floor grid */
+ if (!cave_naked_bold(y, x)) continue;
+
+ /* Require a certain number of adjacent walls */
+ if (next_to_walls(y, x) < walls) continue;
+ }
+
+ /* Town -- must go down */
+ if (!dun_level)
+ {
+ /* Clear previous contents, add down stairs */
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ cave_set_feat(y, x, FEAT_WAY_MORE);
+ }
+ else if ((rand_int(3) == 0) && (!(dungeon_flags2 & DF2_NO_SHAFT)))
+ {
+ cave_set_feat(y, x, FEAT_SHAFT_DOWN);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_MORE);
+ }
+ }
+
+ /* Quest -- must go up */
+ else if ((is_quest(dun_level) && (dun_level >= 1)) ||
+ ((dun_level >= d_info[dungeon_type].maxdepth) &&
+ (!(dungeon_flags1 & DF1_FORCE_DOWN))))
+ {
+ /* Clear previous contents, add up stairs */
+ if (dungeon_flags1 & DF1_FLAT)
+ {
+ cave_set_feat(y, x, FEAT_WAY_LESS);
+ }
+ else if ((rand_int(3) == 0) && (!(dungeon_flags2 & DF2_NO_SHAFT)))
+ {
+ cave_set_feat(y, x, FEAT_SHAFT_UP);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_LESS);
+ }
+ }
+
+ /* Requested type */
+ else
+ {
+ /* Clear previous contents, add stairs */
+ cave_set_feat(y, x, feat);
+ }
+
+ cave[y][x].special = branch;
+
+ /* Count the number of stairs we've actually managed to place. */
+ cnt++;
+
+ /* All done */
+ break;
+ }
+
+ /* Require fewer walls */
+ if (walls) walls--;
+ }
+}
+
+
+
+
+/*
+ * Allocates some objects (using "place" and "type")
+ */
+static void alloc_object(int set, int typ, int num)
+{
+ int y = 1, x = 1, k;
+ int dummy = 0;
+
+ /* Place some objects */
+ for (k = 0; k < num; k++)
+ {
+ /* Pick a "legal" spot */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ bool_ room;
+
+ dummy++;
+
+ /* Location */
+ y = rand_int(cur_hgt);
+ x = rand_int(cur_wid);
+
+ /* Require "naked" floor grid */
+ if (!cave_naked_bold(y, x)) continue;
+
+ /* Check for "room" */
+ room = (cave[y][x].info & (CAVE_ROOM)) ? TRUE : FALSE;
+
+ /* Require corridor? */
+ if ((set == ALLOC_SET_CORR) && room) continue;
+
+ /* Require room? */
+ if ((set == ALLOC_SET_ROOM) && !room) continue;
+
+ /* Accept it */
+ break;
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_format("Warning! Could not place object, type : %d!", typ);
+ }
+
+ return;
+ }
+
+
+ /* Place something */
+ switch (typ)
+ {
+ case ALLOC_TYP_RUBBLE:
+ {
+ place_rubble(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_TRAP:
+ {
+ place_trap(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_GOLD:
+ {
+ place_gold(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_OBJECT:
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ break;
+ }
+
+ case ALLOC_TYP_ALTAR:
+ {
+ place_altar(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_BETWEEN:
+ {
+ place_between(y, x);
+ break;
+ }
+
+ case ALLOC_TYP_FOUNTAIN:
+ {
+ place_fountain(y, x);
+ break;
+ }
+ }
+ }
+}
+
+
+/*
+ * The following functions create a rectangle (e.g. outer wall of rooms)
+ */
+void build_rectangle(int y1, int x1, int y2, int x2, int feat, int info)
+{
+ int y, x;
+
+ /* Top and bottom boundaries */
+ for (x = x1; x <= x2; x++)
+ {
+ cave_set_feat(y1, x, feat);
+ cave[y1][x].info |= (info);
+
+ cave_set_feat(y2, x, feat);
+ cave[y2][x].info |= (info);
+ }
+
+ /* Top and bottom boundaries */
+ for (y = y1; y <= y2; y++)
+ {
+ cave_set_feat(y, x1, feat);
+ cave[y][x1].info |= (info);
+
+ cave_set_feat(y, x2, feat);
+ cave[y][x2].info |= (info);
+ }
+}
+
+
+/*
+ * Place water through the dungeon using recursive fractal algorithm
+ *
+ * Why do those good at math and/or algorithms tend *not* to
+ * place any spaces around binary operators? I've been always
+ * wondering. This seems almost a unversal phenomenon...
+ * Tried to make those conform to the rule, but there may still
+ * some left untouched...
+ */
+static void recursive_river(int x1, int y1, int x2, int y2,
+ int feat1, int feat2, int width)
+{
+ int dx, dy, length, l, x, y;
+ int changex, changey;
+ int ty, tx;
+
+
+ length = distance(x1, y1, x2, y2);
+
+ if (length > 4)
+ {
+ /*
+ * Divide path in half and call routine twice.
+ * There is a small chance of splitting the river
+ */
+ dx = (x2 - x1) / 2;
+ dy = (y2 - y1) / 2;
+
+ if (dy != 0)
+ {
+ /* perturbation perpendicular to path */
+ changex = randint(abs(dy)) * 2 - abs(dy);
+ }
+ else
+ {
+ changex = 0;
+ }
+
+ if (dx != 0)
+ {
+ /* perturbation perpendicular to path */
+ changey = randint(abs(dx)) * 2 - abs(dx);
+ }
+ else
+ {
+ changey = 0;
+ }
+
+
+
+ /* construct river out of two smaller ones */
+ recursive_river(x1, y1, x1 + dx + changex, y1 + dy + changey,
+ feat1, feat2, width);
+ recursive_river(x1 + dx + changex, y1 + dy + changey, x2, y2,
+ feat1, feat2, width);
+
+ /* Split the river some of the time -junctions look cool */
+ if ((width > 0) && (rand_int(DUN_WAT_CHG) == 0))
+ {
+ recursive_river(x1 + dx + changex, y1 + dy + changey,
+ x1 + 8 * (dx + changex), y1 + 8 * (dy + changey),
+ feat1, feat2, width - 1);
+ }
+ }
+
+ /* Actually build the river */
+ else
+ {
+ for (l = 0; l < length; l++)
+ {
+ x = x1 + l * (x2 - x1) / length;
+ y = y1 + l * (y2 - y1) / length;
+
+ for (ty = y - width - 1; ty <= y + width + 1; ty++)
+ {
+ for (tx = x - width - 1; tx <= x + width + 1; tx++)
+ {
+ if (!in_bounds(ty, tx)) continue;
+
+ if (cave[ty][tx].feat == feat1) continue;
+ if (cave[ty][tx].feat == feat2) continue;
+
+ if (distance(ty, tx, y, x) > rand_spread(width, 1)) continue;
+
+ /* Do not convert permanent features */
+ if (cave_perma_bold(ty, tx)) continue;
+
+ /*
+ * Clear previous contents, add feature
+ * The border mainly gets feat2, while the center
+ * gets feat1
+ */
+ if (distance(ty, tx, y, x) > width)
+ {
+ cave_set_feat(ty, tx, feat2);
+ }
+ else
+ {
+ cave_set_feat(ty, tx, feat1);
+ }
+
+ /* Lava terrain glows */
+ if ((feat1 == FEAT_DEEP_LAVA) ||
+ (feat1 == FEAT_SHAL_LAVA))
+ {
+ cave[ty][tx].info |= CAVE_GLOW;
+ }
+
+ /* Hack -- don't teleport here */
+ cave[ty][tx].info |= CAVE_ICKY;
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Places water through dungeon.
+ */
+static void add_river(int feat1, int feat2)
+{
+ int y2, x2;
+ int y1 = 0, x1 = 0, wid;
+
+
+ /* Hack -- Choose starting point */
+ y2 = randint(cur_hgt / 2 - 2) + cur_hgt / 2;
+ x2 = randint(cur_wid / 2 - 2) + cur_wid / 2;
+
+ /* Hack -- Choose ending point somewhere on boundary */
+ switch (randint(4))
+ {
+ case 1:
+ {
+ /* top boundary */
+ x1 = randint(cur_wid - 2) + 1;
+ y1 = 1;
+ break;
+ }
+ case 2:
+ {
+ /* left boundary */
+ x1 = 1;
+ y1 = randint(cur_hgt - 2) + 1;
+ break;
+ }
+ case 3:
+ {
+ /* right boundary */
+ x1 = cur_wid - 1;
+ y1 = randint(cur_hgt - 2) + 1;
+ break;
+ }
+ case 4:
+ {
+ /* bottom boundary */
+ x1 = randint(cur_wid - 2) + 1;
+ y1 = cur_hgt - 1;
+ break;
+ }
+ }
+ wid = randint(DUN_WAT_RNG);
+ recursive_river(x1, y1, x2, y2, feat1, feat2, wid);
+}
+
+
+/*
+ * Places "streamers" of rock through dungeon
+ *
+ * Note that their are actually six different terrain features used
+ * to represent streamers. Three each of magma and quartz, one for
+ * basic vein, one with hidden gold, and one with known gold. The
+ * hidden gold types are currently unused.
+ */
+static void build_streamer(int feat, int chance)
+{
+ int i, tx, ty;
+ int y, x, dir;
+ int dummy = 0;
+ cave_type *c_ptr;
+
+
+ /* Hack -- Choose starting point */
+ y = rand_spread(cur_hgt / 2, 10);
+ x = rand_spread(cur_wid / 2, 15);
+
+ /* Choose a random compass direction */
+ dir = ddd[rand_int(8)];
+
+ /* Place streamer into dungeon */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ dummy++;
+
+ /* One grid per density */
+ for (i = 0; i < DUN_STR_DEN; i++)
+ {
+ int d = DUN_STR_RNG;
+
+ /* Pick a nearby grid */
+ while (1)
+ {
+ ty = rand_spread(y, d);
+ tx = rand_spread(x, d);
+ if (!in_bounds2(ty, tx)) continue;
+ break;
+ }
+
+ /* Access the grid */
+ c_ptr = &cave[ty][tx];
+
+ /* Only convert "granite" walls */
+ if ((c_ptr->feat != feat_wall_inner) &&
+ (c_ptr->feat != feat_wall_outer) &&
+ (c_ptr->feat != d_info[dungeon_type].fill_type1) &&
+ (c_ptr->feat != d_info[dungeon_type].fill_type2) &&
+ (c_ptr->feat != d_info[dungeon_type].fill_type3)) continue;
+
+ /* Clear mimic feature to avoid nasty consequences */
+ c_ptr->mimic = 0;
+
+ /* Clear previous contents, add proper vein type */
+ cave_set_feat(ty, tx, feat);
+
+ /* Hack -- Add some (known) treasure */
+ if (rand_int(chance) == 0)
+ {
+ cave_set_feat(ty, tx, c_ptr->feat + 0x04);
+ }
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place streamer!");
+ }
+ return;
+ }
+
+
+ /* Advance the streamer */
+ y += ddy[dir];
+ x += ddx[dir];
+
+ /* Quit before leaving the dungeon */
+ if (!in_bounds(y, x)) break;
+ }
+}
+
+
+
+/*
+ * Place streams of water, lava, & trees -KMW-
+ * This routine varies the placement based on dungeon level
+ * otherwise is similar to build_streamer
+ */
+static void build_streamer2(int feat, int killwall)
+{
+ int i, j, mid, tx, ty;
+ int y, x, dir;
+ int poolchance;
+ int poolsize;
+ cave_type *c_ptr;
+
+ poolchance = randint(10);
+
+ /* Hack -- Choose starting point */
+ y = rand_spread(cur_hgt / 2, 10);
+ x = rand_spread(cur_wid / 2, 15);
+
+ /* Choose a random compass direction */
+ dir = ddd[rand_int(8)];
+
+ /* Place streamer into dungeon */
+ if (poolchance > 2)
+ {
+ while (TRUE)
+ {
+ /* One grid per density */
+ for (i = 0; i < (DUN_STR_DWLW + 1); i++)
+ {
+ int d = DUN_STR_WLW;
+
+ /* Pick a nearby grid */
+ while (1)
+ {
+ ty = rand_spread(y, d);
+ tx = rand_spread(x, d);
+ if (in_bounds(ty, tx)) break;
+ }
+
+ /* Access grid */
+ c_ptr = &cave[ty][tx];
+
+ /* Never convert vaults */
+ if (c_ptr->info & (CAVE_ICKY)) continue;
+
+ /* Reject permanent features */
+ if ((f_info[c_ptr->feat].flags1 & (FF1_PERMANENT)) &&
+ (f_info[c_ptr->feat].flags1 & (FF1_FLOOR))) continue;
+
+ /* Avoid converting walls when told so */
+ if (killwall == 0)
+ {
+ if (f_info[c_ptr->feat].flags1 & FF1_WALL) continue;
+ }
+
+ /* Clear mimic feature to avoid nasty consequences */
+ c_ptr->mimic = 0;
+
+ /* Clear previous contents, add proper vein type */
+ cave_set_feat(ty, tx, feat);
+ }
+
+ /* Advance the streamer */
+ y += ddy[dir];
+ x += ddx[dir];
+
+ /* Change direction */
+ if (rand_int(20) == 0) dir = ddd[rand_int(8)];
+
+ /* Stop at dungeon edge */
+ if (!in_bounds(y, x)) break;
+ }
+ }
+
+ /* Create pool */
+ else if ((feat == FEAT_DEEP_WATER) || (feat == FEAT_DEEP_LAVA))
+ {
+ poolsize = 5 + randint(10);
+ mid = poolsize / 2;
+
+ /* One grid per density */
+ for (i = 0; i < poolsize; i++)
+ {
+ for (j = 0; j < poolsize; j++)
+ {
+ tx = x + j;
+ ty = y + i;
+
+ if (!in_bounds(ty, tx)) continue;
+
+ if (i < mid)
+ {
+ if (j < mid)
+ {
+ if ((i + j + 1) < mid)
+ continue;
+ }
+ else if (j > (mid + i))
+ continue;
+ }
+ else if (j < mid)
+ {
+ if (i > (mid + j))
+ continue;
+ }
+ else if ((i + j) > ((mid * 3)-1))
+ continue;
+
+ /* Only convert non-permanent features */
+ if (f_info[cave[ty][tx].feat].flags1 & FF1_PERMANENT) continue;
+
+ /* Clear mimic feature to avoid nasty consequences */
+ cave[ty][tx].mimic = 0;
+
+ /* Clear previous contents, add proper vein type */
+ cave_set_feat(ty, tx, feat);
+ }
+ }
+ }
+}
+
+
+
+/*
+ * Build a destroyed level
+ */
+static void destroy_level(void)
+{
+ int y1, x1, y, x, k, t, n;
+
+ cave_type *c_ptr;
+
+ /* Note destroyed levels */
+ if ((cheat_room) || (p_ptr->precognition)) msg_print("Destroyed Level");
+
+ /* Drop a few epi-centers (usually about two) */
+ for (n = 0; n < randint(5); n++)
+ {
+ /* Pick an epi-center */
+ x1 = rand_range(5, cur_wid - 1 - 5);
+ y1 = rand_range(5, cur_hgt - 1 - 5);
+
+ /* Big area of affect */
+ for (y = (y1 - 15); y <= (y1 + 15); y++)
+ {
+ for (x = (x1 - 15); x <= (x1 + 15); x++)
+ {
+ /* Skip illegal grids */
+ if (!in_bounds(y, x)) continue;
+
+ /* Extract the distance */
+ k = distance(y1, x1, y, x);
+
+ /* Stay in the circle of death */
+ if (k >= 16) continue;
+
+ /* Delete the monster (if any) */
+ delete_monster(y, x);
+
+ /* Destroy valid grids */
+ if (cave_valid_bold(y, x))
+ {
+ /* Delete objects */
+ delete_object(y, x);
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Wall (or floor) type */
+ t = rand_int(200);
+
+ /* Granite */
+ if (t < 20)
+ {
+ /* Create granite wall */
+ cave_set_feat(y, x, FEAT_WALL_EXTRA);
+ }
+
+ /* Quartz */
+ else if (t < 60)
+ {
+ /* Create quartz vein */
+ cave_set_feat(y, x, FEAT_QUARTZ);
+ }
+
+ /* Magma */
+ else if (t < 90)
+ {
+ /* Create magma vein */
+ cave_set_feat(y, x, FEAT_MAGMA);
+ }
+
+ /* Sand */
+ else if (t < 110)
+ {
+ /* Create sand vein */
+ cave_set_feat(y, x, FEAT_SANDWALL);
+ }
+
+ /* Floor */
+ else
+ {
+ /* Create floor */
+ place_floor(y, x);
+ }
+
+ /* No longer part of a room or vault */
+ c_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
+
+ /* No longer illuminated or known */
+ c_ptr->info &= ~(CAVE_MARK | CAVE_GLOW);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Function that sees if a square is a floor (Includes range checking)
+ */
+static bool_ get_is_floor(int x, int y)
+{
+ /* Out of bounds */
+ if (!in_bounds(y, x)) return (FALSE);
+
+ /* Do the real check: */
+ if (f_info[cave[y][x].feat].flags1 & FF1_FLOOR) return (TRUE);
+
+ return (FALSE);
+}
+
+
+/*
+ * Tunnel around a room if it will cut off part of a cave system
+ */
+static void check_room_boundary(int x1, int y1, int x2, int y2)
+{
+ int count, x, y;
+ bool_ old_is_floor, new_is_floor;
+
+ /* Avoid doing this in irrelevant places -- pelpel */
+ if (!(dungeon_flags1 & DF1_CAVERN)) return;
+
+ /* Initialize */
+ count = 0;
+
+ old_is_floor = get_is_floor(x1 - 1, y1);
+
+ /*
+ * Count the number of floor-wall boundaries around the room
+ * Note: diagonal squares are ignored since the player can move diagonally
+ * to bypass these if needed.
+ */
+
+ /* Above the top boundary */
+ for (x = x1; x <= x2; x++)
+ {
+ new_is_floor = get_is_floor(x, y1 - 1);
+
+ /* increment counter if they are different */
+ if (new_is_floor != old_is_floor) count++;
+
+ old_is_floor = new_is_floor;
+ }
+
+ /* Right boundary */
+ for (y = y1; y <= y2; y++)
+ {
+ new_is_floor = get_is_floor(x2 + 1, y);
+
+ /* increment counter if they are different */
+ if (new_is_floor != old_is_floor) count++;
+
+ old_is_floor = new_is_floor;
+ }
+
+ /* Bottom boundary*/
+ for (x = x2; x >= x1; x--)
+ {
+ new_is_floor = get_is_floor(x, y2 + 1);
+
+ /* Increment counter if they are different */
+ if (new_is_floor != old_is_floor) count++;
+
+ old_is_floor = new_is_floor;
+ }
+
+ /* Left boundary */
+ for (y = y2; y >= y1; y--)
+ {
+ new_is_floor = get_is_floor(x1 - 1, y);
+
+ /* Increment counter if they are different */
+ if (new_is_floor != old_is_floor) count++;
+
+ old_is_floor = new_is_floor;
+ }
+
+
+ /* If all the same, or only one connection exit */
+ if ((count == 0) || (count == 2)) return;
+
+
+ /* Tunnel around the room so to prevent problems with caves */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ if (in_bounds(y, x)) place_floor(y, x);
+ }
+ }
+}
+
+
+/*
+ * Create up to "num" objects near the given coordinates
+ * Only really called by some of the "vault" routines.
+ */
+static void vault_objects(int y, int x, int num)
+{
+ int dummy = 0;
+ int i = 0, j = y, k = x;
+
+
+ /* Attempt to place 'num' objects */
+ for (; num > 0; --num)
+ {
+ /* Try up to 11 spots looking for empty space */
+ for (i = 0; i < 11; ++i)
+ {
+ /* Pick a random location */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ j = rand_spread(y, 2);
+ k = rand_spread(x, 3);
+ dummy++;
+ if (in_bounds(j, k)) break;
+ }
+
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place vault object!");
+ }
+ }
+
+
+ /* Require "clean" floor space */
+ if (!cave_clean_bold(j, k)) continue;
+
+ /* Place an item */
+ if (rand_int(100) < 75)
+ {
+ place_object(j, k, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+
+ /* Place gold */
+ else
+ {
+ place_gold(j, k);
+ }
+
+ /* Placement accomplished */
+ break;
+ }
+ }
+}
+
+
+/*
+ * Place a trap with a given displacement of point
+ */
+static void vault_trap_aux(int y, int x, int yd, int xd)
+{
+ int count = 0, y1 = y, x1 = x;
+ int dummy = 0;
+
+ /* Place traps */
+ for (count = 0; count <= 5; count++)
+ {
+ /* Get a location */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ y1 = rand_spread(y, yd);
+ x1 = rand_spread(x, xd);
+ dummy++;
+ if (in_bounds(y1, x1)) break;
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place vault trap!");
+ }
+ }
+
+
+ /* Require "naked" floor grids */
+ if (!cave_naked_bold(y1, x1)) continue;
+
+ /* Place the trap */
+ place_trap(y1, x1);
+
+ /* Done */
+ break;
+ }
+}
+
+
+/*
+ * Place some traps with a given displacement of given location
+ */
+static void vault_traps(int y, int x, int yd, int xd, int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ {
+ vault_trap_aux(y, x, yd, xd);
+ }
+}
+
+
+/*
+ * Hack -- Place some sleeping monsters near the given location
+ */
+static void vault_monsters(int y1, int x1, int num)
+{
+ int k, i, y, x;
+
+ /* Try to summon "num" monsters "near" the given location */
+ for (k = 0; k < num; k++)
+ {
+ /* Try nine locations */
+ for (i = 0; i < 9; i++)
+ {
+ int d = 1;
+
+ /* Pick a nearby location */
+ scatter(&y, &x, y1, x1, d);
+
+ /* Require "empty" floor grids */
+ if (!cave_empty_bold(y, x)) continue;
+
+ /* Place the monster (allow groups) */
+ monster_level = dun_level + 2;
+ (void)place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ }
+ }
+}
+
+/*
+ * Allocate the space needed by a room in the room_map array.
+ *
+ * width, height represent the size of the room (0...x-1) by (0...y-1).
+ * crowded is used to denote a monset nest.
+ * by0, bx0 are the positions in the room_map array given to the build_type'x'
+ * function.
+ * cx, cy are the returned center of the allocated room in coordinates for
+ * cave.feat and cave.info etc.
+ */
+bool_ room_alloc(int width, int height, bool_ crowded, int by0, int bx0, int *cx, int *cy)
+{
+ int temp, eby, ebx, by, bx;
+
+ /* Calculate number of room_map squares to allocate */
+
+ /* Total number along width */
+ temp = ((width - 1) / BLOCK_WID) + 1;
+
+ for (ebx = bx0 + temp; bx0 > 0 && ebx > dun->col_rooms; bx0--, ebx--);
+
+ if (ebx > dun->col_rooms) return (FALSE);
+
+ /* Total number along height */
+ temp = ((height - 1) / BLOCK_HGT) + 1;
+
+ for (eby = by0 + temp; by0 > 0 && eby > dun->row_rooms; by0--, eby--);
+
+ /* Never run off the screen */
+ if (eby > dun->row_rooms) return (FALSE);
+
+ /* Verify open space */
+ for (by = by0; by < eby; by++)
+ {
+ for (bx = bx0; bx < ebx; bx++)
+ {
+ if (dun->room_map[by][bx]) return (FALSE);
+ }
+ }
+
+ /*
+ * It is *extremely* important that the following calculation
+ * be *exactly* correct to prevent memory errors XXX XXX XXX
+ */
+
+ /* Acquire the location of the room */
+ *cy = ((by0 + eby) * BLOCK_HGT) / 2;
+ *cx = ((bx0 + ebx) * BLOCK_WID) / 2;
+
+ /* Save the room location */
+ if (dun->cent_n < CENT_MAX)
+ {
+ dun->cent[dun->cent_n].y = *cy;
+ dun->cent[dun->cent_n].x = *cx;
+ dun->cent_n++;
+ }
+
+ /* Reserve some blocks */
+ for (by = by0; by < eby; by++)
+ {
+ for (bx = bx0; bx < ebx; bx++)
+ {
+ dun->room_map[by][bx] = TRUE;
+ }
+ }
+
+ /* Count "crowded" rooms */
+ if (crowded) dun->crowded = TRUE;
+
+ /*
+ * Hack -- See if room will cut off a cavern.
+ * If so, fix by tunneling outside the room in such a way as
+ * to conect the caves.
+ */
+ check_room_boundary(*cx - width / 2 - 1, *cy - height / 2 - 1,
+ *cx + width / 2 + 1, *cy + height / 2 + 1);
+
+ /* Success */
+ return (TRUE);
+}
+
+/*
+ * Room building routines.
+ *
+ * Room types:
+ * 1 -- normal
+ * 2 -- overlapping
+ * 3 -- cross shaped
+ * 4 -- large room with features
+ * 5 -- monster nests
+ * 6 -- monster pits
+ * 7 -- simple vaults
+ * 8 -- greater vaults
+ * 9 -- circular rooms
+ */
+
+/*
+ * Type 1 -- normal rectangular rooms
+ */
+static void build_type1(int by0, int bx0)
+{
+ u16b info;
+ int y, x = 1, y2, x2, yval, xval;
+ int y1, x1, xsize, ysize;
+
+ /* Pick a room size */
+ y1 = rand_range(1, 4);
+ x1 = rand_range(1, 10);
+ y2 = rand_range(1, 3);
+ x2 = rand_range(1, 9);
+
+ xsize = x1 + x2;
+ ysize = y1 + y2;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &xval, &yval)) return;
+
+ /* Get corner values */
+ y1 = yval - ysize / 2;
+ x1 = xval - xsize / 2;
+ y2 = y1 + ysize - 1;
+ x2 = x1 + xsize - 1;
+
+ info = (dun_level <= randint(25)) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ /* Place a full floor under the room */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Walls around the room */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, info);
+
+ /* Hack -- Occasional pillar room */
+ if (ysize > 2 && xsize > 2)
+ {
+ if (rand_int(20) == 0)
+ {
+ for (y = y1; y <= y2; y += 2)
+ {
+ for (x = x1; x <= x2; x += 2)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Hack -- Occasional ragged-edge room */
+ else if (rand_int(50) == 0)
+ {
+ for (y = y1 + 2; y <= y2 - 2; y += 2)
+ {
+ cave_set_feat(y, x1, feat_wall_inner);
+ cave_set_feat(y, x2, feat_wall_inner);
+ }
+ for (x = x1 + 2; x <= x2 - 2; x += 2)
+ {
+ cave_set_feat(y1, x, feat_wall_inner);
+ cave_set_feat(y2, x, feat_wall_inner);
+ }
+ }
+ }
+}
+
+/*
+ * Type 2 -- Overlapping rectangular rooms
+ */
+static void build_type2(int by0, int bx0)
+{
+ u16b info;
+ int y, x, yval, xval;
+ int y1a, x1a, y2a, x2a;
+ int y1b, x1b, y2b, x2b;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return;
+
+ /* Determine extents of the first room */
+ y1a = yval - randint(4);
+ y2a = yval + randint(3);
+ x1a = xval - randint(14);
+ x2a = xval + randint(6);
+
+ /* Determine extents of the second room */
+ y1b = yval - randint(3);
+ y2b = yval + randint(4);
+ x1b = xval - randint(6);
+ x2b = xval + randint(14);
+
+ info = (dun_level <= randint(25)) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ /* Place the walls around room "a" */
+ build_rectangle(y1a - 1, x1a - 1, y2a + 1, x2a + 1, feat_wall_outer, info);
+
+ /* Place the walls around room "a" */
+ build_rectangle(y1b - 1, x1b - 1, y2b + 1, x2b + 1, feat_wall_outer, info);
+
+ /* Replace the floor for room "a" */
+ for (y = y1a; y <= y2a; y++)
+ {
+ for (x = x1a; x <= x2a; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Replace the floor for room "b" */
+ for (y = y1b; y <= y2b; y++)
+ {
+ for (x = x1b; x <= x2b; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+}
+
+/*
+ * Type 3 -- Cross shaped rooms
+ *
+ * Builds a room at a row, column coordinate
+ *
+ * Room "a" runs north/south, and Room "b" runs east/east
+ * So the "central pillar" runs from x1a,y1b to x2a,y2b.
+ *
+ * Note that currently, the "center" is always 3x3, but I think that
+ * the code below will work (with "bounds checking") for 5x5, or even
+ * for unsymetric values like 4x3 or 5x3 or 3x4 or 3x5, or even larger.
+ */
+static void build_type3(int by0, int bx0)
+{
+ u16b info;
+ int y, x, dy, dx, wy, wx;
+ int y1a, x1a, y2a, x2a;
+ int y1b, x1b, y2b, x2b;
+ int yval, xval;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return;
+
+ /* For now, always 3x3 */
+ wx = wy = 1;
+
+ /* Pick max vertical size (at most 4) */
+ dy = rand_range(3, 4);
+
+ /* Pick max horizontal size (at most 11) */
+ dx = rand_range(3, 11);
+
+ /* Determine extents of the north/south room */
+ y1a = yval - dy;
+ y2a = yval + dy;
+ x1a = xval - wx;
+ x2a = xval + wx;
+
+ /* Determine extents of the east/west room */
+ y1b = yval - wy;
+ y2b = yval + wy;
+ x1b = xval - dx;
+ x2b = xval + dx;
+
+ info = (dun_level <= randint(25)) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ /* Place the walls around room "a" */
+ build_rectangle(y1a - 1, x1a - 1, y2a + 1, x2a + 1, feat_wall_outer, info);
+
+ /* Place the walls around room "a" */
+ build_rectangle(y1b - 1, x1b - 1, y2b + 1, x2b + 1, feat_wall_outer, info);
+
+ /* Replace the floor for room "a" */
+ for (y = y1a; y <= y2a; y++)
+ {
+ for (x = x1a; x <= x2a; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Replace the floor for room "b" */
+ for (y = y1b; y <= y2b; y++)
+ {
+ for (x = x1b; x <= x2b; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Special features (3/4) */
+ switch (rand_int(4))
+ {
+ /* Large solid middle pillar */
+ case 1:
+ {
+ for (y = y1b; y <= y2b; y++)
+ {
+ for (x = x1a; x <= x2a; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ break;
+ }
+
+ /* Inner treasure vault */
+ case 2:
+ {
+ /* Build the vault */
+ build_rectangle(y1b, x1a, y2b, x2a, feat_wall_inner, info);
+
+ /* Place a secret door on the inner room */
+ switch (rand_int(4))
+ {
+ case 0:
+ place_secret_door(y1b, xval);
+ break;
+ case 1:
+ place_secret_door(y2b, xval);
+ break;
+ case 2:
+ place_secret_door(yval, x1a);
+ break;
+ case 3:
+ place_secret_door(yval, x2a);
+ break;
+ }
+
+ /* Place a treasure in the vault */
+ place_object(yval, xval, FALSE, FALSE, OBJ_FOUND_FLOOR);
+
+ /* Let's guard the treasure well */
+ vault_monsters(yval, xval, rand_int(2) + 3);
+
+ /* Traps naturally */
+ vault_traps(yval, xval, 4, 4, rand_int(3) + 2);
+
+ break;
+ }
+
+ /* Something else */
+ case 3:
+ {
+ /* Occasionally pinch the center shut */
+ if (rand_int(3) == 0)
+ {
+ /* Pinch the east/west sides */
+ for (y = y1b; y <= y2b; y++)
+ {
+ if (y == yval) continue;
+ cave_set_feat(y, x1a - 1, feat_wall_inner);
+ cave_set_feat(y, x2a + 1, feat_wall_inner);
+ }
+
+ /* Pinch the north/south sides */
+ for (x = x1a; x <= x2a; x++)
+ {
+ if (x == xval) continue;
+ cave_set_feat(y1b - 1, x, feat_wall_inner);
+ cave_set_feat(y2b + 1, x, feat_wall_inner);
+ }
+
+ /* Sometimes shut using secret doors */
+ if (rand_int(3) == 0)
+ {
+ place_secret_door(yval, x1a - 1);
+ place_secret_door(yval, x2a + 1);
+ place_secret_door(y1b - 1, xval);
+ place_secret_door(y2b + 1, xval);
+ }
+ }
+
+ /* Occasionally put a "plus" in the center */
+ else if (rand_int(3) == 0)
+ {
+ cave_set_feat(yval, xval, feat_wall_inner);
+ cave_set_feat(y1b, xval, feat_wall_inner);
+ cave_set_feat(y2b, xval, feat_wall_inner);
+ cave_set_feat(yval, x1a, feat_wall_inner);
+ cave_set_feat(yval, x2a, feat_wall_inner);
+ }
+
+ /* Occasionally put a pillar in the center */
+ else if (rand_int(3) == 0)
+ {
+ cave_set_feat(yval, xval, feat_wall_inner);
+ }
+
+ break;
+ }
+ }
+}
+
+/*
+ * Type 4 -- Large room with inner features
+ *
+ * Possible sub-types:
+ * 1 - Just an inner room with one door
+ * 2 - An inner room within an inner room
+ * 3 - An inner room with pillar(s)
+ * 4 - Inner room has a maze
+ * 5 - A set of four inner rooms
+ */
+static void build_type4(int by0, int bx0)
+{
+ u16b info;
+ int y, x, y1, x1;
+ int y2, x2, tmp, yval, xval;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return;
+
+ /* Large room */
+ y1 = yval - 4;
+ y2 = yval + 4;
+ x1 = xval - 11;
+ x2 = xval + 11;
+
+ info = (dun_level <= randint(25)) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ /* Place a full floor under the room */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= info;
+ }
+ }
+
+ /* Outer Walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, info);
+
+ /* The inner room */
+ y1 = y1 + 2;
+ y2 = y2 - 2;
+ x1 = x1 + 2;
+ x2 = x2 - 2;
+
+ /* The inner walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_inner, info);
+
+ /* Inner room variations */
+ switch (randint(5))
+ {
+ /* Just an inner room with a monster */
+ case 1:
+ {
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Place a monster in the room */
+ vault_monsters(yval, xval, 1);
+
+ break;
+ }
+
+ /* Treasure Vault (with a door) */
+ case 2:
+ {
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Place another inner room */
+ build_rectangle(yval - 1, xval - 1, yval + 1, xval + 1,
+ feat_wall_inner, info);
+
+ /* Place a locked door on the inner room */
+ switch (randint(4))
+ {
+ case 1:
+ place_locked_door(yval - 1, xval);
+ break;
+ case 2:
+ place_locked_door(yval + 1, xval);
+ break;
+ case 3:
+ place_locked_door(yval, xval - 1);
+ break;
+ case 4:
+ place_locked_door(yval, xval + 1);
+ break;
+ }
+
+ /* Monsters to guard the "treasure" */
+ vault_monsters(yval, xval, randint(3) + 2);
+
+ /* Object (80%) */
+ if (rand_int(100) < 80)
+ {
+ place_object(yval, xval, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+
+ /* Stairs (20%) */
+ else
+ {
+ place_random_stairs(yval, xval);
+ }
+
+ /* Traps to protect the treasure */
+ vault_traps(yval, xval, 4, 10, 2 + randint(3));
+
+ break;
+ }
+
+ /* Inner pillar(s). */
+ case 3:
+ {
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Large Inner Pillar */
+ for (y = yval - 1; y <= yval + 1; y++)
+ {
+ for (x = xval - 1; x <= xval + 1; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+
+ /* Occasionally, two more Large Inner Pillars */
+ if (rand_int(2) == 0)
+ {
+ tmp = randint(2);
+ for (y = yval - 1; y <= yval + 1; y++)
+ {
+ for (x = xval - 5 - tmp; x <= xval - 3 - tmp; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ for (x = xval + 3 + tmp; x <= xval + 5 + tmp; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Occasionally, some Inner rooms */
+ if (rand_int(3) == 0)
+ {
+ /* Long horizontal walls */
+ for (x = xval - 5; x <= xval + 5; x++)
+ {
+ cave_set_feat(yval - 1, x, feat_wall_inner);
+ cave_set_feat(yval + 1, x, feat_wall_inner);
+ }
+
+ /* Close off the left/right edges */
+ cave_set_feat(yval, xval - 5, feat_wall_inner);
+ cave_set_feat(yval, xval + 5, feat_wall_inner);
+
+ /* Secret doors (random top/bottom) */
+ place_secret_door(yval - 3 + (randint(2) * 2), xval - 3);
+ place_secret_door(yval - 3 + (randint(2) * 2), xval + 3);
+
+ /* Monsters */
+ vault_monsters(yval, xval - 2, randint(2));
+ vault_monsters(yval, xval + 2, randint(2));
+
+ /* Objects */
+ if (rand_int(3) == 0) place_object(yval, xval - 2, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ if (rand_int(3) == 0) place_object(yval, xval + 2, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+
+ break;
+ }
+
+ /* Maze inside. */
+ case 4:
+ {
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Maze (really a checkerboard) */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ if (0x1 & (x + y))
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Monsters just love mazes. */
+ vault_monsters(yval, xval - 5, randint(3));
+ vault_monsters(yval, xval + 5, randint(3));
+
+ /* Traps make them entertaining. */
+ vault_traps(yval, xval - 3, 2, 8, randint(3));
+ vault_traps(yval, xval + 3, 2, 8, randint(3));
+
+ /* Mazes should have some treasure too. */
+ vault_objects(yval, xval, 3);
+
+ break;
+ }
+
+ /* Four small rooms. */
+ case 5:
+ {
+ /* Inner "cross" */
+ for (y = y1; y <= y2; y++)
+ {
+ cave_set_feat(y, xval, feat_wall_inner);
+ }
+
+ for (x = x1; x <= x2; x++)
+ {
+ cave_set_feat(yval, x, feat_wall_inner);
+ }
+
+ /* Doors into the rooms */
+ if (rand_int(100) < 50)
+ {
+ int i = randint(10);
+ place_secret_door(y1 - 1, xval - i);
+ place_secret_door(y1 - 1, xval + i);
+ place_secret_door(y2 + 1, xval - i);
+ place_secret_door(y2 + 1, xval + i);
+ }
+ else
+ {
+ int i = randint(3);
+ place_secret_door(yval + i, x1 - 1);
+ place_secret_door(yval - i, x1 - 1);
+ place_secret_door(yval + i, x2 + 1);
+ place_secret_door(yval - i, x2 + 1);
+ }
+
+ /* Treasure, centered at the center of the cross */
+ vault_objects(yval, xval, 2 + randint(2));
+
+ /* Gotta have some monsters. */
+ vault_monsters(yval + 1, xval - 4, randint(4));
+ vault_monsters(yval + 1, xval + 4, randint(4));
+ vault_monsters(yval - 1, xval - 4, randint(4));
+ vault_monsters(yval - 1, xval + 4, randint(4));
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * Determine if the given monster is appropriate for inclusion in
+ * a monster nest or monster pit or the given type.
+ *
+ * None of the pits/nests are allowed to include "unique" monsters,
+ * or monsters which can "multiply".
+ *
+ * Some of the pits/nests are asked to avoid monsters which can blink
+ * away or which are invisible. This is probably a hack.
+ *
+ * The old method made direct use of monster "names", which is bad.
+ *
+ * Note the use of Angband 2.7.9 monster race pictures in various places.
+ */
+
+
+/*
+ * Helper function for "monster nest (jelly)"
+ */
+static bool_ vault_aux_jelly(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Also decline evil jellies (like death molds and shoggoths) */
+ if (r_ptr->flags3 & (RF3_EVIL)) return (FALSE);
+
+ /* Require icky thing, jelly, mold, or mushroom */
+ if (!strchr("ijm,", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (animal)"
+ */
+static bool_ vault_aux_animal(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require "animal" flag */
+ if (!(r_ptr->flags3 & (RF3_ANIMAL))) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (undead)"
+ */
+static bool_ vault_aux_undead(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require Undead */
+ if (!(r_ptr->flags3 & (RF3_UNDEAD))) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (chapel)"
+ */
+static bool_ vault_aux_chapel(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require "priest" or Angel */
+ if (!((r_ptr->d_char == 'A') || strstr(r_ptr->name, "riest")))
+ {
+ return (FALSE);
+ }
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (kennel)"
+ */
+static bool_ vault_aux_kennel(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require a Zephyr Hound or a dog */
+ return ((r_ptr->d_char == 'Z') || (r_ptr->d_char == 'C'));
+
+}
+
+
+/*
+ * Helper function for "monster nest (treasure)"
+ */
+static bool_ vault_aux_treasure(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Require "priest" or Angel */
+ if (!((r_ptr->d_char == '!') || (r_ptr->d_char == '|') ||
+ (r_ptr->d_char == '$') || (r_ptr->d_char == '?') ||
+ (r_ptr->d_char == '=')))
+ {
+ return (FALSE);
+ }
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster nest (clone)"
+ */
+static bool_ vault_aux_clone(int r_idx)
+{
+ return (r_idx == template_race);
+}
+
+
+/*
+ * Helper function for "monster nest (symbol clone)"
+ */
+static bool_ vault_aux_symbol(int r_idx)
+{
+ return ((r_info[r_idx].d_char == (r_info[template_race].d_char))
+ && !(r_info[r_idx].flags1 & RF1_UNIQUE));
+}
+
+
+/*
+ * Helper function for "monster pit (orc)"
+ */
+static bool_ vault_aux_orc(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "o" monsters */
+ if (!strchr("o", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+
+/*
+ * Helper function for "monster pit (troll)"
+ */
+static bool_ vault_aux_troll(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "T" monsters */
+ if (!strchr("T", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster pit (giant)"
+ */
+static bool_ vault_aux_giant(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "P" monsters */
+ if (!strchr("P", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Hack -- breath type for "vault_aux_dragon()"
+ */
+static u32b vault_aux_dragon_mask4;
+
+
+/*
+ * Helper function for "monster pit (dragon)"
+ */
+static bool_ vault_aux_dragon(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "d" or "D" monsters */
+ if (!strchr("Dd", r_ptr->d_char)) return (FALSE);
+
+ /* Hack -- Require correct "breath attack" */
+ if (r_ptr->flags4 != vault_aux_dragon_mask4) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Helper function for "monster pit (demon)"
+ */
+static bool_ vault_aux_demon(int r_idx)
+{
+ monster_race *r_ptr = &r_info[r_idx];
+
+ /* Decline unique monsters */
+ if (r_ptr->flags1 & (RF1_UNIQUE)) return (FALSE);
+
+ /* Hack -- Require "U" monsters */
+ if (!strchr("U", r_ptr->d_char)) return (FALSE);
+
+ /* Okay */
+ return (TRUE);
+}
+
+
+/*
+ * Type 5 -- Monster nests
+ *
+ * A monster nest is a "big" room, with an "inner" room, containing
+ * a "collection" of monsters of a given type strewn about the room.
+ *
+ * The monsters are chosen from a set of 64 randomly selected monster
+ * races, to allow the nest creation to fail instead of having "holes".
+ *
+ * Note the use of the "get_mon_num_prep()" function, and the special
+ * "get_mon_num_hook()" restriction function, to prepare the "monster
+ * allocation table" in such a way as to optimize the selection of
+ * "appropriate" non-unique monsters for the nest.
+ *
+ * Currently, a monster nest is one of
+ * a nest of "jelly" monsters (Dungeon level 5 and deeper)
+ * a nest of "animal" monsters (Dungeon level 30 and deeper)
+ * a nest of "undead" monsters (Dungeon level 50 and deeper)
+ *
+ * Note that the "get_mon_num()" function may (rarely) fail, in which
+ * case the nest will be empty, and will not affect the level rating.
+ *
+ * Note that "monster nests" will never contain "unique" monsters.
+ */
+static void build_type5(int by0, int bx0)
+{
+ int y, x, y1, x1, y2, x2, xval, yval;
+ int tmp, i;
+ cptr name;
+ bool_ empty = FALSE;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+ s16b what[64];
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, TRUE, by0, bx0, &xval, &yval)) return;
+
+ /* Large room */
+ y1 = yval - 4;
+ y2 = yval + 4;
+ x1 = xval - 11;
+ x2 = xval + 11;
+
+ /* Place the floor area */
+ for (y = y1; y <= y2; y++)
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= (CAVE_ROOM);
+ }
+ }
+
+ /* Place the outer walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, CAVE_ROOM);
+
+ /* Advance to the center room */
+ y1 = y1 + 2;
+ y2 = y2 - 2;
+ x1 = x1 + 2;
+ x2 = x2 - 2;
+
+ /* The inner walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_inner, CAVE_ROOM);
+
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Hack -- Choose a nest type */
+ tmp = randint(dun_level);
+
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ if ((tmp < 25) && (rand_int(2) != 0))
+ {
+ while (1)
+ {
+ template_race = randint(max_r_idx - 2);
+
+ /* Reject uniques */
+ if (r_info[template_race].flags1 & RF1_UNIQUE) continue;
+
+ /* Reject OoD monsters in a loose fashion */
+ if (((r_info[template_race].level) + randint(5)) >
+ (dun_level + randint(5))) continue;
+
+ /* Don't like 'break's like this, but this cannot be made better */
+ break;
+ }
+
+ if ((dun_level >= (25 + randint(15))) && (rand_int(2) != 0))
+ {
+ name = "symbol clone";
+ get_mon_num_hook = vault_aux_symbol;
+ }
+ else
+ {
+ name = "clone";
+ get_mon_num_hook = vault_aux_clone;
+ }
+ }
+ else if (tmp < 25)
+ /* Monster nest (jelly) */
+ {
+ /* Describe */
+ name = "jelly";
+
+ /* Restrict to jelly */
+ get_mon_num_hook = vault_aux_jelly;
+ }
+
+ else if (tmp < 50)
+ {
+ name = "treasure";
+ get_mon_num_hook = vault_aux_treasure;
+ }
+
+ /* Monster nest (animal) */
+ else if (tmp < 65)
+ {
+ if (rand_int(3) == 0)
+ {
+ name = "kennel";
+ get_mon_num_hook = vault_aux_kennel;
+ }
+ else
+ {
+ /* Describe */
+ name = "animal";
+
+ /* Restrict to animal */
+ get_mon_num_hook = vault_aux_animal;
+ }
+ }
+
+ /* Monster nest (undead) */
+ else
+ {
+ if (rand_int(3) == 0)
+ {
+ name = "chapel";
+ get_mon_num_hook = vault_aux_chapel;
+ }
+ else
+ {
+ /* Describe */
+ name = "undead";
+
+ /* Restrict to undead */
+ get_mon_num_hook = vault_aux_undead;
+ }
+ }
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Pick some monster types */
+ for (i = 0; i < 64; i++)
+ {
+ /* Get a (hard) monster type */
+ what[i] = get_mon_num(dun_level + 10);
+
+ /* Notice failure */
+ if (!what[i]) empty = TRUE;
+ }
+
+ /* Remove restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Oops */
+ if (empty) return;
+
+ /* Describe */
+ if (cheat_room || p_ptr->precognition)
+ {
+ /* Room type */
+ msg_format("Monster nest (%s)", name);
+ }
+
+ /* Increase the level rating */
+ rating += 10;
+
+ /* (Sometimes) Cause a "special feeling" (for "Monster Nests") */
+ if ((dun_level <= 40) && (randint(dun_level * dun_level + 50) < 300))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Place some monsters */
+ for (y = yval - 2; y <= yval + 2; y++)
+ {
+ for (x = xval - 9; x <= xval + 9; x++)
+ {
+ int r_idx = what[rand_int(64)];
+
+ /* Place that "random" monster (no groups) */
+ (void)place_monster_aux(y, x, r_idx, FALSE, FALSE, MSTATUS_ENEMY);
+ }
+ }
+}
+
+
+
+/*
+ * Type 6 -- Monster pits
+ *
+ * A monster pit is a "big" room, with an "inner" room, containing
+ * a "collection" of monsters of a given type organized in the room.
+ *
+ * Monster types in the pit (list out of date...)
+ * orc pit (Dungeon Level 5 and deeper)
+ * troll pit (Dungeon Level 20 and deeper)
+ * giant pit (Dungeon Level 40 and deeper)
+ * dragon pit (Dungeon Level 60 and deeper)
+ * demon pit (Dungeon Level 80 and deeper)
+ *
+ * The inside room in a monster pit appears as shown below, where the
+ * actual monsters in each location depend on the type of the pit
+ *
+ * #####################
+ * #0000000000000000000#
+ * #0112233455543322110#
+ * #0112233467643322110#
+ * #0112233455543322110#
+ * #0000000000000000000#
+ * #####################
+ *
+ * Note that the monsters in the pit are now chosen by using "get_mon_num()"
+ * to request 16 "appropriate" monsters, sorting them by level, and using
+ * the "even" entries in this sorted list for the contents of the pit.
+ *
+ * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",
+ * which is handled by requiring a specific "breath" attack for all of the
+ * dragons. This may include "multi-hued" breath. Note that "wyrms" may
+ * be present in many of the dragon pits, if they have the proper breath.
+ *
+ * Note the use of the "get_mon_num_prep()" function, and the special
+ * "get_mon_num_hook()" restriction function, to prepare the "monster
+ * allocation table" in such a way as to optimize the selection of
+ * "appropriate" non-unique monsters for the pit.
+ *
+ * Note that the "get_mon_num()" function may (rarely) fail, in which case
+ * the pit will be empty, and will not effect the level rating.
+ *
+ * Note that "monster pits" will never contain "unique" monsters.
+ */
+static void build_type6(int by0, int bx0)
+{
+ int tmp, what[16];
+ int i, j, y, x, y1, x1, y2, x2, xval, yval;
+ bool_ empty = FALSE;
+ cptr name;
+ bool_ (*old_get_mon_num_hook)(int r_idx);
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(25, 11, TRUE, by0, bx0, &xval, &yval)) return;
+
+ /* Large room */
+ y1 = yval - 4;
+ y2 = yval + 4;
+ x1 = xval - 11;
+ x2 = xval + 11;
+
+ /* Place the floor area */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ place_floor(y, x);
+ cave[y][x].info |= (CAVE_ROOM);
+ }
+ }
+
+ /* Place the outer walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, CAVE_ROOM);
+
+ /* Advance to the center room */
+ y1 = y1 + 2;
+ y2 = y2 - 2;
+ x1 = x1 + 2;
+ x2 = x2 - 2;
+
+ /* The inner walls */
+ build_rectangle(y1 - 1, x1 - 1, y2 + 1, x2 + 1, feat_wall_outer, CAVE_ROOM);
+
+ /* Place a secret door */
+ switch (randint(4))
+ {
+ case 1:
+ place_secret_door(y1 - 1, xval);
+ break;
+ case 2:
+ place_secret_door(y2 + 1, xval);
+ break;
+ case 3:
+ place_secret_door(yval, x1 - 1);
+ break;
+ case 4:
+ place_secret_door(yval, x2 + 1);
+ break;
+ }
+
+ /* Choose a pit type */
+ tmp = randint(dun_level);
+
+ old_get_mon_num_hook = get_mon_num_hook;
+
+ /* Orc pit */
+ if (tmp < 20)
+ {
+ /* Message */
+ name = "orc";
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_orc;
+ }
+
+ /* Troll pit */
+ else if (tmp < 40)
+ {
+ /* Message */
+ name = "troll";
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_troll;
+ }
+
+ /* Giant pit */
+ else if (tmp < 55)
+ {
+ /* Message */
+ name = "giant";
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_giant;
+ }
+
+ else if (tmp < 70)
+ {
+ if (randint(4) != 1)
+ {
+ /* Message */
+ name = "ordered clones";
+
+ do
+ {
+ template_race = randint(max_r_idx - 2);
+ }
+ while ((r_info[template_race].flags1 & RF1_UNIQUE)
+ || (((r_info[template_race].level) + randint(5)) >
+ (dun_level + randint(5))));
+
+ /* Restrict selection */
+ get_mon_num_hook = vault_aux_symbol;
+ }
+ else
+ {
+ name = "ordered chapel";
+ get_mon_num_hook = vault_aux_chapel;
+ }
+
+ }
+
+ /* Dragon pit */
+ else if (tmp < 80)
+ {
+ /* Pick dragon type */
+ switch (rand_int(6))
+ {
+ /* Black */
+ case 0:
+ {
+ /* Message */
+ name = "acid dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_ACID;
+
+ /* Done */
+ break;
+ }
+
+ /* Blue */
+ case 1:
+ {
+ /* Message */
+ name = "electric dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_ELEC;
+
+ /* Done */
+ break;
+ }
+
+ /* Red */
+ case 2:
+ {
+ /* Message */
+ name = "fire dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_FIRE;
+
+ /* Done */
+ break;
+ }
+
+ /* White */
+ case 3:
+ {
+ /* Message */
+ name = "cold dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_COLD;
+
+ /* Done */
+ break;
+ }
+
+ /* Green */
+ case 4:
+ {
+ /* Message */
+ name = "poison dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = RF4_BR_POIS;
+
+ /* Done */
+ break;
+ }
+
+ /* Multi-hued */
+ default:
+ {
+ /* Message */
+ name = "multi-hued dragon";
+
+ /* Restrict dragon breath type */
+ vault_aux_dragon_mask4 = (RF4_BR_ACID | RF4_BR_ELEC |
+ RF4_BR_FIRE | RF4_BR_COLD |
+ RF4_BR_POIS);
+
+ /* Done */
+ break;
+ }
+
+ }
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_dragon;
+ }
+
+ /* Demon pit */
+ else
+ {
+ /* Message */
+ name = "demon";
+
+ /* Restrict monster selection */
+ get_mon_num_hook = vault_aux_demon;
+ }
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Pick some monster types */
+ for (i = 0; i < 16; i++)
+ {
+ /* Get a (hard) monster type */
+ what[i] = get_mon_num(dun_level + 10);
+
+ /* Notice failure */
+ if (!what[i]) empty = TRUE;
+ }
+
+ /* Remove restriction */
+ get_mon_num_hook = old_get_mon_num_hook;
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Oops */
+ if (empty) return;
+
+ /* XXX XXX XXX */
+ /* Sort the entries */
+ for (i = 0; i < 16 - 1; i++)
+ {
+ /* Sort the entries */
+ for (j = 0; j < 16 - 1; j++)
+ {
+ int i1 = j;
+ int i2 = j + 1;
+
+ int p1 = r_info[what[i1]].level;
+ int p2 = r_info[what[i2]].level;
+
+ /* Bubble */
+ if (p1 > p2)
+ {
+ int tmp = what[i1];
+ what[i1] = what[i2];
+ what[i2] = tmp;
+ }
+ }
+ }
+
+ /* Select the entries */
+ for (i = 0; i < 8; i++)
+ {
+ /* Every other entry */
+ what[i] = what[i * 2];
+ }
+
+ /* Message */
+ if (cheat_room || p_ptr->precognition)
+ {
+ /* Room type */
+ msg_format("Monster pit (%s)", name);
+
+ if (cheat_hear || p_ptr->precognition)
+ {
+ /* Contents */
+ for (i = 0; i < 8; i++)
+ {
+ /* Message */
+ msg_print(r_info[what[i]].name);
+ }
+ }
+ }
+
+ /* Increase the level rating */
+ rating += 10;
+
+ /* (Sometimes) Cause a "special feeling" (for "Monster Pits") */
+ if ((dun_level <= 40) && (randint(dun_level * dun_level + 50) < 300))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Top and bottom rows */
+ for (x = xval - 9; x <= xval + 9; x++)
+ {
+ place_monster_aux(yval - 2, x, what[0], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(yval + 2, x, what[0], FALSE, FALSE, MSTATUS_ENEMY);
+ }
+
+ /* Middle columns */
+ for (y = yval - 1; y <= yval + 1; y++)
+ {
+ place_monster_aux(y, xval - 9, what[0], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 9, what[0], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 8, what[1], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 8, what[1], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 7, what[1], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 7, what[1], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 6, what[2], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 6, what[2], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 5, what[2], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 5, what[2], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 4, what[3], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 4, what[3], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 3, what[3], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 3, what[3], FALSE, FALSE, MSTATUS_ENEMY);
+
+ place_monster_aux(y, xval - 2, what[4], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(y, xval + 2, what[4], FALSE, FALSE, MSTATUS_ENEMY);
+ }
+
+ /* Above/Below the center monster */
+ for (x = xval - 1; x <= xval + 1; x++)
+ {
+ place_monster_aux(yval + 1, x, what[5], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(yval - 1, x, what[5], FALSE, FALSE, MSTATUS_ENEMY);
+ }
+
+ /* Next to the center monster */
+ place_monster_aux(yval, xval + 1, what[6], FALSE, FALSE, MSTATUS_ENEMY);
+ place_monster_aux(yval, xval - 1, what[6], FALSE, FALSE, MSTATUS_ENEMY);
+
+ /* Center monster */
+ place_monster_aux(yval, xval, what[7], FALSE, FALSE, MSTATUS_ENEMY);
+}
+
+/*
+ * Hack -- fill in "vault" rooms
+ */
+static void build_vault(int yval, int xval, int ymax, int xmax, cptr data)
+{
+ int dx, dy, x, y, bwy[8], bwx[8], i;
+
+ cptr t;
+
+ cave_type *c_ptr;
+
+ /* Clean the between gates arrays */
+ for (i = 0; i < 8; i++)
+ {
+ bwy[i] = bwx[i] = 9999;
+ }
+
+ /* Place dungeon features and objects */
+ for (t = data, dy = 0; dy < ymax; dy++)
+ {
+ for (dx = 0; dx < xmax; dx++, t++)
+ {
+ /* Extract the location */
+ x = xval - (xmax / 2) + dx;
+ y = yval - (ymax / 2) + dy;
+
+ /* Hack -- skip "non-grids" */
+ if (*t == ' ') continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Lay down a floor */
+ place_floor(y, x);
+
+ /* Part of a vault */
+ c_ptr->info |= (CAVE_ROOM | CAVE_ICKY);
+
+ /* Analyze the grid */
+ switch (*t)
+ {
+ /* Granite wall (outer) */
+ case '%':
+ {
+ cave_set_feat(y, x, FEAT_WALL_OUTER);
+ break;
+ }
+
+ /* Granite wall (inner) */
+ case '#':
+ {
+ cave_set_feat(y, x, FEAT_WALL_INNER);
+ break;
+ }
+
+ /* Permanent wall (inner) */
+ case 'X':
+ {
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+ break;
+ }
+
+ /* Treasure/trap */
+ case '*':
+ {
+ if (rand_int(100) < 75)
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_VAULT);
+ }
+ else
+ {
+ place_trap(y, x);
+ }
+ break;
+ }
+
+ /* Secret doors */
+ case '+':
+ {
+ place_secret_door(y, x);
+ break;
+ }
+
+ /* Trap */
+ case '^':
+ {
+ place_trap(y, x);
+ break;
+ }
+
+ /* Glass wall */
+ case 'G':
+ {
+ cave_set_feat(y, x, FEAT_GLASS_WALL);
+ break;
+ }
+
+ /* Illusion wall */
+ case 'I':
+ {
+ cave_set_feat(y, x, FEAT_ILLUS_WALL);
+ break;
+ }
+ }
+ }
+ }
+
+ /* Place dungeon monsters and objects */
+ for (t = data, dy = 0; dy < ymax; dy++)
+ {
+ for (dx = 0; dx < xmax; dx++, t++)
+ {
+ /* Extract the grid */
+ x = xval - (xmax / 2) + dx;
+ y = yval - (ymax / 2) + dy;
+
+ /* Hack -- skip "non-grids" */
+ if (*t == ' ') continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Analyze the symbol */
+ switch (*t)
+ {
+ /* Monster */
+ case '&':
+ {
+ monster_level = dun_level + 5;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ break;
+ }
+
+ /* Meaner monster */
+ case '@':
+ {
+ monster_level = dun_level + 11;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ break;
+ }
+
+ /* Meaner monster, plus treasure */
+ case '9':
+ {
+ monster_level = dun_level + 9;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ object_level = dun_level + 7;
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_VAULT);
+ object_level = dun_level;
+ break;
+ }
+
+ /* Nasty monster and treasure */
+ case '8':
+ {
+ monster_level = dun_level + 40;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ object_level = dun_level + 20;
+ place_object(y, x, TRUE, TRUE, OBJ_FOUND_VAULT);
+ object_level = dun_level;
+ break;
+ }
+
+ /* Monster and/or object */
+ case ',':
+ {
+ if (rand_int(100) < 50)
+ {
+ monster_level = dun_level + 3;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ }
+ if (rand_int(100) < 50)
+ {
+ object_level = dun_level + 7;
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_VAULT);
+ object_level = dun_level;
+ }
+ break;
+ }
+
+ case 'p':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_START);
+ break;
+ }
+
+ case 'a':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_1);
+ break;
+ }
+
+ case 'b':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_2);
+ break;
+ }
+
+ case 'c':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_3);
+ break;
+ }
+
+ case 'd':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_4);
+ break;
+ }
+
+ case 'P':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_END);
+ break;
+ }
+
+ case 'B':
+ {
+ cave_set_feat(y, x, FEAT_PATTERN_XTRA1);
+ break;
+ }
+
+ case 'A':
+ {
+ object_level = dun_level + 12;
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_VAULT);
+ object_level = dun_level;
+ break;
+ }
+
+
+ /* Between gates */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ /* Not found before */
+ if (bwy[*t - '0'] == 9999)
+ {
+ cave_set_feat(y, x, FEAT_BETWEEN);
+ bwy[*t - '0'] = y;
+ bwx[*t - '0'] = x;
+ }
+ /* The second time */
+ else
+ {
+ cave_set_feat(y, x, FEAT_BETWEEN);
+ c_ptr->special = bwx[*t - '0'] + (bwy[*t - '0'] << 8);
+ cave[bwy[*t - '0']][bwx[*t - '0']].special = x + (y << 8);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Type 7 -- simple vaults (see "v_info.txt")
+ */
+static void build_type7(int by0, int bx0)
+{
+ vault_type *v_ptr = NULL;
+ int dummy = 0, xval, yval;
+
+ /* Pick a lesser vault */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ dummy++;
+
+ /* Access a random vault record */
+ v_ptr = &v_info[rand_int(max_v_idx)];
+
+ /* Accept the first lesser vault */
+ if (v_ptr->typ == 7) break;
+ }
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(v_ptr->wid, v_ptr->hgt, FALSE, by0, bx0, &xval, &yval))
+ {
+ if (cheat_room) msg_print("Could not allocate this vault here");
+ return;
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place lesser vault!");
+ }
+ return;
+ }
+
+
+ /* Message */
+ if (cheat_room || p_ptr->precognition) msg_print("Lesser Vault");
+
+ /* Boost the rating */
+ rating += v_ptr->rat;
+
+ /* (Sometimes) Cause a special feeling */
+ if ((dun_level <= 50) ||
+ (randint((dun_level - 40) * (dun_level - 40) + 50) < 400))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Hack -- Build the vault */
+ build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, v_ptr->data);
+}
+
+
+
+/*
+ * Type 8 -- greater vaults (see "v_info.txt")
+ */
+static void build_type8(int by0, int bx0)
+{
+ vault_type *v_ptr = NULL;
+ int dummy = 0, xval, yval;
+
+ /* Pick a lesser vault */
+ while (dummy < SAFE_MAX_ATTEMPTS)
+ {
+ dummy++;
+
+ /* Access a random vault record */
+ v_ptr = &v_info[rand_int(max_v_idx)];
+
+ /* Accept the first greater vault */
+ if (v_ptr->typ == 8) break;
+ }
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(v_ptr->wid, v_ptr->hgt, FALSE, by0, bx0, &xval, &yval))
+ {
+ if (cheat_room) msg_print("Could not allocate this vault here");
+ return;
+ }
+
+ if (dummy >= SAFE_MAX_ATTEMPTS)
+ {
+ if (cheat_room)
+ {
+ msg_print("Warning! Could not place greater vault!");
+ }
+ return;
+ }
+
+
+ /* Message */
+ if (cheat_room || p_ptr->precognition) msg_print("Greater Vault");
+
+ /* Boost the rating */
+ rating += v_ptr->rat;
+
+ /* (Sometimes) Cause a special feeling */
+ if ((dun_level <= 50) ||
+ (randint((dun_level - 40) * (dun_level - 40) + 50) < 400))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Hack -- Build the vault */
+ build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, v_ptr->data);
+}
+
+/*
+ * DAG:
+ * Build an vertical oval room.
+ * For every grid in the possible square, check the distance.
+ * If it's less than or == than the radius, make it a room square.
+ * If its less, make it a normal grid. If it's == make it an outer
+ * wall.
+ */
+static void build_type9(int by0, int bx0)
+{
+ u16b info;
+ int rad, x, y, x0, y0;
+
+ rad = 2 + rand_int(8);
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(rad*2 + 1, rad*2 + 1, FALSE, by0, bx0, &x0, &y0)) return;
+
+ info = (randint(dun_level) <= 5) ? (CAVE_ROOM|CAVE_GLOW) : CAVE_ROOM;
+
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ if (distance(y0, x0, y, x) == rad)
+ {
+ cave[y][x].info |= info;
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+
+ if (distance(y0, x0, y, x) < rad)
+ {
+ cave[y][x].info |= info;
+ place_floor(y, x);
+ }
+ }
+ }
+}
+
+
+/*
+ * Store routine for the fractal cave generator
+ * this routine probably should be an inline function or a macro
+ */
+static void store_height(int x, int y, int x0, int y0, byte val,
+ int xhsize, int yhsize, int cutoff)
+{
+ /* Only write to points that are "blank" */
+ if (cave[y + y0 - yhsize][x + x0 - xhsize].feat != 255) return;
+
+ /* If on boundary set val > cutoff so walls are not as square */
+ if (((x == 0) || (y == 0) || (x == xhsize * 2) || (y == yhsize * 2)) &&
+ (val <= cutoff)) val = cutoff + 1;
+
+ /* Store the value in height-map format */
+ /* Meant to be temporary, hence no cave_set_feat */
+ cave[y + y0 - yhsize][x + x0 - xhsize].feat = val;
+
+ return;
+}
+
+
+
+/*
+ * Explanation of the plasma fractal algorithm:
+ *
+ * A grid of points is created with the properties of a 'height-map'
+ * This is done by making the corners of the grid have a random value.
+ * The grid is then subdivided into one with twice the resolution.
+ * The new points midway between two 'known' points can be calculated
+ * by taking the average value of the 'known' ones and randomly adding
+ * or subtracting an amount proportional to the distance between those
+ * points. The final 'middle' points of the grid are then calculated
+ * by averaging all four of the originally 'known' corner points. An
+ * random amount is added or subtracted from this to get a value of the
+ * height at that point. The scaling factor here is adjusted to the
+ * slightly larger distance diagonally as compared to orthogonally.
+ *
+ * This is then repeated recursively to fill an entire 'height-map'
+ * A rectangular map is done the same way, except there are different
+ * scaling factors along the x and y directions.
+ *
+ * A hack to change the amount of correlation between points is done using
+ * the grd variable. If the current step size is greater than grd then
+ * the point will be random, otherwise it will be calculated by the
+ * above algorithm. This makes a maximum distance at which two points on
+ * the height map can affect each other.
+ *
+ * How fractal caves are made:
+ *
+ * When the map is complete, a cut-off value is used to create a cave.
+ * Heights below this value are "floor", and heights above are "wall".
+ * This also can be used to create lakes, by adding more height levels
+ * representing shallow and deep water/ lava etc.
+ *
+ * The grd variable affects the width of passages.
+ * The roug variable affects the roughness of those passages
+ *
+ * The tricky part is making sure the created cave is connected. This
+ * is done by 'filling' from the inside and only keeping the 'filled'
+ * floor. Walls bounding the 'filled' floor are also kept. Everything
+ * else is converted to the normal granite FEAT_WALL_EXTRA.
+ */
+
+
+/*
+ * Note that this uses the cave.feat array in a very hackish way
+ * the values are first set to zero, and then each array location
+ * is used as a "heightmap"
+ * The heightmap then needs to be converted back into the "feat" format.
+ *
+ * grd=level at which fractal turns on. smaller gives more mazelike caves
+ * roug=roughness level. 16=normal. higher values make things more
+ * convoluted small values are good for smooth walls.
+ * size=length of the side of the square cave system.
+ */
+
+void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd,
+ int roug, int cutoff)
+{
+ int xhsize, yhsize, xsize, ysize, maxsize;
+
+ /*
+ * fixed point variables- these are stored as 256 x normal value
+ * this gives 8 binary places of fractional part + 8 places of normal part
+ */
+ u16b xstep, xhstep, ystep, yhstep, i, j, diagsize, xxsize, yysize;
+
+
+ /* Redefine size so can change the value if out of range */
+ xsize = xsiz;
+ ysize = ysiz;
+
+ /* Paranoia about size of the system of caves*/
+ if (xsize > 254) xsize = 254;
+ if (xsize < 4) xsize = 4;
+ if (ysize > 254) ysize = 254;
+ if (ysize < 4) ysize = 4;
+
+ /* Get offsets to middle of array */
+ xhsize = xsize / 2;
+ yhsize = ysize / 2;
+
+ /* Fix rounding problem */
+ xsize = xhsize * 2;
+ ysize = yhsize * 2;
+
+ /*
+ * Scale factor for middle points:
+ * About sqrt(2)*256 - correct for a square lattice
+ * approximately correct for everything else.
+ */
+ diagsize = 362;
+
+ /* Maximum of xsize and ysize */
+ maxsize = (xsize > ysize) ? xsize : ysize;
+
+ /* Clear the section */
+ for (i = 0; i <= xsize; i++)
+ {
+ for (j = 0; j <= ysize; j++)
+ {
+ cave_type *c_ptr;
+
+ /* Access the grid */
+ c_ptr = &cave[j + y0 - yhsize][i + x0 - xhsize];
+
+ /* 255 is a flag for "not done yet" */
+ c_ptr->feat = 255;
+
+ /* Clear icky flag because may be redoing the cave */
+ c_ptr->info &= ~(CAVE_ICKY);
+ }
+ }
+
+ /* Set the corner values just in case grd>size. */
+ store_height(0, 0, x0, y0, maxsize, xhsize, yhsize, cutoff);
+ store_height(0, ysize, x0, y0, maxsize, xhsize, yhsize, cutoff);
+ store_height(xsize, 0, x0, y0, maxsize, xhsize, yhsize, cutoff);
+ store_height(xsize, ysize, x0, y0, maxsize, xhsize, yhsize, cutoff);
+
+ /* Set the middle square to be an open area. */
+ store_height(xhsize, yhsize, x0, y0, 0, xhsize, yhsize, cutoff);
+
+
+ /* Initialise the step sizes */
+ xstep = xhstep = xsize * 256;
+ ystep = yhstep = ysize * 256;
+ xxsize = xsize * 256;
+ yysize = ysize * 256;
+
+ /*
+ * Fill in the rectangle with fractal height data - like the
+ * 'plasma fractal' in fractint
+ */
+ while ((xstep / 256 > 1) || (ystep / 256 > 1))
+ {
+ /* Halve the step sizes */
+ xstep = xhstep;
+ xhstep /= 2;
+ ystep = yhstep;
+ yhstep /= 2;
+
+ /* Middle top to bottom */
+ for (i = xhstep; i <= xxsize - xhstep; i += xstep)
+ {
+ for (j = 0; j <= yysize; j += ystep)
+ {
+ /* If greater than 'grid' level then is random */
+ if (xhstep / 256 > grd)
+ {
+ store_height(i / 256, j / 256, x0, y0, randint(maxsize),
+ xhsize, yhsize, cutoff);
+ }
+ else
+ {
+ cave_type *l, *r;
+ byte val;
+
+ /* Left point */
+ l = &cave[j / 256 + y0 - yhsize][(i - xhstep) / 256 + x0 - xhsize];
+
+ /* Right point */
+ r = &cave[j / 256 + y0 - yhsize][(i + xhstep) / 256 + x0 - xhsize];
+
+ /* Average of left and right points + random bit */
+ val = (l->feat + r->feat) / 2 +
+ (randint(xstep / 256) - xhstep / 256) * roug / 16;
+
+ store_height(i / 256, j / 256, x0, y0, val,
+ xhsize, yhsize, cutoff);
+ }
+ }
+ }
+
+
+ /* Middle left to right */
+ for (j = yhstep; j <= yysize - yhstep; j += ystep)
+ {
+ for (i = 0; i <= xxsize; i += xstep)
+ {
+ /* If greater than 'grid' level then is random */
+ if (xhstep / 256 > grd)
+ {
+ store_height(i / 256, j / 256, x0, y0, randint(maxsize),
+ xhsize, yhsize, cutoff);
+ }
+ else
+ {
+ cave_type *u, *d;
+ byte val;
+
+ /* Up point */
+ u = &cave[(j - yhstep) / 256 + y0 - yhsize][i / 256 + x0 - xhsize];
+
+ /* Down point */
+ d = &cave[(j + yhstep) / 256 + y0 - yhsize][i / 256 + x0 - xhsize];
+
+ /* Average of up and down points + random bit */
+ val = (u->feat + d->feat) / 2 +
+ (randint(ystep / 256) - yhstep / 256) * roug / 16;
+
+ store_height(i / 256, j / 256, x0, y0, val,
+ xhsize, yhsize, cutoff);
+ }
+ }
+ }
+
+ /* Center */
+ for (i = xhstep; i <= xxsize - xhstep; i += xstep)
+ {
+ for (j = yhstep; j <= yysize - yhstep; j += ystep)
+ {
+ /* If greater than 'grid' level then is random */
+ if (xhstep / 256 > grd)
+ {
+ store_height(i / 256, j / 256, x0, y0, randint(maxsize),
+ xhsize, yhsize, cutoff);
+ }
+ else
+ {
+ cave_type *ul, *dl, *ur, *dr;
+ byte val;
+
+ /* Up-left point */
+ ul = &cave[(j - yhstep) / 256 + y0 - yhsize][(i - xhstep) / 256 + x0 - xhsize];
+
+ /* Down-left point */
+ dl = &cave[(j + yhstep) / 256 + y0 - yhsize][(i - xhstep) / 256 + x0 - xhsize];
+
+ /* Up-right point */
+ ur = &cave[(j - yhstep) / 256 + y0 - yhsize][(i + xhstep) / 256 + x0 - xhsize];
+
+ /* Down-right point */
+ dr = &cave[(j + yhstep) / 256 + y0 - yhsize][(i + xhstep) / 256 + x0 - xhsize];
+
+ /*
+ * average over all four corners + scale by diagsize to
+ * reduce the effect of the square grid on the shape
+ * of the fractal
+ */
+ val = (ul->feat + dl->feat + ur->feat + dr->feat) / 4 +
+ (randint(xstep / 256) - xhstep / 256) *
+ (diagsize / 16) / 256 * roug;
+
+ store_height(i / 256, j / 256, x0, y0, val,
+ xhsize, yhsize , cutoff);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Convert from height-map back to the normal Angband cave format
+ */
+static bool_ hack_isnt_wall(int y, int x, int cutoff)
+{
+ /* Already done */
+ if (cave[y][x].info & CAVE_ICKY)
+ {
+ return (FALSE);
+ }
+
+ else
+ {
+ /* Show that have looked at this square */
+ cave[y][x].info |= (CAVE_ICKY);
+
+ /* If less than cutoff then is a floor */
+ if (cave[y][x].feat <= cutoff)
+ {
+ place_floor(y, x);
+ return (TRUE);
+ }
+
+ /* If greater than cutoff then is a wall */
+ else
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ return (FALSE);
+ }
+ }
+}
+
+
+/*
+ * Quick and nasty fill routine used to find the connected region
+ * of floor in the middle of the cave
+ */
+static void fill_hack(int y0, int x0, int y, int x, int xsize, int ysize,
+ int cutoff, int *amount)
+{
+ int i, j;
+
+ /* check 8 neighbours +self (self is caught in the isnt_wall function) */
+ for (i = -1; i <= 1; i++)
+ {
+ for (j = -1; j <= 1; j++)
+ {
+ /* If within bounds */
+ if ((x + i > 0) && (x + i < xsize) &&
+ (y + j > 0) && (y + j < ysize))
+ {
+ /* If not a wall or floor done before */
+ if (hack_isnt_wall(y + j + y0 - ysize / 2,
+ x + i + x0 - xsize / 2, cutoff))
+ {
+ /* then fill from the new point*/
+ fill_hack(y0, x0, y + j, x + i, xsize, ysize,
+ cutoff, amount);
+
+ /* keep tally of size of cave system */
+ (*amount)++;
+ }
+ }
+
+ /* Affect boundary */
+ else
+ {
+ cave[y0 + y + j - ysize / 2][x0 + x + i - xsize / 2].info |= (CAVE_ICKY);
+ }
+ }
+ }
+}
+
+
+bool_ generate_fracave(int y0, int x0, int xsize, int ysize,
+ int cutoff, bool_ light, bool_ room)
+{
+ int x, y, i, amount, xhsize, yhsize;
+ cave_type *c_ptr;
+
+ /* Offsets to middle from corner */
+ xhsize = xsize / 2;
+ yhsize = ysize / 2;
+
+ /* Reset tally */
+ amount = 0;
+
+ /*
+ * Select region connected to center of cave system
+ * this gets rid of alot of isolated one-sqaures that
+ * can make teleport traps instadeaths...
+ */
+ fill_hack(y0, x0, yhsize, xhsize, xsize, ysize, cutoff, &amount);
+
+ /* If tally too small, try again */
+ if (amount < 10)
+ {
+ /* Too small -- clear area and try again later */
+ for (x = 0; x <= xsize; ++x)
+ {
+ for (y = 0; y < ysize; ++y)
+ {
+ place_filler(y0 + y - yhsize, x0 + x - xhsize);
+ cave[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM);
+ }
+ }
+ return FALSE;
+ }
+
+
+ /*
+ * Do boundaries -- check to see if they are next to a filled region
+ * If not then they are set to normal granite
+ * If so then they are marked as room walls
+ */
+ for (i = 0; i <= xsize; ++i)
+ {
+ /* Access top boundary grid */
+ c_ptr = &cave[0 + y0 - yhsize][i + x0 - xhsize];
+
+ /* Next to a 'filled' region? -- set to be room walls */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ cave_set_feat(0 + y0 - yhsize, i + x0 - xhsize, feat_wall_outer);
+
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(0 + y0 - yhsize, i + x0 - xhsize);
+ }
+ }
+
+ /* Outside of the room -- set to be normal granite */
+ else
+ {
+ place_filler(0 + y0 - yhsize, i + x0 - xhsize);
+ }
+
+ /* Clear the icky flag -- don't need it any more */
+ c_ptr->info &= ~(CAVE_ICKY);
+
+
+ /* Access bottom boundary grid */
+ c_ptr = &cave[ysize + y0 - yhsize][i + x0 - xhsize];
+
+ /* Next to a 'filled' region? -- set to be room walls */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ cave_set_feat(ysize + y0 - yhsize, i + x0 - xhsize, feat_wall_outer);
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(ysize + y0 - yhsize, i + x0 - xhsize);
+ }
+ }
+
+ /* Outside of the room -- set to be normal granite */
+ else
+ {
+ place_filler(ysize + y0 - yhsize, i + x0 - xhsize);
+ }
+
+ /* Clear the icky flag -- don't need it any more */
+ c_ptr->info &= ~(CAVE_ICKY);
+ }
+
+
+ /* Do the left and right boundaries minus the corners (done above) */
+ for (i = 1; i < ysize; ++i)
+ {
+ /* Access left boundary grid */
+ c_ptr = &cave[i + y0 - yhsize][0 + x0 - xhsize];
+
+ /* Next to a 'filled' region? -- set to be room walls */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ cave_set_feat(i + y0 - yhsize, 0 + x0 - xhsize, feat_wall_outer);
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(i + y0 - yhsize, 0 + x0 - xhsize);
+ }
+ }
+
+ /* Outside of the room -- set to be normal granite */
+ else
+ {
+ place_filler(i + y0 - yhsize, 0 + x0 - xhsize);
+ }
+
+ /* Clear the icky flag -- don't need it any more */
+ c_ptr->info &= ~(CAVE_ICKY);
+
+
+ /* Access left boundary grid */
+ c_ptr = &cave[i + y0 - yhsize][xsize + x0 - xhsize];
+
+ /* Next to a 'filled' region? -- set to be room walls */
+ if (c_ptr->info & CAVE_ICKY)
+ {
+ cave_set_feat(i + y0 - yhsize, xsize + x0 - xhsize, feat_wall_outer);
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(i + y0 - yhsize, xsize + x0 - xhsize);
+ }
+ }
+
+ /* Outside of the room -- set to be normal granite */
+ else
+ {
+ place_filler(i + y0 - yhsize, xsize + x0 - xhsize);
+ }
+
+ /* Clear the icky flag -- don't need it any more */
+ c_ptr->info &= ~(CAVE_ICKY);
+ }
+
+
+ /*
+ * Do the rest: convert back to the normal format
+ * In other variants, may want to check to see if cave.feat< some value
+ * if so, set to be water:- this will make interesting pools etc.
+ * (I don't do this for standard Angband.)
+ */
+ for (x = 1; x < xsize; ++x)
+ {
+ for (y = 1; y < ysize; ++y)
+ {
+ /* Access the grid */
+ c_ptr = &cave[y + y0 - yhsize][x + x0 - xhsize];
+
+ /* A floor grid to be converted */
+ if ((f_info[c_ptr->feat].flags1 & FF1_FLOOR) &&
+ (c_ptr->info & CAVE_ICKY))
+
+ {
+ /* Clear the icky flag in the filled region */
+ c_ptr->info &= ~(CAVE_ICKY);
+
+ /* Set appropriate flags */
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room) c_ptr->info |= (CAVE_ROOM);
+ }
+
+ /* A wall grid to be convereted */
+ else if ((c_ptr->feat == feat_wall_outer) &&
+ (c_ptr->info & CAVE_ICKY))
+ {
+ /* Clear the icky flag in the filled region */
+ c_ptr->info &= ~(CAVE_ICKY);
+
+ /* Set appropriate flags */
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ if (room)
+ {
+ c_ptr->info |= (CAVE_ROOM);
+ }
+ else
+ {
+ place_filler(y + y0 - yhsize, x + x0 - xhsize);
+ }
+ }
+
+ /* None of the above -- clear the unconnected regions */
+ else
+ {
+ place_filler(y + y0 - yhsize, x + x0 - xhsize);
+ c_ptr->info &= ~(CAVE_ICKY | CAVE_ROOM);
+ }
+ }
+ }
+
+ /*
+ * XXX XXX XXX There is a slight problem when tunnels pierce the caves:
+ * Extra doors appear inside the system. (Its not very noticeable though.)
+ * This can be removed by "filling" from the outside in. This allows
+ * a separation from FEAT_WALL_OUTER with FEAT_WALL_INNER. (Internal
+ * walls are F.W.OUTER instead.)
+ * The extra effort for what seems to be only a minor thing (even
+ * non-existant if you think of the caves not as normal rooms, but as
+ * holes in the dungeon), doesn't seem worth it.
+ */
+
+ return (TRUE);
+}
+
+
+/*
+ * Makes a cave system in the center of the dungeon
+ */
+static void build_cavern(void)
+{
+ int grd, roug, cutoff, xsize, ysize, x0, y0;
+ bool_ done, light, room;
+
+ light = done = room = FALSE;
+ if (dun_level <= randint(25)) light = TRUE;
+
+ /* Make a cave the size of the dungeon */
+ xsize = cur_wid - 1;
+ ysize = cur_hgt - 1;
+ x0 = xsize / 2;
+ y0 = ysize / 2;
+
+ /* Paranoia: make size even */
+ xsize = x0 * 2;
+ ysize = y0 * 2;
+
+ while (!done)
+ {
+ /* Testing values for these parameters: feel free to adjust */
+ grd = 1 << (randint(4) + 4);
+
+ /* Want average of about 16 */
+ roug = randint(8) * randint(4);
+
+ /* About size/2 */
+ cutoff = xsize / 2;
+
+ /* Make it */
+ generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff);
+
+ /* Convert to normal format+ clean up*/
+ done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room);
+ }
+}
+
+/*
+ * Driver routine to create fractal cave system
+ */
+static void build_type10(int by0, int bx0)
+{
+ int grd, roug, cutoff, xsize, ysize, y0, x0;
+
+ bool_ done, light, room;
+
+ /* Get size: note 'Evenness'*/
+ xsize = randint(22) * 2 + 6;
+ ysize = randint(15) * 2 + 6;
+
+ /* Try to allocate space for room. If fails, exit */
+ if (!room_alloc(xsize + 1, ysize + 1, FALSE, by0, bx0, &x0, &y0)) return;
+
+ light = done = FALSE;
+ room = TRUE;
+
+ if (dun_level <= randint(25)) light = TRUE;
+
+ while (!done)
+ {
+ /*
+ * Note: size must be even or there are rounding problems
+ * This causes the tunnels not to connect properly to the room
+ */
+
+ /* Testing values for these parameters feel free to adjust */
+ grd = 1 << (randint(4));
+
+ /* Want average of about 16 */
+ roug = randint(8) * randint(4);
+
+ /* About size/2 */
+ cutoff = randint(xsize / 4) + randint(ysize / 4) +
+ randint(xsize / 4) + randint(ysize / 4);
+
+ /* Make it */
+ generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff);
+
+ /* Convert to normal format + clean up*/
+ done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room);
+ }
+}
+
+
+/*
+ * Random vault generation from Z 2.5.1
+ */
+
+/*
+ * Make a very small room centred at (x0, y0)
+ *
+ * This is used in crypts, and random elemental vaults.
+ *
+ * Note - this should be used only on allocated regions
+ * within another room.
+ */
+static void build_small_room(int x0, int y0)
+{
+ build_rectangle(y0 - 1, x0 - 1, y0 + 1, x0 + 1, feat_wall_inner, CAVE_ROOM);
+
+ /* Place a secret door on one side */
+ switch (rand_int(4))
+ {
+ case 0:
+ {
+ place_secret_door(y0, x0 - 1);
+ break;
+ }
+
+ case 1:
+ {
+ place_secret_door(y0, x0 + 1);
+ break;
+ }
+
+ case 2:
+ {
+ place_secret_door(y0 - 1, x0);
+ break;
+ }
+
+ case 3:
+ {
+ place_secret_door(y0 + 1, x0);
+ break;
+ }
+ }
+
+ /* Add inner open space */
+ place_floor(y0, x0);
+}
+
+
+/*
+ * Add a door to a location in a random vault
+ *
+ * Note that range checking has to be done in the calling routine.
+ *
+ * The doors must be INSIDE the allocated region.
+ */
+static void add_door(int x, int y)
+{
+ /* Need to have a wall in the center square */
+ if (cave[y][x].feat != feat_wall_outer) return;
+
+ /*
+ * Look at:
+ * x#x
+ * .#.
+ * x#x
+ *
+ * where x=don't care
+ * .=floor, #=wall
+ */
+
+ if (get_is_floor(x, y - 1) && get_is_floor(x, y + 1) &&
+ (cave[y][x - 1].feat == feat_wall_outer) &&
+ (cave[y][x + 1].feat == feat_wall_outer))
+ {
+ /* secret door */
+ place_secret_door(y, x);
+
+ /* set boundarys so don't get wide doors */
+ place_filler(y, x - 1);
+ place_filler(y, x + 1);
+ }
+
+
+ /*
+ * Look at:
+ * x#x
+ * .#.
+ * x#x
+ *
+ * where x = don't care
+ * .=floor, #=wall
+ */
+ if ((cave[y - 1][x].feat == feat_wall_outer) &&
+ (cave[y + 1][x].feat == feat_wall_outer) &&
+ get_is_floor(x - 1, y) && get_is_floor(x + 1, y))
+ {
+ /* secret door */
+ place_secret_door(y, x);
+
+ /* set boundarys so don't get wide doors */
+ place_filler(y - 1, x);
+ place_filler(y + 1, x);
+ }
+}
+
+
+/*
+ * Fill the empty areas of a room with treasure and monsters.
+ */
+static void fill_treasure(int x1, int x2, int y1, int y2, int difficulty)
+{
+ int x, y, cx, cy, size;
+ s32b value;
+
+ /* center of room:*/
+ cx = (x1 + x2) / 2;
+ cy = (y1 + y2) / 2;
+
+ /* Rough measure of size of vault= sum of lengths of sides */
+ size = abs(x2 - x1) + abs(y2 - y1);
+
+ for (x = x1; x <= x2; x++)
+ {
+ for (y = y1; y <= y2; y++)
+ {
+ /*
+ * Thing added based on distance to center of vault
+ * Difficulty is 1-easy to 10-hard
+ */
+ value = ((static_cast<s32b>(distance(cx, cy, x, y)) * 100) / size) +
+ randint(10) - difficulty;
+
+ /* Hack -- Empty square part of the time */
+ if ((randint(100) - difficulty * 3) > 50) value = 20;
+
+ /* If floor, shallow water or lava */
+ if (get_is_floor(x, y) ||
+ (cave[y][x].feat == FEAT_SHAL_WATER) ||
+ (cave[y][x].feat == FEAT_SHAL_LAVA))
+ {
+ /* The smaller 'value' is, the better the stuff */
+ if (value < 0)
+ {
+ /* Meanest monster + treasure */
+ monster_level = dun_level + 40;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ object_level = dun_level + 20;
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_FLOOR);
+ object_level = dun_level;
+ }
+ else if (value < 5)
+ {
+ /* Mean monster +treasure */
+ monster_level = dun_level + 20;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ object_level = dun_level + 10;
+ place_object(y, x, TRUE, FALSE, OBJ_FOUND_FLOOR);
+ object_level = dun_level;
+ }
+ else if (value < 10)
+ {
+ /* Monster */
+ monster_level = dun_level + 9;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ }
+ else if (value < 17)
+ {
+ /* Intentional Blank space */
+
+ /*
+ * (Want some of the vault to be empty
+ * so have room for group monsters.
+ * This is used in the hack above to lower
+ * the density of stuff in the vault.)
+ */
+ }
+ else if (value < 23)
+ {
+ /* Object or trap */
+ if (rand_int(100) < 25)
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+ else
+ {
+ place_trap(y, x);
+ }
+ }
+ else if (value < 30)
+ {
+ /* Monster and trap */
+ monster_level = dun_level + 5;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ place_trap(y, x);
+ }
+ else if (value < 40)
+ {
+ /* Monster or object */
+ if (rand_int(100) < 50)
+ {
+ monster_level = dun_level + 3;
+ place_monster(y, x, TRUE, TRUE);
+ monster_level = dun_level;
+ }
+ if (rand_int(100) < 50)
+ {
+ object_level = dun_level + 7;
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ object_level = dun_level;
+ }
+ }
+ else if (value < 50)
+ {
+ /* Trap */
+ place_trap(y, x);
+ }
+ else
+ {
+ /* Various Stuff */
+
+ /* 20% monster, 40% trap, 20% object, 20% blank space */
+ if (rand_int(100) < 20)
+ {
+ place_monster(y, x, TRUE, TRUE);
+ }
+ else if (rand_int(100) < 50)
+ {
+ place_trap(y, x);
+ }
+ else if (rand_int(100) < 50)
+ {
+ place_object(y, x, FALSE, FALSE, OBJ_FOUND_FLOOR);
+ }
+ }
+
+ }
+ }
+ }
+}
+
+
+/*
+ * Creates a random vault that looks like a collection of bubbles
+ *
+ * It works by getting a set of coordinates that represent the center of
+ * each bubble. The entire room is made by seeing which bubble center is
+ * closest. If two centers are equidistant then the square is a wall,
+ * otherwise it is a floor. The only exception is for squares really
+ * near a center, these are always floor.
+ * (It looks better than without this check.)
+ *
+ * Note: If two centers are on the same point then this algorithm will create a
+ * blank bubble filled with walls. - This is prevented from happening.
+ */
+
+#define BUBBLENUM 10 /* number of bubbles */
+
+static void build_bubble_vault(int x0, int y0, int xsize, int ysize)
+{
+ /* array of center points of bubbles */
+ coord center[BUBBLENUM];
+
+ int i, j, k, x = 0, y = 0;
+ u16b min1, min2, temp;
+ bool_ done;
+
+ /* Offset from center to top left hand corner */
+ int xhsize = xsize / 2;
+ int yhsize = ysize / 2;
+
+ if (cheat_room) msg_print("Bubble Vault");
+
+ /* Allocate center of bubbles */
+ center[0].x = randint(xsize - 3) + 1;
+ center[0].y = randint(ysize - 3) + 1;
+
+ for (i = 1; i < BUBBLENUM; i++)
+ {
+ done = FALSE;
+
+ /* Get center and check to see if it is unique */
+ for (k = 0; !done && (k < 2000); k++)
+ {
+ done = TRUE;
+
+ x = randint(xsize - 3) + 1;
+ y = randint(ysize - 3) + 1;
+
+ for (j = 0; j < i; j++)
+ {
+ /* Rough test to see if there is an overlap */
+ if ((x == center[j].x) || (y == center[j].y)) done = FALSE;
+ }
+ }
+
+ /* Too many failures */
+ if (k >= 2000) return;
+
+ center[i].x = x;
+ center[i].y = y;
+ }
+
+ build_rectangle(y0 - yhsize, x0 - xhsize,
+ y0 - yhsize + ysize - 1, x0 - xhsize + xsize - 1,
+ feat_wall_outer, CAVE_ROOM | CAVE_ICKY);
+
+ /* Fill in middle with bubbles */
+ for (x = 1; x < xsize - 1; x++)
+ {
+ for (y = 1; y < ysize - 1; y++)
+ {
+ cave_type *c_ptr;
+
+ /* Get distances to two closest centers */
+
+ /* Initialise */
+ min1 = distance(x, y, center[0].x, center[0].y);
+ min2 = distance(x, y, center[1].x, center[1].y);
+
+ if (min1 > min2)
+ {
+ /* Swap if in wrong order */
+ temp = min1;
+ min1 = min2;
+ min2 = temp;
+ }
+
+ /* Scan the rest */
+ for (i = 2; i < BUBBLENUM; i++)
+ {
+ temp = distance(x, y, center[i].x, center[i].y);
+
+ if (temp < min1)
+ {
+ /* Smallest */
+ min2 = min1;
+ min1 = temp;
+ }
+ else if (temp < min2)
+ {
+ /* Second smallest */
+ min2 = temp;
+ }
+ }
+
+ /* Access the grid */
+ c_ptr = &cave[y + y0 - yhsize][x + x0 - xhsize];
+
+ /*
+ * Boundary at midpoint+ not at inner region of bubble
+ *
+ * SCSCSC: was feat_wall_outer
+ */
+ if (((min2 - min1) <= 2) && (!(min1 < 3)))
+ {
+ place_filler(y + y0 - yhsize, x + x0 - xhsize);
+ }
+
+ /* Middle of a bubble */
+ else
+ {
+ place_floor(y + y0 - yhsize, x + x0 - xhsize);
+ }
+
+ /* Clean up rest of flags */
+ c_ptr->info |= (CAVE_ROOM | CAVE_ICKY);
+ }
+ }
+
+ /* Try to add some random doors */
+ for (i = 0; i < 500; i++)
+ {
+ x = randint(xsize - 3) - xhsize + x0 + 1;
+ y = randint(ysize - 3) - yhsize + y0 + 1;
+ add_door(x, y);
+ }
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 2,
+ y0 - yhsize + 1, y0 - yhsize + ysize - 2, randint(5));
+}
+
+
+/*
+ * Convert FEAT_WALL_EXTRA (used by random vaults) to normal dungeon wall
+ */
+static void convert_extra(int y1, int x1, int y2, int x2)
+{
+ int x, y;
+
+ for (x = x1; x <= x2; x++)
+ {
+ for (y = y1; y <= y2; y++)
+ {
+ if (cave[y][x].feat == FEAT_WALL_OUTER)
+ {
+ place_filler(y, x);
+ }
+ }
+ }
+}
+
+
+/*
+ * Overlay a rectangular room given its bounds
+ *
+ * This routine is used by build_room_vault (hence FEAT_WALL_OUTER)
+ * The area inside the walls is not touched: only granite is removed
+ * and normal walls stay
+ */
+static void build_room(int x1, int x2, int y1, int y2)
+{
+ int x, y, xsize, ysize, temp;
+
+ /* Check if rectangle has no width */
+ if ((x1 == x2) || (y1 == y2)) return;
+
+ /* initialize */
+ if (x1 > x2)
+ {
+ /* Swap boundaries if in wrong order */
+ temp = x1;
+ x1 = x2;
+ x2 = temp;
+ }
+
+ if (y1 > y2)
+ {
+ /* Swap boundaries if in wrong order */
+ temp = y1;
+ y1 = y2;
+ y2 = temp;
+ }
+
+ /* Get total widths */
+ xsize = x2 - x1;
+ ysize = y2 - y1;
+
+ build_rectangle(y1, x1, y2, x2, feat_wall_outer, CAVE_ROOM | CAVE_ICKY);
+
+ /* Middle */
+ for (x = 1; x < xsize; x++)
+ {
+ for (y = 1; y < ysize; y++)
+ {
+ if (cave[y1 + y][x1 + x].feat == FEAT_WALL_OUTER)
+ {
+ /* Clear the untouched region */
+ place_floor(y1 + y, x1 + x);
+ cave[y1 + y][x1 + x].info |= (CAVE_ROOM | CAVE_ICKY);
+ }
+ else
+ {
+ /* Make it a room -- but don't touch */
+ cave[y1 + y][x1 + x].info |= (CAVE_ROOM | CAVE_ICKY);
+ }
+ }
+ }
+}
+
+
+/*
+ * Create a random vault that looks like a collection of overlapping rooms
+ */
+static void build_room_vault(int x0, int y0, int xsize, int ysize)
+{
+ int i, x1, x2, y1, y2, xhsize, yhsize;
+
+ /* Get offset from center */
+ xhsize = xsize / 2;
+ yhsize = ysize / 2;
+
+ if (cheat_room) msg_print("Room Vault");
+
+ /* Fill area so don't get problems with arena levels */
+ for (x1 = 0; x1 <= xsize; x1++)
+ {
+ int x = x0 - xhsize + x1;
+
+ for (y1 = 0; y1 <= ysize; y1++)
+ {
+ int y = y0 - yhsize + y1;
+
+ cave_set_feat(y, x, FEAT_WALL_OUTER);
+ cave[y][x].info &= ~(CAVE_ICKY);
+ }
+ }
+
+ /* Add ten random rooms */
+ for (i = 0; i < 10; i++)
+ {
+ x1 = randint(xhsize) * 2 + x0 - xhsize;
+ x2 = randint(xhsize) * 2 + x0 - xhsize;
+ y1 = randint(yhsize) * 2 + y0 - yhsize;
+ y2 = randint(yhsize) * 2 + y0 - yhsize;
+
+ build_room(x1, x2, y1, y2);
+ }
+
+ convert_extra(y0 - yhsize, x0 - xhsize, y0 - yhsize + ysize,
+ x0 - xhsize + xsize);
+
+ /* Add some random doors */
+ for (i = 0; i < 500; i++)
+ {
+ x1 = randint(xsize - 2) - xhsize + x0 + 1;
+ y1 = randint(ysize - 2) - yhsize + y0 + 1;
+ add_door(x1, y1);
+ }
+
+ /* Fill with monsters and treasure, high difficulty */
+ fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 1,
+ y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint(5) + 5);
+}
+
+
+/*
+ * Create a random vault out of a fractal cave
+ */
+static void build_cave_vault(int x0, int y0, int xsiz, int ysiz)
+{
+ int grd, roug, cutoff, xhsize, yhsize, xsize, ysize, x, y;
+ bool_ done, light, room;
+
+ /* Round to make sizes even */
+ xhsize = xsiz / 2;
+ yhsize = ysiz / 2;
+ xsize = xhsize * 2;
+ ysize = yhsize * 2;
+
+ if (cheat_room) msg_print("Cave Vault");
+
+ light = done = FALSE;
+ room = TRUE;
+
+ while (!done)
+ {
+ /* Testing values for these parameters feel free to adjust */
+ grd = 1 << rand_int(4);
+
+ /* Want average of about 16 */
+ roug = randint(8) * randint(4);
+
+ /* About size/2 */
+ cutoff = randint(xsize / 4) + randint(ysize / 4) +
+ randint(xsize / 4) + randint(ysize / 4);
+
+ /* Make it */
+ generate_hmap(y0, x0, xsize, ysize, grd, roug, cutoff);
+
+ /* Convert to normal format + clean up */
+ done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room);
+ }
+
+ /* Set icky flag because is a vault */
+ for (x = 0; x <= xsize; x++)
+ {
+ for (y = 0; y <= ysize; y++)
+ {
+ cave[y0 - yhsize + y][x0 - xhsize + x].info |= CAVE_ICKY;
+ }
+ }
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x0 - xhsize + 1, x0 - xhsize + xsize - 1,
+ y0 - yhsize + 1, y0 - yhsize + ysize - 1, randint(5));
+}
+
+
+/*
+ * Maze vault -- rectangular labyrinthine rooms
+ *
+ * maze vault uses two routines:
+ * r_visit - a recursive routine that builds the labyrinth
+ * build_maze_vault - a driver routine that calls r_visit and adds
+ * monsters, traps and treasure
+ *
+ * The labyrinth is built by creating a spanning tree of a graph.
+ * The graph vertices are at
+ * (x, y) = (2j + x1, 2k + y1) j = 0,...,m-1 k = 0,...,n-1
+ * and the edges are the vertical and horizontal nearest neighbors.
+ *
+ * The spanning tree is created by performing a suitably randomized
+ * depth-first traversal of the graph. The only adjustable parameter
+ * is the rand_int(3) below; it governs the relative density of
+ * twists and turns in the labyrinth: smaller number, more twists.
+ */
+static void r_visit(int y1, int x1, int y2, int x2,
+ int node, int dir, int *visited)
+{
+ int i, j, m, n, temp, x, y, adj[4];
+
+ /* Dimensions of vertex array */
+ m = (x2 - x1) / 2 + 1;
+ n = (y2 - y1) / 2 + 1;
+
+ /* Mark node visited and set it to a floor */
+ visited[node] = 1;
+ x = 2 * (node % m) + x1;
+ y = 2 * (node / m) + y1;
+ place_floor(y, x);
+
+ /* Setup order of adjacent node visits */
+ if (rand_int(3) == 0)
+ {
+ /* Pick a random ordering */
+ for (i = 0; i < 4; i++)
+ {
+ adj[i] = i;
+ }
+ for (i = 0; i < 4; i++)
+ {
+ j = rand_int(4);
+ temp = adj[i];
+ adj[i] = adj[j];
+ adj[j] = temp;
+ }
+ dir = adj[0];
+ }
+ else
+ {
+ /* Pick a random ordering with dir first */
+ adj[0] = dir;
+ for (i = 1; i < 4; i++)
+ {
+ adj[i] = i;
+ }
+ for (i = 1; i < 4; i++)
+ {
+ j = 1 + rand_int(3);
+ temp = adj[i];
+ adj[i] = adj[j];
+ adj[j] = temp;
+ }
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ switch (adj[i])
+ {
+ /* (0,+) - check for bottom boundary */
+ case 0:
+ {
+ if ((node / m < n - 1) && (visited[node + m] == 0))
+ {
+ place_floor(y + 1, x);
+ r_visit(y1, x1, y2, x2, node + m, dir, visited);
+ }
+ break;
+ }
+
+ /* (0,-) - check for top boundary */
+ case 1:
+ {
+ if ((node / m > 0) && (visited[node - m] == 0))
+ {
+ place_floor(y - 1, x);
+ r_visit(y1, x1, y2, x2, node - m, dir, visited);
+ }
+ break;
+ }
+
+ /* (+,0) - check for right boundary */
+ case 2:
+ {
+ if ((node % m < m - 1) && (visited[node + 1] == 0))
+ {
+ place_floor(y, x + 1);
+ r_visit(y1, x1, y2, x2, node + 1, dir, visited);
+ }
+ break;
+ }
+
+ /* (-,0) - check for left boundary */
+ case 3:
+ {
+ if ((node % m > 0) && (visited[node - 1] == 0))
+ {
+ place_floor(y, x - 1);
+ r_visit(y1, x1, y2, x2, node - 1, dir, visited);
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+static void build_maze_vault(int x0, int y0, int xsize, int ysize)
+{
+ int y, x, dy, dx;
+ int y1, x1, y2, x2;
+ int m, n, num_vertices;
+ bool_ light;
+ cave_type *c_ptr;
+
+
+ if (cheat_room) msg_print("Maze Vault");
+
+ /* Choose lite or dark */
+ light = (dun_level <= randint(25));
+
+ /* Pick a random room size - randomized by calling routine */
+ dy = ysize / 2 - 1;
+ dx = xsize / 2 - 1;
+
+ y1 = y0 - dy;
+ x1 = x0 - dx;
+ y2 = y0 + dy;
+ x2 = x0 + dx;
+
+ /* Generate the room */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ c_ptr = &cave[y][x];
+
+ c_ptr->info |= (CAVE_ROOM | CAVE_ICKY);
+
+ if ((x == x1 - 1) || (x == x2 + 1) ||
+ (y == y1 - 1) || (y == y2 + 1))
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+ else
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ if (light) c_ptr->info |= (CAVE_GLOW);
+ }
+ }
+
+ /* Dimensions of vertex array */
+ m = dx + 1;
+ n = dy + 1;
+ num_vertices = m * n;
+
+ /* Allocate an array for visited vertices */
+ std::vector<int> visited(num_vertices, 0);
+
+ /* Traverse the graph to create a spaning tree, pick a random root */
+ r_visit(y1, x1, y2, x2, rand_int(num_vertices), 0, visited.data());
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x1, x2, y1, y2, randint(5));
+}
+
+
+/*
+ * Build a "mini" checkerboard vault
+ *
+ * This is done by making a permanent wall maze and setting
+ * the diagonal sqaures of the checker board to be granite.
+ * The vault has two entrances on opposite sides to guarantee
+ * a way to get in even if the vault abuts a side of the dungeon.
+ */
+static void build_mini_c_vault(int x0, int y0, int xsize, int ysize)
+{
+ int dy, dx;
+ int y1, x1, y2, x2, y, x, total;
+ int m, n, num_vertices;
+
+ if (cheat_room) msg_print("Mini Checker Board Vault");
+
+ /* Pick a random room size */
+ dy = ysize / 2 - 1;
+ dx = xsize / 2 - 1;
+
+ y1 = y0 - dy;
+ x1 = x0 - dx;
+ y2 = y0 + dy;
+ x2 = x0 + dx;
+
+
+ /* Generate the room */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ cave[y][x].info |= (CAVE_ROOM | CAVE_ICKY);
+
+ /* Permanent walls */
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+ }
+ }
+
+
+ /* Dimensions of vertex array */
+ m = dx + 1;
+ n = dy + 1;
+ num_vertices = m * n;
+
+ /* Allocate an array for visited vertices */
+ std::vector<int> visited(num_vertices, 0);
+
+ /* Traverse the graph to create a spannng tree, pick a random root */
+ r_visit(y1, x1, y2, x2, rand_int(num_vertices), 0, visited.data());
+
+ /* Make it look like a checker board vault */
+ for (x = x1; x <= x2; x++)
+ {
+ for (y = y1; y <= y2; y++)
+ {
+ total = x - x1 + y - y1;
+
+ /* If total is odd and is a floor, then make a wall */
+ if ((total % 2 == 1) && get_is_floor(x, y))
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Make a couple of entrances */
+ if (rand_int(2) == 0)
+ {
+ /* Left and right */
+ y = randint(dy) + dy / 2;
+ cave_set_feat(y1 + y, x1 - 1, feat_wall_outer);
+ cave_set_feat(y1 + y, x2 + 1, feat_wall_outer);
+ }
+ else
+ {
+ /* Top and bottom */
+ x = randint(dx) + dx / 2;
+ cave_set_feat(y1 - 1, x1 + x, feat_wall_outer);
+ cave_set_feat(y2 + 1, x1 + x, feat_wall_outer);
+ }
+
+ /* Fill with monsters and treasure, highest difficulty */
+ fill_treasure(x1, x2, y1, y2, 10);
+}
+
+
+/*
+ * Build a town/ castle by using a recursive algorithm.
+ * Basically divide each region in a probalistic way to create
+ * smaller regions. When the regions get too small stop.
+ *
+ * The power variable is a measure of how well defended a region is.
+ * This alters the possible choices.
+ */
+static void build_recursive_room(int x1, int y1, int x2, int y2, int power)
+{
+ int xsize, ysize;
+ int x, y;
+ int choice;
+
+ /* Temp variables */
+ int t1, t2, t3, t4;
+
+ xsize = x2 - x1;
+ ysize = y2 - y1;
+
+ if ((power < 3) && (xsize > 12) && (ysize > 12))
+ {
+ /* Need outside wall +keep */
+ choice = 1;
+ }
+ else
+ {
+ if (power < 10)
+ {
+ /* Make rooms + subdivide */
+ if ((randint(10) > 2) && (xsize < 8) && (ysize < 8))
+ {
+ choice = 4;
+ }
+ else
+ {
+ choice = randint(2) + 1;
+ }
+ }
+ else
+ {
+ /* Mostly subdivide */
+ choice = randint(3) + 1;
+ }
+ }
+
+ /* Based on the choice made above, do something */
+ switch (choice)
+ {
+ /* Outer walls */
+ case 1:
+ {
+ /* Top and bottom */
+ for (x = x1; x <= x2; x++)
+ {
+ cave_set_feat(y1, x, feat_wall_outer);
+ cave_set_feat(y2, x, feat_wall_outer);
+ }
+
+ /* Left and right */
+ for (y = y1 + 1; y < y2; y++)
+ {
+ cave_set_feat(y, x1, feat_wall_outer);
+ cave_set_feat(y, x2, feat_wall_outer);
+ }
+
+ /* Make a couple of entrances */
+ if (rand_int(2) == 0)
+ {
+ /* Left and right */
+ y = randint(ysize) + y1;
+ place_floor(y, x1);
+ place_floor(y, x2);
+ }
+ else
+ {
+ /* Top and bottom */
+ x = randint(xsize) + x1;
+ place_floor(y1, x);
+ place_floor(y2, x);
+ }
+
+ /* Select size of keep */
+ t1 = randint(ysize / 3) + y1;
+ t2 = y2 - randint(ysize / 3);
+ t3 = randint(xsize / 3) + x1;
+ t4 = x2 - randint(xsize / 3);
+
+ /* Do outside areas */
+
+ /* Above and below keep */
+ build_recursive_room(x1 + 1, y1 + 1, x2 - 1, t1, power + 1);
+ build_recursive_room(x1 + 1, t2, x2 - 1, y2, power + 1);
+
+ /* Left and right of keep */
+ build_recursive_room(x1 + 1, t1 + 1, t3, t2 - 1, power + 3);
+ build_recursive_room(t4, t1 + 1, x2 - 1, t2 - 1, power + 3);
+
+ /* Make the keep itself: */
+ x1 = t3;
+ x2 = t4;
+ y1 = t1;
+ y2 = t2;
+ xsize = x2 - x1;
+ ysize = y2 - y1;
+ power += 2;
+
+ /* Fall through */
+ }
+
+ /* Try to build a room */
+ case 4:
+ {
+ if ((xsize < 3) || (ysize < 3))
+ {
+ for (y = y1; y < y2; y++)
+ {
+ for (x = x1; x < x2; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+
+ /* Too small */
+ return;
+ }
+
+ /* Make outside walls */
+
+ /* Top and bottom */
+ for (x = x1 + 1; x <= x2 - 1; x++)
+ {
+ cave_set_feat(y1 + 1, x, feat_wall_inner);
+ cave_set_feat(y2 - 1, x, feat_wall_inner);
+ }
+
+ /* Left and right */
+ for (y = y1 + 1; y <= y2 - 1; y++)
+ {
+ cave_set_feat(y, x1 + 1, feat_wall_inner);
+ cave_set_feat(y, x2 - 1, feat_wall_inner);
+ }
+
+ /* Make a door */
+ y = randint(ysize - 3) + y1 + 1;
+
+ if (rand_int(2) == 0)
+ {
+ /* Left */
+ place_floor(y, x1 + 1);
+ }
+ else
+ {
+ /* Right */
+ place_floor(y, x2 - 1);
+ }
+
+ /* Build the room */
+ build_recursive_room(x1 + 2, y1 + 2, x2 - 2, y2 - 2, power + 3);
+
+ break;
+ }
+
+ /* Try and divide vertically */
+ case 2:
+ {
+ if (xsize < 3)
+ {
+ /* Too small */
+ for (y = y1; y < y2; y++)
+ {
+ for (x = x1; x < x2; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ return;
+ }
+
+ t1 = randint(xsize - 2) + x1 + 1;
+ build_recursive_room(x1, y1, t1, y2, power - 2);
+ build_recursive_room(t1 + 1, y1, x2, y2, power - 2);
+
+ break;
+ }
+
+ /* Try and divide horizontally */
+ case 3:
+ {
+ if (ysize < 3)
+ {
+ /* Too small */
+ for (y = y1; y < y2; y++)
+ {
+ for (x = x1; x < x2; x++)
+ {
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ return;
+ }
+
+ t1 = randint(ysize - 2) + y1 + 1;
+ build_recursive_room(x1, y1, x2, t1, power - 2);
+ build_recursive_room(x1, t1 + 1, x2, y2, power - 2);
+
+ break;
+ }
+ }
+}
+
+
+/*
+ * Build a castle
+ *
+ * Clear the region and call the recursive room routine.
+ *
+ * This makes a vault that looks like a castle or city in the dungeon.
+ */
+static void build_castle_vault(int x0, int y0, int xsize, int ysize)
+{
+ int dy, dx;
+ int y1, x1, y2, x2;
+ int y, x;
+
+ /* Pick a random room size */
+ dy = ysize / 2 - 1;
+ dx = xsize / 2 - 1;
+
+ y1 = y0 - dy;
+ x1 = x0 - dx;
+ y2 = y0 + dy;
+ x2 = x0 + dx;
+
+ if (cheat_room) msg_print("Castle Vault");
+
+ /* Generate the room */
+ for (y = y1 - 1; y <= y2 + 1; y++)
+ {
+ for (x = x1 - 1; x <= x2 + 1; x++)
+ {
+ cave[y][x].info |= (CAVE_ROOM | CAVE_ICKY);
+
+ /* Make everything a floor */
+ place_floor(y, x);
+ }
+ }
+
+ /* Make the castle */
+ build_recursive_room(x1, y1, x2, y2, randint(5));
+
+ /* Fill with monsters and treasure, low difficulty */
+ fill_treasure(x1, x2, y1, y2, randint(3));
+}
+
+
+/*
+ * Add outer wall to a floored region
+ *
+ * Note: no range checking is done so must be inside dungeon
+ * This routine also stomps on doors
+ */
+static void add_outer_wall(int x, int y, int light, int x1, int y1,
+ int x2, int y2)
+{
+ int i, j;
+
+ if (!in_bounds(y, x)) return;
+
+ /*
+ * Hack -- Check to see if square has been visited before
+ * if so, then exit (use room flag to do this)
+ */
+ if (cave[y][x].info & CAVE_ROOM) return;
+
+ /* Set room flag */
+ cave[y][x].info |= (CAVE_ROOM);
+
+ if (get_is_floor(x, y))
+ {
+ for (i = -1; i <= 1; i++)
+ {
+ for (j = -1; j <= 1; j++)
+ {
+ if ((x + i >= x1) && (x + i <= x2) &&
+ (y + j >= y1) && (y + j <= y2))
+ {
+ add_outer_wall(x + i, y + j, light, x1, y1, x2, y2);
+ if (light) cave[y][x].info |= CAVE_GLOW;
+ }
+ }
+ }
+ }
+
+ /* Set bounding walls */
+ else if (cave[y][x].feat == FEAT_WALL_EXTRA)
+ {
+ cave[y][x].feat = feat_wall_outer;
+ if (light == TRUE) cave[y][x].info |= CAVE_GLOW;
+ }
+
+ /* Set bounding walls */
+ else if (cave[y][x].feat == FEAT_PERM_OUTER)
+ {
+ if (light == TRUE) cave[y][x].info |= CAVE_GLOW;
+ }
+}
+
+
+/*
+ * Hacked distance formula - gives the 'wrong' answer
+ *
+ * Used to build crypts
+ */
+static int dist2(int x1, int y1, int x2, int y2,
+ int h1, int h2, int h3, int h4)
+{
+ int dx, dy;
+ dx = abs(x2 - x1);
+ dy = abs(y2 - y1);
+
+ /*
+ * Basically this works by taking the normal pythagorean formula
+ * and using an expansion to express this in a way without the
+ * square root. This approximate formula is then perturbed to give
+ * the distorted results. (I found this by making a mistake when I was
+ * trying to fix the circular rooms.)
+ */
+
+ /* h1-h4 are constants that describe the metric */
+ if (dx >= 2 * dy) return (dx + (dy * h1) / h2);
+ if (dy >= 2 * dx) return (dy + (dx * h1) / h2);
+
+ /* 128/181 is approx. 1/sqrt(2) */
+ return (((dx + dy) * 128) / 181 +
+ (dx * dx / (dy * h3) + dy * dy / (dx * h3)) * h4);
+}
+
+
+/*
+ * Build target vault
+ *
+ * This is made by two concentric "crypts" with perpendicular
+ * walls creating the cross-hairs.
+ */
+static void build_target_vault(int x0, int y0, int xsize, int ysize)
+{
+ int rad, x, y;
+
+ int h1, h2, h3, h4;
+
+
+ /* Make a random metric */
+ h1 = randint(32) - 16;
+ h2 = randint(16);
+ h3 = randint(32);
+ h4 = randint(32) - 16;
+
+ if (cheat_room) msg_print("Target Vault");
+
+ /* Work out outer radius */
+ if (xsize > ysize)
+ {
+ rad = ysize / 2;
+ }
+ else
+ {
+ rad = xsize / 2;
+ }
+
+ /* Make floor */
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ cave_type *c_ptr;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Clear room flag */
+ c_ptr->info &= ~(CAVE_ROOM);
+
+ /* Grids in vaults are required to be "icky" */
+ c_ptr->info |= (CAVE_ICKY);
+
+ /* Inside -- floor */
+ if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1)
+ {
+ place_floor(y, x);
+ }
+
+ /* Outside -- make it granite so that arena works */
+ else
+ {
+ c_ptr->feat = FEAT_WALL_EXTRA;
+ }
+
+ /* Proper boundary for arena */
+ if (((y + rad) == y0) || ((y - rad) == y0) ||
+ ((x + rad) == x0) || ((x - rad) == x0))
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+ }
+ }
+
+ /* Find visible outer walls and set to be FEAT_OUTER */
+ add_outer_wall(x0, y0, FALSE, x0 - rad - 1, y0 - rad - 1,
+ x0 + rad + 1, y0 + rad + 1);
+
+ /* Add inner wall */
+ for (x = x0 - rad / 2; x <= x0 + rad / 2; x++)
+ {
+ for (y = y0 - rad / 2; y <= y0 + rad / 2; y++)
+ {
+ if (dist2(y0, x0, y, x, h1, h2, h3, h4) == rad / 2)
+ {
+ /* Make an internal wall */
+ cave_set_feat(y, x, feat_wall_inner);
+ }
+ }
+ }
+
+ /* Add perpendicular walls */
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ cave_set_feat(y0, x, feat_wall_inner);
+ }
+
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ cave_set_feat(y, x0, feat_wall_inner);
+ }
+
+ /* Make inner vault */
+ for (y = y0 - 1; y <= y0 + 1; y++)
+ {
+ cave_set_feat(y, x0 - 1, feat_wall_inner);
+ cave_set_feat(y, x0 + 1, feat_wall_inner);
+ }
+ for (x = x0 - 1; x <= x0 + 1; x++)
+ {
+ cave_set_feat(y0 - 1, x, feat_wall_inner);
+ cave_set_feat(y0 + 1, x, feat_wall_inner);
+ }
+
+ place_floor(y0, x0);
+
+
+ /*
+ * Add doors to vault
+ *
+ * Get two distances so can place doors relative to centre
+ */
+ x = (rad - 2) / 4 + 1;
+ y = rad / 2 + x;
+
+ add_door(x0 + x, y0);
+ add_door(x0 + y, y0);
+ add_door(x0 - x, y0);
+ add_door(x0 - y, y0);
+ add_door(x0, y0 + x);
+ add_door(x0, y0 + y);
+ add_door(x0, y0 - x);
+ add_door(x0, y0 - y);
+
+ /* Fill with stuff - medium difficulty */
+ fill_treasure(x0 - rad, x0 + rad, y0 - rad, y0 + rad, randint(3) + 3);
+}
+
+
+/*
+ * Random vaults
+ */
+static void build_type11(int by0, int bx0)
+{
+ int y0, x0, xsize, ysize, vtype;
+
+ /* Get size -- gig enough to look good, small enough to be fairly common */
+ xsize = randint(22) + 22;
+ ysize = randint(11) + 11;
+
+ /* Allocate in room_map. If will not fit, exit */
+ if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &x0, &y0)) return;
+
+ /*
+ * Boost the rating -- Higher than lesser vaults and lower than
+ * greater vaults
+ */
+ rating += 10;
+
+ /* (Sometimes) Cause a special feeling */
+ if ((dun_level <= 50) ||
+ (randint((dun_level - 40) * (dun_level - 40) + 1) < 400))
+ {
+ good_item_flag = TRUE;
+ }
+
+ /* Select type of vault */
+ vtype = randint(8);
+
+ switch (vtype)
+ {
+ /* Build an appropriate room */
+ case 1:
+ {
+ build_bubble_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 2:
+ {
+ build_room_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 3:
+ {
+ build_cave_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 4:
+ {
+ build_maze_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 5:
+ {
+ build_mini_c_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 6:
+ {
+ build_castle_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ case 7:
+ {
+ build_target_vault(x0, y0, xsize, ysize);
+ break;
+ }
+
+ /* I know how to add a few more... give me some time. */
+
+ /* Paranoia */
+ default:
+ {
+ return;
+ }
+ }
+}
+
+/*
+ * Crypt room generation from Z 2.5.1
+ */
+
+/*
+ * Build crypt room.
+ * For every grid in the possible square, check the (fake) distance.
+ * If it's less than the radius, make it a room square.
+ *
+ * When done fill from the inside to find the walls,
+ */
+static void build_type12(int by0, int bx0)
+{
+ int light, rad, x, y, x0, y0;
+ bool_ emptyflag = TRUE;
+ int h1, h2, h3, h4;
+
+ /* Make a random metric */
+ h1 = randint(32) - 16;
+ h2 = randint(16);
+ h3 = randint(32);
+ h4 = randint(32) - 16;
+
+ /* Occasional light */
+ light = (randint(dun_level) <= 5) ? TRUE : FALSE;
+
+ rad = randint(9);
+
+ /* Allocate in room_map. If will not fit, exit */
+ if (!room_alloc(rad * 2 + 3, rad * 2 + 3, FALSE, by0, bx0, &x0, &y0)) return;
+
+ /* Make floor */
+ for (x = x0 - rad; x <= x0 + rad; x++)
+ {
+ for (y = y0 - rad; y <= y0 + rad; y++)
+ {
+ /* Clear room flag */
+ cave[y][x].info &= ~(CAVE_ROOM);
+
+ /* Inside -- floor */
+ if (dist2(y0, x0, y, x, h1, h2, h3, h4) <= rad - 1)
+ {
+ place_floor(y, x);
+ }
+ else if (distance(y0, x0, y, x) < 3)
+ {
+ place_floor(y, x);
+ }
+
+ /* Outside -- make it granite so that arena works */
+ else
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+
+ /* Proper boundary for arena */
+ if (((y + rad) == y0) || ((y - rad) == y0) ||
+ ((x + rad) == x0) || ((x - rad) == x0))
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+ }
+ }
+
+ /* Find visible outer walls and set to be FEAT_OUTER */
+ add_outer_wall(x0, y0, light, x0 - rad - 1, y0 - rad - 1,
+ x0 + rad + 1, y0 + rad + 1);
+
+ /* Check to see if there is room for an inner vault */
+ for (x = x0 - 2; x <= x0 + 2; x++)
+ {
+ for (y = y0 - 2; y <= y0 + 2; y++)
+ {
+ if (!get_is_floor(x, y))
+ {
+ /* Wall in the way */
+ emptyflag = FALSE;
+ }
+ }
+ }
+
+ if (emptyflag && (rand_int(2) == 0))
+ {
+ /* Build the vault */
+ build_small_room(x0, y0);
+
+ /* Place a treasure in the vault */
+ place_object(y0, x0, FALSE, FALSE, OBJ_FOUND_FLOOR);
+
+ /* Let's guard the treasure well */
+ vault_monsters(y0, x0, rand_int(2) + 3);
+
+ /* Traps naturally */
+ vault_traps(y0, x0, 4, 4, rand_int(3) + 2);
+ }
+}
+
+
+/*
+ * Constructs a tunnel between two points
+ *
+ * This function must be called BEFORE any streamers are created,
+ * since we use the special "granite wall" sub-types to keep track
+ * of legal places for corridors to pierce rooms.
+ *
+ * We use "door_flag" to prevent excessive construction of doors
+ * along overlapping corridors.
+ *
+ * We queue the tunnel grids to prevent door creation along a corridor
+ * which intersects itself.
+ *
+ * We queue the wall piercing grids to prevent a corridor from leaving
+ * a room and then coming back in through the same entrance.
+ *
+ * We "pierce" grids which are "outer" walls of rooms, and when we
+ * do so, we change all adjacent "outer" walls of rooms into "solid"
+ * walls so that no two corridors may use adjacent grids for exits.
+ *
+ * The "solid" wall check prevents corridors from "chopping" the
+ * corners of rooms off, as well as "silly" door placement, and
+ * "excessively wide" room entrances.
+ *
+ * Useful "feat" values:
+ * FEAT_WALL_EXTRA -- granite walls
+ * FEAT_WALL_INNER -- inner room walls
+ * FEAT_WALL_OUTER -- outer room walls
+ * FEAT_WALL_SOLID -- solid room walls
+ * FEAT_PERM_EXTRA -- shop walls (perma)
+ * FEAT_PERM_INNER -- inner room walls (perma)
+ * FEAT_PERM_OUTER -- outer room walls (perma)
+ * FEAT_PERM_SOLID -- dungeon border (perma)
+ */
+static void build_tunnel(int row1, int col1, int row2, int col2, bool_ water)
+{
+ int i, y, x;
+ int tmp_row, tmp_col;
+ int row_dir, col_dir;
+ int start_row, start_col;
+ int main_loop_count = 0;
+
+ bool_ door_flag = FALSE;
+
+ cave_type *c_ptr;
+
+
+ /* Reset the arrays */
+ dun->tunn_n = 0;
+ dun->wall_n = 0;
+
+ /* Save the starting location */
+ start_row = row1;
+ start_col = col1;
+
+ /* Start out in the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Keep going until done (or bored) */
+ while ((row1 != row2) || (col1 != col2))
+ {
+ /* Mega-Hack -- Paranoia -- prevent infinite loops */
+ if (main_loop_count++ > 2000) break;
+
+ /* Allow bends in the tunnel */
+ if (rand_int(100) < DUN_TUN_CHG)
+ {
+ /* Acquire the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Random direction */
+ if (rand_int(100) < DUN_TUN_RND)
+ {
+ rand_dir(&row_dir, &col_dir);
+ }
+ }
+
+ /* Get the next location */
+ tmp_row = row1 + row_dir;
+ tmp_col = col1 + col_dir;
+
+
+ /* Extremely Important -- do not leave the dungeon */
+ while (!in_bounds(tmp_row, tmp_col))
+ {
+ /* Acquire the correct direction */
+ correct_dir(&row_dir, &col_dir, row1, col1, row2, col2);
+
+ /* Random direction */
+ if (rand_int(100) < DUN_TUN_RND)
+ {
+ rand_dir(&row_dir, &col_dir);
+ }
+
+ /* Get the next location */
+ tmp_row = row1 + row_dir;
+ tmp_col = col1 + col_dir;
+ }
+
+
+ /* Access the location */
+ c_ptr = &cave[tmp_row][tmp_col];
+
+
+ /* Avoid the edge of the dungeon */
+ if (c_ptr->feat == FEAT_PERM_SOLID) continue;
+
+ /* Avoid the edge of vaults */
+ if (c_ptr->feat == FEAT_PERM_OUTER) continue;
+
+ /* Avoid "solid" granite walls */
+ if (c_ptr->feat == FEAT_WALL_SOLID) continue;
+
+ /*
+ * Pierce "outer" walls of rooms
+ * Cannot trust feat code any longer...
+ */
+ if ((c_ptr->feat == feat_wall_outer) &&
+ (c_ptr->info & CAVE_ROOM))
+ {
+ /* Acquire the "next" location */
+ y = tmp_row + row_dir;
+ x = tmp_col + col_dir;
+
+ /* Hack -- Avoid outer/solid permanent walls */
+ if (cave[y][x].feat == FEAT_PERM_SOLID) continue;
+ if (cave[y][x].feat == FEAT_PERM_OUTER) continue;
+
+ /* Hack -- Avoid outer/solid granite walls */
+ if ((cave[y][x].feat == feat_wall_outer) &&
+ (cave[y][x].info & CAVE_ROOM)) continue;
+ if (cave[y][x].feat == FEAT_WALL_SOLID) continue;
+
+ /* Accept this location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+
+ /* Save the wall location */
+ if (dun->wall_n < WALL_MAX)
+ {
+ dun->wall[dun->wall_n].y = row1;
+ dun->wall[dun->wall_n].x = col1;
+ dun->wall_n++;
+ }
+
+ /* Forbid re-entry near this piercing */
+ for (y = row1 - 1; y <= row1 + 1; y++)
+ {
+ for (x = col1 - 1; x <= col1 + 1; x++)
+ {
+ /* Convert adjacent "outer" walls as "solid" walls */
+ if ((cave[y][x].feat == feat_wall_outer) &&
+ (cave[y][x].info & CAVE_ROOM))
+ {
+ /* Change the wall to a "solid" wall */
+ /* Mega-Hack -- to be brought back later... */
+ cave_set_feat(y, x, FEAT_WALL_SOLID);
+ }
+ }
+ }
+ }
+
+ /* Travel quickly through rooms */
+ else if (c_ptr->info & (CAVE_ROOM))
+ {
+ /* Accept the location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+ }
+
+ /* Tunnel through all other walls */
+ else if ((c_ptr->feat == d_info[dungeon_type].fill_type1) ||
+ (c_ptr->feat == d_info[dungeon_type].fill_type2) ||
+ (c_ptr->feat == d_info[dungeon_type].fill_type3))
+ {
+ /* Accept this location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+
+ /* Save the tunnel location */
+ if (dun->tunn_n < TUNN_MAX)
+ {
+ dun->tunn[dun->tunn_n].y = row1;
+ dun->tunn[dun->tunn_n].x = col1;
+ dun->tunn_n++;
+ }
+
+ /* Allow door in next grid */
+ door_flag = FALSE;
+ }
+
+ /* Handle corridor intersections or overlaps */
+ else
+ {
+ /* Accept the location */
+ row1 = tmp_row;
+ col1 = tmp_col;
+
+ /* Collect legal door locations */
+ if (!door_flag)
+ {
+ /* Save the door location */
+ if (dun->door_n < DOOR_MAX)
+ {
+ dun->door[dun->door_n].y = row1;
+ dun->door[dun->door_n].x = col1;
+ dun->door_n++;
+ }
+
+ /* No door in next grid */
+ door_flag = TRUE;
+ }
+
+ /* Hack -- allow pre-emptive tunnel termination */
+ if (rand_int(100) >= DUN_TUN_CON)
+ {
+ /* Distance between row1 and start_row */
+ tmp_row = row1 - start_row;
+ if (tmp_row < 0) tmp_row = ( -tmp_row);
+
+ /* Distance between col1 and start_col */
+ tmp_col = col1 - start_col;
+ if (tmp_col < 0) tmp_col = ( -tmp_col);
+
+ /* Terminate the tunnel */
+ if ((tmp_row > 10) || (tmp_col > 10)) break;
+ }
+ }
+ }
+
+
+ /* Turn the tunnel into corridor */
+ for (i = 0; i < dun->tunn_n; i++)
+ {
+ /* Access the grid */
+ y = dun->tunn[i].y;
+ x = dun->tunn[i].x;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Clear previous contents, add a floor */
+ if (!water)
+ {
+ place_floor(y, x);
+ }
+ else
+ {
+ cave_set_feat(y, x, FEAT_SHAL_WATER);
+ }
+ }
+
+
+ /* Apply the piercings that we found */
+ for (i = 0; i < dun->wall_n; i++)
+ {
+ /* Access the grid */
+ y = dun->wall[i].y;
+ x = dun->wall[i].x;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Clear previous contents, add up floor */
+ place_floor(y, x);
+
+ /* Occasional doorway */
+ if (!(dungeon_flags1 & DF1_NO_DOORS) &&
+ (rand_int(100) < DUN_TUN_PEN))
+ {
+ /* Place a random door */
+ place_random_door(y, x);
+ }
+ }
+}
+
+
+
+
+/*
+ * Count the number of "corridor" grids adjacent to the given grid.
+ *
+ * Note -- Assumes "in_bounds(y1, x1)"
+ *
+ * XXX XXX This routine currently only counts actual "empty floor"
+ * grids which are not in rooms. We might want to also count stairs,
+ * open doors, closed doors, etc.
+ */
+static int next_to_corr(int y1, int x1)
+{
+ int i, y, x, k = 0;
+
+ cave_type *c_ptr;
+
+ /* Scan adjacent grids */
+ for (i = 0; i < 4; i++)
+ {
+ /* Extract the location */
+ y = y1 + ddy_ddd[i];
+ x = x1 + ddx_ddd[i];
+
+ /* Skip non floors */
+ if (!cave_floor_bold(y, x)) continue;
+
+ /* Access the grid */
+ c_ptr = &cave[y][x];
+
+ /* Skip non "empty floor" grids */
+ if ((c_ptr->feat != d_info[dungeon_type].floor1) &&
+ (c_ptr->feat != d_info[dungeon_type].floor2) &&
+ (c_ptr->feat != d_info[dungeon_type].floor3))
+ {
+ continue;
+ }
+
+ /* Skip grids inside rooms */
+ if (c_ptr->info & (CAVE_ROOM)) continue;
+
+ /* Count these grids */
+ k++;
+ }
+
+ /* Return the number of corridors */
+ return (k);
+}
+
+
+/*
+ * Determine if the given location is "between" two walls,
+ * and "next to" two corridor spaces. XXX XXX XXX
+ *
+ * Assumes "in_bounds(y,x)"
+ */
+static bool_ possible_doorway(int y, int x)
+{
+ /* Count the adjacent corridors */
+ if (next_to_corr(y, x) >= 2)
+ {
+ /* Check Vertical */
+ if ((f_info[cave[y - 1][x].feat].flags1 & FF1_WALL) &&
+ (f_info[cave[y + 1][x].feat].flags1 & FF1_WALL))
+ {
+ return (TRUE);
+ }
+
+ /* Check Horizontal */
+ if ((f_info[cave[y][x - 1].feat].flags1 & FF1_WALL) &&
+ (f_info[cave[y][x + 1].feat].flags1 & FF1_WALL))
+ {
+ return (TRUE);
+ }
+ }
+
+ /* No doorway */
+ return (FALSE);
+}
+
+
+/*
+ * Places doors around y, x position
+ */
+static void try_doors(int y, int x)
+{
+ bool_ dir_ok[4];
+ int i, k, n;
+ int yy, xx;
+
+ /* Paranoia */
+ /* if (!in_bounds(y, x)) return; */
+
+ /* Some dungeons don't have doors at all */
+ if (dungeon_flags1 & (DF1_NO_DOORS)) return;
+
+ /* Reset tally */
+ n = 0;
+
+ /* Look four cardinal directions */
+ for (i = 0; i < 4; i++)
+ {
+ /* Assume NG */
+ dir_ok[i] = FALSE;
+
+ /* Access location */
+ yy = y + ddy_ddd[i];
+ xx = x + ddx_ddd[i];
+
+ /* Out of level boundary */
+ if (!in_bounds(yy, xx)) continue;
+
+ /* Ignore walls */
+ if (f_info[cave[yy][xx].feat].flags1 & (FF1_WALL)) continue;
+
+ /* Ignore room grids */
+ if (cave[yy][xx].info & (CAVE_ROOM)) continue;
+
+ /* Not a doorway */
+ if (!possible_doorway(yy, xx)) continue;
+
+ /* Accept the direction */
+ dir_ok[i] = TRUE;
+
+ /* Count good spots */
+ n++;
+ }
+
+ /* Use the traditional method 75% of time */
+ if (rand_int(100) < 75)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ /* Bad locations */
+ if (!dir_ok[i]) continue;
+
+ /* Place one of various kinds of doors */
+ if (rand_int(100) < DUN_TUN_JCT)
+ {
+ /* Access location */
+ yy = y + ddy_ddd[i];
+ xx = x + ddx_ddd[i];
+
+ /* Place a door */
+ place_random_door(yy, xx);
+ }
+ }
+ }
+
+ /* Use alternative method */
+ else
+ {
+ /* A crossroad */
+ if (n == 4)
+ {
+ /* Clear OK flags XXX */
+ for (i = 0; i < 4; i++) dir_ok[i] = FALSE;
+
+ /* Put one or two secret doors */
+ dir_ok[rand_int(4)] = TRUE;
+ dir_ok[rand_int(4)] = TRUE;
+ }
+
+ /* A T-shaped intersection or two possible doorways */
+ else if ((n == 3) || (n == 2))
+ {
+ /* Pick one random location from the list */
+ k = rand_int(n);
+
+ for (i = 0; i < 4; i++)
+ {
+ /* Reject all but k'th OK direction */
+ if (dir_ok[i] && (k-- != 0)) dir_ok[i] = FALSE;
+ }
+ }
+
+ /* Place secret door(s) */
+ for (i = 0; i < 4; i++)
+ {
+ /* Bad location */
+ if (!dir_ok[i]) continue;
+
+ /* Access location */
+ yy = y + ddy_ddd[i];
+ xx = x + ddx_ddd[i];
+
+ /* Place a secret door */
+ place_secret_door(yy, xx);
+ }
+ }
+}
+
+
+/*
+ * Attempt to build a room of the given type at the given block
+ *
+ * Note that we restrict the number of "crowded" rooms to reduce
+ * the chance of overflowing the monster list during level creation.
+ */
+static bool_ room_build(int y, int x, int typ)
+{
+ /* Restrict level */
+ if ((dun_level < roomdep[typ]) && !ironman_rooms) return (FALSE);
+
+ /* Restrict "crowded" rooms */
+ if (dun->crowded && ((typ == 5) || (typ == 6))) return (FALSE);
+
+ /* Build a room */
+ switch (typ)
+ {
+ /* Build an appropriate room */
+ case 12:
+ build_type12(y, x);
+ break;
+ case 11:
+ build_type11(y, x);
+ break;
+ case 10:
+ build_type10(y, x);
+ break;
+ case 9:
+ build_type9 (y, x);
+ break;
+ case 8:
+ build_type8 (y, x);
+ break;
+ case 7:
+ build_type7 (y, x);
+ break;
+ case 6:
+ build_type6 (y, x);
+ break;
+ case 5:
+ build_type5 (y, x);
+ break;
+ case 4:
+ build_type4 (y, x);
+ break;
+ case 3:
+ build_type3 (y, x);
+ break;
+ case 2:
+ build_type2 (y, x);
+ break;
+ case 1:
+ build_type1 (y, x);
+ break;
+
+ /* Paranoia */
+ default:
+ return (FALSE);
+ }
+
+ /* Success */
+ return (TRUE);
+}
+
+/*
+ * Set level boundaries
+ */
+static void set_bounders(bool_ empty_level)
+{
+ int y, x;
+
+ /* Special boundary walls -- Top */
+ for (x = 0; x < cur_wid; x++)
+ {
+ /* XXX XXX */
+ if (empty_level) cave[0][x].mimic = fill_type[rand_int(100)];
+ else cave[0][x].mimic = cave[0][x].feat;
+
+ /* Clear previous contents, add "solid" perma-wall */
+ cave_set_feat(0, x, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- Bottom */
+ for (x = 0; x < cur_wid; x++)
+ {
+ /* XXX XXX */
+ if (empty_level) cave[cur_hgt - 1][x].mimic = fill_type[rand_int(100)];
+ else cave[cur_hgt - 1][x].mimic = cave[cur_hgt - 1][x].feat;
+
+ /* Clear previous contents, add "solid" perma-wall */
+ cave_set_feat(cur_hgt - 1, x, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- Left */
+ for (y = 1; y < cur_hgt - 1; y++)
+ {
+ /* XXX XXX */
+ if (empty_level) cave[y][0].mimic = fill_type[rand_int(100)];
+ else cave[y][0].mimic = cave[y][0].feat;
+
+ /* Clear previous contents, add "solid" perma-wall */
+ cave_set_feat(y, 0, FEAT_PERM_SOLID);
+ }
+
+ /* Special boundary walls -- Right */
+ for (y = 1; y < cur_hgt - 1; y++)
+ {
+ /* XXX XXX */
+ if (empty_level) cave[y][cur_wid - 1].mimic = fill_type[rand_int(100)];
+ else cave[y][cur_wid - 1].mimic = cave[y][cur_wid - 1].feat;
+
+ /* Clear previous contents, add "solid" perma-wall */
+ cave_set_feat(y, cur_wid - 1, FEAT_PERM_SOLID);
+ }
+}
+
+/* Needed to refill empty levels */
+static void fill_level(bool_ use_floor, byte smooth);
+
+/*
+ * Generate a normal dungeon level
+ */
+bool_ level_generate_dungeon()
+{
+ int i, k, y, x, y1, x1, branch = get_branch();
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ int max_vault_ok = 2;
+
+ bool_ destroyed = FALSE;
+ bool_ empty_level = FALSE;
+ bool_ cavern = FALSE;
+ s16b town_level = 0;
+
+ /* Is it a town level ? */
+ for (i = 0; i < TOWN_DUNGEON; i++)
+ {
+ if (d_ptr->t_level[i] == dun_level) town_level = d_ptr->t_idx[i];
+ }
+
+ /* Check for arena level */
+ if ((dungeon_flags1 & (DF1_EMPTY)) ||
+ (empty_levels && (rand_int(EMPTY_LEVEL) == 0)))
+ {
+ empty_level = TRUE;
+
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print("Arena level.");
+ }
+
+ /* Refill the level with floor tiles */
+ fill_level(empty_level, d_ptr->fill_method);
+ }
+
+ /* Possible cavern */
+ if ((dungeon_flags1 & DF1_CAVERN) && (rand_int(dun_level / 2) > DUN_CAVERN))
+ {
+ cavern = TRUE;
+
+ /* Make a large fractal cave in the middle of the dungeon */
+ if (cheat_room)
+ {
+ msg_print("Cavern on level.");
+ }
+
+ build_cavern();
+ }
+
+ /* Possible "destroyed" level */
+ if ((dun_level > 10) && (rand_int(DUN_DEST) == 0))
+ {
+ destroyed = TRUE;
+ }
+
+ /* Hack -- No destroyed "quest" levels */
+ if (is_quest(dun_level)) destroyed = FALSE;
+
+ /* Hack -- No destroyed "small" levels */
+ if ((cur_wid != MAX_WID) || (cur_hgt != MAX_HGT)) destroyed = FALSE;
+
+ /* Hack -- No destroyed levels */
+ if (dungeon_flags1 & DF1_NO_DESTROY) destroyed = FALSE;
+
+ /* Actual maximum number of rooms on this level */
+ dun->row_rooms = cur_hgt / BLOCK_HGT;
+ dun->col_rooms = cur_wid / BLOCK_WID;
+
+
+ /* Initialize the room table */
+ for (y = 0; y < dun->row_rooms; y++)
+ {
+ for (x = 0; x < dun->col_rooms; x++)
+ {
+ dun->room_map[y][x] = FALSE;
+ }
+ }
+
+ /* No "crowded" rooms yet */
+ dun->crowded = FALSE;
+
+ /* No rooms yet */
+ dun->cent_n = 0;
+
+ /* Pick a block for the room */
+ y = rand_int(dun->row_rooms);
+ x = rand_int(dun->col_rooms);
+
+ /* Align dungeon rooms */
+ if (dungeon_align)
+ {
+ /* Slide some rooms right */
+ if ((x % 3) == 0) x++;
+
+ /* Slide some rooms left */
+ if ((x % 3) == 2) x--;
+ }
+
+ /* Ugly */
+ {
+ struct hook_build_room1_in in = { y, x };
+ process_hooks_new(HOOK_BUILD_ROOM1, &in, NULL);
+ }
+
+ /* Build some rooms */
+ for (i = 0; i < DUN_ROOMS; i++)
+ {
+ /* Pick a block for the room */
+ y = rand_int(dun->row_rooms);
+ x = rand_int(dun->col_rooms);
+
+ /* Align dungeon rooms */
+ if (dungeon_align)
+ {
+ /* Slide some rooms right */
+ if ((x % 3) == 0) x++;
+
+ /* Slide some rooms left */
+ if ((x % 3) == 2) x--;
+ }
+
+ /* Destroyed levels are boring */
+ if (destroyed)
+ {
+ /* The deeper you are, the more cavelike the rooms are */
+
+ /* no caves when cavern exists: they look bad */
+ k = randint(100);
+
+ if (!cavern && (k < dun_level))
+ {
+ /* Type 10 -- Fractal cave */
+ if (room_build(y, x, 10)) continue;
+ }
+ else
+ {
+ /* Attempt a "trivial" room */
+ if ((dungeon_flags1 & DF1_CIRCULAR_ROOMS) &&
+ room_build(y, x, 9))
+ {
+ continue;
+ }
+ else if (room_build(y, x, 1)) continue;
+ }
+
+ /* Never mind */
+ continue;
+ }
+
+ /* Attempt an "unusual" room -- no vaults on town levels */
+ if (!town_level &&
+ (ironman_rooms || (rand_int(DUN_UNUSUAL) < dun_level)))
+ {
+ /* Roll for room type */
+ k = (ironman_rooms ? 0 : rand_int(100));
+
+ /* Attempt a very unusual room */ /* test hack */
+ if (ironman_rooms || (rand_int(DUN_UNUSUAL) < dun_level))
+ {
+ /* Type 8 -- Greater vault (10%) */
+ if (k < 10)
+ {
+ if (max_vault_ok > 1)
+ {
+ if (room_build(y, x, 8)) continue;
+ }
+ else
+ {
+ if (cheat_room) msg_print("Refusing a greater vault.");
+ }
+ }
+
+ /* Type 7 -- Lesser vault (15%) */
+ if (k < 25)
+ {
+ if (max_vault_ok > 0)
+ {
+ if (room_build(y, x, 7)) continue;
+ }
+ else
+ {
+ if (cheat_room) msg_print("Refusing a lesser vault.");
+ }
+ }
+
+
+ /* Type 5 -- Monster nest (15%) */
+ if ((k < 40) && room_build(y, x, 5)) continue;
+
+ /* Type 6 -- Monster pit (15%) */
+ if ((k < 55) && room_build(y, x, 6)) continue;
+
+ /* Type 11 -- Random vault (5%) */
+ if ((k < 60) && room_build(y, x, 11)) continue;
+ }
+
+ /* Type 4 -- Large room (25%) */
+ if ((k < 25) && room_build(y, x, 4)) continue;
+
+ /* Type 3 -- Cross room (20%) */
+ if ((k < 45) && room_build(y, x, 3)) continue;
+
+ /* Type 2 -- Overlapping (20%) */
+ if ((k < 65) && room_build(y, x, 2)) continue;
+
+ /* Type 10 -- Fractal cave (15%) */
+ if ((k < 80) && room_build(y, x, 10)) continue;
+
+ /* Type 9 -- Circular (10%) */
+ /* Hack - build standard rectangular rooms if needed */
+ if (k < 90)
+ {
+ if ((dungeon_flags1 & DF1_CIRCULAR_ROOMS) && room_build(y, x, 1)) continue;
+ else if (room_build(y, x, 9)) continue;
+ }
+
+ /* Type 12 -- Crypt (10%) */
+ if ((k < 100) && room_build(y, x, 12)) continue;
+ }
+
+ /* Attempt a trivial room */
+ if (dungeon_flags1 & DF1_CAVE)
+ {
+ if (room_build(y, x, 10)) continue;
+ }
+ else
+ {
+ if ((dungeon_flags1 & DF1_CIRCULAR_ROOMS) && room_build(y, x, 9)) continue;
+ else if (room_build(y, x, 1)) continue;
+ }
+ }
+
+ /* If no rooms are allocated... */
+ while (dun->cent_n == 0)
+ {
+ /* ...force the creation of a small rectangular room */
+ (void)room_build(0, 0, 1);
+ }
+
+ /* Hack -- Scramble the room order */
+ for (i = 0; i < dun->cent_n; i++)
+ {
+ int pick1 = rand_int(dun->cent_n);
+ int pick2 = rand_int(dun->cent_n);
+ y1 = dun->cent[pick1].y;
+ x1 = dun->cent[pick1].x;
+ dun->cent[pick1].y = dun->cent[pick2].y;
+ dun->cent[pick1].x = dun->cent[pick2].x;
+ dun->cent[pick2].y = y1;
+ dun->cent[pick2].x = x1;
+ }
+
+ /* Start with no tunnel doors */
+ dun->door_n = 0;
+
+ /* Hack -- connect the first room to the last room */
+ y = dun->cent[dun->cent_n - 1].y;
+ x = dun->cent[dun->cent_n - 1].x;
+
+ /* Connect all the rooms together */
+ for (i = 0; i < dun->cent_n; i++)
+ {
+ /* Connect the room to the previous room */
+ build_tunnel(dun->cent[i].y, dun->cent[i].x, y, x, FALSE);
+
+ /* Remember the "previous" room */
+ y = dun->cent[i].y;
+ x = dun->cent[i].x;
+ }
+
+ /* Mega-Hack -- Convert FEAT_WALL_SOLID back into outer walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ if (cave[y][x].feat == FEAT_WALL_SOLID)
+ {
+ cave_set_feat(y, x, feat_wall_outer);
+ }
+ }
+ }
+
+ /* Place intersection doors */
+ for (i = 0; i < dun->door_n; i++)
+ {
+ /* Extract junction location */
+ y = dun->door[i].y;
+ x = dun->door[i].x;
+
+ /* Try placing doors */
+ try_doors(y, x);
+ }
+
+ if (strcmp(game_module, "ToME") == 0)
+ {
+ /* Hack -- Add some magma streamers */
+ if ((dungeon_type == DUNGEON_MORDOR) || (dungeon_type == DUNGEON_ANGBAND))
+ for (i = 0; i < DUN_STR_MAG; i++)
+ {
+ build_streamer(FEAT_MAGMA, DUN_STR_MC);
+ }
+
+ /* Hack -- Add some quartz streamers */
+ if ((dungeon_type == DUNGEON_MORDOR) || (dungeon_type == DUNGEON_ANGBAND))
+ for (i = 0; i < DUN_STR_QUA; i++)
+ {
+ build_streamer(FEAT_QUARTZ, DUN_STR_QC);
+ }
+ }
+
+ /* Add some sand streamers */
+ if ((dungeon_flags1 & DF1_SAND_VEIN) && !rand_int(4))
+ {
+ if ((cheat_room) || (p_ptr->precognition)) msg_print("Sand vein.");
+ build_streamer(FEAT_SANDWALL, DUN_STR_SC);
+ }
+
+ /* Destroy the level if necessary */
+ if (destroyed) destroy_level();
+
+ /* Create the town if needed */
+ if (town_level)
+ {
+ town_gen(town_level);
+ }
+
+ /* Hack -- Add some rivers if requested */
+ if ((dungeon_flags1 & DF1_WATER_RIVER) && !rand_int(4))
+ {
+ if (cheat_room || p_ptr->precognition) msg_print("River of water.");
+ add_river(FEAT_DEEP_WATER, FEAT_SHAL_WATER);
+ }
+ if ((dungeon_flags1 & DF1_LAVA_RIVER) && !rand_int(4))
+ {
+ if ((cheat_room) || (p_ptr->precognition)) msg_print("River of lava.");
+ add_river(FEAT_DEEP_LAVA, FEAT_SHAL_LAVA);
+ }
+
+ if (dungeon_flags1 & DF1_WATER_RIVERS)
+ {
+ int max = 3 + rand_int(2);
+ bool_ said = FALSE;
+
+ for (i = 0; i < max; i++)
+ {
+ if (rand_int(3) == 0)
+ {
+ add_river(FEAT_DEEP_WATER, FEAT_SHAL_WATER);
+ if (!said && ((cheat_room) || (p_ptr->precognition))) msg_print("Rivers of water.");
+ said = TRUE;
+ }
+ }
+ }
+
+ if (dungeon_flags1 & DF1_LAVA_RIVERS)
+ {
+ int max = 2 + rand_int(2);
+ bool_ said = FALSE;
+
+ for (i = 0; i < max; i++)
+ {
+ if (rand_int(3) == 0)
+ {
+ add_river(FEAT_DEEP_LAVA, FEAT_SHAL_LAVA);
+ if (!said && ((cheat_room) || (p_ptr->precognition))) msg_print("Rivers of lava.");
+ said = TRUE;
+ }
+ }
+ }
+
+ /* Add streamers of trees, water, or lava -KMW- */
+ if (!(dungeon_flags1 & DF1_NO_STREAMERS))
+ {
+ int num;
+
+ /*
+ * Flat levels (was: levels 1--2)
+ *
+ * Small trees (penetrate walls)
+ */
+ if ((dungeon_flags1 & DF1_FLAT) && (randint(20) > 15))
+ {
+ num = randint(DUN_STR_QUA);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_SMALL_TREES, 1);
+ }
+ }
+
+ /*
+ * Levels 1 -- 33 (was: 1 -- 19)
+ *
+ * Shallow water (preserve walls)
+ * Deep water (penetrate walls)
+ */
+ if (!(dun_level <= 33) && (randint(20) > 15))
+ {
+ num = randint(DUN_STR_QUA - 1);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_SHAL_WATER, 0);
+ }
+
+ if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_DEEP_WATER, 1);
+ }
+ }
+ }
+
+ /*
+ * Levels 34 -- (was: 20 --)
+ */
+ else if (dun_level > 33)
+ {
+ /*
+ * Shallow lava (preserve walls)
+ * Deep lava (penetrate walls)
+ */
+ if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_SHAL_LAVA, 0);
+ }
+
+ if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA - 1);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_DEEP_LAVA, 1);
+ }
+ }
+ }
+
+ /*
+ * Shallow water (preserve walls)
+ * Deep water (penetrate walls)
+ */
+ else if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA - 1);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_SHAL_WATER, 0);
+ }
+
+ if (randint(20) > 15)
+ {
+ num = randint(DUN_STR_QUA);
+
+ for (i = 0; i < num; i++)
+ {
+ build_streamer2(FEAT_DEEP_WATER, 1);
+ }
+ }
+ }
+ }
+ }
+
+ /* Hack, seems like once a room overrode the level boundaries, this is BAD */
+ set_bounders(empty_level);
+
+ /* Determine the character location */
+ if (!new_player_spot(branch))
+ return FALSE;
+
+ return TRUE;
+}
+
+/*
+ * Bring the imprinted pets from the old level
+ */
+static void replace_all_friends()
+{
+ if (p_ptr->wild_mode)
+ {
+ return;
+ }
+
+ /* Scan every saved pet */
+ for (int i = 0; i < max_m_idx; i++)
+ {
+ if ((km_list[i].r_idx) && (km_list[i].status == MSTATUS_COMPANION))
+ {
+ int y = p_ptr->py;
+ int x = p_ptr->px;
+
+ /* Find a suitable location */
+ get_pos_player(5, &y, &x);
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Get a m_idx to use */
+ c_ptr->m_idx = m_pop();
+ monster_type *m_ptr = &m_list[c_ptr->m_idx];
+
+ /* Actualy place the monster */
+ m_list[c_ptr->m_idx] = km_list[i];
+ m_ptr->fy = y;
+ m_ptr->fx = x;
+ m_ptr->hold_o_idxs.clear(); // Objects have been removed previously by caller
+ }
+ }
+}
+
+/*
+ * Save the imprinted pets from the old level
+ */
+static void save_all_friends()
+{
+ if (p_ptr->old_wild_mode) return;
+
+ for (int i = 0; i < max_m_idx; i++) {
+ km_list[i] = m_list[i];
+ }
+}
+
+
+
+/*
+ * Build probability tables for walls and floors and set feat_wall_outer
+ * and feat_wall_inner according to the current information in d_info.txt
+ *
+ * *hint* *hint* with this made extern, and we no longer have to
+ * store fill_type and floor_type in the savefile...
+ */
+static void init_feat_info(void)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+ int i;
+ int cur_depth, max_depth;
+ int p1, p2;
+ int floor_lim1, floor_lim2;
+ int fill_lim1, fill_lim2;
+
+
+ /* Retrieve dungeon depth info (base 1, to avoid zero divide errors) */
+ cur_depth = (dun_level - d_ptr->mindepth) + 1;
+ max_depth = (d_ptr->maxdepth - d_ptr->mindepth) + 1;
+
+
+ /* Set room wall types */
+ feat_wall_outer = d_ptr->outer_wall;
+ feat_wall_inner = d_ptr->inner_wall;
+
+
+ /* Setup probability info -- Floors */
+ p1 = d_ptr->floor_percent1[0];
+ p2 = d_ptr->floor_percent1[1];
+ floor_lim1 = p1 + (p2 - p1) * cur_depth / max_depth;
+
+ p1 = d_ptr->floor_percent2[0];
+ p2 = d_ptr->floor_percent2[1];
+ floor_lim2 = floor_lim1 + p1 + (p2 - p1) * cur_depth / max_depth;
+
+ /* Setup probability info -- Fillers */
+ p1 = d_ptr->fill_percent1[0];
+ p2 = d_ptr->fill_percent1[1];
+ fill_lim1 = p1 + (p2 - p1) * cur_depth / max_depth;
+
+ p1 = d_ptr->fill_percent2[0];
+ p2 = d_ptr->fill_percent2[1];
+ fill_lim2 = fill_lim1 + p1 + (p2 - p1) * cur_depth / max_depth;
+
+
+ /* Fill the arrays of floors and walls in the good proportions */
+ for (i = 0; i < 100; i++)
+ {
+ if (i < floor_lim1)
+ {
+ floor_type[i] = d_ptr->floor1;
+ }
+ else if (i < floor_lim2)
+ {
+ floor_type[i] = d_ptr->floor2;
+ }
+ else
+ {
+ floor_type[i] = d_ptr->floor3;
+ }
+
+ if (i < fill_lim1)
+ {
+ fill_type[i] = d_ptr->fill_type1;
+ }
+ else if (i < fill_lim2)
+ {
+ fill_type[i] = d_ptr->fill_type2;
+ }
+ else
+ {
+ fill_type[i] = d_ptr->fill_type3;
+ }
+ }
+}
+
+
+/*
+ * Fill a level with wall type specified in A: or L: line of d_info.txt
+ *
+ * 'use_floor', when it is TRUE, tells the function to use floor type
+ * terrains (L:) instead of walls (A:).
+ *
+ * Filling behaviour can be controlled by the second parameter 'smooth',
+ * with the following options available:
+ *
+ * smooth behaviour
+ * ------ ------------------------------------------------------------
+ * 0 Fill the entire level with fill_type1 / floor1
+ * 1 All the grids are randomly selected (== --P5.1.2)
+ * 2 Slightly smoothed -- look like scattered patches
+ * 3 More smoothed -- tend to look like caverns / small scale map
+ * 4-- Max smoothing -- tend to look like landscape/island/
+ * continent etc.
+ *
+ * I put it here, because there's another filler generator in
+ * wild.c, but it works better there, in fact...
+ *
+ * CAVEAT: smoothness of 3 or greater doesn't work well with the
+ * current secret door implementation. Outer walls also need some
+ * rethinking.
+ *
+ * -- pelpel
+ */
+
+/*
+ * Thou shalt not invoke the name of thy RNG in vain.
+ * The Angband RNG generates 28 bit pseudo-random number, hence
+ * 28 / 2 = 14
+ */
+#define MAX_SHIFTS 14
+
+static void fill_level(bool_ use_floor, byte smooth)
+{
+ int y, x;
+ int step;
+ int shift;
+
+
+ /* Convert smoothness to initial step */
+ if (smooth == 0) step = 0;
+ else if (smooth == 1) step = 1;
+ else if (smooth == 2) step = 2;
+ else if (smooth == 3) step = 4;
+ else step = 8;
+
+ /*
+ * Paranoia -- step must be less than or equal to a half of
+ * width or height, whichever shorter
+ */
+ if ((cur_hgt < 16) && (step > 4)) step = 4;
+ if ((cur_wid < 16) && (step > 4)) step = 4;
+
+
+ /* Special case -- simple fill */
+ if (step == 0)
+ {
+ byte filler;
+
+ /* Pick a filler XXX XXX XXX */
+ if (use_floor) filler = d_info[dungeon_type].floor1;
+ else filler = d_info[dungeon_type].fill_type1;
+
+ /* Fill the level with the filler without calling RNG */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, filler);
+ }
+ }
+
+ /* Done */
+ return;
+ }
+
+
+ /*
+ * Fill starting positions -- every 'step' grids horizontally and
+ * vertically
+ */
+ for (y = 0; y < cur_hgt; y += step)
+ {
+ for (x = 0; x < cur_wid; x += step)
+ {
+ /*
+ * Place randomly selected terrain feature using the prebuilt
+ * probability table
+ *
+ * By slightly modifying this, you can build streamers as
+ * well as normal fillers all at once, but this calls for
+ * modifications to the other part of the dungeon generator.
+ */
+ if (use_floor) place_floor(y, x);
+ else place_filler(y, x);
+ }
+ }
+
+
+ /*
+ * Fill spaces between, randomly picking one of their neighbours
+ *
+ * This simple yet powerful algorithm was described by Mike Anderson:
+ *
+ * A B A | B A a B
+ * -> --+-- -> d e b
+ * D C D | C D c C
+ *
+ * a can be either A or B, b B or C, c C or D and d D or A.
+ * e is chosen from A, B, C and D.
+ * Subdivide and repeat the process as many times as you like.
+ *
+ * All the nasty tricks that obscure this simplicity are mine (^ ^;)
+ */
+
+ /* Initialise bit shift counter */
+ shift = MAX_SHIFTS;
+
+ /* Repeat subdivision until all the grids are filled in */
+ while ((step = step >> 1) > 0)
+ {
+ bool_ y_even, x_even;
+ s16b y_wrap, x_wrap;
+ s16b y_sel, x_sel;
+ u32b selector = 0;
+
+ /* Hacklette -- Calculate wrap-around locations */
+ y_wrap = ((cur_hgt - 1) / (step * 2)) * (step * 2);
+ x_wrap = ((cur_wid - 1) / (step * 2)) * (step * 2);
+
+ /* Initialise vertical phase */
+ y_even = 0;
+
+ for (y = 0; y < cur_hgt; y += step)
+ {
+ /* Flip vertical phase */
+ y_even = !y_even;
+
+ /* Initialise horizontal phase */
+ x_even = 0;
+
+ for (x = 0; x < cur_wid; x += step)
+ {
+ /* Flip horizontal phase */
+ x_even = !x_even;
+
+ /* Already filled in by previous iterations */
+ if (y_even && x_even) continue;
+
+ /*
+ * Retrieve next two bits from pseudo-random bit sequence
+ *
+ * You can do well not caring so much about their randomness.
+ *
+ * This is not really necessary, but I don't like to invoke
+ * relatively expensive RNG when we can do with much smaller
+ * number of calls.
+ */
+ if (shift >= MAX_SHIFTS)
+ {
+ selector = rand_int(0x10000000L);
+ shift = 0;
+ }
+ else
+ {
+ selector >>= 2;
+ shift++;
+ }
+
+ /* Vertically in sync */
+ if (y_even) y_sel = y;
+
+ /* Bit 1 selects neighbouring y */
+ else y_sel = (selector & 2) ? y + step : y - step;
+
+ /* Horizontally in sync */
+ if (x_even) x_sel = x;
+
+ /* Bit 0 selects neighbouring x */
+ else x_sel = (selector & 1) ? x + step : x - step;
+
+ /* Hacklette -- Fix out of range indices by wrapping around */
+ if (y_sel >= cur_hgt) y_sel = 0;
+ else if (y_sel < 0) y_sel = y_wrap;
+ if (x_sel >= cur_wid) x_sel = 0;
+ else if (x_sel < 0) x_sel = x_wrap;
+
+ /*
+ * Fill the grid with terrain feature of the randomly
+ * picked up neighbour
+ */
+ cave_set_feat(y, x, cave[y_sel][x_sel].feat);
+ }
+ }
+ }
+}
+
+
+/**
+ * @brief double a grid tile. Used for the double-size dungeons
+ */
+static void supersize_grid_tile(int sy, int sx, int ty, int tx)
+{
+ /* Displacements for copied grid tiles */
+ constexpr std::size_t n_disp = 4;
+ int disp[n_disp][2] = {
+ { 0, 0 },
+ { 0, +1 },
+ { +1, 0 },
+ { +1, +1 }
+ };
+
+ /* Acquire the grid tile and monster */
+ cave_type *cc_ptr = &cave[sy][sx];
+ monster_type *m_ptr = &m_list[cc_ptr->m_idx];
+
+ /* Save the list of objects */
+ auto const object_idxs(cc_ptr->o_idxs);
+
+ /* Save the monster */
+ auto m_idx = cc_ptr->m_idx;
+
+ /* Create pointers to each of the target grid tiles */
+ cave_type *c_ptr[n_disp];
+ for (std::size_t i = 0; i < n_disp; i++)
+ {
+ c_ptr[i] = &cave[ty + disp[i][0]][tx + disp[i][1]];
+ }
+
+ /* Now we copy around the grid tiles. Objects and
+ monsters are "removed" for now. */
+ for (std::size_t i = 0; i < 4; i++)
+ {
+ c_ptr[i] = &cave[ty + disp[i][0]][tx + disp[i][1]];
+
+ /* Copy grid */
+ *c_ptr[i] = *cc_ptr;
+ c_ptr[i]->o_idxs.clear(); // ... except objects in the tile
+ c_ptr[i]->m_idx = 0; // ... except monsters in the tile
+
+ /* Void gates need special attention */
+ if (cc_ptr->feat == FEAT_BETWEEN)
+ {
+ int xxx = cc_ptr->special & 0xFF;
+ int yyy = cc_ptr->special >> 8;
+
+ xxx *= 2;
+ yyy *= 2;
+ xxx += disp[i][1];
+ yyy += disp[i][0];
+ c_ptr[i]->special = xxx + (yyy << 8);
+ }
+ }
+
+ /* Scatter objects randomly into the destination grid tiles */
+ for (auto const o_idx: object_idxs)
+ {
+ std::size_t i = static_cast<std::size_t>(rand_int(4));
+ /* Put object into grid tile */
+ c_ptr[i]->o_idxs.push_back(o_idx);
+ /* Give object its location */
+ object_type *o_ptr = &o_list[o_idx];
+ o_ptr->iy = ty + disp[i][0];
+ o_ptr->ix = tx + disp[i][1];
+ }
+
+ /* Scatter move monster randomly into one of the destination grid tiles */
+ if (m_idx != 0)
+ {
+ std::size_t i = static_cast<std::size_t>(rand_int(4));
+ /* Place monster into grid tile */
+ c_ptr[i]->m_idx = cc_ptr->m_idx;
+ /* Give the monster its location */
+ m_ptr->fy = ty + disp[i][0];
+ m_ptr->fx = tx + disp[i][1];
+ }
+}
+
+
+/*
+ * Generate a new dungeon level
+ *
+ * Note that "dun_body" adds about 4000 bytes of memory to the stack.
+ */
+static bool_ cave_gen(void)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+
+ int max_vault_ok = 2;
+
+ bool_ empty_level = FALSE;
+
+ level_generator_type *generator;
+
+ dun_data dun_body;
+
+ char generator_name[100];
+
+ if (!get_dungeon_generator(generator_name))
+ strnfmt(generator_name, 99, "%s", d_ptr->generator);
+
+ /*
+ * We generate a double dungeon. First we should halve the desired
+ * width/height, generate the dungeon normally, then double it
+ * in both directions
+ */
+ if (dungeon_flags1 & DF1_DOUBLE)
+ {
+ cur_wid /= 2;
+ cur_hgt /= 2;
+ }
+
+ /* Fill the arrays of floors and walls in the good proportions */
+ init_feat_info();
+
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ /* Global data */
+ dun = &dun_body;
+
+ if (!(max_panel_rows)) max_vault_ok--;
+ if (!(max_panel_cols)) max_vault_ok--;
+
+ /*
+ * Hack -- Start with fill_type's
+ *
+ * Need a way to know appropriate smoothing factor for the current
+ * dungeon. Maybe we need another d_info flag/value.
+ */
+ fill_level(empty_level, d_ptr->fill_method);
+
+ set_bounders(empty_level);
+
+ /*
+ * Call the good level generator
+ */
+ generator = level_generators;
+ while (generator)
+ {
+ if (!strcmp(generator->name, generator_name))
+ {
+ if (!generator->generator())
+ return FALSE;
+ break;
+ }
+
+ generator = generator->next;
+ }
+
+ /* Generate stairs */
+ {
+ /* Is there a dungeon branch ? */
+ if (int branch = get_branch())
+ {
+ /* Place 5 down stair some walls */
+ alloc_stairs(FEAT_MORE, 5, 3, branch);
+ }
+
+ /* Is there a father dungeon branch ? */
+ if (int branch = get_fbranch())
+ {
+ /* Place 1 down stair some walls */
+ alloc_stairs(FEAT_LESS, 5, 3, branch);
+ }
+
+ if ((dun_level < d_ptr->maxdepth) || ((dun_level == d_ptr->maxdepth) && (dungeon_flags1 & DF1_FORCE_DOWN)))
+ {
+ /* Place 3 or 4 down stairs near some walls */
+ alloc_stairs((dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_MORE : FEAT_MORE, rand_range(3, 4), 3, 0);
+
+ /* Place 0 or 1 down shafts near some walls */
+ if (!(dungeon_flags2 & DF2_NO_SHAFT)) alloc_stairs((dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_MORE : FEAT_SHAFT_DOWN, rand_range(0, 1), 3, 0);
+ }
+
+ if ((dun_level > d_ptr->mindepth) || ((dun_level == d_ptr->mindepth) && (!(dungeon_flags1 & DF1_NO_UP))))
+ {
+ /* Place 1 or 2 up stairs near some walls */
+ alloc_stairs((dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_LESS : FEAT_LESS, rand_range(1, 2), 3, 0);
+
+ /* Place 0 or 1 up shafts near some walls */
+ if (!(dungeon_flags2 & DF2_NO_SHAFT)) alloc_stairs((dungeon_flags1 & DF1_FLAT) ? FEAT_WAY_LESS : FEAT_SHAFT_UP, rand_range(0, 1), 3, 0);
+ }
+ }
+
+ process_hooks_new(HOOK_GEN_LEVEL, NULL, NULL);
+
+ /* Basic "amount" */
+ int k = (dun_level / 3);
+ if (k > 10) k = 10;
+ if (k < 2) k = 2;
+
+ /* Place monsters */
+ {
+
+ /*
+ * Pick a base number of monsters
+ */
+ int i = d_ptr->min_m_alloc_level;
+
+ /* To make small levels a bit more playable */
+ if ((cur_hgt < MAX_HGT) || (cur_wid < MAX_WID))
+ {
+ int small_tester = i;
+
+ i = (i * cur_hgt) / MAX_HGT;
+ i = (i * cur_wid) / MAX_WID;
+ i += 1;
+
+ if (i > small_tester) i = small_tester;
+ else if (cheat_hear)
+ {
+ msg_format("Reduced monsters base from %d to %d", small_tester, i);
+ }
+ }
+
+ i += randint(8);
+
+ /* Put some monsters in the dungeon */
+ for (i = i + k; i > 0; i--)
+ {
+ (void)alloc_monster(0, TRUE);
+ }
+ }
+
+ /* Check fates */
+ for (std::size_t i = 0; i < MAX_FATES; i++)
+ {
+ /* Ignore empty slots */
+ if (fates[i].fate == FATE_NONE) continue;
+
+ /* Check dungeon depth */
+ if (fates[i].level != dun_level) continue;
+
+ /* Non-serious fates don't always fire */
+ if ((!fates[i].serious) && (randint(2) != 1)) continue;
+
+ /* Player meets his/her fate now... */
+ fate_flag = TRUE;
+
+ switch (fates[i].fate)
+ {
+ case FATE_FIND_O:
+ {
+ int oy = p_ptr->py + 1;
+ int ox = p_ptr->px;
+ object_type *q_ptr, forge;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Mega-Hack */
+ object_prep(q_ptr, fates[i].o_idx);
+
+ /* Mega-Hack */
+ apply_magic(q_ptr, dun_level, TRUE, TRUE, fates[i].serious);
+
+ get_pos_player(10, &oy, &ox);
+
+ /* Drop it from the heaven */
+ drop_near(q_ptr, -1, oy, ox);
+
+ /* Make it icky */
+ fates[i].icky = TRUE;
+ break;
+ }
+ case FATE_FIND_R:
+ {
+ int oy = p_ptr->py + 1;
+ int ox = p_ptr->px;
+
+ get_pos_player(10, &oy, &ox);
+
+ place_monster_one(oy, ox, fates[i].r_idx, 0, fates[i].serious, MSTATUS_ENEMY);
+
+ fates[i].icky = TRUE;
+ break;
+ }
+ case FATE_FIND_A:
+ {
+ int oy = p_ptr->py + 1;
+ int ox = p_ptr->px;
+ object_type *q_ptr = NULL, forge;
+
+ get_pos_player(10, &oy, &ox);
+
+ /* XXX XXX XXX Grant a randart */
+ if (fates[i].a_idx == 0)
+ {
+ int obj_lev;
+ s16b k_idx;
+
+ /* Apply restriction */
+ get_obj_num_hook = kind_is_artifactable;
+
+ /* Object level a la find object fates */
+ obj_lev = max_dlv[dungeon_type] + randint(10);
+
+ /* Rebuild allocation table */
+ get_obj_num_prep();
+
+ /* Roll for an object */
+ k_idx = get_obj_num(obj_lev);
+
+ /* Reset restriction */
+ get_obj_num_hook = kind_is_legal;
+
+ /* Invalidate the allocation table */
+ alloc_kind_table_valid = FALSE;
+
+ /* Get a local object */
+ q_ptr = &forge;
+
+ /* Wipe it */
+ object_wipe(q_ptr);
+
+ /* Create the object */
+ object_prep(q_ptr, k_idx);
+
+ /* SoAC it */
+ create_artifact(q_ptr, FALSE, TRUE);
+
+ /* Drop the artifact from heaven */
+ drop_near(q_ptr, -1, oy, ox);
+ }
+
+ /* Grant a normal artefact */
+ else if (a_info[fates[i].a_idx].cur_num == 0)
+ {
+ artifact_type *a_ptr = &a_info[fates[i].a_idx];
+ s16b I_kind;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Acquire the "kind" index */
+ I_kind = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Create the artifact */
+ object_prep(q_ptr, I_kind);
+
+ /* Save the name */
+ q_ptr->name1 = fates[i].a_idx;
+
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ /* Drop the artifact from heaven */
+ drop_near(q_ptr, -1, oy, ox);
+ }
+
+ fates[i].icky = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Re-scan the list to eliminate the inutile fate */
+ for (std::size_t i = 0; i < MAX_FATES; i++)
+ {
+ switch (fates[i].fate)
+ {
+ case FATE_FIND_A:
+ {
+ if (a_info[fates[i].a_idx].cur_num == 1) fates[i].icky = TRUE;
+ break;
+ }
+ case FATE_FIND_R:
+ {
+ if ((r_info[fates[i].r_idx].cur_num == 1) && (r_info[fates[i].r_idx].flags1 & RF1_UNIQUE)) fates[i].icky = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Place traps and rubble */
+ {
+ /* Place some traps in the dungeon */
+ alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_TRAP, randint(k * 2));
+
+ /* Put some rubble in corridors */
+ alloc_object(ALLOC_SET_CORR, ALLOC_TYP_RUBBLE, randint(k));
+ }
+
+ /* Place objects and treasure */
+ {
+ /* Put some objects in rooms */
+ if (dungeon_type != DUNGEON_DEATH) alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ROOM, 3));
+
+ /* Put some objects/gold in the dungeon */
+ if (dungeon_type != DUNGEON_DEATH) alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ITEM, 3));
+ if (dungeon_type != DUNGEON_DEATH) alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_GOLD, randnor(DUN_AMT_GOLD, 3));
+ }
+
+ /* Place random features such as altars and void gates, etc. */
+ {
+ /* Put some altars */
+ alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_ALTAR, randnor(DUN_AMT_ALTAR, 3));
+
+ /* Put some between gates */
+ alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_BETWEEN, randnor(DUN_AMT_BETWEEN, 3));
+
+ /* Put some fountains */
+ alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_FOUNTAIN, randnor(DUN_AMT_FOUNTAIN, 3));
+ }
+
+ /* Put an Artifact and Artifact Guardian is requested */
+ if (d_ptr->final_guardian && (d_ptr->maxdepth == dun_level))
+ {
+ int oy;
+ int ox;
+ int m_idx, tries = 10000;
+
+ /* Find a good position */
+ while (tries)
+ {
+ /* Get a random spot */
+ oy = randint(cur_hgt - 4) + 2;
+ ox = randint(cur_wid - 4) + 2;
+
+ /* Is it a good spot ? */
+ if (cave_empty_bold(oy, ox)) break;
+
+ /* One less try */
+ tries--;
+ }
+
+ /* Place the guardian */
+ m_allow_special[d_ptr->final_guardian] = TRUE;
+ place_monster_one(oy, ox, d_ptr->final_guardian, 0, FALSE, MSTATUS_ENEMY);
+ m_allow_special[d_ptr->final_guardian] = FALSE;
+
+
+ m_idx = cave[oy][ox].m_idx;
+
+ if (!m_idx && wizard) cmsg_print(TERM_L_RED, "WARNING: Could not place guardian.");
+
+ /*
+ * If guardian is successfully created and his/her/its
+ * treasure hasn't been found, let him/her/it own that
+ */
+ if (m_idx && d_ptr->final_artifact &&
+ (a_info[d_ptr->final_artifact].cur_num == 0))
+ {
+ artifact_type *a_ptr = &a_info[d_ptr->final_artifact];
+ object_type *q_ptr, forge, *o_ptr;
+ int I_kind, o_idx;
+
+ /* Get new object */
+ o_idx = o_pop();
+
+ /* Proceed only if there's an object slot available */
+ if (o_idx)
+ {
+ a_allow_special[d_ptr->final_artifact] = TRUE;
+
+ /* Get local object */
+ q_ptr = &forge;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Acquire the "kind" index */
+ I_kind = lookup_kind(a_ptr->tval, a_ptr->sval);
+
+ /* Create the artifact */
+ object_prep(q_ptr, I_kind);
+
+ /* Save the name */
+ q_ptr->name1 = d_ptr->final_artifact;
+
+ /* Actually create it */
+ apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
+
+ /* Where it is found ? */
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = d_ptr->final_guardian;
+ q_ptr->found_aux2 = 0;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ a_allow_special[d_ptr->final_artifact] = FALSE;
+
+ /* Get the item */
+ o_ptr = &o_list[o_idx];
+
+ /* Structure copy */
+ object_copy(o_ptr, q_ptr);
+
+ /* Build a stack */
+ o_ptr->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idxs.push_back(o_idx);
+ }
+ }
+
+ if (m_idx && d_ptr->final_object &&
+ (k_info[d_ptr->final_object].artifact == FALSE))
+ {
+ object_type *q_ptr, forge, *o_ptr;
+ int o_idx;
+
+ /* Get new object */
+ o_idx = o_pop();
+
+ /* Proceed only if there's an object slot available */
+ if (o_idx)
+ {
+ /* Get local object */
+ q_ptr = &forge;
+
+ k_allow_special[d_ptr->final_object] = TRUE;
+
+ /* Wipe the object */
+ object_wipe(q_ptr);
+
+ /* Create the final object */
+ object_prep(q_ptr, d_ptr->final_object);
+ apply_magic(q_ptr, 1, FALSE, FALSE, FALSE);
+
+ /* Where it is found ? */
+ q_ptr->found = OBJ_FOUND_MONSTER;
+ q_ptr->found_aux1 = d_ptr->final_guardian;
+ q_ptr->found_aux2 = 0;
+ q_ptr->found_aux3 = dungeon_type;
+ q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level);
+
+ k_allow_special[d_ptr->final_object] = FALSE;
+
+ k_info[d_ptr->final_object].artifact = TRUE;
+
+ /* Get the item */
+ o_ptr = &o_list[o_idx];
+
+ /* Structure copy */
+ object_copy(o_ptr, q_ptr);
+
+ /* Build a stack */
+ o_ptr->held_m_idx = m_idx;
+ o_ptr->ix = 0;
+ o_ptr->iy = 0;
+
+ m_list[m_idx].hold_o_idxs.push_back(o_idx);
+ }
+ }
+ }
+
+ if ((empty_level) && (randint(DARK_EMPTY) != 1 || (randint(100) > dun_level)))
+ wiz_lite();
+
+ /* Now double the generated dungeon */
+ if (dungeon_flags1 & DF1_DOUBLE)
+ {
+ /*
+ * We begin at the bottom-right corner and move upwards
+ * to the left. This avoids the need for an extra copy of
+ * the cave array.
+ *
+ * We double the border permanent walls, too.
+ */
+ int y = cur_hgt - 1;
+ int y1 = y * 2;
+ for (; y >= 0; y--, y1 -= 2)
+ {
+ int x = cur_wid - 1;
+ int x1 = x * 2;
+ for (; x >= 0; x--, x1 -= 2)
+ {
+ supersize_grid_tile(y, x, y1, x1);
+ }
+ }
+
+ /* Set the width/height ... */
+ cur_wid *= 2;
+ cur_hgt *= 2;
+
+ /* ... and player position to the right place */
+ p_ptr->py *= 2;
+ p_ptr->px *= 2;
+ }
+
+ return TRUE;
+}
+
+
+
+/*
+ * Creates a special level
+ */
+
+/* Mega-Hack */
+#define REGEN_HACK 0x02
+
+bool_ build_special_level(void)
+{
+ char buf[80];
+ int y, x, ystart = 2, xstart = 2;
+ s16b level;
+
+ /* No special levels on the surface */
+ if (!dun_level) return FALSE;
+
+ level = dun_level - d_info[dungeon_type].mindepth;
+ if ((!get_dungeon_save(buf)) && (special_lvl[level][dungeon_type])) return FALSE;
+ if (!get_dungeon_special(buf)) return FALSE;
+
+ /* Big town */
+ cur_hgt = MAX_HGT;
+ cur_wid = MAX_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ /* Start with perm walls */
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_set_feat(y, x, FEAT_PERM_SOLID);
+ }
+ }
+ /* Set the correct monster hook */
+ set_mon_num_hook();
+
+ /* Prepare allocation table */
+ get_mon_num_prep();
+
+ init_flags = INIT_CREATE_DUNGEON | INIT_POSITION;
+ process_dungeon_file(buf, &ystart, &xstart, cur_hgt, cur_wid, TRUE, TRUE);
+
+ special_lvl[level][dungeon_type] = REGEN_HACK;
+ generate_special_feeling = TRUE;
+
+ /* Special feeling because it's special */
+ good_item_flag = TRUE;
+
+ /*
+ * Hack -- It's better/more dangerous than a greater vault.
+ * Better to have a rating field in special level description.
+ */
+ rating += 40;
+
+ return TRUE;
+}
+
+/*
+ * Prepare regeneration of a special level, which should not happen,
+ * but just in case...
+ */
+static void wipe_special_level(void)
+{
+ s16b level;
+ char buf[80];
+
+ /* No special levels on the surface */
+ if (!dun_level) return;
+
+ process_hooks_new(HOOK_LEVEL_REGEN, NULL, NULL);
+
+ /* Calculate relative depth */
+ level = dun_level - d_info[dungeon_type].mindepth;
+
+ /* No special level at this depth */
+ if ((!get_dungeon_save(buf)) &&
+ special_lvl[level][dungeon_type]) return;
+ if (!get_dungeon_special(buf)) return;
+
+ /* Clear the Mega-Hack flag */
+ if (special_lvl[level][dungeon_type] == REGEN_HACK)
+ special_lvl[level][dungeon_type] = FALSE;
+}
+
+/*
+ * Finalise generation of a special level
+ */
+static void finalise_special_level(void)
+{
+ s16b level;
+ char buf[80];
+
+ /* No special levels on the surface */
+ if (!dun_level) return;
+
+ process_hooks_new(HOOK_LEVEL_END_GEN, NULL, NULL);
+
+ /* Calculate relative depth */
+ level = dun_level - d_info[dungeon_type].mindepth;
+
+ /* No special level at this depth */
+ if ((!get_dungeon_save(buf)) &&
+ special_lvl[level][dungeon_type]) return;
+ if (!get_dungeon_special(buf)) return;
+
+ /* Set the "generated" flag */
+ if (special_lvl[level][dungeon_type] == REGEN_HACK)
+ special_lvl[level][dungeon_type] = TRUE;
+}
+
+/*
+ * Give some magical energy to the each grid of the level
+ */
+static void generate_grid_mana()
+{
+ int y, x, mana, mult;
+ bool_ xtra_magic = FALSE;
+
+ if (randint(XTRA_MAGIC) == 1)
+ {
+ xtra_magic = TRUE;
+
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print("Magical level");
+ }
+ }
+
+ mult = ((xtra_magic) ? 3 : 2);
+
+ for (y = 0; y < cur_hgt; y++)
+ {
+ for (x = 0; x < cur_wid; x++)
+ {
+ cave_type *c_ptr = &cave[y][x];
+
+ /* Calculate the amount of mana in each grid */
+ mana = mult * m_bonus(255, dun_level) / 2;
+ if (xtra_magic) mana += 10 + rand_int(10);
+
+ /* Never more than 255 or less than 0(paranoia) */
+ if (mana < 0) mana = 0;
+ if (mana > 255) mana = 255;
+
+ c_ptr->mana = mana;
+ }
+ }
+}
+
+
+/*
+ * Generates a random dungeon level -RAK-
+ *
+ * Hack -- regenerate any "overflow" levels
+ *
+ * Hack -- allow auto-scumming via a gameplay option.
+ */
+void generate_cave(void)
+{
+ dungeon_info_type *d_ptr = &d_info[dungeon_type];
+ int tester_1, tester_2;
+ int y, x, num, i;
+ bool_ loaded = FALSE;
+ char buf[80];
+ s16b town_level = 0;
+
+ /* The dungeon is not ready */
+ character_dungeon = FALSE;
+ generate_special_feeling = FALSE;
+
+ /* Initialize the flags with the basic dungeon flags */
+ if (!dun_level)
+ {
+ dungeon_flags1 = d_info[DUNGEON_WILDERNESS].flags1;
+ dungeon_flags2 = d_info[DUNGEON_WILDERNESS].flags2;
+ }
+ else
+ {
+ dungeon_flags1 = d_ptr->flags1;
+ dungeon_flags2 = d_ptr->flags2;
+ }
+
+ /* Is it a town level ? */
+ for (i = 0; i < TOWN_DUNGEON; i++)
+ {
+ if (d_ptr->t_level[i] == dun_level) town_level = d_ptr->t_idx[i];
+ }
+
+ /* Save the imprinted monsters */
+ save_all_friends();
+ wipe_m_list();
+
+ /* Seed the RNG if appropriate */
+ if (town_level)
+ {
+ Rand_quick = TRUE;
+ Rand_value = town_info[town_level].seed;
+ }
+
+ process_hooks_new(HOOK_GEN_LEVEL_BEGIN, NULL, NULL);
+
+ /* Try to load a saved level */
+ if (get_dungeon_save(buf))
+ {
+ /* No effects */
+ for (i = 0; i < MAX_EFFECTS; i++)
+ {
+ effects[i].time = 0;
+ }
+
+ /* Start with a blank cave */
+ for (y = 0; y < MAX_HGT; y++)
+ {
+ for (x = 0; x < MAX_WID; x++)
+ {
+ /* Wipe */
+ cave[y][x].wipe();
+
+ /* No features */
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+ }
+ }
+
+ loaded = load_dungeon(buf);
+ }
+
+ /* No saved level -- generate new one */
+ if (!loaded)
+ {
+ if (!get_dungeon_special(buf) ||
+ !special_lvl[dun_level - d_info[dungeon_type].mindepth][dungeon_type])
+ {
+ get_level_flags();
+ }
+
+ /* Generate */
+ for (num = 0; TRUE; num++)
+ {
+ bool_ okay = TRUE;
+
+ cptr why = NULL;
+
+ /* No effects */
+ for (i = 0; i < MAX_EFFECTS; i++)
+ {
+ effects[i].time = 0;
+ }
+
+ /* Start with a blank cave */
+ for (y = 0; y < MAX_HGT; y++)
+ {
+ for (x = 0; x < MAX_WID; x++)
+ {
+ /* Wipe */
+ cave[y][x].wipe();
+
+ /* No features */
+ cave_set_feat(y, x, FEAT_PERM_INNER);
+ }
+ }
+
+
+ /* XXX XXX XXX XXX */
+ o_max = 1;
+
+
+ /* Mega-Hack -- no player yet */
+ p_ptr->px = p_ptr->py = 0;
+
+
+ /* Mega-Hack -- no panel yet */
+ panel_row_min = 0;
+ panel_row_max = 0;
+ panel_col_min = 0;
+ panel_col_max = 0;
+
+
+ /* Reset the monster generation level */
+ if (dungeon_type != DUNGEON_DEATH) monster_level = dun_level;
+ else monster_level = (p_ptr->lev * 2) + 10 + rand_int(40);
+
+ /* Reset the object generation level */
+ object_level = dun_level;
+
+ /* Nothing special here yet */
+ good_item_flag = FALSE;
+
+ /* Nothing good here yet */
+ rating = 0;
+
+ /* No ambush here yet */
+ ambush_flag = FALSE;
+
+ /* No fated level here yet */
+ fate_flag = FALSE;
+
+ /* Quest levels -KMW- */
+ if (p_ptr->inside_quest)
+ {
+ process_hooks_new(HOOK_GEN_QUEST, NULL, NULL);
+ }
+
+ /* Special levels */
+ else if (build_special_level())
+ {
+ /* nothing */
+ }
+
+ /* Build the town */
+ else if (!dun_level)
+ {
+ /* Big town */
+ cur_hgt = MAX_HGT;
+ cur_wid = MAX_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ /* Big wilderness mode */
+ if (!p_ptr->wild_mode)
+ {
+ /* Make the wilderness */
+ wilderness_gen();
+ }
+
+ /* Small wilderness mode */
+ else
+ {
+ /* Make the wilderness */
+ wilderness_gen_small();
+ }
+
+
+ okay = TRUE;
+ }
+
+ /* Build a dungeon level */
+ else
+ {
+ /* Requested size level */
+ if (d_ptr->size_x != -1)
+ {
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print ("A 'size' dungeon level.");
+ }
+
+ cur_hgt = d_ptr->size_y * SCREEN_HGT;
+ cur_wid = d_ptr->size_x * SCREEN_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ if (cheat_room)
+ {
+ msg_format("X:%d, Y:%d.", max_panel_cols, max_panel_rows);
+ }
+ }
+ /* Very small (1 x 1 panel) level */
+ else if (!(dungeon_flags1 & DF1_BIG) &&
+ (dungeon_flags1 & DF1_SMALLEST))
+ {
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print ("A 'small' dungeon level.");
+ }
+
+ cur_hgt = SCREEN_HGT;
+ cur_wid = SCREEN_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = 1;
+ max_panel_cols = 1;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ if (cheat_room)
+ {
+ msg_format("X:1, Y:1.");
+ }
+ }
+
+ /* Small level */
+ else if (!(dungeon_flags1 & DF1_BIG) &&
+ (always_small_level ||
+ (dungeon_flags1 & DF1_SMALL) ||
+ (small_levels && rand_int(SMALL_LEVEL) == 0)))
+ {
+ if (cheat_room || p_ptr->precognition)
+ {
+ msg_print ("A 'small' dungeon level.");
+ }
+
+ tester_1 = rand_range(1, (MAX_HGT / SCREEN_HGT));
+ tester_2 = rand_range(1, (MAX_WID / SCREEN_WID) - 1);
+
+ cur_hgt = tester_1 * SCREEN_HGT;
+ cur_wid = tester_2 * SCREEN_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+
+ if (cheat_room)
+ {
+ msg_format("X:%d, Y:%d.", max_panel_cols, max_panel_rows);
+ }
+ }
+
+ /* Normal level */
+ else
+ {
+ /* Use full panels */
+ cur_hgt = MAX_HGT;
+ cur_wid = MAX_WID;
+
+ /* Determine number of panels */
+ max_panel_rows = (cur_hgt / SCREEN_HGT) * 2 - 2;
+ max_panel_cols = (cur_wid / SCREEN_WID) * 2 - 2;
+
+ /* Assume illegal panel */
+ panel_row_min = max_panel_rows * (SCREEN_HGT / 2);
+ panel_col_min = max_panel_cols * (SCREEN_WID / 2);
+ }
+
+ /* Generate a level */
+ if (!cave_gen())
+ {
+ why = "could not place player";
+ okay = FALSE;
+ }
+ }
+
+ /* Extract the feeling */
+ if (rating > 100) feeling = 2;
+ else if (rating > 80) feeling = 3;
+ else if (rating > 60) feeling = 4;
+ else if (rating > 40) feeling = 5;
+ else if (rating > 30) feeling = 6;
+ else if (rating > 20) feeling = 7;
+ else if (rating > 10) feeling = 8;
+ else if (rating > 0) feeling = 9;
+ else feeling = 10;
+
+ /* Hack -- Have a special feeling sometimes */
+ if (good_item_flag && !p_ptr->preserve) feeling = 1;
+
+ /* It takes 1000 game turns for "feelings" to recharge */
+ if ((turn - old_turn) < 1000) feeling = 0;
+
+ /* Hack -- no feeling in the town */
+ if (!dun_level) feeling = 0;
+
+
+ /* Prevent object over-flow */
+ if (o_max >= max_o_idx)
+ {
+ /* Message */
+ why = "too many objects";
+
+ /* Message */
+ okay = FALSE;
+ }
+
+ /* Prevent monster over-flow */
+ if (m_max >= max_m_idx)
+ {
+ /* Message */
+ why = "too many monsters";
+
+ /* Message */
+ okay = FALSE;
+ }
+
+ /* Mega-Hack -- "auto-scum" */
+ if (auto_scum && (num < 100) && !p_ptr->inside_quest && dun_level)
+ {
+ /* Require "goodness" */
+ if ((feeling > 9) ||
+ ((dun_level >= 5) && (feeling > 8)) ||
+ ((dun_level >= 10) && (feeling > 7)) ||
+ ((dun_level >= 20) && (feeling > 6)) ||
+ ((dun_level >= 40) && (feeling > 5)))
+ {
+ /* Give message to cheaters */
+ if (cheat_room || cheat_hear ||
+ cheat_peek || cheat_xtra || p_ptr->precognition)
+ {
+ /* Message */
+ why = "boring level";
+ }
+
+ /* Try again */
+ okay = FALSE;
+ }
+ }
+
+ /* Accept */
+ if (okay || town_level) break;
+
+ /* Message */
+ if (why) msg_format("Generation restarted (%s)", why);
+
+ /* Wipe the objects */
+ wipe_o_list();
+
+ /* Wipe the monsters */
+ wipe_m_list();
+
+ /* Clear the fate icky flags */
+ for (i = 0; i < MAX_FATES; i++) fates[i].icky = FALSE;
+
+ /*
+ * Mega-Hack -- Reset special level flag if necessary
+ * XXX XXX XXX
+ */
+ wipe_special_level();
+ }
+
+ /* Give some mana to each grid -- DG */
+ generate_grid_mana();
+ }
+
+ /* Put the kept monsters -- DG */
+ if (!p_ptr->wild_mode)
+ {
+ replace_all_friends();
+ }
+
+ /* Hack -- Clear used up fates */
+ for (i = 0; i < MAX_FATES; i++)
+ {
+ if (fates[i].icky)
+ {
+ /* Mark the artefact as generated */
+ if ((fates[i].fate == FATE_FIND_A) && fates[i].a_idx)
+ {
+ a_info[fates[i].a_idx].cur_num = 1;
+ }
+ fates[i].fate = FATE_NONE;
+ fates[i].icky = FALSE;
+ }
+ }
+
+ /* Set special level generated flag if applicable */
+ finalise_special_level();
+
+ /* No teleporatations yet */
+ last_teleportation_y = -1;
+ last_teleportation_x = -1;
+
+ /* Mark the dungeon town as found */
+ if (town_level)
+ {
+ /* Set the known flag */
+ town_info[town_level].flags |= (TOWN_KNOWN);
+ }
+
+ /* The dungeon is ready */
+ character_dungeon = TRUE;
+
+ /* Remember when this level was "created" */
+ old_turn = turn;
+
+ /* Provide astral chars with the full map */
+ if (p_ptr->astral && dun_level)
+ {
+ wiz_lite_extra();
+ }
+
+ /* Player should get the first move upon entering the dungeon */
+ p_ptr->energy = 100;
+}