X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Frooms.c;h=361cb255e1647de710182e7bdace358cb2e4bde3;hb=92d3cff0ee859021acc670812e0a86dbc3158947;hp=403f7c1f6fb94f0ba9946fa7ecf7f06f255540ab;hpb=bc4d829a5d2cb648bcc32677a17251f094369861;p=hengband%2Fhengband.git diff --git a/src/rooms.c b/src/rooms.c index 403f7c1f6..361cb255e 100644 --- a/src/rooms.c +++ b/src/rooms.c @@ -1,14 +1,39 @@ -/* - * File: rooms.c - * Purpose: make rooms. Used by generate.c when creating dungeons. - */ - -/* - * Copyright (c) 1997 Ben Harrison, 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. Other copyrights may also apply. +/*! + * @file rooms.c + * @brief ダンジョンフロアの部屋生成処理 / make rooms. Used by generate.c when creating dungeons. + * @date 2014/01/06 + * @author + * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n + * This software may be copied and distributed for educational, research,\n + * and not for profit purposes provided that this copyright and statement\n + * are included in all such copies. Other copyrights may also apply.\n + * 2014 Deskull rearranged comment for Doxygen. \n + * @details + * Room building routines.\n + *\n + * Room types:\n + * 1 -- normal\n + * 2 -- overlapping\n + * 3 -- cross shaped\n + * 4 -- large room with features\n + * 5 -- monster nests\n + * 6 -- monster pits\n + * 7 -- simple vaults\n + * 8 -- greater vaults\n + * 9 -- fractal caves\n + * 10 -- random vaults\n + * 11 -- circular rooms\n + * 12 -- crypts\n + * 13 -- trapped monster pits\n + * 14 -- trapped room\n + * 15 -- glass room\n + * 16 -- underground arcade\n + *\n + * Some functions are used to determine if the given monster\n + * is appropriate for inclusion in a monster nest or monster pit or\n + * the given type.\n + *\n + * None of the pits/nests are allowed to include "unique" monsters.\n */ #include "angband.h" @@ -16,31 +41,76 @@ #include "grid.h" #include "rooms.h" - -/* - * Array of minimum room depths +#include "rooms-normal.h" + + +/*! + * 各部屋タイプの生成比定義 + *[from SAngband (originally from OAngband)]\n + *\n + * Table of values that control how many times each type of room will\n + * appear. Each type of room has its own row, and each column\n + * corresponds to dungeon levels 0, 10, 20, and so on. The final\n + * value is the minimum depth the room can appear at. -LM-\n + *\n + * Level 101 and below use the values for level 100.\n + *\n + * Rooms with lots of monsters or loot may not be generated if the\n + * object or monster lists are already nearly full. Rooms will not\n + * appear above their minimum depth. Tiny levels will not have space\n + * for all the rooms you ask for.\n */ -static s16b roomdep[] = +static room_info_type room_info_normal[ROOM_T_MAX] = { - 0, /* 0 = Nothing */ - 1, /* 1 = Simple (33x11) */ - 1, /* 2 = Overlapping (33x11) */ - 3, /* 3 = Crossed (33x11) */ - 3, /* 4 = Large (33x11) */ - 10, /* 5 = Monster nest (33x11) */ - 10, /* 6 = Monster pit (33x11) */ - 10, /* 7 = Lesser vault (33x22) */ - 20, /* 8 = Greater vault (66x44) */ - 5, /* 9 = Fractal cave (42x24) */ - 10, /* 10 = Random vault (44x22) */ - 3, /* 11 = Circular rooms (22x22) */ - 10, /* 12 = Crypts (22x22) */ - 20, /* 13 = Trapped monster pit */ - 20, /* 14 = Piranha/Armageddon trap room */ + /* Depth */ + /* 0 10 20 30 40 50 60 70 80 90 100 min limit */ + + {{999,900,800,700,600,500,400,300,200,100, 0}, 0}, /*NORMAL */ + {{ 1, 10, 20, 30, 40, 50, 60, 70, 80, 90,100}, 1}, /*OVERLAP */ + {{ 1, 10, 20, 30, 40, 50, 60, 70, 80, 90,100}, 3}, /*CROSS */ + {{ 1, 10, 20, 30, 40, 50, 60, 70, 80, 90,100}, 3}, /*INNER_F */ + {{ 0, 1, 1, 1, 2, 3, 5, 6, 8, 10, 13}, 10}, /*NEST */ + {{ 0, 1, 1, 2, 3, 4, 6, 8, 10, 13, 16}, 10}, /*PIT */ + {{ 0, 1, 1, 1, 2, 2, 3, 5, 6, 8, 10}, 10}, /*LESSER_V */ + {{ 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4}, 20}, /*GREATER_V*/ + {{ 0,100,200,300,400,500,600,700,800,900,999}, 10}, /*FRACAVE */ + {{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2}, 10}, /*RANDOM_V */ + {{ 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40}, 3}, /*OVAL */ + {{ 1, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60}, 10}, /*CRYPT */ + {{ 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 8}, 20}, /*TRAP_PIT */ + {{ 0, 0, 1, 1, 1, 2, 3, 4, 5, 6, 8}, 20}, /*TRAP */ + {{ 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2}, 40}, /*GLASS */ + {{ 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3}, 1}, /*ARCADE */ }; -static void place_locked_door(int y, int x) +/*! 部屋の生成処理順 / Build rooms in descending order of difficulty. */ +static byte room_build_order[ROOM_T_MAX] = { + ROOM_T_GREATER_VAULT, + ROOM_T_ARCADE, + ROOM_T_RANDOM_VAULT, + ROOM_T_LESSER_VAULT, + ROOM_T_TRAP_PIT, + ROOM_T_PIT, + ROOM_T_NEST, + ROOM_T_TRAP, + ROOM_T_GLASS, + ROOM_T_INNER_FEAT, + ROOM_T_OVAL, + ROOM_T_CRYPT, + ROOM_T_OVERLAP, + ROOM_T_CROSS, + ROOM_T_FRACAVE, + ROOM_T_NORMAL, +}; + +/*! + * @brief 鍵のかかったドアを配置する + * @param y 配置したいフロアのY座標 + * @param x 配置したいフロアのX座標 + * @return なし + */ +void place_locked_door(int y, int x) { if (d_info[dungeon_type].flags1 & DF1_NO_DOORS) { @@ -48,12 +118,20 @@ static void place_locked_door(int y, int x) } else { - set_cave_feat(y, x, FEAT_DOOR_HEAD+randint1(7)); + set_cave_feat(y, x, feat_locked_door_random((d_info[dungeon_type].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR)); cave[y][x].info &= ~(CAVE_FLOOR); + delete_monster(y, x); } } -static void place_secret_door(int y, int x) +/*! + * @brief 隠しドアを配置する + * @param y 配置したいフロアのY座標 + * @param x 配置したいフロアのX座標 + * @param type DOOR_DEFAULT / DOOR_DOOR / DOOR_GLASS_DOOR / DOOR_CURTAIN のいずれか + * @return なし + */ +void place_secret_door(int y, int x, int type) { if (d_info[dungeon_type].flags1 & DF1_NO_DOORS) { @@ -63,24 +141,42 @@ static void place_secret_door(int y, int x) { cave_type *c_ptr = &cave[y][x]; - /* Create secret door */ - place_closed_door(y, x); + if (type == DOOR_DEFAULT) + { + type = ((d_info[dungeon_type].flags1 & DF1_CURTAIN) && + one_in_((d_info[dungeon_type].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN : + ((d_info[dungeon_type].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR); + } - /* Hide */ - c_ptr->mimic = fill_type[randint0(100)]; + /* Create secret door */ + place_closed_door(y, x, type); - /* Floor type terrain cannot hide a door */ - if (!(c_ptr->mimic & 0x20)) + if (type != DOOR_CURTAIN) { - c_ptr->feat = c_ptr->mimic; - c_ptr->mimic = 0; + /* Hide by inner wall because this is used in rooms only */ + c_ptr->mimic = feat_wall_inner; + + /* Floor type terrain cannot hide a door */ + if (feat_supports_los(c_ptr->mimic) && !feat_supports_los(c_ptr->feat)) + { + if (have_flag(f_info[c_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[c_ptr->mimic].flags, FF_CAN_FLY)) + { + c_ptr->feat = one_in_(2) ? c_ptr->mimic : floor_type[randint0(100)]; + } + c_ptr->mimic = 0; + } } c_ptr->info &= ~(CAVE_FLOOR); + delete_monster(y, x); } } -/* +/*! + * @brief 1マスだけの部屋を作成し、上下左右いずれか一つに隠しドアを配置する。 + * @param y0 配置したい中心のY座標 + * @param x0 配置したい中心のX座標 + * @details * This funtion makes a very small room centred at (x0, y0) * This is used in crypts, and random elemental vaults. * @@ -106,10 +202,10 @@ static void build_small_room(int x0, int y0) /* Place a secret door on one side */ switch (randint0(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; + case 0: place_secret_door(y0, x0 - 1, DOOR_DEFAULT); break; + case 1: place_secret_door(y0, x0 + 1, DOOR_DEFAULT); break; + case 2: place_secret_door(y0 - 1, x0, DOOR_DEFAULT); break; + case 3: place_secret_door(y0 + 1, x0, DOOR_DEFAULT); break; } /* Clear mimic type */ @@ -119,10 +215,15 @@ static void build_small_room(int x0, int y0) place_floor_bold(y0, x0); } - -/* - * This function tunnels around a room if - * it will cut off part of a cave system. +/*! + * @brief + * 指定範囲に通路が通っていることを確認した上で床で埋める + * This function tunnels around a room if it will cut off part of a cave system. + * @param x1 範囲の左端 + * @param y1 範囲の上端 + * @param x2 範囲の右端 + * @param y2 範囲の下端 + * @return なし */ static void check_room_boundary(int x1, int y1, int x2, int y2) { @@ -200,1359 +301,678 @@ static void check_room_boundary(int x1, int y1, int x2, int y2) } -/* - * This function is used to allocate the space needed by a room in the room_map - * array. - * x, y 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. - * xx, yy are the returned center of the allocated room in coordinates for - * cave.feat and cave.info etc. +/*! + * @brief + * find_space()の予備処理として部屋の生成が可能かを判定する / + * Helper function for find_space(). Is this a good location? + * @param blocks_high 範囲の高さ + * @param blocks_wide 範囲の幅 + * @param block_y 範囲の上端 + * @param block_x 範囲の左端 + * @return なし */ -static bool room_alloc(int x, int y, bool crowded, int by0, int bx0, int *xx, int *yy) +static bool find_space_aux(int blocks_high, int blocks_wide, int block_y, int block_x) { - int temp, bx1, bx2, by1, by2, by, bx; - - /* Calculate number of room_map squares to allocate */ - - /* temp is total number along width */ - temp = ((x - 1) / BLOCK_WID) + 1; - - /* bx2 = ending block */ - bx2 = temp / 2 + bx0; - - /* bx1 = starting block (Note: rounding taken care of here.) */ - bx1 = bx2 + 1 - temp; - - /* temp is total number along height */ - temp = ((y - 1) / BLOCK_HGT) + 1; - - /* by2 = ending block */ - by2 = temp / 2 + by0; - - /* by1 = starting block */ - by1 = by2 + 1 - temp; + int by1, bx1, by2, bx2, by, bx; - - /* Never run off the screen */ - if ((by1 < 0) || (by2 >= dun->row_rooms)) return (FALSE); - if ((bx1 < 0) || (bx2 >= dun->col_rooms)) return (FALSE); - - /* Verify open space */ - for (by = by1; by <= by2; by++) + /* Itty-bitty rooms must shift about within their rectangle */ + if (blocks_wide < 3) { - for (bx = bx1; bx <= bx2; bx++) - { - if (dun->room_map[by][bx]) return (FALSE); - } + if ((blocks_wide == 2) && (block_x % 3) == 2) + 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 */ - *yy = ((by1 + by2 + 1) * BLOCK_HGT) / 2; - *xx = ((bx1 + bx2 + 1) * BLOCK_WID) / 2; - - - /* Save the room location */ - if (dun->cent_n < CENT_MAX) + /* Rooms with width divisible by 3 must be fitted to a rectangle. */ + else if ((blocks_wide % 3) == 0) { - dun->cent[dun->cent_n].y = *yy; - dun->cent[dun->cent_n].x = *xx; - dun->cent_n++; + /* Must be aligned to the left edge of a 11x33 rectangle. */ + if ((block_x % 3) != 0) + return FALSE; } - /* Reserve some blocks */ - for (by = by1; by <= by2; by++) + /* + * Big rooms that do not have a width divisible by 3 must be + * aligned towards the edge of the dungeon closest to them. + */ + else { - for (bx = bx1; bx <= bx2; bx++) + /* Shift towards left edge of dungeon. */ + if (block_x + (blocks_wide / 2) <= dun->col_rooms / 2) { - dun->room_map[by][bx] = TRUE; + if (((block_x % 3) == 2) && ((blocks_wide % 3) == 2)) + return FALSE; + if ((block_x % 3) == 1) + return FALSE; + } + + /* Shift toward right edge of dungeon. */ + else + { + if (((block_x % 3) == 2) && ((blocks_wide % 3) == 2)) + return FALSE; + if ((block_x % 3) == 1) + return FALSE; } } - /* Count "crowded" rooms */ - if (crowded) dun->crowded++; + /* Extract blocks */ + by1 = block_y + 0; + bx1 = block_x + 0; + by2 = block_y + blocks_high; + bx2 = block_x + blocks_wide; - /* - * Hack- See if room will cut off a cavern. - * If so, fix by tunneling outside the room in such a way as to connect the caves. - */ - check_room_boundary(*xx - x / 2 - 1, *yy - y / 2 - 1, - *xx + (x - 1) / 2 + 1, *yy + (y - 1) / 2 + 1); + /* Never run off the screen */ + if ((by1 < 0) || (by2 > dun->row_rooms)) return FALSE; + if ((bx1 < 0) || (bx2 > dun->col_rooms)) return FALSE; + + /* Verify available space */ + for (by = by1; by < by2; by++) + { + for (bx = bx1; bx < bx2; bx++) + { + if (dun->room_map[by][bx]) + { + return FALSE; + } + } + } - /* Success */ - return (TRUE); + /* This location is okay */ + 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 -- fractal caves - * 10 -- random vaults - * 11 -- circular rooms - * 12 -- crypts - * 13 -- trapped monster pits - * 14 -- trapped room - */ - -/* - * Type 1 -- normal rectangular rooms +/*! + * @brief 部屋生成が可能なスペースを確保する / Find a good spot for the next room. -LM- + * @param y 部屋の生成が可能な中心Y座標を返す参照ポインタ + * @param x 部屋の生成が可能な中心X座標を返す参照ポインタ + * @param height 確保したい領域の高さ + * @param width 確保したい領域の幅 + * @return 所定の範囲が確保できた場合TRUEを返す + * @details + * Find and allocate a free space in the dungeon large enough to hold\n + * the room calling this function.\n + *\n + * We allocate space in 11x11 blocks, but want to make sure that rooms\n + * align neatly on the standard screen. Therefore, we make them use\n + * blocks in few 11x33 rectangles as possible.\n + *\n + * Be careful to include the edges of the room in height and width!\n + *\n + * Return TRUE and values for the center of the room if all went well.\n + * Otherwise, return FALSE.\n */ -static void build_type1(int by0, int bx0) +bool find_space(POSITION *y, POSITION *x, POSITION height, POSITION width) { - int y, x, y2, x2, yval, xval; - int y1, x1, xsize, ysize; - - bool light; - - cave_type *c_ptr; - - /* Pick a room size */ - y1 = randint1(4); - x1 = randint1(11); - y2 = randint1(3); - x2 = randint1(11); - - xsize = x1 + x2 + 1; - ysize = y1 + y2 + 1; - - /* Try to allocate space for room. If fails, exit */ - if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &xval, &yval)) return; + int candidates, pick; + int by, bx, by1, bx1, by2, bx2; + int block_y = 0, block_x = 0; - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[dungeon_type].flags1 & DF1_DARKNESS)); + /* Find out how many blocks we need. */ + int blocks_high = 1 + ((height - 1) / BLOCK_HGT); + int blocks_wide = 1 + ((width - 1) / BLOCK_WID); - /* Get corner values */ - y1 = yval - ysize / 2; - x1 = xval - xsize / 2; - y2 = yval + (ysize - 1) / 2; - x2 = xval + (xsize - 1) / 2; + /* There are no way to allocate such huge space */ + if (dun->row_rooms < blocks_high) return FALSE; + if (dun->col_rooms < blocks_wide) return FALSE; + /* Initiallize */ + candidates = 0; - /* Place a full floor under the room */ - for (y = y1 - 1; y <= y2 + 1; y++) + /* Count the number of valid places */ + for (block_y = dun->row_rooms - blocks_high; block_y >= 0; block_y--) { - for (x = x1 - 1; x <= x2 + 1; x++) + for (block_x = dun->col_rooms - blocks_wide; block_x >= 0; block_x--) { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); + if (find_space_aux(blocks_high, blocks_wide, block_y, block_x)) + { + /* Find a valid place */ + candidates++; + } } } - /* Walls around the room */ - for (y = y1 - 1; y <= y2 + 1; y++) + /* No place! */ + if (!candidates) { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); + return FALSE; } - - /* Hack -- Occasional pillar room */ - if (one_in_(20)) + /* Normal dungeon */ + if (!(d_info[dungeon_type].flags1 & DF1_NO_CAVE)) { - for (y = y1; y <= y2; y += 2) - { - for (x = x1; x <= x2; x += 2) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } + /* Choose a random one */ + pick = randint1(candidates); } - /* Hack -- Occasional room with four pillars */ - else if (one_in_(20)) + /* NO_CAVE dungeon (Castle) */ + else { - if ((y1 + 4 < y2) && (x1 + 4 < x2)) - { - c_ptr = &cave[y1 + 1][x1 + 1]; - place_inner_grid(c_ptr); - - c_ptr = &cave[y1 + 1][x2 - 1]; - place_inner_grid(c_ptr); - - c_ptr = &cave[y2 - 1][x1 + 1]; - place_inner_grid(c_ptr); - - c_ptr = &cave[y2 - 1][x2 - 1]; - place_inner_grid(c_ptr); - } + /* Always choose the center one */ + pick = candidates/2 + 1; } - /* Hack -- Occasional ragged-edge room */ - else if (one_in_(50)) - { - for (y = y1 + 2; y <= y2 - 2; y += 2) - { - c_ptr = &cave[y][x1]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2]; - place_inner_grid(c_ptr); - } - for (x = x1 + 2; x <= x2 - 2; x += 2) - { - c_ptr = &cave[y1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2][x]; - place_inner_grid(c_ptr); - } - } - /* Hack -- Occasional divided room */ - else if (one_in_(50)) + /* Pick up the choosen location */ + for (block_y = dun->row_rooms - blocks_high; block_y >= 0; block_y--) { - if (randint1(100) < 50) + for (block_x = dun->col_rooms - blocks_wide; block_x >= 0; block_x--) { - /* Horizontal wall */ - for (x = x1; x <= x2; x++) + if (find_space_aux(blocks_high, blocks_wide, block_y, block_x)) { - place_inner_bold(yval, x); - } + pick--; - /* Prevent edge of wall from being tunneled */ - place_solid_bold(yval, x1 - 1); - place_solid_bold(yval, x2 + 1); - } - else - { - /* Vertical wall */ - for (y = y1; y <= y2; y++) - { - place_inner_bold(y, xval); + /* This one is picked? */ + if (!pick) break; } - - /* Prevent edge of wall from being tunneled */ - place_solid_bold(y1 - 1, xval); - place_solid_bold(y2 + 1, xval); } - place_random_door(yval, xval); + if (!pick) break; } -} - - -/* - * Type 2 -- Overlapping rectangular rooms - */ -static void build_type2(int by0, int bx0) -{ - int y, x, xval, yval; - int y1a, x1a, y2a, x2a; - int y1b, x1b, y2b, x2b; - bool light; - cave_type *c_ptr; + /* Extract blocks */ + by1 = block_y + 0; + bx1 = block_x + 0; + by2 = block_y + blocks_high; + bx2 = block_x + blocks_wide; - /* Try to allocate space for room. If fails, exit */ - if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return; - - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[dungeon_type].flags1 & DF1_DARKNESS)); - - /* Determine extents of the first room */ - y1a = yval - randint1(4); - y2a = yval + randint1(3); - x1a = xval - randint1(11); - x2a = xval + randint1(10); - - /* Determine extents of the second room */ - y1b = yval - randint1(3); - y2b = yval + randint1(4); - x1b = xval - randint1(10); - x2b = xval + randint1(11); + /* + * It is *extremely* important that the following calculation + * be *exactly* correct to prevent memory errors + */ + /* Acquire the location of the room */ + (*y) = ((by1 + by2) * BLOCK_HGT) / 2; + (*x) = ((bx1 + bx2) * BLOCK_WID) / 2; - /* Place a full floor for room "a" */ - for (y = y1a - 1; y <= y2a + 1; y++) + /* Save the room location */ + if (dun->cent_n < CENT_MAX) { - for (x = x1a - 1; x <= x2a + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } + dun->cent[dun->cent_n].y = (byte_hack)*y; + dun->cent[dun->cent_n].x = (byte_hack)*x; + dun->cent_n++; } - /* Place a full floor for room "b" */ - for (y = y1b - 1; y <= y2b + 1; y++) + /* Reserve some blocks. */ + for (by = by1; by < by2; by++) { - for (x = x1b - 1; x <= x2b + 1; x++) + for (bx = bx1; bx < bx2; bx++) { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); + dun->room_map[by][bx] = TRUE; } } - /* Place the walls around room "a" */ - for (y = y1a - 1; y <= y2a + 1; y++) - { - c_ptr = &cave[y][x1a - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2a + 1]; - place_outer_grid(c_ptr); - } - for (x = x1a - 1; x <= x2a + 1; x++) - { - c_ptr = &cave[y1a - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2a + 1][x]; - place_outer_grid(c_ptr); - } + /* + * Hack- See if room will cut off a cavern. + * + * If so, fix by tunneling outside the room in such a + * way as to connect the caves. + */ + check_room_boundary(*x - width / 2 - 1, *y - height / 2 - 1, *x + (width - 1) / 2 + 1, *y + (height - 1) / 2 + 1); - /* Place the walls around room "b" */ - for (y = y1b - 1; y <= y2b + 1; y++) - { - c_ptr = &cave[y][x1b - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2b + 1]; - place_outer_grid(c_ptr); - } - for (x = x1b - 1; x <= x2b + 1; x++) - { - c_ptr = &cave[y1b - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2b + 1][x]; - place_outer_grid(c_ptr); - } + /* Success. */ + return TRUE; +} - /* Replace the floor for room "a" */ - for (y = y1a; y <= y2a; y++) - { - for (x = x1a; x <= x2a; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - } - } - /* Replace the floor for room "b" */ - for (y = y1b; y <= y2b; y++) - { - for (x = x1b; x <= x2b; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - } - } -} -/* - * 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. +/*! + * vaultに配置可能なモンスターの条件を指定するマクロ / Monster validation macro * - * 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. + * Line 1 -- forbid town monsters + * Line 2 -- forbid uniques + * Line 3 -- forbid aquatic monsters */ -static void build_type3(int by0, int bx0) -{ - int y, x, dy, dx, wy, wx; - int y1a, x1a, y2a, x2a; - int y1b, x1b, y2b, x2b; - int yval, xval; - bool light; - cave_type *c_ptr; +#define vault_monster_okay(I) \ + (mon_hook_dungeon(I) && \ + !(r_info[I].flags1 & RF1_UNIQUE) && \ + !(r_info[I].flags7 & RF7_UNIQUE2) && \ + !(r_info[I].flagsr & RFR_RES_ALL) && \ + !(r_info[I].flags7 & RF7_AQUATIC)) - /* Try to allocate space for room. */ - if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return; +/*! 通常pit生成時のモンスターの構成条件ID / Race index for "monster pit (clone)" */ +static int vault_aux_race; - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[dungeon_type].flags1 & DF1_DARKNESS)); +/*! 単一シンボルpit生成時の指定シンボル / Race index for "monster pit (symbol clone)" */ +static char vault_aux_char; - /* For now, always 3x3 */ - wx = wy = 1; +/*! ブレス属性に基づくドラゴンpit生成時条件マスク / Breath mask for "monster pit (dragon)" */ +static u32b vault_aux_dragon_mask4; - /* Pick max vertical size (at most 4) */ - dy = rand_range(3, 4); - /* Pick max horizontal size (at most 15) */ - dx = rand_range(3, 11); +/*! + * @brief モンスターがVault生成の最低必要条件を満たしているかを返す / + * Helper monster selection function + * @param r_idx 確認したいモンスター種族ID + * @return Vault生成の最低必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_simple(MONRACE_IDX r_idx) +{ + /* Okay */ + return (vault_monster_okay(r_idx)); +} - /* Determine extents of the north/south room */ - y1a = yval - dy; - y2a = yval + dy; - x1a = xval - wx; - x2a = xval + wx; +/*! + * @brief モンスターがゼリーnestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (jelly)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_jelly(MONRACE_IDX r_idx) +{ + monster_race *r_ptr = &r_info[r_idx]; - /* Determine extents of the east/west room */ - y1b = yval - wy; - y2b = yval + wy; - x1b = xval - dx; - x2b = xval + dx; + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); + if ((r_ptr->flags2 & RF2_KILL_BODY) && !(r_ptr->flags1 & RF1_NEVER_BLOW)) return (FALSE); - /* Place a full floor for room "a" */ - for (y = y1a - 1; y <= y2a + 1; y++) - { - for (x = x1a - 1; x <= x2a + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } + /* Also decline evil jellies (like death molds and shoggoths) */ + if (r_ptr->flags3 & (RF3_EVIL)) return (FALSE); - /* Place a full floor for room "b" */ - for (y = y1b - 1; y <= y2b + 1; y++) - { - for (x = x1b - 1; x <= x2b + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } + /* Require icky thing, jelly, mold, or mushroom */ + if (!my_strchr("ijm,", r_ptr->d_char)) return (FALSE); + /* Okay */ + return (TRUE); +} - /* Place the walls around room "a" */ - for (y = y1a - 1; y <= y2a + 1; y++) - { - c_ptr = &cave[y][x1a - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2a + 1]; - place_outer_grid(c_ptr); - } - for (x = x1a - 1; x <= x2a + 1; x++) - { - c_ptr = &cave[y1a - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2a + 1][x]; - place_outer_grid(c_ptr); - } +/*! + * @brief モンスターが動物nestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (animal)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_animal(MONRACE_IDX r_idx) +{ + monster_race *r_ptr = &r_info[r_idx]; - /* Place the walls around room "b" */ - for (y = y1b - 1; y <= y2b + 1; y++) - { - c_ptr = &cave[y][x1b - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2b + 1]; - place_outer_grid(c_ptr); - } - for (x = x1b - 1; x <= x2b + 1; x++) - { - c_ptr = &cave[y1b - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2b + 1][x]; - place_outer_grid(c_ptr); - } + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); + /* Require "animal" flag */ + if (!(r_ptr->flags3 & (RF3_ANIMAL))) return (FALSE); - /* Replace the floor for room "a" */ - for (y = y1a; y <= y2a; y++) - { - for (x = x1a; x <= x2a; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - } - } + /* Okay */ + return (TRUE); +} - /* Replace the floor for room "b" */ - for (y = y1b; y <= y2b; y++) - { - for (x = x1b; x <= x2b; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - } - } +/*! + * @brief モンスターがアンデッドnestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (undead)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_undead(MONRACE_IDX r_idx) +{ + monster_race *r_ptr = &r_info[r_idx]; + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); - /* Special features (3/4) */ - switch (randint0(4)) - { - /* Large solid middle pillar */ - case 1: - { - for (y = y1b; y <= y2b; y++) - { - for (x = x1a; x <= x2a; x++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - break; - } + /* Require Undead */ + if (!(r_ptr->flags3 & (RF3_UNDEAD))) return (FALSE); - /* Inner treasure vault */ - case 2: - { - /* Build the vault */ - for (y = y1b; y <= y2b; y++) - { - c_ptr = &cave[y][x1a]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2a]; - place_inner_grid(c_ptr); - } - for (x = x1a; x <= x2a; x++) - { - c_ptr = &cave[y1b][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2b][x]; - place_inner_grid(c_ptr); - } + /* Okay */ + return (TRUE); +} - /* Place a secret door on the inner room */ - switch (randint0(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; - } +/*! + * @brief モンスターが聖堂nestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (chapel)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_chapel_g(MONRACE_IDX r_idx) +{ + static int chapel_list[] = { + MON_NOV_PRIEST, MON_NOV_PALADIN, MON_NOV_PRIEST_G, MON_NOV_PALADIN_G, + MON_PRIEST, MON_JADE_MONK, MON_IVORY_MONK, MON_ULTRA_PALADIN, + MON_EBONY_MONK, MON_W_KNIGHT, MON_KNI_TEMPLAR, MON_PALADIN, + MON_TOPAZ_MONK, 0}; - /* Place a treasure in the vault */ - place_object(yval, xval, FALSE, FALSE); + int i; - /* Let's guard the treasure well */ - vault_monsters(yval, xval, randint0(2) + 3); + monster_race *r_ptr = &r_info[r_idx]; - /* Traps naturally */ - vault_traps(yval, xval, 4, 4, randint0(3) + 2); + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); - break; - } + if (r_ptr->flags3 & (RF3_EVIL)) return (FALSE); + if ((r_idx == MON_A_GOLD) || (r_idx == MON_A_SILVER)) return (FALSE); - /* Something else */ - case 3: - { - /* Occasionally pinch the center shut */ - if (one_in_(3)) - { - /* Pinch the east/west sides */ - for (y = y1b; y <= y2b; y++) - { - if (y == yval) continue; - c_ptr = &cave[y][x1a - 1]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2a + 1]; - place_inner_grid(c_ptr); - } + /* Require "priest" or Angel */ - /* Pinch the north/south sides */ - for (x = x1a; x <= x2a; x++) - { - if (x == xval) continue; - c_ptr = &cave[y1b - 1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2b + 1][x]; - place_inner_grid(c_ptr); - } + if (r_ptr->d_char == 'A') return TRUE; - /* Sometimes shut using secret doors */ - if (one_in_(3)) - { - place_secret_door(yval, x1a - 1); - place_secret_door(yval, x2a + 1); - place_secret_door(y1b - 1, xval); - place_secret_door(y2b + 1, xval); - } - } + for (i = 0; chapel_list[i]; i++) + if (r_idx == chapel_list[i]) return TRUE; - /* Occasionally put a "plus" in the center */ - else if (one_in_(3)) - { - c_ptr = &cave[yval][xval]; - place_inner_grid(c_ptr); - c_ptr = &cave[y1b][xval]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2b][xval]; - place_inner_grid(c_ptr); - c_ptr = &cave[yval][x1a]; - place_inner_grid(c_ptr); - c_ptr = &cave[yval][x2a]; - place_inner_grid(c_ptr); - } + return FALSE; +} - /* Occasionally put a pillar in the center */ - else if (one_in_(3)) - { - c_ptr = &cave[yval][xval]; - place_inner_grid(c_ptr); - } +/*! + * @brief モンスターが犬小屋nestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (kennel)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_kennel(MONRACE_IDX r_idx) +{ + monster_race *r_ptr = &r_info[r_idx]; - break; - } - } -} + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); + /* Require a Zephyr Hound or a dog */ + if (!my_strchr("CZ", r_ptr->d_char)) return (FALSE); + + /* Okay */ + return (TRUE); +} -/* - * 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 +/*! + * @brief モンスターがミミックnestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (mimic)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 */ -static void build_type4(int by0, int bx0) +static bool vault_aux_mimic(MONRACE_IDX r_idx) { - int y, x, y1, x1; - int y2, x2, tmp, yval, xval; - bool light; - cave_type *c_ptr; + monster_race *r_ptr = &r_info[r_idx]; + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); - /* Try to allocate space for room. */ - if (!room_alloc(25, 11, FALSE, by0, bx0, &xval, &yval)) return; + /* Require mimic */ + if (!my_strchr("!$&(/=?[\\|", r_ptr->d_char)) return (FALSE); - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[dungeon_type].flags1 & DF1_DARKNESS)); + /* Okay */ + return (TRUE); +} - /* Large room */ - y1 = yval - 4; - y2 = yval + 4; - x1 = xval - 11; - x2 = xval + 11; +/*! + * @brief モンスターが単一クローンnestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (clone)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_clone(MONRACE_IDX r_idx) +{ + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); - /* Place a full floor under the room */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); - } - } + return (r_idx == vault_aux_race); +} - /* Outer Walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); - } +/*! + * @brief モンスターが邪悪属性シンボルクローンnestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (symbol clone)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_symbol_e(MONRACE_IDX r_idx) +{ + monster_race *r_ptr = &r_info[r_idx]; - /* The inner room */ - y1 = y1 + 2; - y2 = y2 - 2; - x1 = x1 + 2; - x2 = x2 - 2; + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); - /* The inner walls */ - for (y = y1 - 1; y <= y2 + 1; y++) - { - c_ptr = &cave[y][x1 - 1]; - place_inner_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_inner_grid(c_ptr); - } - for (x = x1 - 1; x <= x2 + 1; x++) - { - c_ptr = &cave[y1 - 1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_inner_grid(c_ptr); - } + if ((r_ptr->flags2 & RF2_KILL_BODY) && !(r_ptr->flags1 & RF1_NEVER_BLOW)) return (FALSE); + if (r_ptr->flags3 & (RF3_GOOD)) return (FALSE); - /* Inner room variations */ - switch (randint1(5)) - { - /* Just an inner room with a monster */ - case 1: - { - /* Place a secret door */ - switch (randint1(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; - } + /* Decline incorrect symbol */ + if (r_ptr->d_char != vault_aux_char) return (FALSE); - /* Place a monster in the room */ - vault_monsters(yval, xval, 1); + /* Okay */ + return (TRUE); +} - break; - } - /* Treasure Vault (with a door) */ - case 2: - { - /* Place a secret door */ - switch (randint1(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; - } +/*! + * @brief モンスターが善良属性シンボルクローンnestの生成必要条件を満たしているかを返す / + * Helper function for "monster nest (symbol clone)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_symbol_g(MONRACE_IDX r_idx) +{ + monster_race *r_ptr = &r_info[r_idx]; - /* Place another inner room */ - for (y = yval - 1; y <= yval + 1; y++) - { - for (x = xval - 1; x <= xval + 1; x++) - { - if ((x == xval) && (y == yval)) continue; - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); - /* Place a locked door on the inner room */ - switch (randint1(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; - } + if ((r_ptr->flags2 & RF2_KILL_BODY) && !(r_ptr->flags1 & RF1_NEVER_BLOW)) return (FALSE); - /* Monsters to guard the "treasure" */ - vault_monsters(yval, xval, randint1(3) + 2); + if (r_ptr->flags3 & (RF3_EVIL)) return (FALSE); - /* Object (80%) */ - if (randint0(100) < 80) - { - place_object(yval, xval, FALSE, FALSE); - } + /* Decline incorrect symbol */ + if (r_ptr->d_char != vault_aux_char) return (FALSE); - /* Stairs (20%) */ - else - { - place_random_stairs(yval, xval); - } - - /* Traps to protect the treasure */ - vault_traps(yval, xval, 4, 10, 2 + randint1(3)); - - break; - } - - /* Inner pillar(s). */ - case 3: - { - /* Place a secret door */ - switch (randint1(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++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - - /* Occasionally, two more Large Inner Pillars */ - if (one_in_(2)) - { - tmp = randint1(2); - for (y = yval - 1; y <= yval + 1; y++) - { - for (x = xval - 5 - tmp; x <= xval - 3 - tmp; x++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - for (x = xval + 3 + tmp; x <= xval + 5 + tmp; x++) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - } - - /* Occasionally, some Inner rooms */ - if (one_in_(3)) - { - /* Long horizontal walls */ - for (x = xval - 5; x <= xval + 5; x++) - { - c_ptr = &cave[yval - 1][x]; - place_inner_grid(c_ptr); - c_ptr = &cave[yval + 1][x]; - place_inner_grid(c_ptr); - } - - /* Close off the left/right edges */ - c_ptr = &cave[yval][xval - 5]; - place_inner_grid(c_ptr); - c_ptr = &cave[yval][xval + 5]; - place_inner_grid(c_ptr); - - /* Secret doors (random top/bottom) */ - place_secret_door(yval - 3 + (randint1(2) * 2), xval - 3); - place_secret_door(yval - 3 + (randint1(2) * 2), xval + 3); - - /* Monsters */ - vault_monsters(yval, xval - 2, randint1(2)); - vault_monsters(yval, xval + 2, randint1(2)); - - /* Objects */ - if (one_in_(3)) place_object(yval, xval - 2, FALSE, FALSE); - if (one_in_(3)) place_object(yval, xval + 2, FALSE, FALSE); - } - - break; - } - - /* Maze inside. */ - case 4: - { - /* Place a secret door */ - switch (randint1(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)) - { - c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); - } - } - } - - /* Monsters just love mazes. */ - vault_monsters(yval, xval - 5, randint1(3)); - vault_monsters(yval, xval + 5, randint1(3)); - - /* Traps make them entertaining. */ - vault_traps(yval, xval - 3, 2, 8, randint1(3)); - vault_traps(yval, xval + 3, 2, 8, randint1(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++) - { - c_ptr = &cave[y][xval]; - place_inner_grid(c_ptr); - } - for (x = x1; x <= x2; x++) - { - c_ptr = &cave[yval][x]; - place_inner_grid(c_ptr); - } - - /* Doors into the rooms */ - if (randint0(100) < 50) - { - int i = randint1(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 = randint1(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 + randint1(2)); - - /* Gotta have some monsters. */ - vault_monsters(yval + 1, xval - 4, randint1(4)); - vault_monsters(yval + 1, xval + 4, randint1(4)); - vault_monsters(yval - 1, xval - 4, randint1(4)); - vault_monsters(yval - 1, xval + 4, randint1(4)); - - break; - } - } -} - - -/* - * The following functions are used to 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. - */ - - -/* - * Monster validation macro - * - * Line 1 -- forbid town monsters - * Line 2 -- forbid uniques - * Line 3 -- forbid aquatic monsters - */ -#define vault_monster_okay(I) \ - (monster_dungeon(I) && \ - !(r_info[I].flags1 & RF1_UNIQUE) && \ - !(r_info[I].flags7 & RF7_UNIQUE2) && \ - !(r_info[I].flags3 & RF3_RES_ALL) && \ - !(r_info[I].flags7 & RF7_AQUATIC)) - - -/* Race index for "monster pit (clone)" */ -static int vault_aux_race; - -/* Race index for "monster pit (symbol clone)" */ -static char vault_aux_char; - -/* Breath mask for "monster pit (dragon)" */ -static u32b vault_aux_dragon_mask4; - - -/* - * Helper monster selection function - */ -static bool vault_aux_simple(int r_idx) -{ /* Okay */ - return (vault_monster_okay(r_idx)); + return (TRUE); } -/* - * Helper function for "monster nest (jelly)" +/*! + * @brief モンスターがオークpitの生成必要条件を満たしているかを返す / + * Helper function for "monster pit (orc)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 */ -static bool vault_aux_jelly(int r_idx) +static bool vault_aux_orc(MONRACE_IDX r_idx) { monster_race *r_ptr = &r_info[r_idx]; /* Validate the monster */ if (!vault_monster_okay(r_idx)) return (FALSE); - if (r_ptr->flags2 & (RF2_KILL_BODY)) return (FALSE); - - /* Also decline evil jellies (like death molds and shoggoths) */ - if (r_ptr->flags3 & (RF3_EVIL)) return (FALSE); + /* Require orc */ + if (!(r_ptr->flags3 & RF3_ORC)) return (FALSE); - /* Require icky thing, jelly, mold, or mushroom */ - if (!strchr("ijm,", r_ptr->d_char)) return (FALSE); + /* Decline undead */ + if (r_ptr->flags3 & RF3_UNDEAD) return (FALSE); /* Okay */ return (TRUE); } -/* - * Helper function for "monster nest (animal)" +/*! + * @brief モンスターがトロルpitの生成必要条件を満たしているかを返す / + * Helper function for "monster pit (troll)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 */ -static bool vault_aux_animal(int r_idx) +static bool vault_aux_troll(MONRACE_IDX r_idx) { monster_race *r_ptr = &r_info[r_idx]; /* Validate the monster */ if (!vault_monster_okay(r_idx)) return (FALSE); - /* Require "animal" flag */ - if (!(r_ptr->flags3 & (RF3_ANIMAL))) return (FALSE); + /* Require troll */ + if (!(r_ptr->flags3 & RF3_TROLL)) return (FALSE); + + /* Decline undead */ + if (r_ptr->flags3 & RF3_UNDEAD) return (FALSE); /* Okay */ return (TRUE); } -/* - * Helper function for "monster nest (undead)" +/*! + * @brief モンスターが巨人pitの生成必要条件を満たしているかを返す / + * Helper function for "monster pit (giant)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 */ -static bool vault_aux_undead(int r_idx) +static bool vault_aux_giant(MONRACE_IDX r_idx) { monster_race *r_ptr = &r_info[r_idx]; /* Validate the monster */ if (!vault_monster_okay(r_idx)) return (FALSE); - /* Require Undead */ - if (!(r_ptr->flags3 & (RF3_UNDEAD))) return (FALSE); + /* Require giant */ + if (!(r_ptr->flags3 & RF3_GIANT)) return (FALSE); + + if (r_ptr->flags3 & RF3_GOOD) return (FALSE); + + /* Decline undead */ + if (r_ptr->flags3 & RF3_UNDEAD) return (FALSE); /* Okay */ return (TRUE); } -/* - * Helper function for "monster nest (chapel)" +/*! + * @brief モンスターがドラゴンpitの生成必要条件を満たしているかを返す / + * Helper function for "monster pit (dragon)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 */ -static bool vault_aux_chapel_g(int r_idx) +static bool vault_aux_dragon(MONRACE_IDX r_idx) { - static int chapel_list[] = { - MON_NOV_PRIEST, MON_NOV_PALADIN, MON_NOV_PRIEST_G, MON_NOV_PALADIN_G, - MON_PRIEST, MON_JADE_MONK, MON_IVORY_MONK, MON_ULTRA_PALADIN, - MON_EBONY_MONK, MON_W_KNIGHT, MON_KNI_TEMPLAR, MON_PALADIN, - MON_TOPAZ_MONK, 0}; - - int i; - monster_race *r_ptr = &r_info[r_idx]; /* Validate the monster */ if (!vault_monster_okay(r_idx)) return (FALSE); - if (r_ptr->flags3 & (RF3_EVIL)) return (FALSE); - if ((r_idx == MON_A_GOLD) || (r_idx == MON_A_SILVER)) return (FALSE); - - /* Require "priest" or Angel */ + /* Require dragon */ + if (!(r_ptr->flags3 & RF3_DRAGON)) return (FALSE); - if (r_ptr->d_char == 'A') return TRUE; + /* Hack -- Require correct "breath attack" */ + if (r_ptr->flags4 != vault_aux_dragon_mask4) return (FALSE); - for (i = 0; chapel_list[i]; i++) - if (r_idx == chapel_list[i]) return TRUE; + /* Decline undead */ + if (r_ptr->flags3 & RF3_UNDEAD) return (FALSE); - return FALSE; + /* Okay */ + return (TRUE); } -/* - * Helper function for "monster nest (kennel)" +/*! + * @brief モンスターが悪魔pitの生成必要条件を満たしているかを返す / + * Helper function for "monster pit (demon)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 */ -static bool vault_aux_kennel(int r_idx) +static bool vault_aux_demon(MONRACE_IDX r_idx) { monster_race *r_ptr = &r_info[r_idx]; /* Validate the monster */ if (!vault_monster_okay(r_idx)) return (FALSE); - /* Require a Zephyr Hound or a dog */ - if (!strchr("CZ", r_ptr->d_char)) return (FALSE); - + if ((r_ptr->flags2 & RF2_KILL_BODY) && !(r_ptr->flags1 & RF1_NEVER_BLOW)) return (FALSE); + + /* Require demon */ + if (!(r_ptr->flags3 & RF3_DEMON)) return (FALSE); + /* Okay */ return (TRUE); } -/* - * Helper function for "monster nest (mimic)" +/*! + * @brief モンスターが狂気pitの生成必要条件を満たしているかを返す / + * Helper function for "monster pit (lovecraftian)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 */ -static bool vault_aux_mimic(int r_idx) +static bool vault_aux_cthulhu(MONRACE_IDX r_idx) { monster_race *r_ptr = &r_info[r_idx]; /* Validate the monster */ if (!vault_monster_okay(r_idx)) return (FALSE); - - /* Require mimic */ - if (!strchr("!|$?=", r_ptr->d_char)) return (FALSE); + + if ((r_ptr->flags2 & RF2_KILL_BODY) && !(r_ptr->flags1 & RF1_NEVER_BLOW)) return (FALSE); + + /* Require eldritch horror */ + if (!(r_ptr->flags2 & (RF2_ELDRITCH_HORROR))) return (FALSE); /* Okay */ return (TRUE); } -/* - * Helper function for "monster nest (clone)" + +/*! + * @brief pit/nestの基準となる単種モンスターを決める / + * @return なし */ -static bool vault_aux_clone(int r_idx) +static void vault_prep_clone(void) { - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); + /* Apply the monster restriction */ + get_mon_num_prep(vault_aux_simple, NULL); - return (r_idx == vault_aux_race); + /* Pick a race to clone */ + vault_aux_race = get_mon_num(dun_level + 10); + + /* Remove the monster restriction */ + get_mon_num_prep(NULL, NULL); } -/* - * Helper function for "monster nest (symbol clone)" +/*! + * @brief pit/nestの基準となるモンスターシンボルを決める / + * @return なし */ -static bool vault_aux_symbol_e(int r_idx) +static void vault_prep_symbol(void) { - monster_race *r_ptr = &r_info[r_idx]; - - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); + MONRACE_IDX r_idx; - if (r_ptr->flags2 & (RF2_KILL_BODY)) return (FALSE); + /* Apply the monster restriction */ + get_mon_num_prep(vault_aux_simple, NULL); - if (r_ptr->flags3 & (RF3_GOOD)) return (FALSE); + /* Pick a race to clone */ + r_idx = get_mon_num(dun_level + 10); - /* Decline incorrect symbol */ - if (r_ptr->d_char != vault_aux_char) return (FALSE); + /* Remove the monster restriction */ + get_mon_num_prep(NULL, NULL); - /* Okay */ - return (TRUE); + /* Extract the symbol */ + vault_aux_char = r_info[r_idx].d_char; } - -/* - * Helper function for "monster nest (symbol clone)" +/*! + * @brief pit/nestの基準となるドラゴンの種類を決める / + * @return なし */ -static bool vault_aux_symbol_g(int r_idx) +static void vault_prep_dragon(void) { - monster_race *r_ptr = &r_info[r_idx]; - - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); + /* Pick dragon type */ + switch (randint0(6)) + { + /* Black */ + case 0: + { + /* Restrict dragon breath type */ + vault_aux_dragon_mask4 = RF4_BR_ACID; - if (r_ptr->flags2 & (RF2_KILL_BODY)) return (FALSE); + /* Done */ + break; + } - if (r_ptr->flags3 & (RF3_EVIL)) return (FALSE); - - /* Decline incorrect symbol */ - if (r_ptr->d_char != vault_aux_char) return (FALSE); - - /* Okay */ - return (TRUE); -} - - -/* - * Helper function for "monster pit (orc)" - */ -static bool vault_aux_orc(int r_idx) -{ - monster_race *r_ptr = &r_info[r_idx]; - - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); - - /* Require orc */ - if (!(r_ptr->flags3 & RF3_ORC)) return (FALSE); - - /* Decline undead */ - if (r_ptr->flags3 & RF3_UNDEAD) 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]; - - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); - - /* Require troll */ - if (!(r_ptr->flags3 & RF3_TROLL)) return (FALSE); - - /* Decline undead */ - if (r_ptr->flags3 & RF3_UNDEAD) 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]; - - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); - - /* Require giant */ - if (!(r_ptr->flags3 & RF3_GIANT)) return (FALSE); - - if (r_ptr->flags3 & RF3_GOOD) return (FALSE); - - /* Decline undead */ - if (r_ptr->flags3 & RF3_UNDEAD) return (FALSE); - - /* Okay */ - return (TRUE); -} - - -/* - * Helper function for "monster pit (dragon)" - */ -static bool vault_aux_dragon(int r_idx) -{ - monster_race *r_ptr = &r_info[r_idx]; - - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); - - /* Require dragon */ - if (!(r_ptr->flags3 & RF3_DRAGON)) return (FALSE); - - /* Hack -- Require correct "breath attack" */ - if (r_ptr->flags4 != vault_aux_dragon_mask4) return (FALSE); - - /* Decline undead */ - if (r_ptr->flags3 & RF3_UNDEAD) 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]; - - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); - - if (r_ptr->flags2 & (RF2_KILL_BODY)) return (FALSE); - - /* Require demon */ - if (!(r_ptr->flags3 & RF3_DEMON)) return (FALSE); - - /* Okay */ - return (TRUE); -} - - -/* - * Helper function for "monster pit (lovecraftian)" - */ -static bool vault_aux_cthulhu(int r_idx) -{ - monster_race *r_ptr = &r_info[r_idx]; - - /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); - - if (r_ptr->flags2 & (RF2_KILL_BODY)) return (FALSE); - - /* Require eldritch horror */ - if (!(r_ptr->flags2 & (RF2_ELDRITCH_HORROR))) return (FALSE); - - /* Okay */ - return (TRUE); -} - - -/* - * Helper function for "monster pit (clone)" - */ -static void vault_prep_clone(void) -{ - /* Apply the monster restriction */ - get_mon_num_prep(vault_aux_simple, NULL); - - /* Pick a race to clone */ - vault_aux_race = get_mon_num(dun_level + 10); - - /* Remove the monster restriction */ - get_mon_num_prep(NULL, NULL); -} - - -/* - * Helper function for "monster pit (symbol clone)" - */ -static void vault_prep_symbol(void) -{ - int r_idx; - - /* Apply the monster restriction */ - get_mon_num_prep(vault_aux_simple, NULL); - - /* Pick a race to clone */ - r_idx = get_mon_num(dun_level + 10); - - /* Remove the monster restriction */ - get_mon_num_prep(NULL, NULL); - - /* Extract the symbol */ - vault_aux_char = r_info[r_idx].d_char; -} - - -/* - * Helper function for "monster pit (dragon)" - */ -static void vault_prep_dragon(void) -{ - /* Pick dragon type */ - switch (randint0(6)) - { - /* Black */ - case 0: - { - /* Restrict dragon breath type */ - vault_aux_dragon_mask4 = RF4_BR_ACID; - - /* Done */ - break; - } - - /* Blue */ - case 1: - { - /* Restrict dragon breath type */ - vault_aux_dragon_mask4 = RF4_BR_ELEC; + /* Blue */ + case 1: + { + /* Restrict dragon breath type */ + vault_aux_dragon_mask4 = RF4_BR_ELEC; /* Done */ break; @@ -1603,23 +1023,53 @@ static void vault_prep_dragon(void) } -#define ROOM_PIT 0 -#define ROOM_NEST 1 +/*! + * @brief モンスターがダークエルフpitの生成必要条件を満たしているかを返す / + * Helper function for "monster pit (dark elf)" + * @param r_idx 確認したいモンスター種族ID + * @return 生成必要条件を満たしているならTRUEを返す。 + */ +static bool vault_aux_dark_elf(MONRACE_IDX r_idx) +{ + int i; + static int dark_elf_list[] = + { + MON_D_ELF, MON_D_ELF_MAGE, MON_D_ELF_WARRIOR, MON_D_ELF_PRIEST, + MON_D_ELF_LORD, MON_D_ELF_WARLOCK, MON_D_ELF_DRUID, MON_NIGHTBLADE, + MON_D_ELF_SORC, MON_D_ELF_SHADE, 0, + }; + + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return FALSE; + + /* Require dark elves */ + for (i = 0; dark_elf_list[i]; i++) + if (r_idx == dark_elf_list[i]) return TRUE; -typedef struct vault_aux_type vault_aux_type; + /* Assume not */ + return FALSE; +} +/*! pit/nest型情報のtypedef */ +typedef struct vault_aux_type vault_aux_type; +/*! pit/nest型情報の構造体定義 */ struct vault_aux_type { cptr name; - bool (*hook_func)(int r_idx); + bool (*hook_func)(MONRACE_IDX r_idx); void (*prep_func)(void); int level; int chance; }; - -static vault_aux_type *pick_vault_type(vault_aux_type *l_ptr, int room) +/*! + * @brief ダンジョン毎に指定されたピット配列を基準にランダムなpit/nestタイプを決める + * @param l_ptr 選択されたpit/nest情報を返す参照ポインタ + * @param allow_flag_mask 生成が許されるpit/nestのビット配列 + * @return 選択されたpit/nestのID、選択失敗した場合-1を返す。 + */ +static int pick_vault_type(vault_aux_type *l_ptr, s16b allow_flag_mask) { int tmp, total, count; @@ -1634,14 +1084,8 @@ static vault_aux_type *pick_vault_type(vault_aux_type *l_ptr, int room) /* Ignore excessive depth */ if (n_ptr->level > dun_level) continue; - if (room == ROOM_PIT) - { - if (!(d_info[dungeon_type].pit & (1L << count))) continue; - } - else if (room == ROOM_NEST) - { - if(!(d_info[dungeon_type].nest & (1L << count))) continue; - } + /* Not matched with pit/nest flag */ + if (!(allow_flag_mask & (1L << count))) continue; /* Count this possibility */ total += n_ptr->chance * MAX_DEPTH / (MIN(dun_level, MAX_DEPTH - 1) - n_ptr->level + 5); @@ -1659,14 +1103,8 @@ static vault_aux_type *pick_vault_type(vault_aux_type *l_ptr, int room) /* Ignore excessive depth */ if (n_ptr->level > dun_level) continue; - if (room == ROOM_PIT) - { - if (!(d_info[dungeon_type].pit & (1L << count))) continue; - } - else if (room == ROOM_NEST) - { - if(!(d_info[dungeon_type].nest & (1L << count))) continue; - } + /* Not matched with pit/nest flag */ + if (!(allow_flag_mask & (1L << count))) continue; /* Count this possibility */ total += n_ptr->chance * MAX_DEPTH / (MIN(dun_level, MAX_DEPTH - 1) - n_ptr->level + 5); @@ -1675,100 +1113,331 @@ static vault_aux_type *pick_vault_type(vault_aux_type *l_ptr, int room) if (tmp < total) break; } - return (n_ptr->name ? n_ptr : NULL); + return n_ptr->name ? count : -1; } -static void build_type6(int by0, int bx0, bool nest); -static void build_type5(int by0, int bx0, bool nest); - +/*!nest情報テーブル*/ static vault_aux_type nest_types[] = { #ifdef JP - {"¥¯¥í¡¼¥ó", vault_aux_clone, vault_prep_clone, 5, 3}, - {"¥¼¥ê¡¼", vault_aux_jelly, NULL, 5, 6}, - {"¥·¥ó¥Ü¥ë(Á±)",vault_aux_symbol_g, vault_prep_symbol, 25, 2}, - {"¥·¥ó¥Ü¥ë(°­)",vault_aux_symbol_e, vault_prep_symbol, 25, 2}, - {"¥ß¥ß¥Ã¥¯", vault_aux_mimic, NULL, 30, 4}, - {"¶¸µ¤", vault_aux_cthulhu, NULL, 70, 2}, - {"¸¤¾®²°", vault_aux_kennel, NULL, 45, 4}, - {"ưʪ±à", vault_aux_animal, NULL, 35, 5}, - {"¶µ²ñ", vault_aux_chapel_g, NULL, 75, 4}, - {"¥¢¥ó¥Ç¥Ã¥É", vault_aux_undead, NULL, 75, 5}, - {NULL, NULL, NULL, 0, 0}, + {"クローン", vault_aux_clone, vault_prep_clone, 5, 3}, + {"ゼリー", vault_aux_jelly, NULL, 5, 6}, + {"シンボル(善)", vault_aux_symbol_g, vault_prep_symbol, 25, 2}, + {"シンボル(悪)", vault_aux_symbol_e, vault_prep_symbol, 25, 2}, + {"ミミック", vault_aux_mimic, NULL, 30, 4}, + {"狂気", vault_aux_cthulhu, NULL, 70, 2}, + {"犬小屋", vault_aux_kennel, NULL, 45, 4}, + {"動物園", vault_aux_animal, NULL, 35, 5}, + {"教会", vault_aux_chapel_g, NULL, 75, 4}, + {"アンデッド", vault_aux_undead, NULL, 75, 5}, + {NULL, NULL, NULL, 0, 0}, #else - {"clone", vault_aux_clone, vault_prep_clone, 5, 3}, - {"jelly", vault_aux_jelly, NULL, 5, 6}, - {"symbol good",vault_aux_symbol_g, vault_prep_symbol, 25, 2}, - {"symbol evil",vault_aux_symbol_e, vault_prep_symbol, 25, 2}, - {"mimic", vault_aux_mimic, NULL, 30, 4}, - {"lovecraftian",vault_aux_cthulhu, NULL, 70, 2}, - {"kennel", vault_aux_kennel, NULL, 45, 4}, - {"animal", vault_aux_animal, NULL, 35, 5}, - {"chapel", vault_aux_chapel_g, NULL, 75, 4}, - {"undead", vault_aux_undead, NULL, 75, 5}, - {NULL, NULL, NULL, 0, 0}, + {"clone", vault_aux_clone, vault_prep_clone, 5, 3}, + {"jelly", vault_aux_jelly, NULL, 5, 6}, + {"symbol good", vault_aux_symbol_g, vault_prep_symbol, 25, 2}, + {"symbol evil", vault_aux_symbol_e, vault_prep_symbol, 25, 2}, + {"mimic", vault_aux_mimic, NULL, 30, 4}, + {"lovecraftian", vault_aux_cthulhu, NULL, 70, 2}, + {"kennel", vault_aux_kennel, NULL, 45, 4}, + {"animal", vault_aux_animal, NULL, 35, 5}, + {"chapel", vault_aux_chapel_g, NULL, 75, 4}, + {"undead", vault_aux_undead, NULL, 75, 5}, + {NULL, NULL, NULL, 0, 0}, #endif }; - -/* - * 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. - * - * 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, bool pit) +/*!pit情報テーブル*/ +static vault_aux_type pit_types[] = { - int y, x, y1, x1, y2, x2, xval, yval; - int i; - int what[64]; - - int align = 0; +#ifdef JP + {"オーク", vault_aux_orc, NULL, 5, 6}, + {"トロル", vault_aux_troll, NULL, 20, 6}, + {"ジャイアント", vault_aux_giant, NULL, 50, 6}, + {"狂気", vault_aux_cthulhu, NULL, 80, 2}, + {"シンボル(善)", vault_aux_symbol_g, vault_prep_symbol, 70, 1}, + {"シンボル(悪)", vault_aux_symbol_e, vault_prep_symbol, 70, 1}, + {"教会", vault_aux_chapel_g, NULL, 65, 2}, + {"ドラゴン", vault_aux_dragon, vault_prep_dragon, 70, 6}, + {"デーモン", vault_aux_demon, NULL, 80, 6}, + {"ダークエルフ", vault_aux_dark_elf, NULL, 45, 4}, + {NULL, NULL, NULL, 0, 0}, +#else + {"orc", vault_aux_orc, NULL, 5, 6}, + {"troll", vault_aux_troll, NULL, 20, 6}, + {"giant", vault_aux_giant, NULL, 50, 6}, + {"lovecraftian", vault_aux_cthulhu, NULL, 80, 2}, + {"symbol good", vault_aux_symbol_g, vault_prep_symbol, 70, 1}, + {"symbol evil", vault_aux_symbol_e, vault_prep_symbol, 70, 1}, + {"chapel", vault_aux_chapel_g, NULL, 65, 2}, + {"dragon", vault_aux_dragon, vault_prep_dragon, 70, 6}, + {"demon", vault_aux_demon, NULL, 80, 6}, + {"dark elf", vault_aux_dark_elf, NULL, 45, 4}, + {NULL, NULL, NULL, 0, 0}, +#endif +}; - cave_type *c_ptr; - vault_aux_type *n_ptr = pick_vault_type(nest_types, ROOM_NEST); +/*! nestのID定義 / Nest types code */ +#define NEST_TYPE_CLONE 0 +#define NEST_TYPE_JELLY 1 +#define NEST_TYPE_SYMBOL_GOOD 2 +#define NEST_TYPE_SYMBOL_EVIL 3 +#define NEST_TYPE_MIMIC 4 +#define NEST_TYPE_LOVECRAFTIAN 5 +#define NEST_TYPE_KENNEL 6 +#define NEST_TYPE_ANIMAL 7 +#define NEST_TYPE_CHAPEL 8 +#define NEST_TYPE_UNDEAD 9 + +/*! pitのID定義 / Pit types code */ +#define PIT_TYPE_ORC 0 +#define PIT_TYPE_TROLL 1 +#define PIT_TYPE_GIANT 2 +#define PIT_TYPE_LOVECRAFTIAN 3 +#define PIT_TYPE_SYMBOL_GOOD 4 +#define PIT_TYPE_SYMBOL_EVIL 5 +#define PIT_TYPE_CHAPEL 6 +#define PIT_TYPE_DRAGON 7 +#define PIT_TYPE_DEMON 8 +#define PIT_TYPE_DARK_ELF 9 + + +/*! + * @brief デバッグ時に生成されたpit/nestの型を出力する処理 + * @param type pit/nestの型ID + * @param nest TRUEならばnest、FALSEならばpit + * @return デバッグ表示文字列の参照ポインタ + * @details + * Hack -- Get the string describing subtype of pit/nest + * Determined in prepare function (some pit/nest only) + */ +static cptr pit_subtype_string(int type, bool nest) +{ + static char inner_buf[256] = ""; - /* Try to allocate space for room. */ - if (!room_alloc(25, 11, TRUE, by0, bx0, &xval, &yval)) return; + inner_buf[0] = '\0'; /* Init string */ - /* No type available */ - if (!n_ptr) + if (nest) /* Nests */ { - if (pit) return; - else {build_type6(by0, bx0, TRUE);return;} + switch (type) + { + case NEST_TYPE_CLONE: + sprintf(inner_buf, "(%s)", r_name + r_info[vault_aux_race].name); + break; + case NEST_TYPE_SYMBOL_GOOD: + case NEST_TYPE_SYMBOL_EVIL: + sprintf(inner_buf, "(%c)", vault_aux_char); + break; + } } - - /* Process a preparation function if necessary */ - if (n_ptr->prep_func) (*(n_ptr->prep_func))(); - - /* 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++) + else /* Pits */ { - for (x = x1 - 1; x <= x2 + 1; x++) + switch (type) { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); + case PIT_TYPE_SYMBOL_GOOD: + case PIT_TYPE_SYMBOL_EVIL: + sprintf(inner_buf, "(%c)", vault_aux_char); + break; + case PIT_TYPE_DRAGON: + switch (vault_aux_dragon_mask4) + { +#ifdef JP + case RF4_BR_ACID: strcpy(inner_buf, "(酸)"); break; + case RF4_BR_ELEC: strcpy(inner_buf, "(稲妻)"); break; + case RF4_BR_FIRE: strcpy(inner_buf, "(火炎)"); break; + case RF4_BR_COLD: strcpy(inner_buf, "(冷気)"); break; + case RF4_BR_POIS: strcpy(inner_buf, "(毒)"); break; + case (RF4_BR_ACID | RF4_BR_ELEC | RF4_BR_FIRE | RF4_BR_COLD | RF4_BR_POIS): + strcpy(inner_buf, "(万色)"); break; + default: strcpy(inner_buf, "(未定義)"); break; +#else + case RF4_BR_ACID: strcpy(inner_buf, "(acid)"); break; + case RF4_BR_ELEC: strcpy(inner_buf, "(lightning)"); break; + case RF4_BR_FIRE: strcpy(inner_buf, "(fire)"); break; + case RF4_BR_COLD: strcpy(inner_buf, "(frost)"); break; + case RF4_BR_POIS: strcpy(inner_buf, "(poison)"); break; + case (RF4_BR_ACID | RF4_BR_ELEC | RF4_BR_FIRE | RF4_BR_COLD | RF4_BR_POIS): + strcpy(inner_buf, "(multi-hued)"); break; + default: strcpy(inner_buf, "(undefined)"); break; +#endif + } + break; + } + } + + return inner_buf; +} + + +/*! デバッグ時にnestのモンスター情報を確認するための構造体 / A struct for nest monster information with cheat_hear */ +typedef struct +{ + s16b r_idx; + bool used; +} +nest_mon_info_type; + + +/* + *! @brief nestのモンスターリストをソートするための関数 / + * Comp function for sorting nest monster information + * @param u ソート処理対象配列ポインタ + * @param v 未使用 + * @param a 比較対象参照ID1 + * @param b 比較対象参照ID2 + */ +static bool ang_sort_comp_nest_mon_info(vptr u, vptr v, int a, int b) +{ + nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u; + int w1 = nest_mon_info[a].r_idx; + int w2 = nest_mon_info[b].r_idx; + monster_race *r1_ptr = &r_info[w1]; + monster_race *r2_ptr = &r_info[w2]; + int z1, z2; + + /* Unused */ + (void)v; + + /* Extract used info */ + z1 = nest_mon_info[a].used; + z2 = nest_mon_info[b].used; + + /* Compare used status */ + if (z1 < z2) return FALSE; + if (z1 > z2) return TRUE; + + /* Compare levels */ + if (r1_ptr->level < r2_ptr->level) return TRUE; + if (r1_ptr->level > r2_ptr->level) return FALSE; + + /* Compare experience */ + if (r1_ptr->mexp < r2_ptr->mexp) return TRUE; + if (r1_ptr->mexp > r2_ptr->mexp) return FALSE; + + /* Compare indexes */ + return w1 <= w2; +} + +/*! + * @brief nestのモンスターリストをスワップするための関数 / + * Swap function for sorting nest monster information + * @param u スワップ処理対象配列ポインタ + * @param v 未使用 + * @param a スワップ対象参照ID1 + * @param b スワップ対象参照ID2 + */ +static void ang_sort_swap_nest_mon_info(vptr u, vptr v, int a, int b) +{ + nest_mon_info_type *nest_mon_info = (nest_mon_info_type *)u; + nest_mon_info_type holder; + + /* Unused */ + (void)v; + + /* Swap */ + holder = nest_mon_info[a]; + nest_mon_info[a] = nest_mon_info[b]; + nest_mon_info[b] = holder; +} + + +#define NUM_NEST_MON_TYPE 64 /*!prep_func) (*(n_ptr->prep_func))(); + + /* Prepare allocation table */ + get_mon_num_prep(n_ptr->hook_func, NULL); + + align.sub_align = SUB_ALIGN_NEUTRAL; + + /* Pick some monster types */ + for (i = 0; i < NUM_NEST_MON_TYPE; i++) + { + MONRACE_IDX r_idx = 0; + int attempts = 100; + monster_race *r_ptr = NULL; + + while (attempts--) + { + /* Get a (hard) monster type */ + r_idx = get_mon_num(dun_level + 11); + r_ptr = &r_info[r_idx]; + + /* Decline incorrect alignment */ + if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; + + /* Accept this monster */ + break; + } + + /* Notice failure */ + if (!r_idx || !attempts) return FALSE; + + /* Note the alignment */ + if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; + if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; + + nest_mon_info[i].r_idx = (s16b)r_idx; + nest_mon_info[i].used = FALSE; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 11, 25)) return FALSE; + + /* 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++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); } } @@ -1819,177 +1488,154 @@ static void build_type5(int by0, int bx0, bool pit) } } - /* Place a secret door */ switch (randint1(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; + case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; + case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; } + msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(nest)(%s%s)を生成します。", "Monster nest (%s%s)"), n_ptr->name, pit_subtype_string(cur_nest_type, TRUE)); - /* Prepare allocation table */ - get_mon_num_prep(n_ptr->hook_func, NULL); - - /* Pick some monster types */ - for (i = 0; i < 64; i++) + /* Place some monsters */ + for (y = yval - 2; y <= yval + 2; y++) { - int r_idx = 0, attempts = 100; - - while (attempts--) + for (x = xval - 9; x <= xval + 9; x++) { - /* Get a (hard) monster type */ - r_idx = get_mon_num(dun_level + 10); - - /* Decline incorrect alignment */ - if (((align < 0) && (r_info[r_idx].flags3 & RF3_GOOD)) || - ((align > 0) && (r_info[r_idx].flags3 & RF3_EVIL))) - { - continue; - } - - /* Accept this monster */ - break; - } + MONRACE_IDX r_idx; - /* Notice failure */ - if (!r_idx || !attempts) return; + i = randint0(NUM_NEST_MON_TYPE); + r_idx = nest_mon_info[i].r_idx; - /* Note the alignment */ - if (r_info[r_idx].flags3 & RF3_GOOD) align++; - else if (r_info[r_idx].flags3 & RF3_EVIL) align--; + /* Place that "random" monster (no groups) */ + (void)place_monster_aux(0, y, x, r_idx, 0L); - what[i] = r_idx; + nest_mon_info[i].used = TRUE; + } } - /* Describe */ if (cheat_room) { - /* Room type */ -#ifdef JP -msg_format("¥â¥ó¥¹¥¿¡¼Éô²°(%s)", n_ptr->name); -#else - msg_format("Monster nest (%s)", n_ptr->name); -#endif - - } - - - /* Increase the level rating */ - rating += 10; - - /* (Sometimes) Cause a "special feeling" (for "Monster Nests") */ - if ((dun_level <= 40) && (randint1(dun_level * dun_level + 50) < 300)) - { - good_item_flag = TRUE; - } + ang_sort_comp = ang_sort_comp_nest_mon_info; + ang_sort_swap = ang_sort_swap_nest_mon_info; + ang_sort(nest_mon_info, NULL, NUM_NEST_MON_TYPE); - /* Place some monsters */ - for (y = yval - 2; y <= yval + 2; y++) - { - for (x = xval - 9; x <= xval + 9; x++) + /* Dump the entries (prevent multi-printing) */ + for (i = 0; i < NUM_NEST_MON_TYPE; i++) { - int r_idx = what[randint0(64)]; - - /* Place that "random" monster (no groups) */ - (void)place_monster_aux(0, y, x, r_idx, 0L); + if (!nest_mon_info[i].used) break; + for (; i < NUM_NEST_MON_TYPE - 1; i++) + { + if (nest_mon_info[i].r_idx != nest_mon_info[i + 1].r_idx) break; + if (!nest_mon_info[i + 1].used) break; + } + msg_format_wizard(CHEAT_DUNGEON, "Nest構成モンスターNo.%d:%s", i, r_name + r_info[nest_mon_info[i].r_idx].name); } } -} - -static vault_aux_type pit_types[] = -{ -#ifdef JP - {"¥ª¡¼¥¯", vault_aux_orc, NULL, 5, 6}, - {"¥È¥í¥ë", vault_aux_troll, NULL, 20, 6}, - {"¥¸¥ã¥¤¥¢¥ó¥È",vault_aux_giant, NULL, 50, 6}, - {"¶¸µ¤", vault_aux_cthulhu, NULL, 80, 2}, - {"¥·¥ó¥Ü¥ë(Á±)",vault_aux_symbol_g, vault_prep_symbol, 70, 1}, - {"¥·¥ó¥Ü¥ë(°­)",vault_aux_symbol_e, vault_prep_symbol, 70, 1}, - {"¶µ²ñ", vault_aux_chapel_g, NULL, 65, 2}, - {"¥É¥é¥´¥ó", vault_aux_dragon, vault_prep_dragon, 70, 6}, - {"¥Ç¡¼¥â¥ó", vault_aux_demon, NULL, 80, 6}, - {NULL, NULL, NULL, 0, 0}, -#else - {"orc", vault_aux_orc, NULL, 5, 6}, - {"troll", vault_aux_troll, NULL, 20, 6}, - {"giant", vault_aux_giant, NULL, 50, 6}, - {"lovecraftian",vault_aux_cthulhu, NULL, 80, 2}, - {"symbol good",vault_aux_symbol_g, vault_prep_symbol, 70, 1}, - {"symbol evil",vault_aux_symbol_e, vault_prep_symbol, 70, 1}, - {"chapel", vault_aux_chapel_g, NULL, 65, 2}, - {"dragon", vault_aux_dragon, vault_prep_dragon, 70, 6}, - {"demon", vault_aux_demon, NULL, 80, 6}, - {NULL, NULL, NULL, 0, 0}, -#endif -}; + return TRUE; +} -/* - * 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. - * - * 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. +/*! + * @brief タイプ6の部屋…pitを生成する / Type 6 -- Monster pits + * @return なし + * @details + * A monster pit is a "big" room, with an "inner" room, containing\n + * a "collection" of monsters of a given type organized in the room.\n + *\n + * The inside room in a monster pit appears as shown below, where the\n + * actual monsters in each location depend on the type of the pit\n + *\n + * XXXXXXXXXXXXXXXXXXXXX\n + * X0000000000000000000X\n + * X0112233455543322110X\n + * X0112233467643322110X\n + * X0112233455543322110X\n + * X0000000000000000000X\n + * XXXXXXXXXXXXXXXXXXXXX\n + *\n + * Note that the monsters in the pit are now chosen by using "get_mon_num()"\n + * to request 16 "appropriate" monsters, sorting them by level, and using\n + * the "even" entries in this sorted list for the contents of the pit.\n + *\n + * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n + * which is handled by requiring a specific "breath" attack for all of the\n + * dragons. This may include "multi-hued" breath. Note that "wyrms" may\n + * be present in many of the dragon pits, if they have the proper breath.\n + *\n + * Note the use of the "get_mon_num_prep()" function, and the special\n + * "get_mon_num_hook()" restriction function, to prepare the "monster\n + * allocation table" in such a way as to optimize the selection of\n + * "appropriate" non-unique monsters for the pit.\n + *\n + * Note that the "get_mon_num()" function may (rarely) fail, in which case\n + * the pit will be empty.\n + *\n + * Note that "monster pits" will never contain "unique" monsters.\n */ -static void build_type6(int by0, int bx0, bool nest) +static bool build_type6(void) { - int y, x, y1, x1, y2, x2, xval, yval; + POSITION y, x, y1, x1, y2, x2, xval, yval; int i, j; - int what[16]; + MONRACE_IDX what[16]; - int align = 0; + monster_type align; cave_type *c_ptr; - vault_aux_type *n_ptr = pick_vault_type(pit_types, ROOM_PIT); - - /* Try to allocate space for room. */ - if (!room_alloc(25, 11, TRUE, by0, bx0, &xval, &yval)) return; + int cur_pit_type = pick_vault_type(pit_types, d_info[dungeon_type].pit); + vault_aux_type *n_ptr; /* No type available */ - if (!n_ptr) - { - if (nest) return; - else {build_type5(by0, bx0, TRUE);return;} - } + if (cur_pit_type < 0) return FALSE; + + n_ptr = &pit_types[cur_pit_type]; /* Process a preparation function if necessary */ if (n_ptr->prep_func) (*(n_ptr->prep_func))(); + /* Prepare allocation table */ + get_mon_num_prep(n_ptr->hook_func, NULL); + + align.sub_align = SUB_ALIGN_NEUTRAL; + + /* Pick some monster types */ + for (i = 0; i < 16; i++) + { + MONRACE_IDX r_idx = 0; + int attempts = 100; + monster_race *r_ptr = NULL; + + while (attempts--) + { + /* Get a (hard) monster type */ + r_idx = get_mon_num(dun_level + 11); + r_ptr = &r_info[r_idx]; + + /* Decline incorrect alignment */ + if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; + + /* Accept this monster */ + break; + } + + /* Notice failure */ + if (!r_idx || !attempts) return FALSE; + + /* Note the alignment */ + if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; + if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; + + what[i] = r_idx; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 11, 25)) return FALSE; + /* Large room */ y1 = yval - 4; y2 = yval + 4; @@ -2055,45 +1701,10 @@ static void build_type6(int by0, int bx0, bool nest) /* Place a secret door */ switch (randint1(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; - } - - - /* Prepare allocation table */ - get_mon_num_prep(n_ptr->hook_func, NULL); - - /* Pick some monster types */ - for (i = 0; i < 16; i++) - { - int r_idx = 0, attempts = 100; - - while (attempts--) - { - /* Get a (hard) monster type */ - r_idx = get_mon_num(dun_level + 10); - - /* Decline incorrect alignment */ - if (((align < 0) && (r_info[r_idx].flags3 & RF3_GOOD)) || - ((align > 0) && (r_info[r_idx].flags3 & RF3_EVIL))) - { - continue; - } - - /* Accept this monster */ - break; - } - - /* Notice failure */ - if (!r_idx || !attempts) return; - - /* Note the alignment */ - if (r_info[r_idx].flags3 & RF3_GOOD) align++; - else if (r_info[r_idx].flags3 & RF3_EVIL) align--; - - what[i] = r_idx; + case 1: place_secret_door(y1 - 1, xval, DOOR_DEFAULT); break; + case 2: place_secret_door(y2 + 1, xval, DOOR_DEFAULT); break; + case 3: place_secret_door(yval, x1 - 1, DOOR_DEFAULT); break; + case 4: place_secret_door(yval, x2 + 1, DOOR_DEFAULT); break; } /* Sort the entries */ @@ -2111,44 +1722,21 @@ static void build_type6(int by0, int bx0, bool nest) /* Bubble */ if (p1 > p2) { - int tmp = what[i1]; + MONRACE_IDX tmp = what[i1]; what[i1] = what[i2]; what[i2] = tmp; } } } - /* Message */ - if (cheat_room) - { -#ifdef JP -msg_format("%s¤ÎÁã", n_ptr->name); -#else - /* Room type */ - msg_format("Monster pit (%s)", n_ptr->name); -#endif - } + msg_format_wizard(CHEAT_DUNGEON, _("モンスター部屋(pit)(%s%s)を生成します。", "Monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, FALSE)); /* Select the entries */ for (i = 0; i < 8; i++) { /* Every other entry */ what[i] = what[i * 2]; - - if (cheat_hear) - { - /* Message */ - msg_print(r_name + r_info[what[i]].name); - } - } - - /* Increase the level rating */ - rating += 10; - - /* (Sometimes) Cause a "special feeling" (for "Monster Pits") */ - if ((dun_level <= 40) && (randint1(dun_level * dun_level + 50) < 300)) - { - good_item_flag = TRUE; + msg_format_wizard(CHEAT_DUNGEON, _("Nest構成モンスター選択No.%d:%s", "Nest Monster Select No.%d:%s"), i, r_name + r_info[what[i]].name); } /* Top and bottom rows */ @@ -2199,11 +1787,21 @@ msg_format("%s /* Center monster */ place_monster_aux(0, yval, xval, what[7], PM_NO_KAGE); + + return TRUE; } -/* coordinate translation code */ -static void coord_trans(int *x, int *y, int xoffset, int yoffset, int transno) +/*! + * @brief Vault地形を回転、上下左右反転するための座標変換を返す / coordinate translation code + * @param x 変換したい点のX座標参照ポインタ + * @param y 変換したい点のY座標参照ポインタ + * @param xoffset Vault生成時の基準X座標 + * @param yoffset Vault生成時の基準Y座標 + * @param transno 処理ID + * @return なし + */ +static void coord_trans(POSITION *x, POSITION *y, POSITION xoffset, POSITION yoffset, int transno) { int i; int temp; @@ -2217,7 +1815,7 @@ static void coord_trans(int *x, int *y, int xoffset, int yoffset, int transno) * be expressed simply in terms of swapping and inverting the * x and y coordinates. */ - for (i = 0; i <= transno % 4; i++) + for (i = 0; i < transno % 4; i++) { /* rotate by 90 degrees */ temp = *x; @@ -2236,20 +1834,25 @@ static void coord_trans(int *x, int *y, int xoffset, int yoffset, int transno) *y += yoffset; } - -/* - * Hack -- fill in "vault" rooms +/*! + * @brief Vaultをフロアに配置する / Hack -- fill in "vault" rooms + * @param yval 生成基準Y座標 + * @param xval 生成基準X座標 + * @param ymax VaultのYサイズ + * @param xmax VaultのXサイズ + * @param data Vaultのデータ文字列 + * @param xoffset 変換基準X座標 + * @param yoffset 変換基準Y座標 + * @param transno 変換ID + * @return なし */ -static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, - int xoffset, int yoffset, int transno) +static void build_vault(POSITION yval, POSITION xval, POSITION ymax, POSITION xmax, cptr data, + POSITION xoffset, POSITION yoffset, int transno) { - int dx, dy, x, y, i, j; - + POSITION dx, dy, x, y, i, j; cptr t; - cave_type *c_ptr; - /* Place dungeon features and objects */ for (t = data, dy = 0; dy < ymax; dy++) { @@ -2263,7 +1866,7 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, coord_trans(&i, &j, xoffset, yoffset, transno); /* Extract the location */ - if (transno%2) + if (transno % 2 == 0) { /* no swap of x/y */ x = xval - (xmax / 2) + i; @@ -2304,18 +1907,28 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, place_inner_grid(c_ptr); break; + /* Glass wall (inner) */ + case '$': + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + break; + /* Permanent wall (inner) */ case 'X': - c_ptr->feat = FEAT_PERM_INNER; - c_ptr->info &= ~(CAVE_MASK); - c_ptr->info |= CAVE_INNER; + place_inner_perm_grid(c_ptr); + break; + + /* Permanent glass wall (inner) */ + case 'Y': + place_inner_perm_grid(c_ptr); + c_ptr->feat = feat_permanent_glass_wall; break; /* Treasure/trap */ case '*': if (randint0(100) < 75) { - place_object(y, x, FALSE, FALSE); + place_object(y, x, 0L); } else { @@ -2325,7 +1938,18 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, /* Secret doors */ case '+': - place_secret_door(y, x); + place_secret_door(y, x, DOOR_DEFAULT); + break; + + /* Secret glass doors */ + case '-': + place_secret_door(y, x, DOOR_GLASS_DOOR); + if (is_closed_door(c_ptr->feat)) c_ptr->mimic = feat_glass_wall; + break; + + /* Curtains */ + case '\'': + place_secret_door(y, x, DOOR_CURTAIN); break; /* Trap */ @@ -2335,43 +1959,43 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, /* Black market in a dungeon */ case 'S': - set_cave_feat(y, x, FEAT_SHOP_HEAD + STORE_BLACK); + set_cave_feat(y, x, feat_black_market); store_init(NO_TOWN, STORE_BLACK); break; - + /* The Pattern */ case 'p': - set_cave_feat(y, x, FEAT_PATTERN_START); + set_cave_feat(y, x, feat_pattern_start); break; - + case 'a': - set_cave_feat(y, x, FEAT_PATTERN_1); + set_cave_feat(y, x, feat_pattern_1); break; - + case 'b': - set_cave_feat(y, x, FEAT_PATTERN_2); + set_cave_feat(y, x, feat_pattern_2); break; - + case 'c': - set_cave_feat(y, x, FEAT_PATTERN_3); + set_cave_feat(y, x, feat_pattern_3); break; - + case 'd': - set_cave_feat(y, x, FEAT_PATTERN_4); + set_cave_feat(y, x, feat_pattern_4); break; - + case 'P': - set_cave_feat(y, x, FEAT_PATTERN_END); + set_cave_feat(y, x, feat_pattern_end); break; - + case 'B': - set_cave_feat(y, x, FEAT_PATTERN_XTRA1); + set_cave_feat(y, x, feat_pattern_exit); break; case 'A': /* Reward for Pattern walk */ object_level = base_level + 12; - place_object(y, x, TRUE, FALSE); + place_object(y, x, AM_GOOD | AM_GREAT); object_level = base_level; break; } @@ -2392,7 +2016,7 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, coord_trans(&i, &j, xoffset, yoffset, transno); /* Extract the location */ - if (transno % 2) + if (transno % 2 == 0) { /* no swap of x/y */ x = xval - (xmax / 2) + i; @@ -2436,7 +2060,7 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, place_monster(y, x, PM_ALLOW_SLEEP); monster_level = base_level; object_level = base_level + 7; - place_object(y, x, TRUE, FALSE); + place_object(y, x, AM_GOOD); object_level = base_level; break; } @@ -2448,7 +2072,7 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, place_monster(y, x, PM_ALLOW_SLEEP); monster_level = base_level; object_level = base_level + 20; - place_object(y, x, TRUE, TRUE); + place_object(y, x, AM_GOOD | AM_GREAT); object_level = base_level; break; } @@ -2465,7 +2089,7 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, if (randint0(100) < 50) { object_level = base_level + 7; - place_object(y, x, FALSE, FALSE); + place_object(y, x, 0L); object_level = base_level; } break; @@ -2477,23 +2101,22 @@ static void build_vault(int yval, int xval, int ymax, int xmax, cptr data, } -/* - * Type 7 -- simple vaults (see "v_info.txt") +/*! + * @brief タイプ7の部屋…v_info.txtより小型vaultを生成する / Type 7 -- simple vaults (see "v_info.txt") + * @return なし */ -static void build_type7(int by0, int bx0) +static bool build_type7(void) { vault_type *v_ptr = NULL; - int dummy = 0; - int x, y; - int xval, yval; - int xoffset, yoffset; + int dummy; + POSITION x, y; + POSITION xval, yval; + POSITION xoffset, yoffset; int transno; /* Pick a lesser vault */ - while (dummy < SAFE_MAX_ATTEMPTS) + for (dummy = 0; dummy < SAFE_MAX_ATTEMPTS; dummy++) { - dummy++; - /* Access a random vault record */ v_ptr = &v_info[randint0(max_v_idx)]; @@ -2502,7 +2125,11 @@ static void build_type7(int by0, int bx0) } /* No lesser vault found */ - if (!v_ptr) return; + if (dummy >= SAFE_MAX_ATTEMPTS) + { + msg_print_wizard(CHEAT_DUNGEON, _("小型固定Vaultを配置できませんでした。", "Could not place lesser vault.")); + return FALSE; + } /* pick type of transformation (0-7) */ transno = randint0(8); @@ -2511,6 +2138,13 @@ static void build_type7(int by0, int bx0) x = v_ptr->wid; y = v_ptr->hgt; + /* Some huge vault cannot be ratated to fit in the dungeon */ + if (x+2 > cur_hgt-2) + { + /* Forbid 90 or 270 degree ratation */ + transno &= ~1; + } + coord_trans(&x, &y, 0, 0, transno); if (x < 0) @@ -2531,64 +2165,39 @@ static void build_type7(int by0, int bx0) yoffset = 0; } - /* Try to allocate space for room. */ - if (!room_alloc(abs(x), abs(y), FALSE, by0, bx0, &xval, &yval)) return; + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, abs(y), abs(x))) return FALSE; - if (dummy >= SAFE_MAX_ATTEMPTS) - { - if (cheat_room) - { -#ifdef JP -msg_print("·Ù¹ð¡ª¾®¤µ¤ÊÃϲ¼¼¼¤òÇÛÃ֤Ǥ­¤Þ¤»¤ó¡ª"); -#else - msg_print("Warning! Could not place lesser vault!"); -#endif - - } - return; - } - - -#ifdef FORCE_V_IDX - v_ptr = &v_info[2]; +#ifdef FORCE_V_IDX + v_ptr = &v_info[2]; #endif /* Message */ - if (cheat_room) msg_format("%s", v_name + v_ptr->name); - - /* Boost the rating */ - rating += v_ptr->rat; - - /* (Sometimes) Cause a special feeling */ - if ((dun_level <= 50) || - (randint1((dun_level - 40) * (dun_level - 40) + 50) < 400)) - { - good_item_flag = TRUE; - } + msg_format_wizard(CHEAT_DUNGEON, _("小型Vault(%s)を生成しました。", "Lesser vault (%s)."), v_name + v_ptr->name); /* Hack -- Build the vault */ build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, v_text + v_ptr->text, xoffset, yoffset, transno); -} + return TRUE; +} -/* - * Type 8 -- greater vaults (see "v_info.txt") +/*! + * @brief タイプ8の部屋…v_info.txtより大型vaultを生成する / Type 8 -- greater vaults (see "v_info.txt") + * @return なし */ -static void build_type8(int by0, int bx0) +static bool build_type8(void) { - vault_type *v_ptr = NULL; - int dummy = 0; - int xval, yval; - int x, y; + vault_type *v_ptr; + int dummy; + POSITION xval, yval; + POSITION x, y; int transno; int xoffset, yoffset; /* Pick a greater vault */ - while (dummy < SAFE_MAX_ATTEMPTS) + for (dummy = 0; dummy < SAFE_MAX_ATTEMPTS; dummy++) { - dummy++; - /* Access a random vault record */ v_ptr = &v_info[randint0(max_v_idx)]; @@ -2597,7 +2206,11 @@ static void build_type8(int by0, int bx0) } /* No greater vault found */ - if (!v_ptr) return; + if (dummy >= SAFE_MAX_ATTEMPTS) + { + msg_print_wizard(CHEAT_DUNGEON, _("大型固定Vaultを配置できませんでした。", "Could not place greater vault.")); + return FALSE; + } /* pick type of transformation (0-7) */ transno = randint0(8); @@ -2606,6 +2219,13 @@ static void build_type8(int by0, int bx0) x = v_ptr->wid; y = v_ptr->hgt; + /* Some huge vault cannot be ratated to fit in the dungeon */ + if (x+2 > cur_hgt-2) + { + /* Forbid 90 or 270 degree ratation */ + transno &= ~1; + } + coord_trans(&x, &y, 0, 0, transno); if (x < 0) @@ -2632,43 +2252,20 @@ static void build_type8(int by0, int bx0) * Hack -- Prepare a bit larger space (+2, +2) to * prevent generation of vaults with no-entrance. */ - if (!room_alloc(abs(x) + 2, abs(y) + 2, FALSE, by0, bx0, &xval, &yval)) return; - - if (dummy >= SAFE_MAX_ATTEMPTS) - { - if (cheat_room) - { -#ifdef JP -msg_print("·Ù¹ð¡ªµðÂç¤ÊÃϲ¼¼¼¤òÇÛÃ֤Ǥ­¤Þ¤»¤ó¡ª"); -#else - msg_print("Warning! Could not place greater vault!"); -#endif - - } - return; - } - + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, (POSITION)(abs(y) + 2), (POSITION)(abs(x) + 2))) return FALSE; #ifdef FORCE_V_IDX v_ptr = &v_info[76 + randint1(3)]; #endif - /* Message */ - if (cheat_room) msg_format("%s", v_name + v_ptr->name); - - /* Boost the rating */ - rating += v_ptr->rat; - - /* (Sometimes) Cause a special feeling */ - if ((dun_level <= 50) || - (randint1((dun_level - 40) * (dun_level - 40) + 50) < 400)) - { - good_item_flag = TRUE; - } + msg_format_wizard(CHEAT_DUNGEON, _("大型固定Vault(%s)を生成しました。", "Greater vault (%s)."), v_name + v_ptr->name); /* Hack -- Build the vault */ build_vault(yval, xval, v_ptr->hgt, v_ptr->wid, v_text + v_ptr->text, xoffset, yoffset, transno); + + return TRUE; } /* @@ -2716,7 +2313,7 @@ static void store_height(int x, int y, int val) (val <= fill_data.c1)) val = fill_data.c1 + 1; /* store the value in height-map format */ - cave[y][x].feat = val; + cave[y][x].feat = (s16b)val; return; } @@ -2760,7 +2357,7 @@ static void store_height(int x, int y, int val) * 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. +* else is converted to the normal _extra_. */ @@ -2814,10 +2411,10 @@ static void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd, int roug, fill_data.ymin = y0 - yhsize; fill_data.xmax = x0 + xhsize; fill_data.ymax = y0 + yhsize; - + /* Store cutoff in global for quick access */ fill_data.c1 = cutoff; - + /* * Scale factor for middle points: * About sqrt(2) * 256 - correct for a square lattice @@ -2833,18 +2430,18 @@ static void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd, int roug, { for (j = 0; j <= ysize; j++) { - /* 255 is a flag for "not done yet" */ - cave[(int)(fill_data.ymin + j)][(int)(fill_data.xmin + i)].feat = 255; + /* -1 is a flag for "not done yet" */ + cave[(int)(fill_data.ymin + j)][(int)(fill_data.xmin + i)].feat = -1; /* Clear icky flag because may be redoing the cave */ cave[(int)(fill_data.ymin + j)][(int)(fill_data.xmin + i)].info &= ~(CAVE_ICKY); } } /* Boundaries are walls */ - cave[fill_data.ymin][fill_data.xmin].feat = maxsize; - cave[fill_data.ymax][fill_data.xmin].feat = maxsize; - cave[fill_data.ymin][fill_data.xmax].feat = maxsize; - cave[fill_data.ymax][fill_data.xmax].feat = maxsize; + cave[fill_data.ymin][fill_data.xmin].feat = (s16b)maxsize; + cave[fill_data.ymax][fill_data.xmin].feat = (s16b)maxsize; + cave[fill_data.ymin][fill_data.xmax].feat = (s16b)maxsize; + cave[fill_data.ymax][fill_data.xmax].feat = (s16b)maxsize; /* Set the middle square to be an open area. */ cave[y0][x0].feat = 0; @@ -2866,11 +2463,11 @@ static void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd, int roug, xhstep /= 2; ystep = yhstep; yhstep /= 2; - + /* cache well used values */ xstep2 = xstep / 256; ystep2 = ystep / 256; - + xhstep2 = xhstep / 256; yhstep2 = yhstep / 256; @@ -2882,10 +2479,10 @@ static void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd, int roug, /* cache often used values */ ii = i / 256 + fill_data.xmin; jj = j / 256 + fill_data.ymin; - + /* Test square */ - if (cave[jj][ii].feat == 255) - { + if (cave[jj][ii].feat == -1) + { if (xhstep2 > grd) { /* If greater than 'grid' level then is random */ @@ -2912,9 +2509,9 @@ static void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd, int roug, /* cache often used values */ ii = i / 256 + fill_data.xmin; jj = j / 256 + fill_data.ymin; - + /* Test square */ - if (cave[jj][ii].feat == 255) + if (cave[jj][ii].feat == -1) { if (xhstep2 > grd) { @@ -2941,10 +2538,10 @@ static void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd, int roug, /* cache often used values */ ii = i / 256 + fill_data.xmin; jj = j / 256 + fill_data.ymin; - + /* Test square */ - if (cave[jj][ii].feat == 255) - { + if (cave[jj][ii].feat == -1) + { if (xhstep2 > grd) { /* If greater than 'grid' level then is random */ @@ -2956,12 +2553,12 @@ static void generate_hmap(int y0, int x0, int xsiz, int ysiz, int grd, int roug, xm = fill_data.xmin + (i - xhstep) / 256; xp = fill_data.xmin + (i + xhstep) / 256; ym = fill_data.ymin + (j - yhstep) / 256; - yp = fill_data.ymin + (j + yhstep) / 256; - + yp = fill_data.ymin + (j + yhstep) / 256; + /* * Average over all four corners + scale by diagsize to * reduce the effect of the square grid on the shape of the fractal - */ + */ store_height(ii, jj, (cave[ym][xm].feat + cave[yp][xm].feat + cave[ym][xp].feat + cave[yp][xp].feat) / 4 @@ -2996,14 +2593,14 @@ static bool hack_isnt_wall(int y, int x, int c1, int c2, int c3, int feat1, int /* 25% of the time use the other tile : it looks better this way */ if (randint1(100) < 75) { - cave[y][x].feat = feat1; + cave[y][x].feat = (s16b)feat1; cave[y][x].info &= ~(CAVE_MASK); cave[y][x].info |= info1; return TRUE; } else { - cave[y][x].feat = feat2; + cave[y][x].feat = (s16b)feat2; cave[y][x].info &= ~(CAVE_MASK); cave[y][x].info |= info2; return TRUE; @@ -3014,14 +2611,14 @@ static bool hack_isnt_wall(int y, int x, int c1, int c2, int c3, int feat1, int /* 25% of the time use the other tile : it looks better this way */ if (randint1(100) < 75) { - cave[y][x].feat = feat2; + cave[y][x].feat = (s16b)feat2; cave[y][x].info &= ~(CAVE_MASK); cave[y][x].info |= info2; return TRUE; } else { - cave[y][x].feat = feat1; + cave[y][x].feat = (s16b)feat1; cave[y][x].info &= ~(CAVE_MASK); cave[y][x].info |= info1; return TRUE; @@ -3029,7 +2626,8 @@ static bool hack_isnt_wall(int y, int x, int c1, int c2, int c3, int feat1, int } else if (cave[y][x].feat <= c3) { - cave[y][x].feat = feat3; + cave[y][x].feat = (s16b)feat3; + cave[y][x].info &= ~(CAVE_MASK); cave[y][x].info |= info3; return TRUE; } @@ -3049,7 +2647,7 @@ static bool hack_isnt_wall(int y, int x, int c1, int c2, int c3, int feat1, int * Quick and nasty fill routine used to find the connected region * of floor in the middle of the cave */ -static void cave_fill(byte y, byte x) +static void cave_fill(POSITION y, POSITION x) { int i, j, d; int ty, tx; @@ -3103,8 +2701,8 @@ static void cave_fill(byte y, byte x) fill_data.info1, fill_data.info2, fill_data.info3)) { /* Enqueue that entry */ - temp_y[flow_tail] = j; - temp_x[flow_tail] = i; + temp_y[flow_tail] = (byte_hack)j; + temp_x[flow_tail] = (byte_hack)i; /* Advance the queue */ if (++flow_tail == TEMP_MAX) flow_tail = 0; @@ -3134,7 +2732,6 @@ static void cave_fill(byte y, byte x) static bool generate_fracave(int y0, int x0, int xsize, int ysize, int cutoff, bool light, bool room) { int x, y, i, xhsize, yhsize; - /* offsets to middle from corner */ xhsize = xsize / 2; @@ -3306,7 +2903,7 @@ static bool generate_fracave(int y0, int x0, int xsize, int ysize, int cutoff, b * 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.) + * from _outer_ with _inner_. (Internal walls are _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. @@ -3316,12 +2913,14 @@ static bool generate_fracave(int y0, int x0, int xsize, int ysize, int cutoff, b } -/* - * Driver routine to create fractal cave system +/*! + * @brief タイプ9の部屋…フラクタルカーブによる洞窟生成 / Type 9 -- Driver routine to create fractal cave system + * @return なし */ -static void build_type9(int by0, int bx0) +static bool build_type9(void) { - int grd, roug, cutoff, xsize, ysize, y0, x0; + int grd, roug, cutoff; + POSITION xsize, ysize, y0, x0; bool done, light, room; @@ -3329,8 +2928,23 @@ static void build_type9(int by0, int bx0) xsize = randint1(22) * 2 + 6; ysize = randint1(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; + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) + { + /* Limit to the minimum room size, and retry */ + xsize = 8; + ysize = 8; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) + { + /* + * Still no space?! + * Try normal room + */ + return build_type1(); + } + } light = done = FALSE; room = TRUE; @@ -3358,6 +2972,8 @@ static void build_type9(int by0, int bx0) /* Convert to normal format + clean up */ done = generate_fracave(y0, x0, xsize, ysize, cutoff, light, room); } + + return TRUE; } #ifdef ALLOW_CAVERNS_AND_LAKES @@ -3413,51 +3029,44 @@ static bool generate_lake(int y0, int x0, int xsize, int ysize, int c1, int c2, /* Get features based on type */ switch (type) { - case 1: { - /* Lava */ - feat1 = FEAT_DEEP_LAVA; - feat2 = FEAT_SHAL_LAVA; - feat3 = floor_type[randint0(100)]; - }; break; - case 2:{ - /* Water */ - feat1 = FEAT_DEEP_WATER; - feat2 = FEAT_SHAL_WATER; - feat3 = floor_type[randint0(100)]; - }; break; - case 3: { - /* Collapsed cave */ - feat1 = floor_type[randint0(100)]; - feat2 = floor_type[randint0(100)]; - feat3 = FEAT_RUBBLE; - }; break; - case 4: { - /* Earth vault */ - feat1 = FEAT_RUBBLE; - feat2 = floor_type[randint0(100)]; - feat3 = FEAT_RUBBLE; - }; break; - case 5: { - /* Air vault */ - feat1 = FEAT_GRASS; - feat2 = FEAT_TREES; - feat3 = FEAT_GRASS; - }; break; - case 6: { - /* Water vault */ - feat1 = FEAT_SHAL_WATER; - feat2 = FEAT_DEEP_WATER; - feat3 = FEAT_SHAL_WATER; - }; break; - case 7: { - /* Fire Vault */ - feat1 = FEAT_SHAL_LAVA; - feat2 = FEAT_DEEP_LAVA; - feat3 = FEAT_SHAL_LAVA; - }; break; - - /* Paranoia */ - default: return FALSE; + case LAKE_T_LAVA: /* Lava */ + feat1 = feat_deep_lava; + feat2 = feat_shallow_lava; + feat3 = floor_type[randint0(100)]; + break; + case LAKE_T_WATER: /* Water */ + feat1 = feat_deep_water; + feat2 = feat_shallow_water; + feat3 = floor_type[randint0(100)]; + break; + case LAKE_T_CAVE: /* Collapsed cave */ + feat1 = floor_type[randint0(100)]; + feat2 = floor_type[randint0(100)]; + feat3 = feat_rubble; + break; + case LAKE_T_EARTH_VAULT: /* Earth vault */ + feat1 = feat_rubble; + feat2 = floor_type[randint0(100)]; + feat3 = feat_rubble; + break; + case LAKE_T_AIR_VAULT: /* Air vault */ + feat1 = feat_grass; + feat2 = feat_tree; + feat3 = feat_grass; + break; + case LAKE_T_WATER_VAULT: /* Water vault */ + feat1 = feat_shallow_water; + feat2 = feat_deep_water; + feat3 = feat_shallow_water; + break; + case LAKE_T_FIRE_VAULT: /* Fire Vault */ + feat1 = feat_shallow_lava; + feat2 = feat_deep_lava; + feat3 = feat_shallow_lava; + break; + + /* Paranoia */ + default: return FALSE; } /* @@ -3465,7 +3074,7 @@ static bool generate_lake(int y0, int x0, int xsize, int ysize, int c1, int c2, * this gets rid of alot of isolated one-sqaures that * can make teleport traps instadeaths... */ - + /* cutoffs */ fill_data.c1 = c1; fill_data.c2 = c2; @@ -3540,11 +3149,10 @@ static bool generate_lake(int y0, int x0, int xsize, int ysize, int c1, int c2, /* turn off icky flag (no longer needed.) */ cave[y0 + y - yhsize][x0 + x - xhsize].info &= ~(CAVE_ICKY | CAVE_ROOM); - /* Light lava and trees */ - if ((cave[y0 + y - yhsize][x0 + x - xhsize].feat == FEAT_DEEP_LAVA) || - (cave[y0 + y - yhsize][x0 + x - xhsize].feat == FEAT_SHAL_LAVA)) + /* Light lava */ + if (cave_have_flag_bold(y0 + y - yhsize, x0 + x - xhsize, FF_LAVA)) { - cave[y0 + y - yhsize][x0 + x - xhsize].info |= CAVE_GLOW; + if (!(d_info[dungeon_type].flags1 & DF1_DARKNESS)) cave[y0 + y - yhsize][x0 + x - xhsize].info |= CAVE_GLOW; } } } @@ -3563,7 +3171,7 @@ void build_lake(int type) int c1, c2, c3; /* paranoia - exit if lake type out of range. */ - if ((type < 1) || (type > 7)) + if ((type < LAKE_T_LAVA) || (type > LAKE_T_FIRE_VAULT)) { msg_format("Invalid lake type (%d)", type); return; @@ -3631,7 +3239,7 @@ static void add_door(int x, int y) (is_outer_bold(y, x - 1) && is_outer_bold(y, x + 1))) { /* secret door */ - place_secret_door(y, x); + place_secret_door(y, x, DOOR_DEFAULT); /* set boundarys so don't get wide doors */ place_solid_bold(y, x - 1); @@ -3651,7 +3259,7 @@ static void add_door(int x, int y) is_floor_bold(y,x-1) && is_floor_bold(y,x+1)) { /* secret door */ - place_secret_door(y, x); + place_secret_door(y, x, DOOR_DEFAULT); /* set boundarys so don't get wide doors */ place_solid_bold(y - 1, x); @@ -3688,8 +3296,7 @@ static void fill_treasure(int x1, int x2, int y1, int y2, int difficulty) /* if floor, shallow water and lava */ if (is_floor_bold(y, x) || - (cave[y][x].feat == FEAT_SHAL_WATER) || - (cave[y][x].feat == FEAT_SHAL_LAVA)) + (cave_have_flag_bold(y, x, FF_PLACE) && cave_have_flag_bold(y, x, FF_DROP))) { /* The smaller 'value' is, the better the stuff */ if (value < 0) @@ -3699,7 +3306,7 @@ static void fill_treasure(int x1, int x2, int y1, int y2, int difficulty) place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP)); monster_level = base_level; object_level = base_level + 20; - place_object(y, x, TRUE, FALSE); + place_object(y, x, AM_GOOD); object_level = base_level; } else if (value < 5) @@ -3709,7 +3316,7 @@ static void fill_treasure(int x1, int x2, int y1, int y2, int difficulty) place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP)); monster_level = base_level; object_level = base_level + 10; - place_object(y, x, TRUE, FALSE); + place_object(y, x, AM_GOOD); object_level = base_level; } else if (value < 10) @@ -3735,7 +3342,7 @@ static void fill_treasure(int x1, int x2, int y1, int y2, int difficulty) /* Object or trap */ if (randint0(100) < 25) { - place_object(y, x, FALSE, FALSE); + place_object(y, x, 0L); } else { @@ -3762,7 +3369,7 @@ static void fill_treasure(int x1, int x2, int y1, int y2, int difficulty) if (randint0(100) < 50) { object_level = base_level + 7; - place_object(y, x, FALSE, FALSE); + place_object(y, x, 0L); object_level = base_level; } } @@ -3786,7 +3393,7 @@ static void fill_treasure(int x1, int x2, int y1, int y2, int difficulty) } else if (randint0(100) < 50) { - place_object(y, x, FALSE, FALSE); + place_object(y, x, 0L); } } @@ -3822,12 +3429,11 @@ static void build_bubble_vault(int x0, int y0, int xsize, int ysize) int xhsize = xsize / 2; int yhsize = ysize / 2; - - if (cheat_room) msg_print("Bubble Vault"); + msg_print_wizard(CHEAT_DUNGEON, _("泡型ランダムVaultを生成しました。", "Room Vault.")); /* Allocate center of bubbles */ - center[0].x = randint1(xsize - 3) + 1; - center[0].y = randint1(ysize - 3) + 1; + center[0].x = (byte)randint1(xsize - 3) + 1; + center[0].y = (byte)randint1(ysize - 3) + 1; for (i = 1; i < BUBBLENUM; i++) { @@ -3848,31 +3454,31 @@ static void build_bubble_vault(int x0, int y0, int xsize, int ysize) } } - center[i].x = x; - center[i].y = y; + center[i].x = (byte_hack)x; + center[i].y = (byte_hack)y; } /* Top and bottom boundaries */ for (i = 0; i < xsize; i++) { - int x = x0 - xhsize + i; + int side_x = x0 - xhsize + i; - place_outer_noperm_bold(y0 - yhsize + 0, x); - cave[y0 - yhsize + 0][x].info |= (CAVE_ROOM | CAVE_ICKY); - place_outer_noperm_bold(y0 - yhsize + ysize - 1, x); - cave[y0 - yhsize + ysize - 1][x].info |= (CAVE_ROOM | CAVE_ICKY); + place_outer_noperm_bold(y0 - yhsize + 0, side_x); + cave[y0 - yhsize + 0][side_x].info |= (CAVE_ROOM | CAVE_ICKY); + place_outer_noperm_bold(y0 - yhsize + ysize - 1, side_x); + cave[y0 - yhsize + ysize - 1][side_x].info |= (CAVE_ROOM | CAVE_ICKY); } /* Left and right boundaries */ for (i = 1; i < ysize - 1; i++) { - int y = y0 - yhsize + i; + int side_y = y0 - yhsize + i; - place_outer_noperm_bold(y, x0 - xhsize + 0); - cave[y][x0 - xhsize + 0].info |= (CAVE_ROOM | CAVE_ICKY); - place_outer_noperm_bold(y, x0 - xhsize + xsize - 1); - cave[y][x0 - xhsize + xsize - 1].info |= (CAVE_ROOM | CAVE_ICKY); + place_outer_noperm_bold(side_y, x0 - xhsize + 0); + cave[side_y][x0 - xhsize + 0].info |= (CAVE_ROOM | CAVE_ICKY); + place_outer_noperm_bold(side_y, x0 - xhsize + xsize - 1); + cave[side_y][x0 - xhsize + xsize - 1].info |= (CAVE_ROOM | CAVE_ICKY); } /* Fill in middle with bubbles */ @@ -3883,8 +3489,8 @@ static void build_bubble_vault(int x0, int y0, int xsize, int ysize) /* Get distances to two closest centers */ /* initialize */ - min1 = distance(x, y, center[0].x, center[0].y); - min2 = distance(x, y, center[1].x, center[1].y); + min1 = (u16b)distance(x, y, center[0].x, center[0].y); + min2 = (u16b)distance(x, y, center[1].x, center[1].y); if (min1 > min2) { @@ -3897,7 +3503,7 @@ static void build_bubble_vault(int x0, int y0, int xsize, int ysize) /* Scan the rest */ for (i = 2; i < BUBBLENUM; i++) { - temp = distance(x, y, center[i].x, center[i].y); + temp = (u16b)distance(x, y, center[i].x, center[i].y); if (temp < min1) { @@ -4024,7 +3630,7 @@ static void build_room_vault(int x0, int y0, int xsize, int ysize) xhsize = xsize / 2; yhsize = ysize / 2; - if (cheat_room) msg_print("Room Vault"); + msg_print_wizard(CHEAT_DUNGEON, _("部屋型ランダムVaultを生成しました。", "Room Vault.")); /* fill area so don't get problems with arena levels */ for (x1 = 0; x1 < xsize; x1++) @@ -4075,7 +3681,7 @@ static void build_cave_vault(int x0, int y0, int xsiz, int ysiz) xsize = xhsize * 2; ysize = yhsize * 2; - if (cheat_room) msg_print("Cave Vault"); + msg_print_wizard(CHEAT_DUNGEON, _("洞穴ランダムVaultを生成しました。", "Cave Vault.")); light = done = FALSE; room = TRUE; @@ -4223,8 +3829,7 @@ void build_maze_vault(int x0, int y0, int xsize, int ysize, bool is_vault) bool light; cave_type *c_ptr; - - if (cheat_room && is_vault) msg_print("Maze Vault"); + msg_print_wizard(CHEAT_DUNGEON, _("迷路ランダムVaultを生成しました。", "Maze Vault.")); /* Choose lite or dark */ light = ((dun_level <= randint1(25)) && is_vault && !(d_info[dungeon_type].flags1 & DF1_DARKNESS)); @@ -4288,13 +3893,13 @@ void build_maze_vault(int x0, int y0, int xsize, int ysize, bool is_vault) * 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; int *visited; - if (cheat_room) msg_print("Mini Checker Board Vault"); + msg_print_wizard(CHEAT_DUNGEON, _("小型チェッカーランダムVaultを生成しました。", "Mini Checker Board Vault.")); /* Pick a random room size */ dy = ysize / 2 - 1; @@ -4313,7 +3918,7 @@ static void build_mini_c_vault(int x0, int y0, int xsize, int ysize) cave[y1-2][x].info |= (CAVE_ROOM | CAVE_ICKY); - place_extra_noperm_bold(y1-2, x); + place_outer_noperm_bold(y1-2, x); } for (x = x1 - 2; x <= x2 + 2; x++) @@ -4322,7 +3927,7 @@ static void build_mini_c_vault(int x0, int y0, int xsize, int ysize) cave[y2+2][x].info |= (CAVE_ROOM | CAVE_ICKY); - place_extra_noperm_bold(y2+2, x); + place_outer_noperm_bold(y2+2, x); } for (y = y1 - 2; y <= y2 + 2; y++) @@ -4331,7 +3936,7 @@ static void build_mini_c_vault(int x0, int y0, int xsize, int ysize) cave[y][x1-2].info |= (CAVE_ROOM | CAVE_ICKY); - place_extra_noperm_bold(y, x1-2); + place_outer_noperm_bold(y, x1-2); } for (y = y1 - 2; y <= y2 + 2; y++) @@ -4340,17 +3945,19 @@ static void build_mini_c_vault(int x0, int y0, int xsize, int ysize) cave[y][x2+2].info |= (CAVE_ROOM | CAVE_ICKY); - place_extra_noperm_bold(y, x2+2); + place_outer_noperm_bold(y, x2+2); } for (y = y1 - 1; y <= y2 + 1; y++) { for (x = x1 - 1; x <= x2 + 1; x++) { - cave[y][x].info |= (CAVE_ROOM | CAVE_ICKY); + cave_type *c_ptr = &cave[y][x]; + + c_ptr->info |= (CAVE_ROOM | CAVE_ICKY); /* Permanent walls */ - cave[y][x].feat = FEAT_PERM_INNER; + place_inner_perm_grid(c_ptr); } } @@ -4385,15 +3992,15 @@ static void build_mini_c_vault(int x0, int y0, int xsize, int ysize) { /* left and right */ y = randint1(dy) + dy / 2; - place_outer_noperm_bold(y1 + y, x1 - 1); - place_outer_noperm_bold(y1 + y, x2 + 1); + place_inner_bold(y1 + y, x1 - 1); + place_inner_bold(y1 + y, x2 + 1); } else { /* top and bottom */ x = randint1(dx) + dx / 2; - place_outer_noperm_bold(y1 - 1, x1 + x); - place_outer_noperm_bold(y2 + 1, x1 + x); + place_inner_bold(y1 - 1, x1 + x); + place_inner_bold(y2 + 1, x1 + x); } /* Fill with monsters and treasure, highest difficulty */ @@ -4631,7 +4238,7 @@ static void build_castle_vault(int x0, int y0, int xsize, int ysize) y2 = y0 + dy; x2 = x0 + dx; - if (cheat_room) msg_print("Castle Vault"); + msg_print_wizard(CHEAT_DUNGEON, _("城型ランダムVaultを生成しました。", "Castle Vault")); /* generate the room */ for (y = y1 - 1; y <= y2 + 1; y++) @@ -4657,19 +4264,24 @@ static void build_castle_vault(int x0, int y0, int xsize, int ysize) * 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) +static void add_outer_wall(int x, int y, int light, int x1, int y1, int x2, int y2) { + cave_type *c_ptr; + feature_type *f_ptr; int i, j; if (!in_bounds(y, x)) return; + c_ptr = &cave[y][x]; + /* 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; + if (c_ptr->info & CAVE_ROOM) return; /* set room flag */ - cave[y][x].info |= CAVE_ROOM; + c_ptr->info |= CAVE_ROOM; + + f_ptr = &f_info[c_ptr->feat]; if (is_floor_bold(y, x)) { @@ -4681,7 +4293,7 @@ static void add_outer_wall(int x, int y, int light, (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; + if (light) c_ptr->info |= CAVE_GLOW; } } } @@ -4690,12 +4302,12 @@ static void add_outer_wall(int x, int y, int light, { /* Set bounding walls */ place_outer_bold(y, x); - if (light == TRUE) cave[y][x].info |= CAVE_GLOW; + if (light) c_ptr->info |= CAVE_GLOW; } - else if (cave[y][x].feat == FEAT_PERM_OUTER) + else if (permanent_wall(f_ptr)) { /* Set bounding walls */ - if (light == TRUE) cave[y][x].info |= CAVE_GLOW; + if (light) c_ptr->info |= CAVE_GLOW; } } @@ -4743,7 +4355,7 @@ static void build_target_vault(int x0, int y0, int xsize, int ysize) h3 = randint1(32); h4 = randint1(32) - 16; - if (cheat_room) msg_print("Target Vault"); + msg_print_wizard(CHEAT_DUNGEON, _("対称形ランダムVaultを生成しました。", "Elemental Vault")); /* work out outer radius */ if (xsize > ysize) @@ -4864,8 +4476,7 @@ static void build_elemental_vault(int x0, int y0, int xsiz, int ysiz) int xsize, ysize, xhsize, yhsize, x, y, i; int type; - - if (cheat_room) msg_print("Elemental Vault"); + msg_print_wizard(CHEAT_DUNGEON, _("精霊界ランダムVaultを生成しました。", "Elemental Vault")); /* round to make sizes even */ xhsize = xsiz / 2; @@ -4876,22 +4487,22 @@ static void build_elemental_vault(int x0, int y0, int xsiz, int ysiz) if (dun_level < 25) { /* Earth vault (Rubble) */ - type = 4; + type = LAKE_T_EARTH_VAULT; } else if (dun_level < 50) { /* Air vault (Trees) */ - type = 5; + type = LAKE_T_AIR_VAULT; } else if (dun_level < 75) { /* Water vault (shallow water) */ - type = 6; + type = LAKE_T_WATER_VAULT; } else { /* Fire vault (shallow lava) */ - type = 7; + type = LAKE_T_FIRE_VAULT; } while (!done) @@ -4942,36 +4553,37 @@ static void build_elemental_vault(int x0, int y0, int xsiz, int ysiz) #endif /* ALLOW_CAVERNS_AND_LAKES */ -/* - * Random vaults +/*! + * @brief タイプ10の部屋…ランダム生成vault / Type 10 -- Random vaults + * @return なし */ -static void build_type10(int by0, int bx0) +static bool build_type10(void) { - int y0, x0, xsize, ysize, vtype; + POSITION y0, x0, xsize, ysize, vtype; /* Get size */ /* big enough to look good, small enough to be fairly common. */ xsize = randint1(22) + 22; ysize = randint1(11) + 11; - /* Allocate in room_map. If will not fit, exit */ - if (!room_alloc(xsize + 1, ysize + 1, 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) || - (randint1((dun_level - 40) * (dun_level - 40) + 1) < 400)) - { - good_item_flag = TRUE; - } + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, ysize + 1, xsize + 1)) return FALSE; /* Select type of vault */ #ifdef ALLOW_CAVERNS_AND_LAKES - vtype = randint1(15); + do + { + vtype = randint1(15); + } + while ((d_info[dungeon_type].flags1 & DF1_NO_CAVE) && + ((vtype == 1) || (vtype == 3) || (vtype == 8) || (vtype == 9) || (vtype == 11))); #else /* ALLOW_CAVERNS_AND_LAKES */ - vtype = randint1(7); + do + { + vtype = randint1(7); + } + while ((d_info[dungeon_type].flags1 & DF1_NO_CAVE) && + ((vtype == 1) || (vtype == 3))); #endif /* ALLOW_CAVERNS_AND_LAKES */ switch (vtype) @@ -4990,21 +4602,25 @@ static void build_type10(int by0, int bx0) /* I know how to add a few more... give me some time. */ /* Paranoia */ - default: return; + default: return FALSE; } + + return TRUE; } -/* - * Build an vertical oval room. - * For every grid in the possible square, check the distance. - * If it's less than the radius, make it a room square. - * - * When done fill from the inside to find the walls, +/*! + * @brief タイプ11の部屋…円形部屋の生成 / Type 11 -- Build an vertical oval room. + * @return なし + * @details + * For every grid in the possible square, check the distance.\n + * If it's less than the radius, make it a room square.\n + *\n + * When done fill from the inside to find the walls,\n */ -static void build_type11(int by0, int bx0) +static bool build_type11(void) { - int rad, x, y, x0, y0; + POSITION rad, x, y, x0, y0; int light = FALSE; /* Occasional light */ @@ -5012,8 +4628,8 @@ static void build_type11(int by0, int bx0) rad = randint0(9); - /* Allocate in room_map. If will not fit, exit */ - if (!room_alloc(rad * 2 + 1, rad * 2 + 1, FALSE, by0, bx0, &x0, &y0)) return; + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, rad * 2 + 1, rad * 2 + 1)) return FALSE; /* Make circular floor */ for (x = x0 - rad; x <= x0 + rad; x++) @@ -5035,19 +4651,23 @@ static void build_type11(int by0, int bx0) /* Find visible outer walls and set to be FEAT_OUTER */ add_outer_wall(x0, y0, light, x0 - rad, y0 - rad, x0 + rad, y0 + rad); + + return TRUE; } -/* - * 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, +/*! + * @brief タイプ12の部屋…ドーム型部屋の生成 / Type 12 -- Build crypt room. + * @return なし + * @details + * For every grid in the possible square, check the (fake) distance.\n + * If it's less than the radius, make it a room square.\n + *\n + * When done fill from the inside to find the walls,\n */ -static void build_type12(int by0, int bx0) - { - int rad, x, y, x0, y0; +static bool build_type12(void) +{ + POSITION rad, x, y, x0, y0; int light = FALSE; bool emptyflag = TRUE; @@ -5063,8 +4683,8 @@ static void build_type12(int by0, int bx0) rad = randint1(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; + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&y0, &x0, rad * 2 + 3, rad * 2 + 3)) return FALSE; /* Make floor */ for (x = x0 - rad; x <= x0 + rad; x++) @@ -5115,462 +4735,1252 @@ static void build_type12(int by0, int bx0) } } - if (emptyflag && one_in_(2)) + if (emptyflag && one_in_(2)) + { + /* Build the vault */ + build_small_room(x0, y0); + + /* Place a treasure in the vault */ + place_object(y0, x0, 0L); + + /* Let's guard the treasure well */ + vault_monsters(y0, x0, randint0(2) + 3); + + /* Traps naturally */ + vault_traps(y0, x0, 4, 4, randint0(3) + 2); + } + + return TRUE; +} + + +/* + * Helper function for "trapped monster pit" + */ +static bool vault_aux_trapped_pit(MONRACE_IDX r_idx) +{ + monster_race *r_ptr = &r_info[r_idx]; + + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return (FALSE); + + /* No wall passing monster */ + if (r_ptr->flags2 & (RF2_PASS_WALL | RF2_KILL_WALL)) return (FALSE); + + /* Okay */ + return (TRUE); +} + + +/*! + * @brief タイプ13の部屋…トラップpitの生成 / Type 13 -- Trapped monster pits + * @return なし + * @details + * A trapped monster pit is a "big" room with a straight corridor in\n + * which wall opening traps are placed, and with two "inner" rooms\n + * containing a "collection" of monsters of a given type organized in\n + * the room.\n + *\n + * The trapped monster pit appears as shown below, where the actual\n + * monsters in each location depend on the type of the pit\n + *\n + * XXXXXXXXXXXXXXXXXXXXXXXXX\n + * X X\n + * XXXXXXXXXXXXXXXXXXXXXXX X\n + * XXXXX001123454321100XXX X\n + * XXX0012234567654322100X X\n + * XXXXXXXXXXXXXXXXXXXXXXX X\n + * X ^ X\n + * X XXXXXXXXXXXXXXXXXXXXXXX\n + * X X0012234567654322100XXX\n + * X XXX001123454321100XXXXX\n + * X XXXXXXXXXXXXXXXXXXXXXXX\n + * X X\n + * XXXXXXXXXXXXXXXXXXXXXXXXX\n + *\n + * Note that the monsters in the pit are now chosen by using "get_mon_num()"\n + * to request 16 "appropriate" monsters, sorting them by level, and using\n + * the "even" entries in this sorted list for the contents of the pit.\n + *\n + * Hack -- all of the "dragons" in a "dragon" pit must be the same "color",\n + * which is handled by requiring a specific "breath" attack for all of the\n + * dragons. This may include "multi-hued" breath. Note that "wyrms" may\n + * be present in many of the dragon pits, if they have the proper breath.\n + *\n + * Note the use of the "get_mon_num_prep()" function, and the special\n + * "get_mon_num_hook()" restriction function, to prepare the "monster\n + * allocation table" in such a way as to optimize the selection of\n + * "appropriate" non-unique monsters for the pit.\n + *\n + * Note that the "get_mon_num()" function may (rarely) fail, in which case\n + * the pit will be empty.\n + *\n + * Note that "monster pits" will never contain "unique" monsters.\n + */ +static bool build_type13(void) +{ + static int placing[][3] = { + {-2, -9, 0}, {-2, -8, 0}, {-3, -7, 0}, {-3, -6, 0}, + {+2, -9, 0}, {+2, -8, 0}, {+3, -7, 0}, {+3, -6, 0}, + {-2, +9, 0}, {-2, +8, 0}, {-3, +7, 0}, {-3, +6, 0}, + {+2, +9, 0}, {+2, +8, 0}, {+3, +7, 0}, {+3, +6, 0}, + {-2, -7, 1}, {-3, -5, 1}, {-3, -4, 1}, + {+2, -7, 1}, {+3, -5, 1}, {+3, -4, 1}, + {-2, +7, 1}, {-3, +5, 1}, {-3, +4, 1}, + {+2, +7, 1}, {+3, +5, 1}, {+3, +4, 1}, + {-2, -6, 2}, {-2, -5, 2}, {-3, -3, 2}, + {+2, -6, 2}, {+2, -5, 2}, {+3, -3, 2}, + {-2, +6, 2}, {-2, +5, 2}, {-3, +3, 2}, + {+2, +6, 2}, {+2, +5, 2}, {+3, +3, 2}, + {-2, -4, 3}, {-3, -2, 3}, + {+2, -4, 3}, {+3, -2, 3}, + {-2, +4, 3}, {-3, +2, 3}, + {+2, +4, 3}, {+3, +2, 3}, + {-2, -3, 4}, {-3, -1, 4}, + {+2, -3, 4}, {+3, -1, 4}, + {-2, +3, 4}, {-3, +1, 4}, + {+2, +3, 4}, {+3, +1, 4}, + {-2, -2, 5}, {-3, 0, 5}, {-2, +2, 5}, + {+2, -2, 5}, {+3, 0, 5}, {+2, +2, 5}, + {-2, -1, 6}, {-2, +1, 6}, + {+2, -1, 6}, {+2, +1, 6}, + {-2, 0, 7}, {+2, 0, 7}, + {0, 0, -1} + }; + + POSITION y, x, y1, x1, y2, x2, xval, yval; + int i, j; + + MONRACE_IDX what[16]; + + monster_type align; + + cave_type *c_ptr; + + int cur_pit_type = pick_vault_type(pit_types, d_info[dungeon_type].pit); + vault_aux_type *n_ptr; + + /* Only in Angband */ + if (dungeon_type != DUNGEON_ANGBAND) return FALSE; + + /* No type available */ + if (cur_pit_type < 0) return FALSE; + + n_ptr = &pit_types[cur_pit_type]; + + /* Process a preparation function if necessary */ + if (n_ptr->prep_func) (*(n_ptr->prep_func))(); + + /* Prepare allocation table */ + get_mon_num_prep(n_ptr->hook_func, vault_aux_trapped_pit); + + align.sub_align = SUB_ALIGN_NEUTRAL; + + /* Pick some monster types */ + for (i = 0; i < 16; i++) + { + MONRACE_IDX r_idx = 0; + int attempts = 100; + monster_race *r_ptr = NULL; + + while (attempts--) + { + /* Get a (hard) monster type */ + r_idx = get_mon_num(dun_level + 0); + r_ptr = &r_info[r_idx]; + + /* Decline incorrect alignment */ + if (monster_has_hostile_align(&align, 0, 0, r_ptr)) continue; + + /* Accept this monster */ + break; + } + + /* Notice failure */ + if (!r_idx || !attempts) return FALSE; + + /* Note the alignment */ + if (r_ptr->flags3 & RF3_EVIL) align.sub_align |= SUB_ALIGN_EVIL; + if (r_ptr->flags3 & RF3_GOOD) align.sub_align |= SUB_ALIGN_GOOD; + + what[i] = r_idx; + } + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, 13, 25)) return FALSE; + + /* Large room */ + y1 = yval - 5; + y2 = yval + 5; + x1 = xval - 11; + x2 = xval + 11; + + /* Fill with inner walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_inner_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + } + } + + /* Place the floor area 1 */ + for (x = x1 + 3; x <= x2 - 3; x++) + { + c_ptr = &cave[yval-2][x]; + place_floor_grid(c_ptr); + add_cave_info(yval-2, x, CAVE_ICKY); + + c_ptr = &cave[yval+2][x]; + place_floor_grid(c_ptr); + add_cave_info(yval+2, x, CAVE_ICKY); + } + + /* Place the floor area 2 */ + for (x = x1 + 5; x <= x2 - 5; x++) + { + c_ptr = &cave[yval-3][x]; + place_floor_grid(c_ptr); + add_cave_info(yval-3, x, CAVE_ICKY); + + c_ptr = &cave[yval+3][x]; + place_floor_grid(c_ptr); + add_cave_info(yval+3, x, CAVE_ICKY); + } + + /* Corridor */ + for (x = x1; x <= x2; x++) + { + c_ptr = &cave[yval][x]; + place_floor_grid(c_ptr); + c_ptr = &cave[y1][x]; + place_floor_grid(c_ptr); + c_ptr = &cave[y2][x]; + place_floor_grid(c_ptr); + } + + /* Place the outer walls */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + } + + /* Random corridor */ + if (one_in_(2)) + { + for (y = y1; y <= yval; y++) + { + place_floor_bold(y, x2); + place_solid_bold(y, x1-1); + } + for (y = yval; y <= y2 + 1; y++) + { + place_floor_bold(y, x1); + place_solid_bold(y, x2+1); + } + } + else + { + for (y = yval; y <= y2 + 1; y++) + { + place_floor_bold(y, x1); + place_solid_bold(y, x2+1); + } + for (y = y1; y <= yval; y++) + { + place_floor_bold(y, x2); + place_solid_bold(y, x1-1); + } + } + + /* Place the wall open trap */ + cave[yval][xval].mimic = cave[yval][xval].feat; + cave[yval][xval].feat = feat_trap_open; + + /* 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) + { + MONRACE_IDX tmp = what[i1]; + what[i1] = what[i2]; + what[i2] = tmp; + } + } + } + + msg_format_wizard(CHEAT_DUNGEON, _("%s%sの罠ピットが生成されました。", "Trapped monster pit (%s%s)"), + n_ptr->name, pit_subtype_string(cur_pit_type, FALSE)); + + /* Select the entries */ + for (i = 0; i < 8; i++) + { + /* Every other entry */ + what[i] = what[i * 2]; + + if (cheat_hear) + { + /* Message */ + msg_print(r_name + r_info[what[i]].name); + } + } + + for (i = 0; placing[i][2] >= 0; i++) + { + y = yval + placing[i][0]; + x = xval + placing[i][1]; + place_monster_aux(0, y, x, what[placing[i][2]], PM_NO_KAGE); + } + + return TRUE; +} + + +/*! + * @brief タイプ14の部屋…特殊トラップ部屋の生成 / Type 14 -- trapped rooms + * @return なし + * @details + * A special trap is placed at center of the room + */ +static bool build_type14(void) +{ + POSITION y, x, y2, x2, yval, xval; + POSITION y1, x1, xsize, ysize; + + bool light; + + cave_type *c_ptr; + s16b trap; + + /* Pick a room size */ + y1 = randint1(4); + x1 = randint1(11); + y2 = randint1(3); + x2 = randint1(11); + + xsize = x1 + x2 + 1; + ysize = y1 + y2 + 1; + + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) return FALSE; + + /* Choose lite or dark */ + light = ((dun_level <= randint1(25)) && !(d_info[dungeon_type].flags1 & DF1_DARKNESS)); + + + /* Get corner values */ + y1 = yval - ysize / 2; + x1 = xval - xsize / 2; + y2 = yval + (ysize - 1) / 2; + x2 = xval + (xsize - 1) / 2; + + + /* Place a full floor under the room */ + for (y = y1 - 1; y <= y2 + 1; y++) + { + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } + + /* Walls around the room */ + for (y = y1 - 1; y <= y2 + 1; y++) { - /* Build the vault */ - build_small_room(x0, y0); + c_ptr = &cave[y][x1 - 1]; + place_outer_grid(c_ptr); + c_ptr = &cave[y][x2 + 1]; + place_outer_grid(c_ptr); + } + for (x = x1 - 1; x <= x2 + 1; x++) + { + c_ptr = &cave[y1 - 1][x]; + place_outer_grid(c_ptr); + c_ptr = &cave[y2 + 1][x]; + place_outer_grid(c_ptr); + } - /* Place a treasure in the vault */ - place_object(y0, x0, FALSE, FALSE); + if (dun_level < 30 + randint1(30)) + trap = feat_trap_piranha; + else + trap = feat_trap_armageddon; - /* Let's guard the treasure well */ - vault_monsters(y0, x0, randint0(2) + 3); + /* Place a special trap */ + c_ptr = &cave[rand_spread(yval, ysize/4)][rand_spread(xval, xsize/4)]; + c_ptr->mimic = c_ptr->feat; + c_ptr->feat = trap; - /* Traps naturally */ - vault_traps(y0, x0, 4, 4, randint0(3) + 2); - } + msg_format_wizard(CHEAT_DUNGEON, _("%sの部屋が生成されました。", "Room of %s was generated."), f_name + f_info[trap].name); + + return TRUE; } /* - * Helper function for "trapped monster pit" + * Helper function for "glass room" */ -static bool vault_aux_trapped_pit(int r_idx) +static bool vault_aux_lite(MONRACE_IDX r_idx) { monster_race *r_ptr = &r_info[r_idx]; /* Validate the monster */ - if (!vault_monster_okay(r_idx)) return (FALSE); + if (!vault_monster_okay(r_idx)) return FALSE; - /* No wall passing monster */ - if (r_ptr->flags2 & (RF2_PASS_WALL | RF2_KILL_WALL)) return (FALSE); + /* Require lite attack */ + if (!(r_ptr->flags4 & RF4_BR_LITE) && !(r_ptr->a_ability_flags1 & RF5_BA_LITE)) return FALSE; - /* Okay */ - return (TRUE); -} + /* No wall passing monsters */ + if (r_ptr->flags2 & (RF2_PASS_WALL | RF2_KILL_WALL)) return FALSE; + + /* No disintegrating monsters */ + if (r_ptr->flags4 & RF4_BR_DISI) return FALSE; + return TRUE; +} /* - * Type 12 -- Trapped monster pits - * - * A trapped monster pit is a "big" room with a straight corridor in - * which wall opening traps are placed, and with two "inner" rooms - * containing a "collection" of monsters of a given type organized in - * the room. - * - * The trapped monster pit appears as shown below, where the actual - * monsters in each location depend on the type of the pit - * - * ######################### - * # # - * ####################### # - * #####001123454321100### # - * ###0012234567654322100# # - * ####################### # - * # ^ # - * # ####################### - * # #0012234567654322100### - * # ###001123454321100##### - * # ####################### - * # # - * ######################### - * - * 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. + * Helper function for "glass room" */ -static void build_type13(int by0, int bx0) +static bool vault_aux_shards(MONRACE_IDX r_idx) { - static int placing[][3] = { - {-2, -9, 0}, {-2, -8, 0}, {-3, -7, 0}, {-3, -6, 0}, - {+2, -9, 0}, {+2, -8, 0}, {+3, -7, 0}, {+3, -6, 0}, - {-2, +9, 0}, {-2, +8, 0}, {-3, +7, 0}, {-3, +6, 0}, - {+2, +9, 0}, {+2, +8, 0}, {+3, +7, 0}, {+3, +6, 0}, - {-2, -7, 1}, {-3, -5, 1}, {-3, -4, 1}, - {+2, -7, 1}, {+3, -5, 1}, {+3, -4, 1}, - {-2, +7, 1}, {-3, +5, 1}, {-3, +4, 1}, - {+2, +7, 1}, {+3, +5, 1}, {+3, +4, 1}, - {-2, -6, 2}, {-2, -5, 2}, {-3, -3, 2}, - {+2, -6, 2}, {+2, -5, 2}, {+3, -3, 2}, - {-2, +6, 2}, {-2, +5, 2}, {-3, +3, 2}, - {+2, +6, 2}, {+2, +5, 2}, {+3, +3, 2}, - {-2, -4, 3}, {-3, -2, 3}, - {+2, -4, 3}, {+3, -2, 3}, - {-2, +4, 3}, {-3, +2, 3}, - {+2, +4, 3}, {+3, +2, 3}, - {-2, -3, 4}, {-3, -1, 4}, - {+2, -3, 4}, {+3, -1, 4}, - {-2, +3, 4}, {-3, +1, 4}, - {+2, +3, 4}, {+3, +1, 4}, - {-2, -2, 5}, {-3, 0, 5}, {-2, +2, 5}, - {+2, -2, 5}, {+3, 0, 5}, {+2, +2, 5}, - {-2, -1, 6}, {-2, +1, 6}, - {+2, -1, 6}, {+2, +1, 6}, - {-2, 0, 7}, {+2, 0, 7}, - {0, 0, -1} - }; + monster_race *r_ptr = &r_info[r_idx]; - int y, x, y1, x1, y2, x2, xval, yval; - int i, j; + /* Validate the monster */ + if (!vault_monster_okay(r_idx)) return FALSE; - int what[16]; + /* Require shards breath attack */ + if (!(r_ptr->flags4 & RF4_BR_SHAR)) return FALSE; - int align = 0; + return TRUE; +} - cave_type *c_ptr; +/* + * Hack -- determine if a template is potion + */ +static bool kind_is_potion(KIND_OBJECT_IDX k_idx) +{ + return k_info[k_idx].tval == TV_POTION; +} - vault_aux_type *n_ptr = pick_vault_type(pit_types, ROOM_PIT); +/*! + * @brief タイプ15の部屋…ガラス部屋の生成 / Type 15 -- glass rooms + * @return なし + */ +static bool build_type15(void) +{ + POSITION y, x, y2, x2, yval, xval; + POSITION y1, x1, xsize, ysize; + bool light; - /* Only in Angband */ - if (dungeon_type != 1) return; + cave_type *c_ptr; - /* Try to allocate space for room. */ - if (!room_alloc(25, 13, TRUE, by0, bx0, &xval, &yval)) return; + /* Pick a room size */ + xsize = rand_range(9, 13); + ysize = rand_range(9, 13); - /* No type available */ - if (!n_ptr) return; + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, ysize + 2, xsize + 2)) return FALSE; - /* Process a preparation function if necessary */ - if (n_ptr->prep_func) (*(n_ptr->prep_func))(); + /* Choose lite or dark */ + light = ((dun_level <= randint1(25)) && !(d_info[dungeon_type].flags1 & DF1_DARKNESS)); - /* Large room */ - y1 = yval - 5; - y2 = yval + 5; - x1 = xval - 11; - x2 = xval + 11; + /* Get corner values */ + y1 = yval - ysize / 2; + x1 = xval - xsize / 2; + y2 = yval + (ysize - 1) / 2; + x2 = xval + (xsize - 1) / 2; - /* Fill with inner walls */ + /* Place a full floor under the room */ for (y = y1 - 1; y <= y2 + 1; y++) { for (x = x1 - 1; x <= x2 + 1; x++) { c_ptr = &cave[y][x]; - place_inner_grid(c_ptr); + place_floor_grid(c_ptr); + c_ptr->feat = feat_glass_floor; c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); } } - /* Place the floor area 1 */ - for (x = x1 + 3; x <= x2 - 3; x++) - { - c_ptr = &cave[yval-2][x]; - place_floor_grid(c_ptr); - add_cave_info(yval-2, x, CAVE_ICKY); - - c_ptr = &cave[yval+2][x]; - place_floor_grid(c_ptr); - add_cave_info(yval+2, x, CAVE_ICKY); - } - - /* Place the floor area 2 */ - for (x = x1 + 5; x <= x2 - 5; x++) - { - c_ptr = &cave[yval-3][x]; - place_floor_grid(c_ptr); - add_cave_info(yval-3, x, CAVE_ICKY); - - c_ptr = &cave[yval+3][x]; - place_floor_grid(c_ptr); - add_cave_info(yval+3, x, CAVE_ICKY); - } - - /* Corridor */ - for (x = x1; x <= x2; x++) - { - c_ptr = &cave[yval][x]; - place_floor_grid(c_ptr); - c_ptr = &cave[y1][x]; - place_floor_grid(c_ptr); - c_ptr = &cave[y2][x]; - place_floor_grid(c_ptr); - } - - /* Place the outer walls */ + /* Walls around the room */ for (y = y1 - 1; y <= y2 + 1; y++) { c_ptr = &cave[y][x1 - 1]; place_outer_grid(c_ptr); + c_ptr->feat = feat_glass_wall; c_ptr = &cave[y][x2 + 1]; place_outer_grid(c_ptr); + c_ptr->feat = feat_glass_wall; } for (x = x1 - 1; x <= x2 + 1; x++) { c_ptr = &cave[y1 - 1][x]; place_outer_grid(c_ptr); + c_ptr->feat = feat_glass_wall; c_ptr = &cave[y2 + 1][x]; place_outer_grid(c_ptr); + c_ptr->feat = feat_glass_wall; } - /* Random corridor */ - if (one_in_(2)) + switch (randint1(3)) { - for (y = y1; y <= yval; y++) + case 1: /* 4 lite breathers + potion */ { - place_floor_bold(y, x2); - place_solid_bold(y, x1-1); + int dir1, dir2; + + /* Prepare allocation table */ + get_mon_num_prep(vault_aux_lite, NULL); + + /* Place fixed lite berathers */ + for (dir1 = 4; dir1 < 8; dir1++) + { + MONRACE_IDX r_idx = get_mon_num(dun_level); + + y = yval + 2 * ddy_ddd[dir1]; + x = xval + 2 * ddx_ddd[dir1]; + if (r_idx) place_monster_aux(0, y, x, r_idx, PM_ALLOW_SLEEP); + + /* Walls around the breather */ + for (dir2 = 0; dir2 < 8; dir2++) + { + c_ptr = &cave[y + ddy_ddd[dir2]][x + ddx_ddd[dir2]]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + } + + /* Walls around the potion */ + for (dir1 = 0; dir1 < 4; dir1++) + { + y = yval + 2 * ddy_ddd[dir1]; + x = xval + 2 * ddx_ddd[dir1]; + c_ptr = &cave[y][x]; + place_inner_perm_grid(c_ptr); + c_ptr->feat = feat_permanent_glass_wall; + cave[yval + ddy_ddd[dir1]][xval + ddx_ddd[dir1]].info |= (CAVE_ICKY); + } + + /* Glass door */ + dir1 = randint0(4); + y = yval + 2 * ddy_ddd[dir1]; + x = xval + 2 * ddx_ddd[dir1]; + place_secret_door(y, x, DOOR_GLASS_DOOR); + c_ptr = &cave[y][x]; + if (is_closed_door(c_ptr->feat)) c_ptr->mimic = feat_glass_wall; + + /* Place a potion */ + get_obj_num_hook = kind_is_potion; + place_object(yval, xval, AM_NO_FIXED_ART); + cave[yval][xval].info |= (CAVE_ICKY); } - for (y = yval; y <= y2 + 1; y++) + break; + + case 2: /* 1 lite breather + random object */ { - place_floor_bold(y, x1); - place_solid_bold(y, x2+1); + MONRACE_IDX r_idx; + DIRECTION dir1; + + /* Pillars */ + c_ptr = &cave[y1 + 1][x1 + 1]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + + c_ptr = &cave[y1 + 1][x2 - 1]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + + c_ptr = &cave[y2 - 1][x1 + 1]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + + c_ptr = &cave[y2 - 1][x2 - 1]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + + /* Prepare allocation table */ + get_mon_num_prep(vault_aux_lite, NULL); + + r_idx = get_mon_num(dun_level); + if (r_idx) place_monster_aux(0, yval, xval, r_idx, 0L); + + /* Walls around the breather */ + for (dir1 = 0; dir1 < 8; dir1++) + { + c_ptr = &cave[yval + ddy_ddd[dir1]][xval + ddx_ddd[dir1]]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + + /* Curtains around the breather */ + for (y = yval - 1; y <= yval + 1; y++) + { + place_closed_door(y, xval - 2, DOOR_CURTAIN); + place_closed_door(y, xval + 2, DOOR_CURTAIN); + } + for (x = xval - 1; x <= xval + 1; x++) + { + place_closed_door(yval - 2, x, DOOR_CURTAIN); + place_closed_door(yval + 2, x, DOOR_CURTAIN); + } + + /* Place an object */ + place_object(yval, xval, AM_NO_FIXED_ART); + cave[yval][xval].info |= (CAVE_ICKY); + } + break; + + case 3: /* 4 shards breathers + 2 potions */ + { + int dir1; + + /* Walls around the potion */ + for (y = yval - 2; y <= yval + 2; y++) + { + c_ptr = &cave[y][xval - 3]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + c_ptr = &cave[y][xval + 3]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + for (x = xval - 2; x <= xval + 2; x++) + { + c_ptr = &cave[yval - 3][x]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + c_ptr = &cave[yval + 3][x]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + for (dir1 = 4; dir1 < 8; dir1++) + { + c_ptr = &cave[yval + 2 * ddy_ddd[dir1]][xval + 2 * ddx_ddd[dir1]]; + place_inner_grid(c_ptr); + c_ptr->feat = feat_glass_wall; + } + + /* Prepare allocation table */ + get_mon_num_prep(vault_aux_shards, NULL); + + /* Place shard berathers */ + for (dir1 = 4; dir1 < 8; dir1++) + { + MONRACE_IDX r_idx = get_mon_num(dun_level); + + y = yval + ddy_ddd[dir1]; + x = xval + ddx_ddd[dir1]; + if (r_idx) place_monster_aux(0, y, x, r_idx, 0L); + } + + /* Place two potions */ + if (one_in_(2)) + { + get_obj_num_hook = kind_is_potion; + place_object(yval, xval - 1, AM_NO_FIXED_ART); + get_obj_num_hook = kind_is_potion; + place_object(yval, xval + 1, AM_NO_FIXED_ART); + } + else + { + get_obj_num_hook = kind_is_potion; + place_object(yval - 1, xval, AM_NO_FIXED_ART); + get_obj_num_hook = kind_is_potion; + place_object(yval + 1, xval, AM_NO_FIXED_ART); + } + + for (y = yval - 2; y <= yval + 2; y++) + for (x = xval - 2; x <= xval + 2; x++) + cave[y][x].info |= (CAVE_ICKY); + } + break; } - else + + msg_print_wizard(CHEAT_DUNGEON, _("ガラスの部屋が生成されました。", "Glass room was generated.")); + + return TRUE; +} + + +/* Create a new floor room with optional light */ +void generate_room_floor(int y1, int x1, int y2, int x2, int light) +{ + int y, x; + + cave_type *c_ptr; + + for (y = y1; y <= y2; y++) + { + for (x = x1; x <= x2; x++) + { + /* Point to grid */ + c_ptr = &cave[y][x]; + place_floor_grid(c_ptr); + c_ptr->info |= (CAVE_ROOM); + if (light) c_ptr->info |= (CAVE_GLOW); + } + } +} + +void generate_fill_perm_bold(int y1, int x1, int y2, int x2) +{ + int y, x; + + for (y = y1; y <= y2; y++) { - for (y = yval; y <= y2 + 1; y++) - { - place_floor_bold(y, x1); - place_solid_bold(y, x2+1); - } - for (y = y1; y <= yval; y++) + for (x = x1; x <= x2; x++) { - place_floor_bold(y, x2); - place_solid_bold(y, x1-1); + /* Point to grid */ + place_inner_perm_bold(y, x); } } +} - /* Place the wall open trap */ - cave[yval][xval].mimic = cave[yval][xval].feat; - cave[yval][xval].feat = FEAT_TRAP_OPEN; +/* Minimum & maximum town size */ +#define MIN_TOWN_WID ((MAX_WID / 3) / 2) +#define MIN_TOWN_HGT ((MAX_HGT / 3) / 2) +#define MAX_TOWN_WID ((MAX_WID / 3) * 2 / 3) +#define MAX_TOWN_HGT ((MAX_HGT / 3) * 2 / 3) - /* Prepare allocation table */ - get_mon_num_prep(n_ptr->hook_func, vault_aux_trapped_pit); +/* Struct for build underground buildings */ +typedef struct +{ + int y0, x0; /* North-west corner (relative) */ + int y1, x1; /* South-east corner (relative) */ +} +ugbldg_type; - /* Pick some monster types */ - for (i = 0; i < 16; i++) +ugbldg_type *ugbldg; + +/* + * Precalculate buildings' location of underground arcade + */ +static bool precalc_ugarcade(int town_hgt, int town_wid, int n) +{ + int i, y, x, center_y, center_x, tmp, attempt = 10000; + int max_bldg_hgt = 3 * town_hgt / MAX_TOWN_HGT; + int max_bldg_wid = 5 * town_wid / MAX_TOWN_WID; + ugbldg_type *cur_ugbldg; + bool **ugarcade_used, abort; + + /* Allocate "ugarcade_used" array (2-dimension) */ + C_MAKE(ugarcade_used, town_hgt, bool *); + C_MAKE(*ugarcade_used, town_hgt * town_wid, bool); + for (y = 1; y < town_hgt; y++) ugarcade_used[y] = *ugarcade_used + y * town_wid; + + /* Calculate building locations */ + for (i = 0; i < n; i++) { - int r_idx = 0, attempts = 100; + cur_ugbldg = &ugbldg[i]; + (void)WIPE(cur_ugbldg, ugbldg_type); - while (attempts--) + do { - /* Get a (hard) monster type */ - r_idx = get_mon_num(dun_level + 0); - - /* Decline incorrect alignment */ - if (((align < 0) && (r_info[r_idx].flags3 & RF3_GOOD)) || - ((align > 0) && (r_info[r_idx].flags3 & RF3_EVIL))) + /* Find the "center" of the store */ + center_y = rand_range(2, town_hgt - 3); + center_x = rand_range(2, town_wid - 3); + + /* Determine the store boundaries */ + tmp = center_y - randint1(max_bldg_hgt); + cur_ugbldg->y0 = MAX(tmp, 1); + tmp = center_x - randint1(max_bldg_wid); + cur_ugbldg->x0 = MAX(tmp, 1); + tmp = center_y + randint1(max_bldg_hgt); + cur_ugbldg->y1 = MIN(tmp, town_hgt - 2); + tmp = center_x + randint1(max_bldg_wid); + cur_ugbldg->x1 = MIN(tmp, town_wid - 2); + + /* Scan this building's area */ + for (abort = FALSE, y = cur_ugbldg->y0; (y <= cur_ugbldg->y1) && !abort; y++) { - continue; + for (x = cur_ugbldg->x0; x <= cur_ugbldg->x1; x++) + { + if (ugarcade_used[y][x]) + { + abort = TRUE; + break; + } + } } - /* Accept this monster */ - break; + attempt--; } + while (abort && attempt); /* Accept this building if no overlapping */ - /* Notice failure */ - if (!r_idx || !attempts) return; + /* Failed to generate underground arcade */ + if (!attempt) break; - /* Note the alignment */ - if (r_info[r_idx].flags3 & RF3_GOOD) align++; - else if (r_info[r_idx].flags3 & RF3_EVIL) align--; + /* + * Mark to ugarcade_used[][] as "used" + * Note: Building-adjacent grids are included for preventing + * connected bulidings. + */ + for (y = cur_ugbldg->y0 - 1; y <= cur_ugbldg->y1 + 1; y++) + { + for (x = cur_ugbldg->x0 - 1; x <= cur_ugbldg->x1 + 1; x++) + { + ugarcade_used[y][x] = TRUE; + } + } + } - what[i] = r_idx; + /* Free "ugarcade_used" array (2-dimension) */ + C_KILL(*ugarcade_used, town_hgt * town_wid, bool); + C_KILL(ugarcade_used, town_hgt, bool *); + + /* If i < n, generation is not allowed */ + return i == n; +} + +/*! + * @brief タイプ16の部屋…地下都市生成のサブルーチン / Actually create buildings + * @return なし + * @param ltcy 生成基準Y座標 + * @param ltcx 生成基準X座標 + * @param stotes[] 生成する店舗のリスト + * @param n 生成する店舗の数 + * @note + * Note: ltcy and ltcx indicate "left top corner". + */ +static void build_stores(int ltcy, int ltcx, int stores[], int n) +{ + int i, y, x; + IDX j; + ugbldg_type *cur_ugbldg; + + for (i = 0; i < n; i++) + { + cur_ugbldg = &ugbldg[i]; + + /* Generate new room */ + generate_room_floor( + ltcy + cur_ugbldg->y0 - 2, ltcx + cur_ugbldg->x0 - 2, + ltcy + cur_ugbldg->y1 + 2, ltcx + cur_ugbldg->x1 + 2, + FALSE); } - /* Sort the entries */ - for (i = 0; i < 16 - 1; i++) + for (i = 0; i < n; i++) { - /* Sort the entries */ - for (j = 0; j < 16 - 1; j++) + cur_ugbldg = &ugbldg[i]; + + /* Build an invulnerable rectangular building */ + generate_fill_perm_bold( + ltcy + cur_ugbldg->y0, ltcx + cur_ugbldg->x0, + ltcy + cur_ugbldg->y1, ltcx + cur_ugbldg->x1); + + /* Pick a door direction (S,N,E,W) */ + switch (randint0(4)) { - int i1 = j; - int i2 = j + 1; + /* Bottom side */ + case 0: + y = cur_ugbldg->y1; + x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1); + break; - int p1 = r_info[what[i1]].level; - int p2 = r_info[what[i2]].level; + /* Top side */ + case 1: + y = cur_ugbldg->y0; + x = rand_range(cur_ugbldg->x0, cur_ugbldg->x1); + break; - /* Bubble */ - if (p1 > p2) + /* Right side */ + case 2: + y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1); + x = cur_ugbldg->x1; + break; + + /* Left side */ + default: + y = rand_range(cur_ugbldg->y0, cur_ugbldg->y1); + x = cur_ugbldg->x0; + break; + } + + for (j = 0; j < max_f_idx; j++) + { + if (have_flag(f_info[j].flags, FF_STORE)) { - int tmp = what[i1]; - what[i1] = what[i2]; - what[i2] = tmp; + if (f_info[j].subtype == stores[i]) break; } } - } - /* Message */ - if (cheat_room) - { -#ifdef JP - msg_format("%s¤Î櫥ԥåÈ", n_ptr->name); -#else - /* Room type */ - msg_format("Trapped monster pit (%s)", n_ptr->name); -#endif + /* Clear previous contents, add a store door */ + if (j < max_f_idx) + { + cave_set_feat(ltcy + y, ltcx + x, j); + + /* Init store */ + store_init(NO_TOWN, stores[i]); + } } +} - /* Select the entries */ - for (i = 0; i < 8; i++) + +/*! + * @brief タイプ16の部屋…地下都市の生成 / Type 16 -- Underground Arcade + * @return なし + * @details + * Town logic flow for generation of new town\n + * Originally from Vanilla 3.0.3\n + *\n + * We start with a fully wiped cave of normal floors.\n + *\n + * Note that town_gen_hack() plays games with the R.N.G.\n + *\n + * This function does NOT do anything about the owners of the stores,\n + * nor the contents thereof. It only handles the physical layout.\n + */ +static bool build_type16(void) +{ + int stores[] = { - /* Every other entry */ - what[i] = what[i * 2]; + STORE_GENERAL, STORE_ARMOURY, STORE_WEAPON, STORE_TEMPLE, + STORE_ALCHEMIST, STORE_MAGIC, STORE_BLACK, STORE_BOOK, + }; + int n = sizeof stores / sizeof (int); + POSITION i, y, x, y1, x1, yval, xval; + int town_hgt = rand_range(MIN_TOWN_HGT, MAX_TOWN_HGT); + int town_wid = rand_range(MIN_TOWN_WID, MAX_TOWN_WID); + bool prevent_bm = FALSE; - if (cheat_hear) + /* Hack -- If already exist black market, prevent building */ + for (y = 0; (y < cur_hgt) && !prevent_bm; y++) + { + for (x = 0; x < cur_wid; x++) { - /* Message */ - msg_print(r_name + r_info[what[i]].name); + if (cave[y][x].feat == FF_STORE) + { + prevent_bm = (f_info[cave[y][x].feat].subtype == STORE_BLACK); + break; + } } } + for (i = 0; i < n; i++) + { + if ((stores[i] == STORE_BLACK) && prevent_bm) stores[i] = stores[--n]; + } + if (!n) return FALSE; - /* Increase the level rating */ - rating += 20; + /* Allocate buildings array */ + C_MAKE(ugbldg, n, ugbldg_type); - /* (Sometimes) Cause a "special feeling" (for "Monster Pits") */ - if ((dun_level <= 40) && (randint1(dun_level * dun_level + 50) < 300)) + /* If cannot build stores, abort */ + if (!precalc_ugarcade(town_hgt, town_wid, n)) { - good_item_flag = TRUE; + /* Free buildings array */ + C_KILL(ugbldg, n, ugbldg_type); + return FALSE; } - - for (i = 0; placing[i][2] >= 0; i++) + /* Find and reserve some space in the dungeon. Get center of room. */ + if (!find_space(&yval, &xval, town_hgt + 4, town_wid + 4)) { - y = yval + placing[i][0]; - x = xval + placing[i][1]; - place_monster_aux(0, y, x, what[placing[i][2]], PM_NO_KAGE); + /* Free buildings array */ + C_KILL(ugbldg, n, ugbldg_type); + return FALSE; } -} + /* Get top left corner */ + y1 = yval - (town_hgt / 2); + x1 = xval - (town_wid / 2); -/* - * Type 14 -- trapped rooms - * - * A special trap is placed at center of the room - */ -static void build_type14(int by0, int bx0) -{ - int y, x, y2, x2, yval, xval; - int y1, x1, xsize, ysize; + /* Generate new room */ + generate_room_floor( + y1 + town_hgt / 3, x1 + town_wid / 3, + y1 + town_hgt * 2 / 3, x1 + town_wid * 2 / 3, FALSE); - bool light; + /* Build stores */ + build_stores(y1, x1, stores, n); - cave_type *c_ptr; - byte trap; + msg_print_wizard(CHEAT_DUNGEON, _("地下街を生成しました", "Underground arcade was generated.")); - /* Pick a room size */ - y1 = randint1(4); - x1 = randint1(11); - y2 = randint1(3); - x2 = randint1(11); + /* Free buildings array */ + C_KILL(ugbldg, n, ugbldg_type); - xsize = x1 + x2 + 1; - ysize = y1 + y2 + 1; + return TRUE; +} - /* Try to allocate space for room. If fails, exit */ - if (!room_alloc(xsize + 2, ysize + 2, FALSE, by0, bx0, &xval, &yval)) return; - /* Choose lite or dark */ - light = ((dun_level <= randint1(25)) && !(d_info[dungeon_type].flags1 & DF1_DARKNESS)); +/*! + * @brief 与えられた部屋型IDに応じて部屋の生成処理分岐を行い結果を返す / Attempt to build a room of the given type at the given block + * @param type 部屋型ID + * @note that we restrict the number of "crowded" rooms to reduce the chance of overflowing the monster list during level creation. + * @return 部屋の精製に成功した場合 TRUE を返す。 + */ +static bool room_build(int typ) +{ + /* Build a room */ + switch (typ) + { + /* Build an appropriate room */ + case ROOM_T_NORMAL: return build_type1(); + case ROOM_T_OVERLAP: return build_type2(); + case ROOM_T_CROSS: return build_type3(); + case ROOM_T_INNER_FEAT: return build_type4(); + case ROOM_T_NEST: return build_type5(); + case ROOM_T_PIT: return build_type6(); + case ROOM_T_LESSER_VAULT: return build_type7(); + case ROOM_T_GREATER_VAULT: return build_type8(); + case ROOM_T_FRACAVE: return build_type9(); + case ROOM_T_RANDOM_VAULT: return build_type10(); + case ROOM_T_OVAL: return build_type11(); + case ROOM_T_CRYPT: return build_type12(); + case ROOM_T_TRAP_PIT: return build_type13(); + case ROOM_T_TRAP: return build_type14(); + case ROOM_T_GLASS: return build_type15(); + case ROOM_T_ARCADE: return build_type16(); + } + + /* Paranoia */ + return FALSE; +} +/*! + * @brief 指定した部屋の生成確率を別の部屋に加算し、指定した部屋の生成率を0にする + * @param dst 確率を移す先の部屋種ID + * @param src 確率を与える元の部屋種ID + */ +#define MOVE_PLIST(dst, src) (prob_list[dst] += prob_list[src], prob_list[src] = 0) - /* Get corner values */ - y1 = yval - ysize / 2; - x1 = xval - xsize / 2; - y2 = yval + (ysize - 1) / 2; - x2 = xval + (xsize - 1) / 2; +/*! + * @brief 部屋生成処理のメインルーチン(Sangbandを経由してOangbandからの実装を引用) / Generate rooms in dungeon. Build bigger rooms at first. [from SAngband (originally from OAngband)] + * @return 部屋生成に成功した場合 TRUE を返す。 + */ +bool generate_rooms(void) +{ + int i; + bool remain; + int crowded = 0; + int total_prob; + int prob_list[ROOM_T_MAX]; + int rooms_built = 0; + int area_size = 100 * (cur_hgt*cur_wid) / (MAX_HGT*MAX_WID); + int level_index = MIN(10, div_round(dun_level, 10)); + /* Number of each type of room on this level */ + s16b room_num[ROOM_T_MAX]; - /* Place a full floor under the room */ - for (y = y1 - 1; y <= y2 + 1; y++) + /* Limit number of rooms */ + int dun_rooms = DUN_ROOMS_MAX * area_size / 100; + + /* Assume normal cave */ + room_info_type *room_info_ptr = room_info_normal; + + /* + * Initialize probability list. + */ + for (i = 0; i < ROOM_T_MAX; i++) { - for (x = x1 - 1; x <= x2 + 1; x++) + /* No rooms allowed above their minimum depth. */ + if (dun_level < room_info_ptr[i].min_level) { - c_ptr = &cave[y][x]; - place_floor_grid(c_ptr); - c_ptr->info |= (CAVE_ROOM); - if (light) c_ptr->info |= (CAVE_GLOW); + prob_list[i] = 0; + } + else + { + prob_list[i] = room_info_ptr[i].prob[level_index]; } } - /* Walls around the room */ - for (y = y1 - 1; y <= y2 + 1; y++) + /* + * XXX -- Various dungeon types and options. + */ + + /*! @details ダンジョンにBEGINNER、CHAMELEON、SMALLESTいずれのフラグもなく、かつ「常に通常でない部屋を生成する」フラグがONならば、GRATER_VAULTのみを生成対象とする。 / Ironman sees only Greater Vaults */ + if (ironman_rooms && !((d_info[dungeon_type].flags1 & (DF1_BEGINNER | DF1_CHAMELEON | DF1_SMALLEST)))) { - c_ptr = &cave[y][x1 - 1]; - place_outer_grid(c_ptr); - c_ptr = &cave[y][x2 + 1]; - place_outer_grid(c_ptr); + for (i = 0; i < ROOM_T_MAX; i++) + { + if (i == ROOM_T_GREATER_VAULT) prob_list[i] = 1; + else prob_list[i] = 0; + } } - for (x = x1 - 1; x <= x2 + 1; x++) + + /*! @details ダンジョンにNO_VAULTフラグがあるならば、LESSER_VAULT / GREATER_VAULT/ RANDOM_VAULTを除外 / Forbidden vaults */ + else if (d_info[dungeon_type].flags1 & DF1_NO_VAULT) { - c_ptr = &cave[y1 - 1][x]; - place_outer_grid(c_ptr); - c_ptr = &cave[y2 + 1][x]; - place_outer_grid(c_ptr); + prob_list[ROOM_T_LESSER_VAULT] = 0; + prob_list[ROOM_T_GREATER_VAULT] = 0; + prob_list[ROOM_T_RANDOM_VAULT] = 0; } - if (dun_level < 30 + randint1(30)) - trap = FEAT_TRAP_PIRANHA; - else - trap = FEAT_TRAP_ARMAGEDDON; + /*! @details ダンジョンにNO_CAVEフラグがある場合、FRACAVEの生成枠がNORMALに与えられる。CRIPT、OVALの生成枠がINNER_Fに与えられる。/ NO_CAVE dungeon (Castle)*/ + if (d_info[dungeon_type].flags1 & DF1_NO_CAVE) + { + MOVE_PLIST(ROOM_T_NORMAL, ROOM_T_FRACAVE); + MOVE_PLIST(ROOM_T_INNER_FEAT, ROOM_T_CRYPT); + MOVE_PLIST(ROOM_T_INNER_FEAT, ROOM_T_OVAL); + } - /* Place a special trap */ - c_ptr = &cave[rand_spread(yval, ysize/4)][rand_spread(xval, xsize/4)]; - c_ptr->mimic = c_ptr->feat; - c_ptr->feat = trap; + /*! @details ダンジョンにCAVEフラグがある場合、NORMALの生成枠がFRACAVEに与えられる。/ CAVE dungeon (Orc cave etc.) */ + else if (d_info[dungeon_type].flags1 & DF1_CAVE) + { + MOVE_PLIST(ROOM_T_FRACAVE, ROOM_T_NORMAL); + } - /* Message */ - if (cheat_room) + /*! @details ダンジョンの基本地形が最初から渓谷かアリーナ型の場合 FRACAVE は生成から除外。 / No caves when a (random) cavern exists: they look bad */ + else if (dun->cavern || dun->empty_level) { -#ifdef JP - msg_format("%s¤ÎÉô²°", f_name + f_info[trap].name); -#else - msg_format("Room of %s", f_name + f_info[trap].name); -#endif + prob_list[ROOM_T_FRACAVE] = 0; } -} + /*! @details ダンジョンに最初からGLASS_ROOMフラグがある場合、GLASS を生成から除外。/ Forbidden glass rooms */ + if (!(d_info[dungeon_type].flags1 & DF1_GLASS_ROOM)) + { + prob_list[ROOM_T_GLASS] = 0; + } -/* - * 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. - */ -bool room_build(int by0, int bx0, int typ) -{ - /* Restrict level */ - if ((dun_level < roomdep[typ]) && !ironman_rooms) return (FALSE); + /*! @details ARCADEは同フラグがダンジョンにないと生成されない。 / Forbidden glass rooms */ + if (!(d_info[dungeon_type].flags1 & DF1_ARCADE)) + { + prob_list[ROOM_T_ARCADE] = 0; + } - /* Restrict "crowded" rooms */ - if ((dun->crowded >= 2) && ((typ == 5) || (typ == 6) || (typ == 13))) return (FALSE); + /* + * Initialize number of rooms, + * And calcurate total probability. + */ + for (total_prob = 0, i = 0; i < ROOM_T_MAX; i++) + { + room_num[i] = 0; + total_prob += prob_list[i]; + } - /* Build a room */ - switch (typ) + /* + * Prepare the number of rooms, of all types, we should build + * on this level. + */ + for (i = dun_rooms; i > 0; i--) { - /* Build an appropriate room */ - case 14: build_type14(by0, bx0); break; - case 13: build_type13(by0, bx0); break; - case 12: build_type12(by0, bx0); break; - case 11: build_type11(by0, bx0); break; - case 10: build_type10(by0, bx0); break; - case 9: build_type9(by0, bx0); break; - case 8: build_type8(by0, bx0); break; - case 7: build_type7(by0, bx0); break; - case 6: build_type6(by0, bx0, FALSE); break; - case 5: build_type5(by0, bx0, FALSE); break; - case 4: build_type4(by0, bx0); break; - case 3: build_type3(by0, bx0); break; - case 2: build_type2(by0, bx0); break; - case 1: build_type1(by0, bx0); break; + int room_type; + int rand = randint0(total_prob); + + /* Get room_type randomly */ + for (room_type = 0; room_type < ROOM_T_MAX; room_type++) + { + if (rand < prob_list[room_type]) break; + else rand -= prob_list[room_type]; + } /* Paranoia */ - default: return (FALSE); + if (room_type >= ROOM_T_MAX) room_type = ROOM_T_NORMAL; + + /* Increase the number of rooms of that type we should build. */ + room_num[room_type]++; + + switch (room_type) + { + case ROOM_T_NEST: + case ROOM_T_PIT: + case ROOM_T_LESSER_VAULT: + case ROOM_T_TRAP_PIT: + case ROOM_T_GLASS: + case ROOM_T_ARCADE: + + /* Large room */ + i -= 2; + break; + + case ROOM_T_GREATER_VAULT: + case ROOM_T_RANDOM_VAULT: + + /* Largest room */ + i -= 3; + break; + } } - return (TRUE); + /* + * Build each type of room one by one until we cannot build any more. + * [from SAngband (originally from OAngband)] + */ + while (TRUE) + { + /* Assume no remaining rooms */ + remain = FALSE; + + for (i = 0; i < ROOM_T_MAX; i++) + { + /* What type of room are we building now? */ + int room_type = room_build_order[i]; + + /* Go next if none available */ + if (!room_num[room_type]) continue; + + /* Use up one unit */ + room_num[room_type]--; + + /* Build the room. */ + if (room_build(room_type)) + { + /* Increase the room built count. */ + rooms_built++; + + /* Mark as there was some remaining rooms */ + remain = TRUE; + + switch (room_type) + { + case ROOM_T_PIT: + case ROOM_T_NEST: + case ROOM_T_TRAP_PIT: + + /* Avoid too many monsters */ + if (++crowded >= 2) + { + room_num[ROOM_T_PIT] = 0; + room_num[ROOM_T_NEST] = 0; + room_num[ROOM_T_TRAP_PIT] = 0; + } + break; + + case ROOM_T_ARCADE: + + /* Avoid double-town */ + room_num[ROOM_T_ARCADE] = 0; + break; + } + } + } + + /* End loop if no room remain */ + if (!remain) break; + } + + /*! @details 部屋生成数が2未満の場合生成失敗を返す */ + if (rooms_built < 2) + { + msg_format_wizard(CHEAT_DUNGEON, _("部屋数が2未満でした。生成を再試行します。", "Number of rooms was under 2. Retry."), rooms_built); + return FALSE; + } + + msg_format_wizard(CHEAT_DUNGEON, _("このダンジョンの部屋数は %d です。", "Number of Rooms: %d"), rooms_built); + + return TRUE; }