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-generator-util.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 "mind/mind-ninja.h"
19 #include "monster-floor/monster-generator.h"
20 #include "monster-floor/monster-remover.h"
21 #include "monster-floor/place-monster-types.h"
22 #include "monster/monster-update.h"
23 #include "object-enchant/special-object-flags.h"
24 #include "object-hook/hook-checker.h"
25 #include "object-hook/hook-enchant.h"
26 #include "object/object-generator.h"
27 #include "object/object-kind.h"
28 #include "perception/object-perception.h"
29 #include "player/special-defense-types.h"
30 #include "room/door-definition.h"
31 #include "system/artifact-type-definition.h"
32 #include "system/floor-type-definition.h"
33 #include "target/projection-path-calculator.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 * @brief 鍵のかかったドアを配置する
48 * @param player_ptr プレーヤーへの参照ポインタ
49 * @param y 配置したいフロアのY座標
50 * @param x 配置したいフロアのX座標
53 void place_locked_door(player_type *player_ptr, POSITION y, POSITION x)
55 floor_type *floor_ptr = player_ptr->current_floor_ptr;
56 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
57 place_bold(player_ptr, y, x, GB_FLOOR);
61 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));
62 floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
63 delete_monster(player_ptr, y, x);
68 * @param player_ptr プレーヤーへの参照ポインタ
69 * @param y 配置したいフロアのY座標
70 * @param x 配置したいフロアのX座標
71 * @param type DOOR_DEFAULT / DOOR_DOOR / DOOR_GLASS_DOOR / DOOR_CURTAIN のいずれか
74 void place_secret_door(player_type *player_ptr, POSITION y, POSITION x, int type)
76 floor_type *floor_ptr = player_ptr->current_floor_ptr;
77 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
78 place_bold(player_ptr, y, x, GB_FLOOR);
82 if (type == DOOR_DEFAULT) {
83 type = ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && one_in_((d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256))
85 : ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
88 place_closed_door(player_ptr, y, x, type);
89 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
90 if (type != DOOR_CURTAIN) {
91 g_ptr->mimic = feat_wall_inner;
92 if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat)) {
93 if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY)) {
94 g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
101 g_ptr->info &= ~(CAVE_FLOOR);
102 delete_monster(player_ptr, y, x);
105 static int scent_when = 0;
108 * Characters leave scent trails for perceptive monsters to track.
110 * Smell is rather more limited than sound. Many creatures cannot use
111 * it at all, it doesn't extend very far outwards from the character's
112 * current position, and monsters can use it to home in the character,
113 * but not to run away from him.
115 * Smell is valued according to age. When a character takes his turn,
116 * scent is aged by one, and new scent of the current age is laid down.
117 * Speedy characters leave more scent, true, but it also ages faster,
118 * which makes it harder to hunt them down.
120 * Whenever the age count loops, most of the scent trail is erased and
121 * the age of the remainder is recalculated.
123 void update_smell(floor_type *floor_ptr, player_type *subject_ptr)
125 /* Create a table that controls the spread of scent */
126 const int scent_adjust[5][5] = {
134 if (++scent_when == 254) {
135 for (POSITION y = 0; y < floor_ptr->height; y++) {
136 for (POSITION x = 0; x < floor_ptr->width; x++) {
137 int w = floor_ptr->grid_array[y][x].when;
138 floor_ptr->grid_array[y][x].when = (w > 128) ? (w - 128) : 0;
145 for (POSITION i = 0; i < 5; i++) {
146 for (POSITION j = 0; j < 5; j++) {
148 POSITION y = i + subject_ptr->y - 2;
149 POSITION x = j + subject_ptr->x - 2;
150 if (!in_bounds(floor_ptr, y, x))
153 g_ptr = &floor_ptr->grid_array[y][x];
154 if (!cave_have_flag_grid(g_ptr, FF_MOVE) && !is_closed_door(subject_ptr, g_ptr->feat))
156 if (!player_has_los_bold(subject_ptr, y, x))
158 if (scent_adjust[i][j] == -1)
161 g_ptr->when = scent_when + scent_adjust[i][j];
167 * Hack -- forget the "flow" information
169 void forget_flow(floor_type *floor_ptr)
171 for (POSITION y = 0; y < floor_ptr->height; y++) {
172 for (POSITION x = 0; x < floor_ptr->width; x++) {
173 floor_ptr->grid_array[y][x].dist = 0;
174 floor_ptr->grid_array[y][x].cost = 0;
175 floor_ptr->grid_array[y][x].when = 0;
181 * Routine used by the random vault creators to add a door to a location
182 * Note that range checking has to be done in the calling routine.
184 * The doors must be INSIDE the allocated region.
186 void add_door(player_type *player_ptr, POSITION x, POSITION y)
188 floor_type *floor_ptr = player_ptr->current_floor_ptr;
189 if (!is_outer_bold(floor_ptr, y, x))
201 if (is_floor_bold(floor_ptr, y - 1, x) && is_floor_bold(floor_ptr, y + 1, x)
202 && (is_outer_bold(floor_ptr, y, x - 1) && is_outer_bold(floor_ptr, y, x + 1))) {
203 place_secret_door(player_ptr, y, x, DOOR_DEFAULT);
204 place_bold(player_ptr, y, x - 1, GB_SOLID);
205 place_bold(player_ptr, y, x + 1, GB_SOLID);
213 * where x = don't care
216 if (is_outer_bold(floor_ptr, y - 1, x) && is_outer_bold(floor_ptr, y + 1, x) && is_floor_bold(floor_ptr, y, x - 1) && is_floor_bold(floor_ptr, y, x + 1)) {
217 place_secret_door(player_ptr, y, x, DOOR_DEFAULT);
218 place_bold(player_ptr, y - 1, x, GB_SOLID);
219 place_bold(player_ptr, y + 1, x, GB_SOLID);
224 * @brief 所定の位置に上り階段か下り階段を配置する / Place an up/down staircase at given location
225 * @param player_ptr プレーヤーへの参照ポインタ
226 * @param y 配置を試みたいマスのY座標
227 * @param x 配置を試みたいマスのX座標
230 void place_random_stairs(player_type *player_ptr, POSITION y, POSITION x)
232 bool up_stairs = TRUE;
233 bool down_stairs = TRUE;
235 floor_type *floor_ptr = player_ptr->current_floor_ptr;
236 g_ptr = &floor_ptr->grid_array[y][x];
237 if (!is_floor_grid(g_ptr) || g_ptr->o_idx)
240 if (!floor_ptr->dun_level)
242 if (ironman_downward)
244 if (floor_ptr->dun_level >= d_info[player_ptr->dungeon_idx].maxdepth)
246 if (quest_number(player_ptr, floor_ptr->dun_level) && (floor_ptr->dun_level > 1))
249 if (down_stairs && up_stairs) {
250 if (randint0(100) < 50)
257 set_cave_feat(floor_ptr, y, x, feat_up_stair);
258 else if (down_stairs)
259 set_cave_feat(floor_ptr, y, x, feat_down_stair);
263 * @brief LOS(Line Of Sight / 視線が通っているか)の判定を行う。
264 * @param player_ptr プレーヤーへの参照ポインタ
269 * @return LOSが通っているならTRUEを返す。
271 * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall,\n
272 * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu.\n
274 * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).\n
276 * The LOS begins at the center of the tile (x1,y1) and ends at the center of\n
277 * the tile (x2,y2). If los() is to return TRUE, all of the tiles this line\n
278 * passes through must be floor tiles, except for (x1,y1) and (x2,y2).\n
280 * We assume that the "mathematical corner" of a non-floor tile does not\n
281 * block line of sight.\n
283 * Because this function uses (short) ints for all calculations, overflow may\n
284 * occur if dx and dy exceed 90.\n
286 * Once all the degenerate cases are eliminated, the values "qx", "qy", and\n
287 * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that\n
288 * we can use integer arithmetic.\n
290 * We travel from start to finish along the longer axis, starting at the border\n
291 * between the first and second tiles, where the y offset = .5 * slope, taking\n
292 * into account the scale factor. See below.\n
294 * Also note that this function and the "move towards target" code do NOT\n
295 * share the same properties. Thus, you can see someone, target them, and\n
296 * then fire a bolt at them, but the bolt may hit a wall, not them. However\n,
297 * by clever choice of target locations, you can sometimes throw a "curve".\n
299 * Note that "line of sight" is not "reflexive" in all cases.\n
301 * Use the "projectable()" routine to test "spell/missile line of sight".\n
303 * Use the "update_view()" function to determine player line-of-sight.\n
305 bool los(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
307 POSITION dy = y2 - y1;
308 POSITION dx = x2 - x1;
309 POSITION ay = ABS(dy);
310 POSITION ax = ABS(dx);
311 if ((ax < 2) && (ay < 2))
314 /* Directly South/North */
315 floor_type *floor_ptr = player_ptr->current_floor_ptr;
318 /* South -- check for walls */
320 for (ty = y1 + 1; ty < y2; ty++) {
321 if (!cave_los_bold(floor_ptr, ty, x1))
326 /* North -- check for walls */
328 for (ty = y1 - 1; ty > y2; ty--) {
329 if (!cave_los_bold(floor_ptr, ty, x1))
338 /* Directly East/West */
340 /* East -- check for walls */
342 for (tx = x1 + 1; tx < x2; tx++) {
343 if (!cave_los_bold(floor_ptr, y1, tx))
348 /* West -- check for walls */
350 for (tx = x1 - 1; tx > x2; tx--) {
351 if (!cave_los_bold(floor_ptr, y1, tx))
359 POSITION sx = (dx < 0) ? -1 : 1;
360 POSITION sy = (dy < 0) ? -1 : 1;
364 if (cave_los_bold(floor_ptr, y1 + sy, x1))
367 } else if (ay == 1) {
369 if (cave_los_bold(floor_ptr, y1, x1 + sx))
374 POSITION f2 = (ax * ay);
375 POSITION f1 = f2 << 1;
389 /* Note (below) the case (qy == f2), where */
390 /* the LOS exactly meets the corner of a tile. */
392 if (!cave_los_bold(floor_ptr, ty, tx))
404 if (!cave_los_bold(floor_ptr, ty, tx))
419 /* Travel vertically */
420 POSITION qx = ax * ax;
430 /* Note (below) the case (qx == f2), where */
431 /* the LOS exactly meets the corner of a tile. */
433 if (!cave_los_bold(floor_ptr, ty, tx))
445 if (!cave_los_bold(floor_ptr, ty, tx))
461 * @briefプレイヤーの攻撃射程(マス) / Maximum range (spells, etc)
462 * @param creature_ptr プレーヤーへの参照ポインタ
465 int get_max_range(player_type *creature_ptr) { return creature_ptr->phase_out ? 36 : 18; }
468 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
469 * at the final destination, assuming no monster gets in the way.
471 * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
473 bool projectable(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
476 int grid_n = projection_path(player_ptr, grid_g, (project_length ? project_length : get_max_range(player_ptr)), y1, x1, y2, x2, 0);
480 POSITION y = GRID_Y(grid_g[grid_n - 1]);
481 POSITION x = GRID_X(grid_g[grid_n - 1]);
482 if ((y != y2) || (x != x2))
489 * Grid based version of "creature_bold()"
491 static bool player_grid(player_type *player_ptr, grid_type *g_ptr) { return g_ptr == &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x]; }
494 * Grid based version of "cave_empty_bold()"
496 static bool is_cave_empty_grid(player_type *player_ptr, grid_type *g_ptr)
498 bool is_empty_grid = cave_have_flag_grid(g_ptr, FF_PLACE);
499 is_empty_grid &= g_ptr->m_idx == 0;
500 is_empty_grid &= !player_grid(player_ptr, g_ptr);
501 return is_empty_grid;
505 * @brief 特殊な部屋地形向けにモンスターを配置する / Place some sleeping monsters near the given location
506 * @param player_ptr プレーヤーへの参照ポインタ
507 * @param y1 モンスターを配置したいマスの中心Y座標
508 * @param x1 モンスターを配置したいマスの中心X座標
509 * @param num 配置したいモンスターの数
512 * Only really called by some of the "vault" routines.
514 void vault_monsters(player_type *player_ptr, POSITION y1, POSITION x1, int num)
516 floor_type *floor_ptr = player_ptr->current_floor_ptr;
517 for (int k = 0; k < num; k++) {
518 for (int i = 0; i < 9; i++) {
521 scatter(player_ptr, &y, &x, y1, x1, d, 0);
523 g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
524 if (!is_cave_empty_grid(player_ptr, g_ptr))
527 floor_ptr->monster_level = floor_ptr->base_level + 2;
528 (void)place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
529 floor_ptr->monster_level = floor_ptr->base_level;
535 * @brief 指定された座標が地震や階段生成の対象となるマスかを返す。 / Determine if a given location may be "destroyed"
536 * @param player_ptr プレーヤーへの参照ポインタ
539 * @return 各種の変更が可能ならTRUEを返す。
541 * 条件は永久地形でなく、なおかつ該当のマスにアーティファクトが存在しないか、である。英語の旧コメントに反して*破壊*の抑止判定には現在使われていない。
543 bool cave_valid_bold(floor_type *floor_ptr, POSITION y, POSITION x)
545 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
546 if (cave_have_flag_grid(g_ptr, FF_PERMANENT))
549 OBJECT_IDX next_o_idx = 0;
550 for (OBJECT_IDX this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
552 o_ptr = &floor_ptr->o_list[this_o_idx];
553 next_o_idx = o_ptr->next_o_idx;
554 if (object_is_artifact(o_ptr))
562 * Determine if a "legal" grid is within "los" of the player *
563 * Note the use of comparison to zero to force a "boolean" result
565 static bool player_has_los_grid(grid_type *g_ptr) { return (g_ptr->info & CAVE_VIEW) != 0; }
568 * Change the "feat" flag for a grid, and notice/redraw the grid
570 void cave_set_feat(player_type *player_ptr, POSITION y, POSITION x, FEAT_IDX feat)
572 floor_type *floor_ptr = player_ptr->current_floor_ptr;
573 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
574 feature_type *f_ptr = &f_info[feat];
575 if (!current_world_ptr->character_dungeon) {
578 if (have_flag(f_ptr->flags, FF_GLOW) && !(d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) {
579 for (DIRECTION i = 0; i < 9; i++) {
580 POSITION yy = y + ddy_ddd[i];
581 POSITION xx = x + ddx_ddd[i];
582 if (!in_bounds2(floor_ptr, yy, xx))
584 floor_ptr->grid_array[yy][xx].info |= CAVE_GLOW;
591 bool old_los = cave_have_flag_bold(floor_ptr, y, x, FF_LOS);
592 bool old_mirror = is_mirror_grid(g_ptr);
596 g_ptr->info &= ~(CAVE_OBJECT);
597 if (old_mirror && (d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) {
598 g_ptr->info &= ~(CAVE_GLOW);
599 if (!view_torch_grids)
600 g_ptr->info &= ~(CAVE_MARK);
602 update_local_illumination(player_ptr, y, x);
605 if (!have_flag(f_ptr->flags, FF_REMEMBER))
606 g_ptr->info &= ~(CAVE_MARK);
608 update_monster(player_ptr, g_ptr->m_idx, FALSE);
610 note_spot(player_ptr, y, x);
611 lite_spot(player_ptr, y, x);
612 if (old_los ^ have_flag(f_ptr->flags, FF_LOS)) {
614 #ifdef COMPLEX_WALL_ILLUMINATION /* COMPLEX_WALL_ILLUMINATION */
616 update_local_illumination(player_ptr, y, x);
618 #endif /* COMPLEX_WALL_ILLUMINATION */
620 player_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE | PU_MONSTERS);
623 if (!have_flag(f_ptr->flags, FF_GLOW) || (d_info[player_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
626 for (DIRECTION i = 0; i < 9; i++) {
627 POSITION yy = y + ddy_ddd[i];
628 POSITION xx = x + ddx_ddd[i];
629 if (!in_bounds2(floor_ptr, yy, xx))
633 cc_ptr = &floor_ptr->grid_array[yy][xx];
634 cc_ptr->info |= CAVE_GLOW;
636 if (player_has_los_grid(cc_ptr)) {
638 update_monster(player_ptr, cc_ptr->m_idx, FALSE);
639 note_spot(player_ptr, yy, xx);
640 lite_spot(player_ptr, yy, xx);
643 update_local_illumination(player_ptr, yy, xx);
646 if (player_ptr->special_defense & NINJA_S_STEALTH) {
647 if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW)
648 set_superstealth(player_ptr, FALSE);
653 * @brief 所定の位置にさまざまな状態や種類のドアを配置する / Place a random type of door at the given location
654 * @param player_ptr プレーヤーへの参照ポインタ
655 * @param y ドアの配置を試みたいマスのY座標
656 * @param x ドアの配置を試みたいマスのX座標
657 * @param room 部屋に接している場合向けのドア生成か否か
660 void place_random_door(player_type *player_ptr, POSITION y, POSITION x, bool room)
662 floor_type *floor_ptr = player_ptr->current_floor_ptr;
663 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
666 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
667 place_bold(player_ptr, y, x, GB_FLOOR);
671 int type = ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && one_in_((d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256))
673 : ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
675 int tmp = randint0(1000);
676 FEAT_IDX feat = feat_none;
678 feat = feat_door[type].open;
679 } else if (tmp < 400) {
680 feat = feat_door[type].broken;
681 } else if (tmp < 600) {
682 place_closed_door(player_ptr, y, x, type);
684 if (type != DOOR_CURTAIN) {
685 g_ptr->mimic = room ? feat_wall_outer : feat_wall_type[randint0(100)];
686 if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat)) {
687 if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY)) {
688 g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
694 place_closed_door(player_ptr, y, x, type);
698 delete_monster(player_ptr, y, x);
702 if (feat != feat_none) {
703 set_cave_feat(floor_ptr, y, x, feat);
705 place_bold(player_ptr, y, x, GB_FLOOR);
708 delete_monster(player_ptr, y, x);
712 * @brief グローバルオブジェクト配列を初期化する /
713 * Delete all the items when player leaves the level
714 * @note we do NOT visually reflect these (irrelevant) changes
716 * Hack -- we clear the "g_ptr->o_idx" field for every grid,
717 * and the "m_ptr->next_o_idx" field for every monster, since
718 * we know we are clearing every object. Technically, we only
719 * clear those fields for grids/monsters containing objects,
720 * and we clear it once for every such object.
723 void wipe_o_list(floor_type *floor_ptr)
725 for (int i = 1; i < floor_ptr->o_max; i++) {
726 object_type *o_ptr = &floor_ptr->o_list[i];
727 if (!object_is_valid(o_ptr))
730 if (!current_world_ptr->character_dungeon || preserve_mode) {
731 if (object_is_fixed_artifact(o_ptr) && !object_is_known(o_ptr)) {
732 a_info[o_ptr->name1].cur_num = 0;
736 if (object_is_held_monster(o_ptr)) {
738 m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
739 m_ptr->hold_o_idx = 0;
745 POSITION y = o_ptr->iy;
746 POSITION x = o_ptr->ix;
748 g_ptr = &floor_ptr->grid_array[y][x];
753 floor_ptr->o_max = 1;
754 floor_ptr->o_cnt = 0;
758 * @brief 所定の位置に各種の閉じたドアを配置する / Place a random type of normal door at the given location.
759 * @param player_ptr プレーヤーへの参照ポインタ
760 * @param y ドアの配置を試みたいマスのY座標
761 * @param x ドアの配置を試みたいマスのX座標
762 * @param type ドアの地形ID
765 void place_closed_door(player_type *player_ptr, POSITION y, POSITION x, int type)
767 floor_type *floor_ptr = player_ptr->current_floor_ptr;
768 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
769 place_bold(player_ptr, y, x, GB_FLOOR);
773 int tmp = randint0(400);
774 FEAT_IDX feat = feat_none;
776 /* Create closed door */
777 feat = feat_door[type].closed;
778 } else if (tmp < 399) {
779 feat = feat_locked_door_random(type);
781 feat = feat_jammed_door_random(type);
784 if (feat == feat_none) {
785 place_bold(player_ptr, y, x, GB_FLOOR);
789 cave_set_feat(player_ptr, y, x, feat);
790 floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
794 * @brief 指定のマスが床系地形であるかを返す / Function that sees if a square is a floor. (Includes range checking.)
795 * @param x チェックするマスのX座標
796 * @param y チェックするマスのY座標
797 * @return 床系地形ならばTRUE
799 bool get_is_floor(floor_type *floor_ptr, POSITION x, POSITION y)
801 if (!in_bounds(floor_ptr, y, x)) {
805 if (is_floor_bold(floor_ptr, y, x))
811 FEAT_IDX conv_dungeon_feat(floor_type *floor_ptr, FEAT_IDX newfeat)
813 feature_type *f_ptr = &f_info[newfeat];
814 if (have_flag(f_ptr->flags, FF_CONVERT)) {
815 switch (f_ptr->subtype) {
816 case CONVERT_TYPE_FLOOR:
817 return feat_ground_type[randint0(100)];
818 case CONVERT_TYPE_WALL:
819 return feat_wall_type[randint0(100)];
820 case CONVERT_TYPE_INNER:
821 return feat_wall_inner;
822 case CONVERT_TYPE_OUTER:
823 return feat_wall_outer;
824 case CONVERT_TYPE_SOLID:
825 return feat_wall_solid;
826 case CONVERT_TYPE_STREAM1:
827 return d_info[floor_ptr->dungeon_idx].stream1;
828 case CONVERT_TYPE_STREAM2:
829 return d_info[floor_ptr->dungeon_idx].stream2;
838 * @brief 特殊な部屋向けに各種アイテムを配置する / Create up to "num" objects near the given coordinates
839 * @param player_ptr プレーヤーへの参照ポインタ
840 * @param y 配置したい中心マスのY座標
841 * @param x 配置したい中心マスのX座標
845 * Only really called by some of the "vault" routines.
847 void vault_objects(player_type *player_ptr, POSITION y, POSITION x, int num)
849 floor_type *floor_ptr = player_ptr->current_floor_ptr;
850 for (; num > 0; --num) {
853 for (int i = 0; i < 11; ++i) {
854 while (dummy < SAFE_MAX_ATTEMPTS) {
855 j = rand_spread(y, 2);
856 k = rand_spread(x, 3);
858 if (!in_bounds(floor_ptr, j, k))
863 if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room) {
864 msg_print(_("警告!地下室のアイテムを配置できません!", "Warning! Could not place vault object!"));
868 g_ptr = &floor_ptr->grid_array[j][k];
869 if (!is_floor_grid(g_ptr) || g_ptr->o_idx)
872 if (randint0(100) < 75) {
873 place_object(player_ptr, j, k, 0L);
875 place_gold(player_ptr, j, k);
884 * @brief 指定のマスを床地形に変える / Set a square to be floor. (Includes range checking.)
885 * @param player_ptr プレーヤーへの参照ポインタ
886 * @param x 地形を変えたいマスのX座標
887 * @param y 地形を変えたいマスのY座標
890 void set_floor(player_type *player_ptr, POSITION x, POSITION y)
892 floor_type *floor_ptr = player_ptr->current_floor_ptr;
893 if (!in_bounds(floor_ptr, y, x)) {
897 if (floor_ptr->grid_array[y][x].info & CAVE_ROOM) {
901 if (is_extra_bold(floor_ptr, y, x))
902 place_bold(player_ptr, y, x, GB_FLOOR);
906 * @brief フロアの指定位置に生成階に応じたベースアイテムの生成を行う。
907 * Attempt to place an object (normal or good/great) at the given location.
908 * @param owner_ptr プレーヤーへの参照ポインタ
909 * @param y 配置したいフロアのY座標
910 * @param x 配置したいフロアのX座標
911 * @param mode オプションフラグ
912 * @return 生成に成功したらTRUEを返す。
914 * This routine plays nasty games to generate the "special artifacts".\n
915 * This routine uses "object_level" for the "generation level".\n
916 * This routine requires a clean floor grid destination.\n
918 void place_object(player_type *owner_ptr, POSITION y, POSITION x, BIT_FLAGS mode)
920 floor_type *floor_ptr = owner_ptr->current_floor_ptr;
921 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
924 if (!in_bounds(floor_ptr, y, x))
926 if (!cave_drop_bold(floor_ptr, y, x))
933 if (!make_object(owner_ptr, q_ptr, mode))
936 OBJECT_IDX o_idx = o_pop(floor_ptr);
938 if (object_is_fixed_artifact(q_ptr)) {
939 a_info[q_ptr->name1].cur_num = 0;
946 o_ptr = &floor_ptr->o_list[o_idx];
947 object_copy(o_ptr, q_ptr);
951 o_ptr->next_o_idx = g_ptr->o_idx;
953 g_ptr->o_idx = o_idx;
954 note_spot(owner_ptr, y, x);
955 lite_spot(owner_ptr, y, x);
959 * @brief フロアの指定位置に生成階に応じた財宝オブジェクトの生成を行う。
960 * Places a treasure (Gold or Gems) at given location
961 * @param player_ptr プレーヤーへの参照ポインタ
962 * @param y 配置したいフロアのY座標
963 * @param x 配置したいフロアのX座標
964 * @return 生成に成功したらTRUEを返す。
966 * The location must be a legal, clean, floor grid.
968 void place_gold(player_type *player_ptr, POSITION y, POSITION x)
970 floor_type *floor_ptr = player_ptr->current_floor_ptr;
971 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
972 if (!in_bounds(floor_ptr, y, x))
974 if (!cave_drop_bold(floor_ptr, y, x))
983 if (!make_gold(player_ptr, q_ptr))
986 OBJECT_IDX o_idx = o_pop(floor_ptr);
991 o_ptr = &floor_ptr->o_list[o_idx];
992 object_copy(o_ptr, q_ptr);
996 o_ptr->next_o_idx = g_ptr->o_idx;
998 g_ptr->o_idx = o_idx;
999 note_spot(player_ptr, y, x);
1000 lite_spot(player_ptr, y, x);
1004 * @brief 指定位置に存在するモンスターを削除する / Delete the monster, if any, at a given location
1005 * @param player_ptr プレーヤーへの参照ポインタ
1010 void delete_monster(player_type *player_ptr, POSITION y, POSITION x)
1013 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1014 if (!in_bounds(floor_ptr, y, x))
1017 g_ptr = &floor_ptr->grid_array[y][x];
1019 delete_monster_idx(player_ptr, g_ptr->m_idx);
1023 * @brief グローバルオブジェクト配列に対し指定範囲のオブジェクトを整理してIDの若い順に寄せる /
1024 * Move an object from index i1 to index i2 in the object list
1025 * @param i1 整理したい配列の始点
1026 * @param i2 整理したい配列の終点
1029 static void compact_objects_aux(floor_type *floor_ptr, OBJECT_IDX i1, OBJECT_IDX i2)
1035 for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++) {
1036 o_ptr = &floor_ptr->o_list[i];
1040 if (o_ptr->next_o_idx == i1) {
1041 o_ptr->next_o_idx = i2;
1045 o_ptr = &floor_ptr->o_list[i1];
1047 if (object_is_held_monster(o_ptr)) {
1048 monster_type *m_ptr;
1049 m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
1050 if (m_ptr->hold_o_idx == i1) {
1051 m_ptr->hold_o_idx = i2;
1054 POSITION y = o_ptr->iy;
1055 POSITION x = o_ptr->ix;
1057 g_ptr = &floor_ptr->grid_array[y][x];
1059 if (g_ptr->o_idx == i1) {
1064 floor_ptr->o_list[i2] = floor_ptr->o_list[i1];
1069 * @brief グローバルオブジェクト配列から優先度の低いものを削除し、データを圧縮する。 /
1070 * Compact and Reorder the object list.
1071 * @param player_ptr プレーヤーへの参照ポインタ
1072 * @param size 最低でも減らしたいオブジェクト数の水準
1076 * This function can be very dangerous, use with caution!\n
1078 * When actually "compacting" objects, we base the saving throw on a\n
1079 * combination of object level, distance from player, and current\n
1082 * After "compacting" (if needed), we "reorder" the objects into a more\n
1083 * compact order, and we reset the allocation info, and the "live" array.\n
1085 void compact_objects(player_type *player_ptr, int size)
1089 msg_print(_("アイテム情報を圧縮しています...", "Compacting objects..."));
1090 player_ptr->redraw |= (PR_MAP);
1091 player_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
1094 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1095 for (int num = 0, cnt = 1; num < size; cnt++) {
1096 int cur_lev = 5 * cnt;
1097 int cur_dis = 5 * (20 - cnt);
1098 for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++) {
1099 o_ptr = &floor_ptr->o_list[i];
1101 if (!object_is_valid(o_ptr))
1103 if (k_info[o_ptr->k_idx].level > cur_lev)
1107 if (object_is_held_monster(o_ptr)) {
1108 monster_type *m_ptr;
1109 m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
1113 if (randint0(100) < 90)
1120 if ((cur_dis > 0) && (distance(player_ptr->y, player_ptr->x, y, x) < cur_dis))
1124 if ((object_is_fixed_artifact(o_ptr) || o_ptr->art_name) && (cnt < 1000))
1127 if (randint0(100) < chance)
1130 delete_object_idx(player_ptr, i);
1135 for (OBJECT_IDX i = floor_ptr->o_max - 1; i >= 1; i--) {
1136 o_ptr = &floor_ptr->o_list[i];
1140 compact_objects_aux(floor_ptr, floor_ptr->o_max - 1, i);
1146 * @brief 特殊な部屋向けに各種アイテムを配置する(vault_trapのサブセット) / Place a trap with a given displacement of point
1147 * @param y トラップを配置したいマスの中心Y座標
1148 * @param x トラップを配置したいマスの中心X座標
1149 * @param yd Y方向の配置分散マス数
1150 * @param xd X方向の配置分散マス数
1153 * Only really called by some of the "vault" routines.
1155 static void vault_trap_aux(player_type *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd)
1158 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1161 for (int count = 0; count <= 5; count++) {
1162 while (dummy < SAFE_MAX_ATTEMPTS) {
1163 y1 = rand_spread(y, yd);
1164 x1 = rand_spread(x, xd);
1166 if (!in_bounds(floor_ptr, y1, x1))
1171 if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room) {
1172 msg_print(_("警告!地下室のトラップを配置できません!", "Warning! Could not place vault trap!"));
1175 g_ptr = &floor_ptr->grid_array[y1][x1];
1176 if (!is_floor_grid(g_ptr) || g_ptr->o_idx || g_ptr->m_idx)
1179 place_trap(player_ptr, y1, x1);
1185 * todo rooms-normal からしか呼ばれていない、要調整
1186 * @brief 特殊な部屋向けに各種アイテムを配置する(メインルーチン) / Place some traps with a given displacement of given location
1187 * @param player_ptr プレーヤーへの参照ポインタ
1188 * @param y トラップを配置したいマスの中心Y座標
1189 * @param x トラップを配置したいマスの中心X座標
1190 * @param yd Y方向の配置分散マス数
1191 * @param xd X方向の配置分散マス数
1192 * @param num 配置したいトラップの数
1195 * Only really called by some of the "vault" routines.
1197 void vault_traps(player_type *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd, int num)
1199 for (int i = 0; i < num; i++) {
1200 vault_trap_aux(player_ptr, y, x, yd, xd);
1205 * Standard "find me a location" function
1207 * Obtains a legal location within the given distance of the initial
1208 * location, and with "los()" from the source to destination location.
1210 * This function is often called from inside a loop which searches for
1211 * locations while increasing the "d" distance.
1213 * Currently the "m" parameter is unused.
1215 void scatter(player_type *player_ptr, POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION d, BIT_FLAGS mode)
1217 floor_type *floor_ptr = player_ptr->current_floor_ptr;
1220 ny = rand_spread(y, d);
1221 nx = rand_spread(x, d);
1223 if (!in_bounds(floor_ptr, ny, nx))
1225 if ((d > 1) && (distance(y, x, ny, nx) > d))
1227 if (mode & PROJECT_LOS) {
1228 if (los(player_ptr, y, x, ny, nx))
1233 if (projectable(player_ptr, y, x, ny, nx))