1 #include "floor/floor.h"
2 #include "core/player-redraw-types.h"
3 #include "core/player-update-types.h"
4 #include "core/window-redrawer.h"
5 #include "dungeon/dungeon-flag-types.h"
6 #include "dungeon/dungeon.h"
7 #include "dungeon/quest.h"
8 #include "effect/effect-characteristics.h"
9 #include "effect/spells-effect-util.h"
10 #include "floor/cave.h"
11 #include "floor/floor-generate.h"
12 #include "floor/floor-object.h"
13 #include "game-option/birth-options.h"
14 #include "game-option/cheat-options.h"
15 #include "game-option/map-screen-options.h"
16 #include "grid/grid.h"
17 #include "grid/trap.h"
18 #include "io/targeting.h"
19 #include "mind/mind-ninja.h"
20 #include "monster-floor/monster-generator.h"
21 #include "monster-floor/monster-remover.h"
22 #include "monster/monster-update.h"
23 #include "monster-floor/place-monster-types.h"
24 #include "object-enchant/special-object-flags.h"
25 #include "object-hook/hook-checker.h"
26 #include "object-hook/hook-enchant.h"
27 #include "object/object-generator.h"
28 #include "object/object-kind.h"
29 #include "perception/object-perception.h"
30 #include "player/special-defense-types.h"
31 #include "room/rooms.h"
32 #include "system/artifact-type-definition.h"
33 #include "system/floor-type-definition.h"
34 #include "util/bit-flags-calculator.h"
35 #include "view/display-messages.h"
36 #include "world/world-object.h"
37 #include "world/world.h"
40 * The array of floor [MAX_WID][MAX_HGT].
41 * Not completely allocated, that would be inefficient
42 * Not completely hardcoded, that would overflow memory
44 floor_type floor_info;
47 * Grid based version of "cave_empty_bold()"
49 bool is_cave_empty_grid(player_type *player_ptr, grid_type *g_ptr)
51 bool is_empty_grid = cave_have_flag_grid(g_ptr, FF_PLACE);
52 is_empty_grid &= g_ptr->m_idx == 0;
53 is_empty_grid &= !player_grid(player_ptr, g_ptr);
58 bool pattern_tile(floor_type *floor_ptr, POSITION y, POSITION x)
60 return cave_have_flag_bold(floor_ptr, y, x, FF_PATTERN);
65 * Determine if a "legal" grid is an "empty" floor grid
66 * Determine if monsters are allowed to move into a grid
68 * Line 1 -- forbid non-placement grids
69 * Line 2 -- forbid normal monsters
70 * Line 3 -- forbid the player
72 bool is_cave_empty_bold(player_type *player_ptr, POSITION y, POSITION x)
74 floor_type *floor_ptr = player_ptr->current_floor_ptr;
75 bool is_empty_grid = cave_have_flag_bold(floor_ptr, y, x, FF_PLACE);
76 is_empty_grid &= !(floor_ptr->grid_array[y][x].m_idx);
77 is_empty_grid &= !player_bold(player_ptr, y, x);
83 * Determine if a "legal" grid is an "empty" floor grid
84 * Determine if monster generation is allowed in a grid
86 * Line 1 -- forbid non-empty grids
87 * Line 2 -- forbid trees while dungeon generation
89 bool is_cave_empty_bold2(player_type *player_ptr, POSITION y, POSITION x)
91 bool is_empty_grid = is_cave_empty_bold(player_ptr, y, x);
92 is_empty_grid &= current_world_ptr->character_dungeon || !cave_have_flag_bold(player_ptr->current_floor_ptr, y, x, FF_TREE);
98 * @brief 鍵のかかったドアを配置する
99 * @param player_ptr プレーヤーへの参照ポインタ
100 * @param y 配置したいフロアのY座標
101 * @param x 配置したいフロアのX座標
104 void place_locked_door(player_type *player_ptr, POSITION y, POSITION x)
106 floor_type *floor_ptr = player_ptr->current_floor_ptr;
107 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
109 place_bold(player_ptr, y, x, GB_FLOOR);
113 set_cave_feat(floor_ptr, y, x, feat_locked_door_random((d_info[player_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR));
114 floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
115 delete_monster(player_ptr, y, x);
121 * @param player_ptr プレーヤーへの参照ポインタ
122 * @param y 配置したいフロアのY座標
123 * @param x 配置したいフロアのX座標
124 * @param type DOOR_DEFAULT / DOOR_DOOR / DOOR_GLASS_DOOR / DOOR_CURTAIN のいずれか
127 void place_secret_door(player_type *player_ptr, POSITION y, POSITION x, int type)
129 floor_type *floor_ptr = player_ptr->current_floor_ptr;
130 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
132 place_bold(player_ptr, y, x, GB_FLOOR);
136 if (type == DOOR_DEFAULT)
138 type = ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_CURTAIN) &&
139 one_in_((d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN :
140 ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
143 place_closed_door(player_ptr, y, x, type);
144 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
145 if (type != DOOR_CURTAIN)
147 g_ptr->mimic = feat_wall_inner;
148 if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat))
150 if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY))
152 g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
159 g_ptr->info &= ~(CAVE_FLOOR);
160 delete_monster(player_ptr, y, x);
163 static int scent_when = 0;
166 * Characters leave scent trails for perceptive monsters to track.
168 * Smell is rather more limited than sound. Many creatures cannot use
169 * it at all, it doesn't extend very far outwards from the character's
170 * current position, and monsters can use it to home in the character,
171 * but not to run away from him.
173 * Smell is valued according to age. When a character takes his turn,
174 * scent is aged by one, and new scent of the current age is laid down.
175 * Speedy characters leave more scent, true, but it also ages faster,
176 * which makes it harder to hunt them down.
178 * Whenever the age count loops, most of the scent trail is erased and
179 * the age of the remainder is recalculated.
181 void update_smell(floor_type *floor_ptr, player_type *subject_ptr)
183 /* Create a table that controls the spread of scent */
184 const int scent_adjust[5][5] =
193 if (++scent_when == 254)
195 for (POSITION y = 0; y < floor_ptr->height; y++)
197 for (POSITION x = 0; x < floor_ptr->width; x++)
199 int w = floor_ptr->grid_array[y][x].when;
200 floor_ptr->grid_array[y][x].when = (w > 128) ? (w - 128) : 0;
207 for (POSITION i = 0; i < 5; i++)
209 for (POSITION j = 0; j < 5; j++)
212 POSITION y = i + subject_ptr->y - 2;
213 POSITION x = j + subject_ptr->x - 2;
214 if (!in_bounds(floor_ptr, y, x)) continue;
216 g_ptr = &floor_ptr->grid_array[y][x];
217 if (!cave_have_flag_grid(g_ptr, FF_MOVE) && !is_closed_door(subject_ptr, g_ptr->feat)) continue;
218 if (!player_has_los_bold(subject_ptr, y, x)) continue;
219 if (scent_adjust[i][j] == -1) continue;
221 g_ptr->when = scent_when + scent_adjust[i][j];
228 * Hack -- forget the "flow" information
230 void forget_flow(floor_type *floor_ptr)
232 for (POSITION y = 0; y < floor_ptr->height; y++)
234 for (POSITION x = 0; x < floor_ptr->width; x++)
236 floor_ptr->grid_array[y][x].dist = 0;
237 floor_ptr->grid_array[y][x].cost = 0;
238 floor_ptr->grid_array[y][x].when = 0;
245 * Routine used by the random vault creators to add a door to a location
246 * Note that range checking has to be done in the calling routine.
248 * The doors must be INSIDE the allocated region.
250 void add_door(player_type *player_ptr, POSITION x, POSITION y)
252 floor_type *floor_ptr = player_ptr->current_floor_ptr;
253 if (!is_outer_bold(floor_ptr, y, x)) return;
264 if (is_floor_bold(floor_ptr, y - 1, x) && is_floor_bold(floor_ptr, y + 1, x) &&
265 (is_outer_bold(floor_ptr, y, x - 1) && is_outer_bold(floor_ptr, y, x + 1)))
267 place_secret_door(player_ptr, y, x, DOOR_DEFAULT);
268 place_bold(player_ptr, y, x - 1, GB_SOLID);
269 place_bold(player_ptr, y, x + 1, GB_SOLID);
277 * where x = don't care
280 if (is_outer_bold(floor_ptr, y - 1, x) && is_outer_bold(floor_ptr, y + 1, x) &&
281 is_floor_bold(floor_ptr, y, x - 1) && is_floor_bold(floor_ptr, y, x + 1))
283 place_secret_door(player_ptr, y, x, DOOR_DEFAULT);
284 place_bold(player_ptr, y - 1, x, GB_SOLID);
285 place_bold(player_ptr, y + 1, x, GB_SOLID);
291 * @brief 所定の位置に上り階段か下り階段を配置する / Place an up/down staircase at given location
292 * @param player_ptr プレーヤーへの参照ポインタ
293 * @param y 配置を試みたいマスのY座標
294 * @param x 配置を試みたいマスのX座標
297 void place_random_stairs(player_type *player_ptr, POSITION y, POSITION x)
299 bool up_stairs = TRUE;
300 bool down_stairs = TRUE;
302 floor_type *floor_ptr = player_ptr->current_floor_ptr;
303 g_ptr = &floor_ptr->grid_array[y][x];
304 if (!is_floor_grid(g_ptr) || g_ptr->o_idx) return;
306 if (!floor_ptr->dun_level) up_stairs = FALSE;
307 if (ironman_downward) up_stairs = FALSE;
308 if (floor_ptr->dun_level >= d_info[player_ptr->dungeon_idx].maxdepth) down_stairs = FALSE;
309 if (quest_number(player_ptr, floor_ptr->dun_level) && (floor_ptr->dun_level > 1)) down_stairs = FALSE;
311 if (down_stairs && up_stairs)
313 if (randint0(100) < 50) up_stairs = FALSE;
314 else down_stairs = FALSE;
317 if (up_stairs) set_cave_feat(floor_ptr, y, x, feat_up_stair);
318 else if (down_stairs) set_cave_feat(floor_ptr, y, x, feat_down_stair);
323 * @brief LOS(Line Of Sight / 視線が通っているか)の判定を行う。
324 * @param player_ptr プレーヤーへの参照ポインタ
329 * @return LOSが通っているならTRUEを返す。
331 * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall,\n
332 * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu.\n
334 * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).\n
336 * The LOS begins at the center of the tile (x1,y1) and ends at the center of\n
337 * the tile (x2,y2). If los() is to return TRUE, all of the tiles this line\n
338 * passes through must be floor tiles, except for (x1,y1) and (x2,y2).\n
340 * We assume that the "mathematical corner" of a non-floor tile does not\n
341 * block line of sight.\n
343 * Because this function uses (short) ints for all calculations, overflow may\n
344 * occur if dx and dy exceed 90.\n
346 * Once all the degenerate cases are eliminated, the values "qx", "qy", and\n
347 * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that\n
348 * we can use integer arithmetic.\n
350 * We travel from start to finish along the longer axis, starting at the border\n
351 * between the first and second tiles, where the y offset = .5 * slope, taking\n
352 * into account the scale factor. See below.\n
354 * Also note that this function and the "move towards target" code do NOT\n
355 * share the same properties. Thus, you can see someone, target them, and\n
356 * then fire a bolt at them, but the bolt may hit a wall, not them. However\n,
357 * by clever choice of target locations, you can sometimes throw a "curve".\n
359 * Note that "line of sight" is not "reflexive" in all cases.\n
361 * Use the "projectable()" routine to test "spell/missile line of sight".\n
363 * Use the "update_view()" function to determine player line-of-sight.\n
365 bool los(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
367 POSITION dy = y2 - y1;
368 POSITION dx = x2 - x1;
369 POSITION ay = ABS(dy);
370 POSITION ax = ABS(dx);
371 if ((ax < 2) && (ay < 2)) return TRUE;
373 /* Directly South/North */
374 floor_type *floor_ptr = player_ptr->current_floor_ptr;
378 /* South -- check for walls */
381 for (ty = y1 + 1; ty < y2; ty++)
383 if (!cave_los_bold(floor_ptr, ty, x1)) return FALSE;
387 /* North -- check for walls */
390 for (ty = y1 - 1; ty > y2; ty--)
392 if (!cave_los_bold(floor_ptr, ty, x1)) return FALSE;
400 /* Directly East/West */
403 /* East -- check for walls */
406 for (tx = x1 + 1; tx < x2; tx++)
408 if (!cave_los_bold(floor_ptr, y1, tx)) return FALSE;
412 /* West -- check for walls */
415 for (tx = x1 - 1; tx > x2; tx--)
417 if (!cave_los_bold(floor_ptr, y1, tx)) return FALSE;
424 POSITION sx = (dx < 0) ? -1 : 1;
425 POSITION sy = (dy < 0) ? -1 : 1;
431 if (cave_los_bold(floor_ptr, y1 + sy, x1)) return TRUE;
438 if (cave_los_bold(floor_ptr, y1, x1 + sx)) return TRUE;
442 POSITION f2 = (ax * ay);
443 POSITION f1 = f2 << 1;
461 /* Note (below) the case (qy == f2), where */
462 /* the LOS exactly meets the corner of a tile. */
465 if (!cave_los_bold(floor_ptr, ty, tx)) return FALSE;
478 if (!cave_los_bold(floor_ptr, ty, tx)) return FALSE;
492 /* Travel vertically */
493 POSITION qx = ax * ax;
506 /* Note (below) the case (qx == f2), where */
507 /* the LOS exactly meets the corner of a tile. */
510 if (!cave_los_bold(floor_ptr, ty, tx)) return FALSE;
523 if (!cave_los_bold(floor_ptr, ty, tx)) return FALSE;
539 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
540 * at the final destination, assuming no monster gets in the way.
542 * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
544 bool projectable(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
547 int grid_n = project_path(player_ptr, grid_g, (project_length ? project_length : get_max_range(player_ptr)), y1, x1, y2, x2, 0);
548 if (!grid_n) return TRUE;
550 POSITION y = GRID_Y(grid_g[grid_n - 1]);
551 POSITION x = GRID_X(grid_g[grid_n - 1]);
552 if ((y != y2) || (x != x2)) return FALSE;
559 * @brief 特殊な部屋地形向けにモンスターを配置する / Hack -- Place some sleeping monsters near the given location
560 * @param player_ptr プレーヤーへの参照ポインタ
561 * @param y1 モンスターを配置したいマスの中心Y座標
562 * @param x1 モンスターを配置したいマスの中心X座標
563 * @param num 配置したいモンスターの数
566 * Only really called by some of the "vault" routines.
568 void vault_monsters(player_type *player_ptr, POSITION y1, POSITION x1, int num)
570 floor_type *floor_ptr = player_ptr->current_floor_ptr;
571 for (int k = 0; k < num; k++)
573 for (int i = 0; i < 9; i++)
577 scatter(player_ptr, &y, &x, y1, x1, d, 0);
579 g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
580 if (!is_cave_empty_grid(player_ptr, g_ptr)) continue;
582 floor_ptr->monster_level = floor_ptr->base_level + 2;
583 (void)place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
584 floor_ptr->monster_level = floor_ptr->base_level;
591 * @brief 指定された座標が地震や階段生成の対象となるマスかを返す。 / Determine if a given location may be "destroyed"
592 * @param player_ptr プレーヤーへの参照ポインタ
595 * @return 各種の変更が可能ならTRUEを返す。
597 * 条件は永久地形でなく、なおかつ該当のマスにアーティファクトが存在しないか、である。英語の旧コメントに反して*破壊*の抑止判定には現在使われていない。
599 bool cave_valid_bold(floor_type *floor_ptr, POSITION y, POSITION x)
601 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
602 if (cave_perma_grid(g_ptr)) return FALSE;
604 OBJECT_IDX next_o_idx = 0;
605 for (OBJECT_IDX this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
608 o_ptr = &floor_ptr->o_list[this_o_idx];
609 next_o_idx = o_ptr->next_o_idx;
610 if (object_is_artifact(o_ptr)) return FALSE;
618 * Change the "feat" flag for a grid, and notice/redraw the grid
620 void cave_set_feat(player_type *player_ptr, POSITION y, POSITION x, FEAT_IDX feat)
622 floor_type *floor_ptr = player_ptr->current_floor_ptr;
623 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
624 feature_type *f_ptr = &f_info[feat];
625 if (!current_world_ptr->character_dungeon)
629 if (have_flag(f_ptr->flags, FF_GLOW) && !(d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
631 for (DIRECTION i = 0; i < 9; i++)
633 POSITION yy = y + ddy_ddd[i];
634 POSITION xx = x + ddx_ddd[i];
635 if (!in_bounds2(floor_ptr, yy, xx)) continue;
636 floor_ptr->grid_array[yy][xx].info |= CAVE_GLOW;
643 bool old_los = cave_have_flag_bold(floor_ptr, y, x, FF_LOS);
644 bool old_mirror = is_mirror_grid(g_ptr);
648 g_ptr->info &= ~(CAVE_OBJECT);
649 if (old_mirror && (d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
651 g_ptr->info &= ~(CAVE_GLOW);
652 if (!view_torch_grids) g_ptr->info &= ~(CAVE_MARK);
654 update_local_illumination(player_ptr, y, x);
657 if (!have_flag(f_ptr->flags, FF_REMEMBER)) g_ptr->info &= ~(CAVE_MARK);
658 if (g_ptr->m_idx) update_monster(player_ptr, g_ptr->m_idx, FALSE);
660 note_spot(player_ptr, y, x);
661 lite_spot(player_ptr, y, x);
662 if (old_los ^ have_flag(f_ptr->flags, FF_LOS))
665 #ifdef COMPLEX_WALL_ILLUMINATION /* COMPLEX_WALL_ILLUMINATION */
667 update_local_illumination(player_ptr, y, x);
669 #endif /* COMPLEX_WALL_ILLUMINATION */
671 player_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE | PU_MONSTERS);
674 if (!have_flag(f_ptr->flags, FF_GLOW) || (d_info[player_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
677 for (DIRECTION i = 0; i < 9; i++)
679 POSITION yy = y + ddy_ddd[i];
680 POSITION xx = x + ddx_ddd[i];
681 if (!in_bounds2(floor_ptr, yy, xx)) continue;
684 cc_ptr = &floor_ptr->grid_array[yy][xx];
685 cc_ptr->info |= CAVE_GLOW;
687 if (player_has_los_grid(cc_ptr))
689 if (cc_ptr->m_idx) update_monster(player_ptr, cc_ptr->m_idx, FALSE);
690 note_spot(player_ptr, yy, xx);
691 lite_spot(player_ptr, yy, xx);
694 update_local_illumination(player_ptr, yy, xx);
697 if (player_ptr->special_defense & NINJA_S_STEALTH)
699 if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) set_superstealth(player_ptr, FALSE);
705 * @brief 所定の位置にさまざまな状態や種類のドアを配置する / Place a random type of door at the given location
706 * @param player_ptr プレーヤーへの参照ポインタ
707 * @param y ドアの配置を試みたいマスのY座標
708 * @param x ドアの配置を試みたいマスのX座標
709 * @param room 部屋に接している場合向けのドア生成か否か
712 void place_random_door(player_type *player_ptr, POSITION y, POSITION x, bool room)
714 floor_type *floor_ptr = player_ptr->current_floor_ptr;
715 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
718 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
720 place_bold(player_ptr, y, x, GB_FLOOR);
724 int type = ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_CURTAIN) &&
725 one_in_((d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN :
726 ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
728 int tmp = randint0(1000);
729 FEAT_IDX feat = feat_none;
732 feat = feat_door[type].open;
736 feat = feat_door[type].broken;
740 place_closed_door(player_ptr, y, x, type);
742 if (type != DOOR_CURTAIN)
744 g_ptr->mimic = room ? feat_wall_outer : feat_wall_type[randint0(100)];
745 if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat))
747 if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY))
749 g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
757 place_closed_door(player_ptr, y, x, type);
762 delete_monster(player_ptr, y, x);
766 if (feat != feat_none)
768 set_cave_feat(floor_ptr, y, x, feat);
772 place_bold(player_ptr, y, x, GB_FLOOR);
775 delete_monster(player_ptr, y, x);
780 * @brief グローバルオブジェクト配列を初期化する /
781 * Delete all the items when player leaves the level
782 * @note we do NOT visually reflect these (irrelevant) changes
784 * Hack -- we clear the "g_ptr->o_idx" field for every grid,
785 * and the "m_ptr->next_o_idx" field for every monster, since
786 * we know we are clearing every object. Technically, we only
787 * clear those fields for grids/monsters containing objects,
788 * and we clear it once for every such object.
791 void wipe_o_list(floor_type *floor_ptr)
793 for (int i = 1; i < floor_ptr->o_max; i++)
795 object_type *o_ptr = &floor_ptr->o_list[i];
796 if (!object_is_valid(o_ptr)) continue;
798 if (!current_world_ptr->character_dungeon || preserve_mode)
800 if (object_is_fixed_artifact(o_ptr) && !object_is_known(o_ptr))
802 a_info[o_ptr->name1].cur_num = 0;
806 if (object_is_held_monster(o_ptr))
809 m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
810 m_ptr->hold_o_idx = 0;
816 POSITION y = o_ptr->iy;
817 POSITION x = o_ptr->ix;
819 g_ptr = &floor_ptr->grid_array[y][x];
824 floor_ptr->o_max = 1;
825 floor_ptr->o_cnt = 0;
830 * @brief 所定の位置に各種の閉じたドアを配置する / Place a random type of normal door at the given location.
831 * @param player_ptr プレーヤーへの参照ポインタ
832 * @param y ドアの配置を試みたいマスのY座標
833 * @param x ドアの配置を試みたいマスのX座標
834 * @param type ドアの地形ID
837 void place_closed_door(player_type *player_ptr, POSITION y, POSITION x, int type)
839 floor_type *floor_ptr = player_ptr->current_floor_ptr;
840 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
842 place_bold(player_ptr, y, x, GB_FLOOR);
846 int tmp = randint0(400);
847 FEAT_IDX feat = feat_none;
850 /* Create closed door */
851 feat = feat_door[type].closed;
855 feat = feat_locked_door_random(type);
859 feat = feat_jammed_door_random(type);
862 if (feat == feat_none)
864 place_bold(player_ptr, y, x, GB_FLOOR);
868 cave_set_feat(player_ptr, y, x, feat);
869 floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
874 * @brief 特殊な部屋向けに各種アイテムを配置する(vault_trapのサブセット) / Place a trap with a given displacement of point
875 * @param y トラップを配置したいマスの中心Y座標
876 * @param x トラップを配置したいマスの中心X座標
877 * @param yd Y方向の配置分散マス数
878 * @param xd X方向の配置分散マス数
881 * Only really called by some of the "vault" routines.
883 void vault_trap_aux(player_type *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd)
886 floor_type *floor_ptr = player_ptr->current_floor_ptr;
889 for (int count = 0; count <= 5; count++)
891 while (dummy < SAFE_MAX_ATTEMPTS)
893 y1 = rand_spread(y, yd);
894 x1 = rand_spread(x, xd);
896 if (!in_bounds(floor_ptr, y1, x1)) continue;
900 if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room)
902 msg_print(_("警告!地下室のトラップを配置できません!", "Warning! Could not place vault trap!"));
905 g_ptr = &floor_ptr->grid_array[y1][x1];
906 if (!is_floor_grid(g_ptr) || g_ptr->o_idx || g_ptr->m_idx) continue;
908 place_trap(player_ptr, y1, x1);
915 * @brief 指定のマスが床系地形であるかを返す / Function that sees if a square is a floor. (Includes range checking.)
916 * @param x チェックするマスのX座標
917 * @param y チェックするマスのY座標
918 * @return 床系地形ならばTRUE
920 bool get_is_floor(floor_type *floor_ptr, POSITION x, POSITION y)
922 if (!in_bounds(floor_ptr, y, x))
927 if (is_floor_bold(floor_ptr, y, x)) return TRUE;
934 * @brief 隣接4マスに存在する通路の数を返す / Count the number of "corridor" grids adjacent to the given grid.
935 * @param y1 基準となるマスのY座標
936 * @param x1 基準となるマスのX座標
938 * @note Assumes "in_bounds(y1, x1)"
940 * XXX XXX This routine currently only counts actual "empty floor"\n
941 * grids which are not in rooms. We might want to also count stairs,\n
942 * open doors, closed doors, etc.
944 static int next_to_corr(floor_type *floor_ptr, POSITION y1, POSITION x1)
947 for (int i = 0; i < 4; i++)
949 POSITION y = y1 + ddy_ddd[i];
950 POSITION x = x1 + ddx_ddd[i];
952 g_ptr = &floor_ptr->grid_array[y][x];
954 if (cave_have_flag_grid(g_ptr, FF_WALL)) continue;
955 if (!is_floor_grid(g_ptr)) continue;
956 if (g_ptr->info & (CAVE_ROOM)) continue;
965 * @brief ドアを設置可能な地形かを返す / Determine if the given location is "between" two walls, and "next to" two corridor spaces.
966 * @param y 判定を行いたいマスのY座標
967 * @param x 判定を行いたいマスのX座標
968 * @return ドアを設置可能ならばTRUEを返す
969 * @note Assumes "in_bounds()"
972 * Assumes "in_bounds()"\n
974 static bool possible_doorway(floor_type *floor_ptr, POSITION y, POSITION x)
976 if (next_to_corr(floor_ptr, y, x) < 2) return FALSE;
979 if (cave_have_flag_bold(floor_ptr, y - 1, x, FF_WALL) &&
980 cave_have_flag_bold(floor_ptr, y + 1, x, FF_WALL))
985 /* Check Horizontal */
986 if (cave_have_flag_bold(floor_ptr, y, x - 1, FF_WALL) &&
987 cave_have_flag_bold(floor_ptr, y, x + 1, FF_WALL))
997 * @brief ドアの設置を試みる / Places door at y, x position if at least 2 walls found
998 * @param player_ptr プレーヤーへの参照ポインタ
999 * @param y 設置を行いたいマスのY座標
1000 * @param x 設置を行いたいマスのX座標
1003 void try_door(player_type *player_ptr, POSITION y, POSITION x)
1005 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1006 if (!in_bounds(floor_ptr, y, x)) return;
1008 if (cave_have_flag_bold(floor_ptr, y, x, FF_WALL)) return;
1009 if (floor_ptr->grid_array[y][x].info & (CAVE_ROOM)) return;
1011 bool can_place_door = randint0(100) < dun_tun_jct;
1012 can_place_door &= possible_doorway(floor_ptr, y, x);
1013 can_place_door &= (d_info[player_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) == 0;
1016 place_random_door(player_ptr, y, x, FALSE);
1021 FEAT_IDX conv_dungeon_feat(floor_type *floor_ptr, FEAT_IDX newfeat)
1023 feature_type *f_ptr = &f_info[newfeat];
1024 if (have_flag(f_ptr->flags, FF_CONVERT))
1026 switch (f_ptr->subtype)
1028 case CONVERT_TYPE_FLOOR:
1029 return feat_ground_type[randint0(100)];
1030 case CONVERT_TYPE_WALL:
1031 return feat_wall_type[randint0(100)];
1032 case CONVERT_TYPE_INNER:
1033 return feat_wall_inner;
1034 case CONVERT_TYPE_OUTER:
1035 return feat_wall_outer;
1036 case CONVERT_TYPE_SOLID:
1037 return feat_wall_solid;
1038 case CONVERT_TYPE_STREAM1:
1039 return d_info[floor_ptr->dungeon_idx].stream1;
1040 case CONVERT_TYPE_STREAM2:
1041 return d_info[floor_ptr->dungeon_idx].stream2;
1046 else return newfeat;
1051 * @brief 特殊な部屋向けに各種アイテムを配置する / Create up to "num" objects near the given coordinates
1052 * @param player_ptr プレーヤーへの参照ポインタ
1053 * @param y 配置したい中心マスのY座標
1054 * @param x 配置したい中心マスのX座標
1058 * Only really called by some of the "vault" routines.
1060 void vault_objects(player_type *player_ptr, POSITION y, POSITION x, int num)
1062 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1063 for (; num > 0; --num)
1067 for (int i = 0; i < 11; ++i)
1069 while (dummy < SAFE_MAX_ATTEMPTS)
1071 j = rand_spread(y, 2);
1072 k = rand_spread(x, 3);
1074 if (!in_bounds(floor_ptr, j, k)) continue;
1078 if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room)
1080 msg_print(_("警告!地下室のアイテムを配置できません!", "Warning! Could not place vault object!"));
1084 g_ptr = &floor_ptr->grid_array[j][k];
1085 if (!is_floor_grid(g_ptr) || g_ptr->o_idx) continue;
1087 if (randint0(100) < 75)
1089 place_object(player_ptr, j, k, 0L);
1093 place_gold(player_ptr, j, k);
1103 * @brief 始点から終点への直線経路を返す /
1104 * Determine the path taken by a projection.
1105 * @param player_ptr プレーヤーへの参照ポインタ
1106 * @param gp 経路座標リストを返す参照ポインタ
1116 * The projection will always start from the grid (y1,x1), and will travel
1117 * towards the grid (y2,x2), touching one grid per unit of distance along
1118 * the major axis, and stopping when it enters the destination grid or a
1119 * wall grid, or has travelled the maximum legal distance of "range".
1121 * Note that "distance" in this function (as in the "update_view()" code)
1122 * is defined as "MAX(dy,dx) + MIN(dy,dx)/2", which means that the player
1123 * actually has an "octagon of projection" not a "circle of projection".
1125 * The path grids are saved into the grid array pointed to by "gp", and
1126 * there should be room for at least "range" grids in "gp". Note that
1127 * due to the way in which distance is calculated, this function normally
1128 * uses fewer than "range" grids for the projection path, so the result
1129 * of this function should never be compared directly to "range". Note
1130 * that the initial grid (y1,x1) is never saved into the grid array, not
1131 * even if the initial grid is also the final grid.
1133 * The "flg" flags can be used to modify the behavior of this function.
1135 * In particular, the "PROJECT_STOP" and "PROJECT_THRU" flags have the same
1136 * semantics as they do for the "project" function, namely, that the path
1137 * will stop as soon as it hits a monster, or that the path will continue
1138 * through the destination grid, respectively.
1140 * The "PROJECT_JUMP" flag, which for the "project()" function means to
1141 * start at a special grid (which makes no sense in this function), means
1142 * that the path should be "angled" slightly if needed to avoid any wall
1143 * grids, allowing the player to "target" any grid which is in "view".
1144 * This flag is non-trivial and has not yet been implemented, but could
1145 * perhaps make use of the "vinfo" array (above).
1147 * This function returns the number of grids (if any) in the path. This
1148 * function will return zero if and only if (y1,x1) and (y2,x2) are equal.
1150 * This algorithm is similar to, but slightly different from, the one used
1151 * by "update_view_los()", and very different from the one used by "los()".
1154 int project_path(player_type *player_ptr, u16b *gp, POSITION range, POSITION y1, POSITION x1, POSITION y2, POSITION x2, BIT_FLAGS flg)
1156 if ((x1 == x2) && (y1 == y2)) return 0;
1186 int half = (ay * ax);
1187 int full = half << 1;
1190 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1208 gp[n++] = GRID(y, x);
1209 if ((n + (k >> 1)) >= range) break;
1211 if (!(flg & (PROJECT_THRU)))
1213 if ((x == x2) && (y == y2)) break;
1216 if (flg & (PROJECT_DISI))
1218 if ((n > 0) && cave_stop_disintegration(floor_ptr, y, x)) break;
1220 else if (flg & (PROJECT_LOS))
1222 if ((n > 0) && !cave_los_bold(floor_ptr, y, x)) break;
1224 else if (!(flg & (PROJECT_PATH)))
1226 if ((n > 0) && !cave_have_flag_bold(floor_ptr, y, x, FF_PROJECT)) break;
1229 if (flg & (PROJECT_STOP))
1232 (player_bold(player_ptr, y, x) || floor_ptr->grid_array[y][x].m_idx != 0))
1236 if (!in_bounds(floor_ptr, y, x)) break;
1271 gp[n++] = GRID(y, x);
1272 if ((n + (k >> 1)) >= range) break;
1274 if (!(flg & (PROJECT_THRU)))
1276 if ((x == x2) && (y == y2)) break;
1279 if (flg & (PROJECT_DISI))
1281 if ((n > 0) && cave_stop_disintegration(floor_ptr, y, x)) break;
1283 else if (flg & (PROJECT_LOS))
1285 if ((n > 0) && !cave_los_bold(floor_ptr, y, x)) break;
1287 else if (!(flg & (PROJECT_PATH)))
1289 if ((n > 0) && !cave_have_flag_bold(floor_ptr, y, x, FF_PROJECT)) break;
1292 if (flg & (PROJECT_STOP))
1295 (player_bold(player_ptr, y, x) || floor_ptr->grid_array[y][x].m_idx != 0))
1299 if (!in_bounds(floor_ptr, y, x)) break;
1323 gp[n++] = GRID(y, x);
1324 if ((n + (n >> 1)) >= range) break;
1326 if (!(flg & (PROJECT_THRU)))
1328 if ((x == x2) && (y == y2)) break;
1331 if (flg & (PROJECT_DISI))
1333 if ((n > 0) && cave_stop_disintegration(floor_ptr, y, x)) break;
1335 else if (flg & (PROJECT_LOS))
1337 if ((n > 0) && !cave_los_bold(floor_ptr, y, x)) break;
1339 else if (!(flg & (PROJECT_PATH)))
1341 if ((n > 0) && !cave_have_flag_bold(floor_ptr, y, x, FF_PROJECT)) break;
1344 if (flg & (PROJECT_STOP))
1347 (player_bold(player_ptr, y, x) || floor_ptr->grid_array[y][x].m_idx != 0))
1351 if (!in_bounds(floor_ptr, y, x)) break;
1362 * @brief 指定のマスを床地形に変える / Set a square to be floor. (Includes range checking.)
1363 * @param player_ptr プレーヤーへの参照ポインタ
1364 * @param x 地形を変えたいマスのX座標
1365 * @param y 地形を変えたいマスのY座標
1368 void set_floor(player_type *player_ptr, POSITION x, POSITION y)
1370 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1371 if (!in_bounds(floor_ptr, y, x))
1376 if (floor_ptr->grid_array[y][x].info & CAVE_ROOM)
1381 if (is_extra_bold(floor_ptr, y, x))
1382 place_bold(player_ptr, y, x, GB_FLOOR);
1387 * @brief フロアの指定位置に生成階に応じたベースアイテムの生成を行う。
1388 * Attempt to place an object (normal or good/great) at the given location.
1389 * @param owner_ptr プレーヤーへの参照ポインタ
1390 * @param y 配置したいフロアのY座標
1391 * @param x 配置したいフロアのX座標
1392 * @param mode オプションフラグ
1393 * @return 生成に成功したらTRUEを返す。
1395 * This routine plays nasty games to generate the "special artifacts".\n
1396 * This routine uses "object_level" for the "generation level".\n
1397 * This routine requires a clean floor grid destination.\n
1399 void place_object(player_type *owner_ptr, POSITION y, POSITION x, BIT_FLAGS mode)
1401 floor_type *floor_ptr = owner_ptr->current_floor_ptr;
1402 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
1405 if (!in_bounds(floor_ptr, y, x)) return;
1406 if (!cave_drop_bold(floor_ptr, y, x)) return;
1407 if (g_ptr->o_idx) return;
1411 if (!make_object(owner_ptr, q_ptr, mode)) return;
1413 OBJECT_IDX o_idx = o_pop(floor_ptr);
1416 if (object_is_fixed_artifact(q_ptr))
1418 a_info[q_ptr->name1].cur_num = 0;
1425 o_ptr = &floor_ptr->o_list[o_idx];
1426 object_copy(o_ptr, q_ptr);
1430 o_ptr->next_o_idx = g_ptr->o_idx;
1432 g_ptr->o_idx = o_idx;
1433 note_spot(owner_ptr, y, x);
1434 lite_spot(owner_ptr, y, x);
1439 * @brief フロアの指定位置に生成階に応じた財宝オブジェクトの生成を行う。
1440 * Places a treasure (Gold or Gems) at given location
1441 * @param player_ptr プレーヤーへの参照ポインタ
1442 * @param y 配置したいフロアのY座標
1443 * @param x 配置したいフロアのX座標
1444 * @return 生成に成功したらTRUEを返す。
1446 * The location must be a legal, clean, floor grid.
1448 void place_gold(player_type *player_ptr, POSITION y, POSITION x)
1450 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1451 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
1452 if (!in_bounds(floor_ptr, y, x)) return;
1453 if (!cave_drop_bold(floor_ptr, y, x)) return;
1454 if (g_ptr->o_idx) return;
1460 if (!make_gold(player_ptr, q_ptr)) return;
1462 OBJECT_IDX o_idx = o_pop(floor_ptr);
1463 if (o_idx == 0) return;
1466 o_ptr = &floor_ptr->o_list[o_idx];
1467 object_copy(o_ptr, q_ptr);
1471 o_ptr->next_o_idx = g_ptr->o_idx;
1473 g_ptr->o_idx = o_idx;
1474 note_spot(player_ptr, y, x);
1475 lite_spot(player_ptr, y, x);
1480 * @brief 指定位置に存在するモンスターを削除する / Delete the monster, if any, at a given location
1481 * @param player_ptr プレーヤーへの参照ポインタ
1486 void delete_monster(player_type *player_ptr, POSITION y, POSITION x)
1489 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1490 if (!in_bounds(floor_ptr, y, x)) return;
1492 g_ptr = &floor_ptr->grid_array[y][x];
1493 if (g_ptr->m_idx) delete_monster_idx(player_ptr, g_ptr->m_idx);
1498 * @brief グローバルオブジェクト配列に対し指定範囲のオブジェクトを整理してIDの若い順に寄せる /
1499 * Move an object from index i1 to index i2 in the object list
1500 * @param i1 整理したい配列の始点
1501 * @param i2 整理したい配列の終点
1504 static void compact_objects_aux(floor_type *floor_ptr, OBJECT_IDX i1, OBJECT_IDX i2)
1506 if (i1 == i2) return;
1509 for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++)
1511 o_ptr = &floor_ptr->o_list[i];
1512 if (!o_ptr->k_idx) continue;
1514 if (o_ptr->next_o_idx == i1)
1516 o_ptr->next_o_idx = i2;
1520 o_ptr = &floor_ptr->o_list[i1];
1522 if (object_is_held_monster(o_ptr))
1524 monster_type *m_ptr;
1525 m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
1526 if (m_ptr->hold_o_idx == i1)
1528 m_ptr->hold_o_idx = i2;
1533 POSITION y = o_ptr->iy;
1534 POSITION x = o_ptr->ix;
1536 g_ptr = &floor_ptr->grid_array[y][x];
1538 if (g_ptr->o_idx == i1)
1544 floor_ptr->o_list[i2] = floor_ptr->o_list[i1];
1550 * @brief グローバルオブジェクト配列から優先度の低いものを削除し、データを圧縮する。 /
1551 * Compact and Reorder the object list.
1552 * @param player_ptr プレーヤーへの参照ポインタ
1553 * @param size 最低でも減らしたいオブジェクト数の水準
1557 * This function can be very dangerous, use with caution!\n
1559 * When actually "compacting" objects, we base the saving throw on a\n
1560 * combination of object level, distance from player, and current\n
1563 * After "compacting" (if needed), we "reorder" the objects into a more\n
1564 * compact order, and we reset the allocation info, and the "live" array.\n
1566 void compact_objects(player_type *player_ptr, int size)
1571 msg_print(_("アイテム情報を圧縮しています...", "Compacting objects..."));
1572 player_ptr->redraw |= (PR_MAP);
1573 player_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
1576 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1577 for (int num = 0, cnt = 1; num < size; cnt++)
1579 int cur_lev = 5 * cnt;
1580 int cur_dis = 5 * (20 - cnt);
1581 for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++)
1583 o_ptr = &floor_ptr->o_list[i];
1585 if (!object_is_valid(o_ptr)) continue;
1586 if (k_info[o_ptr->k_idx].level > cur_lev) continue;
1589 if (object_is_held_monster(o_ptr))
1591 monster_type *m_ptr;
1592 m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
1596 if (randint0(100) < 90) continue;
1604 if ((cur_dis > 0) && (distance(player_ptr->y, player_ptr->x, y, x) < cur_dis)) continue;
1607 if ((object_is_fixed_artifact(o_ptr) || o_ptr->art_name) &&
1608 (cnt < 1000)) chance = 100;
1610 if (randint0(100) < chance) continue;
1612 delete_object_idx(player_ptr, i);
1617 for (OBJECT_IDX i = floor_ptr->o_max - 1; i >= 1; i--)
1619 o_ptr = &floor_ptr->o_list[i];
1620 if (o_ptr->k_idx) continue;
1622 compact_objects_aux(floor_ptr, floor_ptr->o_max - 1, i);
1629 * @brief 特殊な部屋向けに各種アイテムを配置する(メインルーチン) / Place some traps with a given displacement of given location
1630 * @param player_ptr プレーヤーへの参照ポインタ
1631 * @param y トラップを配置したいマスの中心Y座標
1632 * @param x トラップを配置したいマスの中心X座標
1633 * @param yd Y方向の配置分散マス数
1634 * @param xd X方向の配置分散マス数
1635 * @param num 配置したいトラップの数
1638 * Only really called by some of the "vault" routines.
1640 void vault_traps(player_type *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd, int num)
1642 for (int i = 0; i < num; i++)
1644 vault_trap_aux(player_ptr, y, x, yd, xd);
1650 * Standard "find me a location" function
1652 * Obtains a legal location within the given distance of the initial
1653 * location, and with "los()" from the source to destination location.
1655 * This function is often called from inside a loop which searches for
1656 * locations while increasing the "d" distance.
1658 * Currently the "m" parameter is unused.
1660 void scatter(player_type *player_ptr, POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION d, BIT_FLAGS mode)
1662 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1666 ny = rand_spread(y, d);
1667 nx = rand_spread(x, d);
1669 if (!in_bounds(floor_ptr, ny, nx)) continue;
1670 if ((d > 1) && (distance(y, x, ny, nx) > d)) continue;
1671 if (mode & PROJECT_LOS)
1673 if (los(player_ptr, y, x, ny, nx)) break;
1677 if (projectable(player_ptr, y, x, ny, nx)) break;
1686 * @brief 指定のマスが光を通すか(LOSフラグを持つか)を返す。 / Aux function -- see below
1687 * @param floor_ptr 配置するフロアの参照ポインタ
1690 * @return 光を通すならばtrueを返す。
1692 bool cave_los_bold(floor_type *floor_ptr, POSITION y, POSITION x)
1694 return feat_supports_los(floor_ptr->grid_array[y][x].feat);