OSDN Git Service

Merge remote-tracking branch 'remotes/origin/For2.2.2-Fix-Hourier' into For2.2.2...
[hengband/hengband.git] / src / floor / floor.c
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-generator.h" // todo 相互依存している、後で消す.
13 #include "floor/floor-object.h"
14 #include "game-option/birth-options.h"
15 #include "game-option/cheat-options.h"
16 #include "game-option/map-screen-options.h"
17 #include "grid/grid.h"
18 #include "grid/trap.h"
19 #include "mind/mind-ninja.h"
20 #include "monster-floor/monster-generator.h"
21 #include "monster-floor/monster-remover.h"
22 #include "monster-floor/place-monster-types.h"
23 #include "monster/monster-update.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/door-definition.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"
38
39 /*
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
43  */
44 floor_type floor_info;
45
46 bool pattern_tile(floor_type *floor_ptr, POSITION y, POSITION x) { return cave_have_flag_bold(floor_ptr, y, x, FF_PATTERN); }
47
48 /*!
49  * @brief 鍵のかかったドアを配置する
50  * @param player_ptr プレーヤーへの参照ポインタ
51  * @param y 配置したいフロアのY座標
52  * @param x 配置したいフロアのX座標
53  * @return なし
54  */
55 void place_locked_door(player_type *player_ptr, POSITION y, POSITION x)
56 {
57     floor_type *floor_ptr = player_ptr->current_floor_ptr;
58     if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
59         place_bold(player_ptr, y, x, GB_FLOOR);
60         return;
61     }
62
63     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));
64     floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
65     delete_monster(player_ptr, y, x);
66 }
67
68 /*!
69  * @brief 隠しドアを配置する
70  * @param player_ptr プレーヤーへの参照ポインタ
71  * @param y 配置したいフロアのY座標
72  * @param x 配置したいフロアのX座標
73  * @param type DOOR_DEFAULT / DOOR_DOOR / DOOR_GLASS_DOOR / DOOR_CURTAIN のいずれか
74  * @return なし
75  */
76 void place_secret_door(player_type *player_ptr, POSITION y, POSITION x, int type)
77 {
78     floor_type *floor_ptr = player_ptr->current_floor_ptr;
79     if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
80         place_bold(player_ptr, y, x, GB_FLOOR);
81         return;
82     }
83
84     if (type == DOOR_DEFAULT) {
85         type = ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_CURTAIN) && one_in_((d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256))
86             ? DOOR_CURTAIN
87             : ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
88     }
89
90     place_closed_door(player_ptr, y, x, type);
91     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
92     if (type != DOOR_CURTAIN) {
93         g_ptr->mimic = feat_wall_inner;
94         if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat)) {
95             if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY)) {
96                 g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
97             }
98
99             g_ptr->mimic = 0;
100         }
101     }
102
103     g_ptr->info &= ~(CAVE_FLOOR);
104     delete_monster(player_ptr, y, x);
105 }
106
107 static int scent_when = 0;
108
109 /*
110  * Characters leave scent trails for perceptive monsters to track.
111  *
112  * Smell is rather more limited than sound.  Many creatures cannot use
113  * it at all, it doesn't extend very far outwards from the character's
114  * current position, and monsters can use it to home in the character,
115  * but not to run away from him.
116  *
117  * Smell is valued according to age.  When a character takes his turn,
118  * scent is aged by one, and new scent of the current age is laid down.
119  * Speedy characters leave more scent, true, but it also ages faster,
120  * which makes it harder to hunt them down.
121  *
122  * Whenever the age count loops, most of the scent trail is erased and
123  * the age of the remainder is recalculated.
124  */
125 void update_smell(floor_type *floor_ptr, player_type *subject_ptr)
126 {
127     /* Create a table that controls the spread of scent */
128     const int scent_adjust[5][5] = {
129         { -1, 0, 0, 0, -1 },
130         { 0, 1, 1, 1, 0 },
131         { 0, 1, 2, 1, 0 },
132         { 0, 1, 1, 1, 0 },
133         { -1, 0, 0, 0, -1 },
134     };
135
136     if (++scent_when == 254) {
137         for (POSITION y = 0; y < floor_ptr->height; y++) {
138             for (POSITION x = 0; x < floor_ptr->width; x++) {
139                 int w = floor_ptr->grid_array[y][x].when;
140                 floor_ptr->grid_array[y][x].when = (w > 128) ? (w - 128) : 0;
141             }
142         }
143
144         scent_when = 126;
145     }
146
147     for (POSITION i = 0; i < 5; i++) {
148         for (POSITION j = 0; j < 5; j++) {
149             grid_type *g_ptr;
150             POSITION y = i + subject_ptr->y - 2;
151             POSITION x = j + subject_ptr->x - 2;
152             if (!in_bounds(floor_ptr, y, x))
153                 continue;
154
155             g_ptr = &floor_ptr->grid_array[y][x];
156             if (!cave_have_flag_grid(g_ptr, FF_MOVE) && !is_closed_door(subject_ptr, g_ptr->feat))
157                 continue;
158             if (!player_has_los_bold(subject_ptr, y, x))
159                 continue;
160             if (scent_adjust[i][j] == -1)
161                 continue;
162
163             g_ptr->when = scent_when + scent_adjust[i][j];
164         }
165     }
166 }
167
168 /*
169  * Hack -- forget the "flow" information
170  */
171 void forget_flow(floor_type *floor_ptr)
172 {
173     for (POSITION y = 0; y < floor_ptr->height; y++) {
174         for (POSITION x = 0; x < floor_ptr->width; x++) {
175             floor_ptr->grid_array[y][x].dist = 0;
176             floor_ptr->grid_array[y][x].cost = 0;
177             floor_ptr->grid_array[y][x].when = 0;
178         }
179     }
180 }
181
182 /*
183  * Routine used by the random vault creators to add a door to a location
184  * Note that range checking has to be done in the calling routine.
185  *
186  * The doors must be INSIDE the allocated region.
187  */
188 void add_door(player_type *player_ptr, POSITION x, POSITION y)
189 {
190     floor_type *floor_ptr = player_ptr->current_floor_ptr;
191     if (!is_outer_bold(floor_ptr, y, x))
192         return;
193
194     /* look at:
195      *  x#x
196      *  .#.
197      *  x#x
198      *
199      *  where x=don't care
200      *  .=floor, #=wall
201      */
202
203     if (is_floor_bold(floor_ptr, y - 1, x) && is_floor_bold(floor_ptr, y + 1, x)
204         && (is_outer_bold(floor_ptr, y, x - 1) && is_outer_bold(floor_ptr, y, x + 1))) {
205         place_secret_door(player_ptr, y, x, DOOR_DEFAULT);
206         place_bold(player_ptr, y, x - 1, GB_SOLID);
207         place_bold(player_ptr, y, x + 1, GB_SOLID);
208     }
209
210     /* look at:
211      *  x#x
212      *  .#.
213      *  x#x
214      *
215      *  where x = don't care
216      *  .=floor, #=wall
217      */
218     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)) {
219         place_secret_door(player_ptr, y, x, DOOR_DEFAULT);
220         place_bold(player_ptr, y - 1, x, GB_SOLID);
221         place_bold(player_ptr, y + 1, x, GB_SOLID);
222     }
223 }
224
225 /*!
226  * @brief 所定の位置に上り階段か下り階段を配置する / Place an up/down staircase at given location
227  * @param player_ptr プレーヤーへの参照ポインタ
228  * @param y 配置を試みたいマスのY座標
229  * @param x 配置を試みたいマスのX座標
230  * @return なし
231  */
232 void place_random_stairs(player_type *player_ptr, POSITION y, POSITION x)
233 {
234     bool up_stairs = TRUE;
235     bool down_stairs = TRUE;
236     grid_type *g_ptr;
237     floor_type *floor_ptr = player_ptr->current_floor_ptr;
238     g_ptr = &floor_ptr->grid_array[y][x];
239     if (!is_floor_grid(g_ptr) || g_ptr->o_idx)
240         return;
241
242     if (!floor_ptr->dun_level)
243         up_stairs = FALSE;
244     if (ironman_downward)
245         up_stairs = FALSE;
246     if (floor_ptr->dun_level >= d_info[player_ptr->dungeon_idx].maxdepth)
247         down_stairs = FALSE;
248     if (quest_number(player_ptr, floor_ptr->dun_level) && (floor_ptr->dun_level > 1))
249         down_stairs = FALSE;
250
251     if (down_stairs && up_stairs) {
252         if (randint0(100) < 50)
253             up_stairs = FALSE;
254         else
255             down_stairs = FALSE;
256     }
257
258     if (up_stairs)
259         set_cave_feat(floor_ptr, y, x, feat_up_stair);
260     else if (down_stairs)
261         set_cave_feat(floor_ptr, y, x, feat_down_stair);
262 }
263
264 /*!
265  * @brief LOS(Line Of Sight / 視線が通っているか)の判定を行う。
266  * @param player_ptr プレーヤーへの参照ポインタ
267  * @param y1 始点のy座標
268  * @param x1 始点のx座標
269  * @param y2 終点のy座標
270  * @param x2 終点のx座標
271  * @return LOSが通っているならTRUEを返す。
272  * @details
273  * A simple, fast, integer-based line-of-sight algorithm.  By Joseph Hall,\n
274  * 4116 Brewster Drive, Raleigh NC 27606.  Email to jnh@ecemwl.ncsu.edu.\n
275  *\n
276  * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).\n
277  *\n
278  * The LOS begins at the center of the tile (x1,y1) and ends at the center of\n
279  * the tile (x2,y2).  If los() is to return TRUE, all of the tiles this line\n
280  * passes through must be floor tiles, except for (x1,y1) and (x2,y2).\n
281  *\n
282  * We assume that the "mathematical corner" of a non-floor tile does not\n
283  * block line of sight.\n
284  *\n
285  * Because this function uses (short) ints for all calculations, overflow may\n
286  * occur if dx and dy exceed 90.\n
287  *\n
288  * Once all the degenerate cases are eliminated, the values "qx", "qy", and\n
289  * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that\n
290  * we can use integer arithmetic.\n
291  *\n
292  * We travel from start to finish along the longer axis, starting at the border\n
293  * between the first and second tiles, where the y offset = .5 * slope, taking\n
294  * into account the scale factor.  See below.\n
295  *\n
296  * Also note that this function and the "move towards target" code do NOT\n
297  * share the same properties.  Thus, you can see someone, target them, and\n
298  * then fire a bolt at them, but the bolt may hit a wall, not them.  However\n,
299  * by clever choice of target locations, you can sometimes throw a "curve".\n
300  *\n
301  * Note that "line of sight" is not "reflexive" in all cases.\n
302  *\n
303  * Use the "projectable()" routine to test "spell/missile line of sight".\n
304  *\n
305  * Use the "update_view()" function to determine player line-of-sight.\n
306  */
307 bool los(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
308 {
309     POSITION dy = y2 - y1;
310     POSITION dx = x2 - x1;
311     POSITION ay = ABS(dy);
312     POSITION ax = ABS(dx);
313     if ((ax < 2) && (ay < 2))
314         return TRUE;
315
316     /* Directly South/North */
317     floor_type *floor_ptr = player_ptr->current_floor_ptr;
318     POSITION tx, ty;
319     if (!dx) {
320         /* South -- check for walls */
321         if (dy > 0) {
322             for (ty = y1 + 1; ty < y2; ty++) {
323                 if (!cave_los_bold(floor_ptr, ty, x1))
324                     return FALSE;
325             }
326         }
327
328         /* North -- check for walls */
329         else {
330             for (ty = y1 - 1; ty > y2; ty--) {
331                 if (!cave_los_bold(floor_ptr, ty, x1))
332                     return FALSE;
333             }
334         }
335
336         /* Assume los */
337         return TRUE;
338     }
339
340     /* Directly East/West */
341     if (!dy) {
342         /* East -- check for walls */
343         if (dx > 0) {
344             for (tx = x1 + 1; tx < x2; tx++) {
345                 if (!cave_los_bold(floor_ptr, y1, tx))
346                     return FALSE;
347             }
348         }
349
350         /* West -- check for walls */
351         else {
352             for (tx = x1 - 1; tx > x2; tx--) {
353                 if (!cave_los_bold(floor_ptr, y1, tx))
354                     return FALSE;
355             }
356         }
357
358         return TRUE;
359     }
360
361     POSITION sx = (dx < 0) ? -1 : 1;
362     POSITION sy = (dy < 0) ? -1 : 1;
363
364     if (ax == 1) {
365         if (ay == 2) {
366             if (cave_los_bold(floor_ptr, y1 + sy, x1))
367                 return TRUE;
368         }
369     } else if (ay == 1) {
370         if (ax == 2) {
371             if (cave_los_bold(floor_ptr, y1, x1 + sx))
372                 return TRUE;
373         }
374     }
375
376     POSITION f2 = (ax * ay);
377     POSITION f1 = f2 << 1;
378     POSITION qy;
379     POSITION m;
380     if (ax >= ay) {
381         qy = ay * ay;
382         m = qy << 1;
383         tx = x1 + sx;
384         if (qy == f2) {
385             ty = y1 + sy;
386             qy -= f1;
387         } else {
388             ty = y1;
389         }
390
391         /* Note (below) the case (qy == f2), where */
392         /* the LOS exactly meets the corner of a tile. */
393         while (x2 - tx) {
394             if (!cave_los_bold(floor_ptr, ty, tx))
395                 return FALSE;
396
397             qy += m;
398
399             if (qy < f2) {
400                 tx += sx;
401                 continue;
402             }
403
404             if (qy > f2) {
405                 ty += sy;
406                 if (!cave_los_bold(floor_ptr, ty, tx))
407                     return FALSE;
408                 qy -= f1;
409                 tx += sx;
410                 continue;
411             }
412
413             ty += sy;
414             qy -= f1;
415             tx += sx;
416         }
417
418         return TRUE;
419     }
420
421     /* Travel vertically */
422     POSITION qx = ax * ax;
423     m = qx << 1;
424     ty = y1 + sy;
425     if (qx == f2) {
426         tx = x1 + sx;
427         qx -= f1;
428     } else {
429         tx = x1;
430     }
431
432     /* Note (below) the case (qx == f2), where */
433     /* the LOS exactly meets the corner of a tile. */
434     while (y2 - ty) {
435         if (!cave_los_bold(floor_ptr, ty, tx))
436             return FALSE;
437
438         qx += m;
439
440         if (qx < f2) {
441             ty += sy;
442             continue;
443         }
444
445         if (qx > f2) {
446             tx += sx;
447             if (!cave_los_bold(floor_ptr, ty, tx))
448                 return FALSE;
449             qx -= f1;
450             ty += sy;
451             continue;
452         }
453
454         tx += sx;
455         qx -= f1;
456         ty += sy;
457     }
458
459     return TRUE;
460 }
461
462 /*!
463  * @briefプレイヤーの攻撃射程(マス) / Maximum range (spells, etc)
464  * @param creature_ptr プレーヤーへの参照ポインタ
465  * @return 射程
466  */
467 int get_max_range(player_type *creature_ptr) { return creature_ptr->phase_out ? 36 : 18; }
468
469 /*
470  * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
471  * at the final destination, assuming no monster gets in the way.
472  *
473  * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
474  */
475 bool projectable(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
476 {
477     u16b grid_g[512];
478     int grid_n = project_path(player_ptr, grid_g, (project_length ? project_length : get_max_range(player_ptr)), y1, x1, y2, x2, 0);
479     if (!grid_n)
480         return TRUE;
481
482     POSITION y = GRID_Y(grid_g[grid_n - 1]);
483     POSITION x = GRID_X(grid_g[grid_n - 1]);
484     if ((y != y2) || (x != x2))
485         return FALSE;
486
487     return TRUE;
488 }
489
490 /*
491  * Grid based version of "creature_bold()"
492  */
493 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
495 /*
496  * Grid based version of "cave_empty_bold()"
497  */
498 static bool is_cave_empty_grid(player_type *player_ptr, grid_type *g_ptr)
499 {
500     bool is_empty_grid = cave_have_flag_grid(g_ptr, FF_PLACE);
501     is_empty_grid &= g_ptr->m_idx == 0;
502     is_empty_grid &= !player_grid(player_ptr, g_ptr);
503     return is_empty_grid;
504 }
505
506 /*!
507  * @brief 特殊な部屋地形向けにモンスターを配置する / Place some sleeping monsters near the given location
508  * @param player_ptr プレーヤーへの参照ポインタ
509  * @param y1 モンスターを配置したいマスの中心Y座標
510  * @param x1 モンスターを配置したいマスの中心X座標
511  * @param num 配置したいモンスターの数
512  * @return なし
513  * @details
514  * Only really called by some of the "vault" routines.
515  */
516 void vault_monsters(player_type *player_ptr, POSITION y1, POSITION x1, int num)
517 {
518     floor_type *floor_ptr = player_ptr->current_floor_ptr;
519     for (int k = 0; k < num; k++) {
520         for (int i = 0; i < 9; i++) {
521             int d = 1;
522             POSITION y, x;
523             scatter(player_ptr, &y, &x, y1, x1, d, 0);
524             grid_type *g_ptr;
525             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
526             if (!is_cave_empty_grid(player_ptr, g_ptr))
527                 continue;
528
529             floor_ptr->monster_level = floor_ptr->base_level + 2;
530             (void)place_monster(player_ptr, y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
531             floor_ptr->monster_level = floor_ptr->base_level;
532         }
533     }
534 }
535
536 /*!
537  * @brief 指定された座標が地震や階段生成の対象となるマスかを返す。 / Determine if a given location may be "destroyed"
538  * @param player_ptr プレーヤーへの参照ポインタ
539  * @param y y座標
540  * @param x x座標
541  * @return 各種の変更が可能ならTRUEを返す。
542  * @details
543  * 条件は永久地形でなく、なおかつ該当のマスにアーティファクトが存在しないか、である。英語の旧コメントに反して*破壊*の抑止判定には現在使われていない。
544  */
545 bool cave_valid_bold(floor_type *floor_ptr, POSITION y, POSITION x)
546 {
547     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
548     if (cave_have_flag_grid(g_ptr, FF_PERMANENT))
549         return FALSE;
550
551     OBJECT_IDX next_o_idx = 0;
552     for (OBJECT_IDX this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
553         object_type *o_ptr;
554         o_ptr = &floor_ptr->o_list[this_o_idx];
555         next_o_idx = o_ptr->next_o_idx;
556         if (object_is_artifact(o_ptr))
557             return FALSE;
558     }
559
560     return TRUE;
561 }
562
563 /*
564  * Determine if a "legal" grid is within "los" of the player *
565  * Note the use of comparison to zero to force a "boolean" result
566  */
567 static bool player_has_los_grid(grid_type *g_ptr) { return (g_ptr->info & CAVE_VIEW) != 0; }
568
569 /*
570  * Change the "feat" flag for a grid, and notice/redraw the grid
571  */
572 void cave_set_feat(player_type *player_ptr, POSITION y, POSITION x, FEAT_IDX feat)
573 {
574     floor_type *floor_ptr = player_ptr->current_floor_ptr;
575     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
576     feature_type *f_ptr = &f_info[feat];
577     if (!current_world_ptr->character_dungeon) {
578         g_ptr->mimic = 0;
579         g_ptr->feat = feat;
580         if (have_flag(f_ptr->flags, FF_GLOW) && !(d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) {
581             for (DIRECTION i = 0; i < 9; i++) {
582                 POSITION yy = y + ddy_ddd[i];
583                 POSITION xx = x + ddx_ddd[i];
584                 if (!in_bounds2(floor_ptr, yy, xx))
585                     continue;
586                 floor_ptr->grid_array[yy][xx].info |= CAVE_GLOW;
587             }
588         }
589
590         return;
591     }
592
593     bool old_los = cave_have_flag_bold(floor_ptr, y, x, FF_LOS);
594     bool old_mirror = is_mirror_grid(g_ptr);
595
596     g_ptr->mimic = 0;
597     g_ptr->feat = feat;
598     g_ptr->info &= ~(CAVE_OBJECT);
599     if (old_mirror && (d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) {
600         g_ptr->info &= ~(CAVE_GLOW);
601         if (!view_torch_grids)
602             g_ptr->info &= ~(CAVE_MARK);
603
604         update_local_illumination(player_ptr, y, x);
605     }
606
607     if (!have_flag(f_ptr->flags, FF_REMEMBER))
608         g_ptr->info &= ~(CAVE_MARK);
609     if (g_ptr->m_idx)
610         update_monster(player_ptr, g_ptr->m_idx, FALSE);
611
612     note_spot(player_ptr, y, x);
613     lite_spot(player_ptr, y, x);
614     if (old_los ^ have_flag(f_ptr->flags, FF_LOS)) {
615
616 #ifdef COMPLEX_WALL_ILLUMINATION /* COMPLEX_WALL_ILLUMINATION */
617
618         update_local_illumination(player_ptr, y, x);
619
620 #endif /* COMPLEX_WALL_ILLUMINATION */
621
622         player_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE | PU_MONSTERS);
623     }
624
625     if (!have_flag(f_ptr->flags, FF_GLOW) || (d_info[player_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
626         return;
627
628     for (DIRECTION i = 0; i < 9; i++) {
629         POSITION yy = y + ddy_ddd[i];
630         POSITION xx = x + ddx_ddd[i];
631         if (!in_bounds2(floor_ptr, yy, xx))
632             continue;
633
634         grid_type *cc_ptr;
635         cc_ptr = &floor_ptr->grid_array[yy][xx];
636         cc_ptr->info |= CAVE_GLOW;
637
638         if (player_has_los_grid(cc_ptr)) {
639             if (cc_ptr->m_idx)
640                 update_monster(player_ptr, cc_ptr->m_idx, FALSE);
641             note_spot(player_ptr, yy, xx);
642             lite_spot(player_ptr, yy, xx);
643         }
644
645         update_local_illumination(player_ptr, yy, xx);
646     }
647
648     if (player_ptr->special_defense & NINJA_S_STEALTH) {
649         if (floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW)
650             set_superstealth(player_ptr, FALSE);
651     }
652 }
653
654 /*!
655  * @brief 所定の位置にさまざまな状態や種類のドアを配置する / Place a random type of door at the given location
656  * @param player_ptr プレーヤーへの参照ポインタ
657  * @param y ドアの配置を試みたいマスのY座標
658  * @param x ドアの配置を試みたいマスのX座標
659  * @param room 部屋に接している場合向けのドア生成か否か
660  * @return なし
661  */
662 void place_random_door(player_type *player_ptr, POSITION y, POSITION x, bool room)
663 {
664     floor_type *floor_ptr = player_ptr->current_floor_ptr;
665     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
666     g_ptr->mimic = 0;
667
668     if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
669         place_bold(player_ptr, y, x, GB_FLOOR);
670         return;
671     }
672
673     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))
674         ? DOOR_CURTAIN
675         : ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
676
677     int tmp = randint0(1000);
678     FEAT_IDX feat = feat_none;
679     if (tmp < 300) {
680         feat = feat_door[type].open;
681     } else if (tmp < 400) {
682         feat = feat_door[type].broken;
683     } else if (tmp < 600) {
684         place_closed_door(player_ptr, y, x, type);
685
686         if (type != DOOR_CURTAIN) {
687             g_ptr->mimic = room ? feat_wall_outer : feat_wall_type[randint0(100)];
688             if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat)) {
689                 if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY)) {
690                     g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
691                 }
692                 g_ptr->mimic = 0;
693             }
694         }
695     } else {
696         place_closed_door(player_ptr, y, x, type);
697     }
698
699     if (tmp >= 400) {
700         delete_monster(player_ptr, y, x);
701         return;
702     }
703
704     if (feat != feat_none) {
705         set_cave_feat(floor_ptr, y, x, feat);
706     } else {
707         place_bold(player_ptr, y, x, GB_FLOOR);
708     }
709
710     delete_monster(player_ptr, y, x);
711 }
712
713 /*!
714  * @brief グローバルオブジェクト配列を初期化する /
715  * Delete all the items when player leaves the level
716  * @note we do NOT visually reflect these (irrelevant) changes
717  * @details
718  * Hack -- we clear the "g_ptr->o_idx" field for every grid,
719  * and the "m_ptr->next_o_idx" field for every monster, since
720  * we know we are clearing every object.  Technically, we only
721  * clear those fields for grids/monsters containing objects,
722  * and we clear it once for every such object.
723  * @return なし
724  */
725 void wipe_o_list(floor_type *floor_ptr)
726 {
727     for (int i = 1; i < floor_ptr->o_max; i++) {
728         object_type *o_ptr = &floor_ptr->o_list[i];
729         if (!object_is_valid(o_ptr))
730             continue;
731
732         if (!current_world_ptr->character_dungeon || preserve_mode) {
733             if (object_is_fixed_artifact(o_ptr) && !object_is_known(o_ptr)) {
734                 a_info[o_ptr->name1].cur_num = 0;
735             }
736         }
737
738         if (object_is_held_monster(o_ptr)) {
739             monster_type *m_ptr;
740             m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
741             m_ptr->hold_o_idx = 0;
742             object_wipe(o_ptr);
743             continue;
744         }
745
746         grid_type *g_ptr;
747         POSITION y = o_ptr->iy;
748         POSITION x = o_ptr->ix;
749
750         g_ptr = &floor_ptr->grid_array[y][x];
751         g_ptr->o_idx = 0;
752         object_wipe(o_ptr);
753     }
754
755     floor_ptr->o_max = 1;
756     floor_ptr->o_cnt = 0;
757 }
758
759 /*!
760  * @brief 所定の位置に各種の閉じたドアを配置する / Place a random type of normal door at the given location.
761  * @param player_ptr プレーヤーへの参照ポインタ
762  * @param y ドアの配置を試みたいマスのY座標
763  * @param x ドアの配置を試みたいマスのX座標
764  * @param type ドアの地形ID
765  * @return なし
766  */
767 void place_closed_door(player_type *player_ptr, POSITION y, POSITION x, int type)
768 {
769     floor_type *floor_ptr = player_ptr->current_floor_ptr;
770     if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
771         place_bold(player_ptr, y, x, GB_FLOOR);
772         return;
773     }
774
775     int tmp = randint0(400);
776     FEAT_IDX feat = feat_none;
777     if (tmp < 300) {
778         /* Create closed door */
779         feat = feat_door[type].closed;
780     } else if (tmp < 399) {
781         feat = feat_locked_door_random(type);
782     } else {
783         feat = feat_jammed_door_random(type);
784     }
785
786     if (feat == feat_none) {
787         place_bold(player_ptr, y, x, GB_FLOOR);
788         return;
789     }
790
791     cave_set_feat(player_ptr, y, x, feat);
792     floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
793 }
794
795 /*!
796  * @brief 指定のマスが床系地形であるかを返す / Function that sees if a square is a floor.  (Includes range checking.)
797  * @param x チェックするマスのX座標
798  * @param y チェックするマスのY座標
799  * @return 床系地形ならばTRUE
800  */
801 bool get_is_floor(floor_type *floor_ptr, POSITION x, POSITION y)
802 {
803     if (!in_bounds(floor_ptr, y, x)) {
804         return FALSE;
805     }
806
807     if (is_floor_bold(floor_ptr, y, x))
808         return TRUE;
809
810     return FALSE;
811 }
812
813 FEAT_IDX conv_dungeon_feat(floor_type *floor_ptr, FEAT_IDX newfeat)
814 {
815     feature_type *f_ptr = &f_info[newfeat];
816     if (have_flag(f_ptr->flags, FF_CONVERT)) {
817         switch (f_ptr->subtype) {
818         case CONVERT_TYPE_FLOOR:
819             return feat_ground_type[randint0(100)];
820         case CONVERT_TYPE_WALL:
821             return feat_wall_type[randint0(100)];
822         case CONVERT_TYPE_INNER:
823             return feat_wall_inner;
824         case CONVERT_TYPE_OUTER:
825             return feat_wall_outer;
826         case CONVERT_TYPE_SOLID:
827             return feat_wall_solid;
828         case CONVERT_TYPE_STREAM1:
829             return d_info[floor_ptr->dungeon_idx].stream1;
830         case CONVERT_TYPE_STREAM2:
831             return d_info[floor_ptr->dungeon_idx].stream2;
832         default:
833             return newfeat;
834         }
835     } else
836         return newfeat;
837 }
838
839 /*!
840  * @brief 特殊な部屋向けに各種アイテムを配置する / Create up to "num" objects near the given coordinates
841  * @param player_ptr プレーヤーへの参照ポインタ
842  * @param y 配置したい中心マスのY座標
843  * @param x 配置したい中心マスのX座標
844  * @param num 配置したい数
845  * @return なし
846  * @details
847  * Only really called by some of the "vault" routines.
848  */
849 void vault_objects(player_type *player_ptr, POSITION y, POSITION x, int num)
850 {
851     floor_type *floor_ptr = player_ptr->current_floor_ptr;
852     for (; num > 0; --num) {
853         int j = y, k = x;
854         int dummy = 0;
855         for (int i = 0; i < 11; ++i) {
856             while (dummy < SAFE_MAX_ATTEMPTS) {
857                 j = rand_spread(y, 2);
858                 k = rand_spread(x, 3);
859                 dummy++;
860                 if (!in_bounds(floor_ptr, j, k))
861                     continue;
862                 break;
863             }
864
865             if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room) {
866                 msg_print(_("警告!地下室のアイテムを配置できません!", "Warning! Could not place vault object!"));
867             }
868
869             grid_type *g_ptr;
870             g_ptr = &floor_ptr->grid_array[j][k];
871             if (!is_floor_grid(g_ptr) || g_ptr->o_idx)
872                 continue;
873
874             if (randint0(100) < 75) {
875                 place_object(player_ptr, j, k, 0L);
876             } else {
877                 place_gold(player_ptr, j, k);
878             }
879
880             break;
881         }
882     }
883 }
884
885 /*!
886  * @brief 始点から終点への直線経路を返す /
887  * Determine the path taken by a projection.
888  * @param player_ptr プレーヤーへの参照ポインタ
889  * @param gp 経路座標リストを返す参照ポインタ
890  * @param range 距離
891  * @param y1 始点Y座標
892  * @param x1 始点X座標
893  * @param y2 終点Y座標
894  * @param x2 終点X座標
895  * @param flg フラグID
896  * @return リストの長さ
897  * @details
898  * <pre>
899  * The projection will always start from the grid (y1,x1), and will travel
900  * towards the grid (y2,x2), touching one grid per unit of distance along
901  * the major axis, and stopping when it enters the destination grid or a
902  * wall grid, or has travelled the maximum legal distance of "range".
903  *
904  * Note that "distance" in this function (as in the "update_view()" code)
905  * is defined as "MAX(dy,dx) + MIN(dy,dx)/2", which means that the player
906  * actually has an "octagon of projection" not a "circle of projection".
907  *
908  * The path grids are saved into the grid array pointed to by "gp", and
909  * there should be room for at least "range" grids in "gp".  Note that
910  * due to the way in which distance is calculated, this function normally
911  * uses fewer than "range" grids for the projection path, so the result
912  * of this function should never be compared directly to "range".  Note
913  * that the initial grid (y1,x1) is never saved into the grid array, not
914  * even if the initial grid is also the final grid.
915  *
916  * The "flg" flags can be used to modify the behavior of this function.
917  *
918  * In particular, the "PROJECT_STOP" and "PROJECT_THRU" flags have the same
919  * semantics as they do for the "project" function, namely, that the path
920  * will stop as soon as it hits a monster, or that the path will continue
921  * through the destination grid, respectively.
922  *
923  * The "PROJECT_JUMP" flag, which for the "project()" function means to
924  * start at a special grid (which makes no sense in this function), means
925  * that the path should be "angled" slightly if needed to avoid any wall
926  * grids, allowing the player to "target" any grid which is in "view".
927  * This flag is non-trivial and has not yet been implemented, but could
928  * perhaps make use of the "vinfo" array (above).
929  *
930  * This function returns the number of grids (if any) in the path.  This
931  * function will return zero if and only if (y1,x1) and (y2,x2) are equal.
932  *
933  * This algorithm is similar to, but slightly different from, the one used
934  * by "update_view_los()", and very different from the one used by "los()".
935  * </pre>
936  */
937 int project_path(player_type *player_ptr, u16b *gp, POSITION range, POSITION y1, POSITION x1, POSITION y2, POSITION x2, BIT_FLAGS flg)
938 {
939     if ((x1 == x2) && (y1 == y2))
940         return 0;
941
942     POSITION y, x;
943     POSITION ay, ax;
944     POSITION sy, sx;
945     int frac;
946     int m;
947
948     if (y2 < y1) {
949         ay = (y1 - y2);
950         sy = -1;
951     } else {
952         ay = (y2 - y1);
953         sy = 1;
954     }
955
956     if (x2 < x1) {
957         ax = (x1 - x2);
958         sx = -1;
959     } else {
960         ax = (x2 - x1);
961         sx = 1;
962     }
963
964     int half = (ay * ax);
965     int full = half << 1;
966
967     /* Vertical */
968     floor_type *floor_ptr = player_ptr->current_floor_ptr;
969     int n = 0;
970     int k = 0;
971     if (ay > ax) {
972         m = ax * ax * 2;
973         y = y1 + sy;
974         x = x1;
975         frac = m;
976         if (frac > half) {
977             x += sx;
978             frac -= full;
979             k++;
980         }
981
982         while (TRUE) {
983             gp[n++] = GRID(y, x);
984             if ((n + (k >> 1)) >= range)
985                 break;
986
987             if (!(flg & (PROJECT_THRU))) {
988                 if ((x == x2) && (y == y2))
989                     break;
990             }
991
992             if (flg & (PROJECT_DISI)) {
993                 if ((n > 0) && cave_stop_disintegration(floor_ptr, y, x))
994                     break;
995             } else if (flg & (PROJECT_LOS)) {
996                 if ((n > 0) && !cave_los_bold(floor_ptr, y, x))
997                     break;
998             } else if (!(flg & (PROJECT_PATH))) {
999                 if ((n > 0) && !cave_have_flag_bold(floor_ptr, y, x, FF_PROJECT))
1000                     break;
1001             }
1002
1003             if (flg & (PROJECT_STOP)) {
1004                 if ((n > 0) && (player_bold(player_ptr, y, x) || floor_ptr->grid_array[y][x].m_idx != 0))
1005                     break;
1006             }
1007
1008             if (!in_bounds(floor_ptr, y, x))
1009                 break;
1010
1011             if (m) {
1012                 frac += m;
1013                 if (frac > half) {
1014                     x += sx;
1015                     frac -= full;
1016                     k++;
1017                 }
1018             }
1019
1020             y += sy;
1021         }
1022
1023         return n;
1024     }
1025
1026     /* Horizontal */
1027     if (ax > ay) {
1028         m = ay * ay * 2;
1029         y = y1;
1030         x = x1 + sx;
1031         frac = m;
1032         if (frac > half) {
1033             y += sy;
1034             frac -= full;
1035             k++;
1036         }
1037
1038         while (TRUE) {
1039             gp[n++] = GRID(y, x);
1040             if ((n + (k >> 1)) >= range)
1041                 break;
1042
1043             if (!(flg & (PROJECT_THRU))) {
1044                 if ((x == x2) && (y == y2))
1045                     break;
1046             }
1047
1048             if (flg & (PROJECT_DISI)) {
1049                 if ((n > 0) && cave_stop_disintegration(floor_ptr, y, x))
1050                     break;
1051             } else if (flg & (PROJECT_LOS)) {
1052                 if ((n > 0) && !cave_los_bold(floor_ptr, y, x))
1053                     break;
1054             } else if (!(flg & (PROJECT_PATH))) {
1055                 if ((n > 0) && !cave_have_flag_bold(floor_ptr, y, x, FF_PROJECT))
1056                     break;
1057             }
1058
1059             if (flg & (PROJECT_STOP)) {
1060                 if ((n > 0) && (player_bold(player_ptr, y, x) || floor_ptr->grid_array[y][x].m_idx != 0))
1061                     break;
1062             }
1063
1064             if (!in_bounds(floor_ptr, y, x))
1065                 break;
1066
1067             if (m) {
1068                 frac += m;
1069                 if (frac > half) {
1070                     y += sy;
1071                     frac -= full;
1072                     k++;
1073                 }
1074             }
1075
1076             x += sx;
1077         }
1078
1079         return n;
1080     }
1081
1082     y = y1 + sy;
1083     x = x1 + sx;
1084
1085     while (TRUE) {
1086         gp[n++] = GRID(y, x);
1087         if ((n + (n >> 1)) >= range)
1088             break;
1089
1090         if (!(flg & (PROJECT_THRU))) {
1091             if ((x == x2) && (y == y2))
1092                 break;
1093         }
1094
1095         if (flg & (PROJECT_DISI)) {
1096             if ((n > 0) && cave_stop_disintegration(floor_ptr, y, x))
1097                 break;
1098         } else if (flg & (PROJECT_LOS)) {
1099             if ((n > 0) && !cave_los_bold(floor_ptr, y, x))
1100                 break;
1101         } else if (!(flg & (PROJECT_PATH))) {
1102             if ((n > 0) && !cave_have_flag_bold(floor_ptr, y, x, FF_PROJECT))
1103                 break;
1104         }
1105
1106         if (flg & (PROJECT_STOP)) {
1107             if ((n > 0) && (player_bold(player_ptr, y, x) || floor_ptr->grid_array[y][x].m_idx != 0))
1108                 break;
1109         }
1110
1111         if (!in_bounds(floor_ptr, y, x))
1112             break;
1113
1114         y += sy;
1115         x += sx;
1116     }
1117
1118     return n;
1119 }
1120
1121 /*!
1122  * @brief 指定のマスを床地形に変える / Set a square to be floor.  (Includes range checking.)
1123  * @param player_ptr プレーヤーへの参照ポインタ
1124  * @param x 地形を変えたいマスのX座標
1125  * @param y 地形を変えたいマスのY座標
1126  * @return なし
1127  */
1128 void set_floor(player_type *player_ptr, POSITION x, POSITION y)
1129 {
1130     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1131     if (!in_bounds(floor_ptr, y, x)) {
1132         return;
1133     }
1134
1135     if (floor_ptr->grid_array[y][x].info & CAVE_ROOM) {
1136         return;
1137     }
1138
1139     if (is_extra_bold(floor_ptr, y, x))
1140         place_bold(player_ptr, y, x, GB_FLOOR);
1141 }
1142
1143 /*!
1144  * @brief フロアの指定位置に生成階に応じたベースアイテムの生成を行う。
1145  * Attempt to place an object (normal or good/great) at the given location.
1146  * @param owner_ptr プレーヤーへの参照ポインタ
1147  * @param y 配置したいフロアのY座標
1148  * @param x 配置したいフロアのX座標
1149  * @param mode オプションフラグ
1150  * @return 生成に成功したらTRUEを返す。
1151  * @details
1152  * This routine plays nasty games to generate the "special artifacts".\n
1153  * This routine uses "object_level" for the "generation level".\n
1154  * This routine requires a clean floor grid destination.\n
1155  */
1156 void place_object(player_type *owner_ptr, POSITION y, POSITION x, BIT_FLAGS mode)
1157 {
1158     floor_type *floor_ptr = owner_ptr->current_floor_ptr;
1159     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
1160     object_type forge;
1161     object_type *q_ptr;
1162     if (!in_bounds(floor_ptr, y, x))
1163         return;
1164     if (!cave_drop_bold(floor_ptr, y, x))
1165         return;
1166     if (g_ptr->o_idx)
1167         return;
1168
1169     q_ptr = &forge;
1170     object_wipe(q_ptr);
1171     if (!make_object(owner_ptr, q_ptr, mode))
1172         return;
1173
1174     OBJECT_IDX o_idx = o_pop(floor_ptr);
1175     if (o_idx == 0) {
1176         if (object_is_fixed_artifact(q_ptr)) {
1177             a_info[q_ptr->name1].cur_num = 0;
1178         }
1179
1180         return;
1181     }
1182
1183     object_type *o_ptr;
1184     o_ptr = &floor_ptr->o_list[o_idx];
1185     object_copy(o_ptr, q_ptr);
1186
1187     o_ptr->iy = y;
1188     o_ptr->ix = x;
1189     o_ptr->next_o_idx = g_ptr->o_idx;
1190
1191     g_ptr->o_idx = o_idx;
1192     note_spot(owner_ptr, y, x);
1193     lite_spot(owner_ptr, y, x);
1194 }
1195
1196 /*!
1197  * @brief フロアの指定位置に生成階に応じた財宝オブジェクトの生成を行う。
1198  * Places a treasure (Gold or Gems) at given location
1199  * @param player_ptr プレーヤーへの参照ポインタ
1200  * @param y 配置したいフロアのY座標
1201  * @param x 配置したいフロアのX座標
1202  * @return 生成に成功したらTRUEを返す。
1203  * @details
1204  * The location must be a legal, clean, floor grid.
1205  */
1206 void place_gold(player_type *player_ptr, POSITION y, POSITION x)
1207 {
1208     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1209     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
1210     if (!in_bounds(floor_ptr, y, x))
1211         return;
1212     if (!cave_drop_bold(floor_ptr, y, x))
1213         return;
1214     if (g_ptr->o_idx)
1215         return;
1216
1217     object_type forge;
1218     object_type *q_ptr;
1219     q_ptr = &forge;
1220     object_wipe(q_ptr);
1221     if (!make_gold(player_ptr, q_ptr))
1222         return;
1223
1224     OBJECT_IDX o_idx = o_pop(floor_ptr);
1225     if (o_idx == 0)
1226         return;
1227
1228     object_type *o_ptr;
1229     o_ptr = &floor_ptr->o_list[o_idx];
1230     object_copy(o_ptr, q_ptr);
1231
1232     o_ptr->iy = y;
1233     o_ptr->ix = x;
1234     o_ptr->next_o_idx = g_ptr->o_idx;
1235
1236     g_ptr->o_idx = o_idx;
1237     note_spot(player_ptr, y, x);
1238     lite_spot(player_ptr, y, x);
1239 }
1240
1241 /*!
1242  * @brief 指定位置に存在するモンスターを削除する / Delete the monster, if any, at a given location
1243  * @param player_ptr プレーヤーへの参照ポインタ
1244  * @param x 削除位置x座標
1245  * @param y 削除位置y座標
1246  * @return なし
1247  */
1248 void delete_monster(player_type *player_ptr, POSITION y, POSITION x)
1249 {
1250     grid_type *g_ptr;
1251     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1252     if (!in_bounds(floor_ptr, y, x))
1253         return;
1254
1255     g_ptr = &floor_ptr->grid_array[y][x];
1256     if (g_ptr->m_idx)
1257         delete_monster_idx(player_ptr, g_ptr->m_idx);
1258 }
1259
1260 /*!
1261  * @brief グローバルオブジェクト配列に対し指定範囲のオブジェクトを整理してIDの若い順に寄せる /
1262  * Move an object from index i1 to index i2 in the object list
1263  * @param i1 整理したい配列の始点
1264  * @param i2 整理したい配列の終点
1265  * @return なし
1266  */
1267 static void compact_objects_aux(floor_type *floor_ptr, OBJECT_IDX i1, OBJECT_IDX i2)
1268 {
1269     if (i1 == i2)
1270         return;
1271
1272     object_type *o_ptr;
1273     for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++) {
1274         o_ptr = &floor_ptr->o_list[i];
1275         if (!o_ptr->k_idx)
1276             continue;
1277
1278         if (o_ptr->next_o_idx == i1) {
1279             o_ptr->next_o_idx = i2;
1280         }
1281     }
1282
1283     o_ptr = &floor_ptr->o_list[i1];
1284
1285     if (object_is_held_monster(o_ptr)) {
1286         monster_type *m_ptr;
1287         m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
1288         if (m_ptr->hold_o_idx == i1) {
1289             m_ptr->hold_o_idx = i2;
1290         }
1291     } else {
1292         POSITION y = o_ptr->iy;
1293         POSITION x = o_ptr->ix;
1294         grid_type *g_ptr;
1295         g_ptr = &floor_ptr->grid_array[y][x];
1296
1297         if (g_ptr->o_idx == i1) {
1298             g_ptr->o_idx = i2;
1299         }
1300     }
1301
1302     floor_ptr->o_list[i2] = floor_ptr->o_list[i1];
1303     object_wipe(o_ptr);
1304 }
1305
1306 /*!
1307  * @brief グローバルオブジェクト配列から優先度の低いものを削除し、データを圧縮する。 /
1308  * Compact and Reorder the object list.
1309  * @param player_ptr プレーヤーへの参照ポインタ
1310  * @param size 最低でも減らしたいオブジェクト数の水準
1311  * @return なし
1312  * @details
1313  * (危険なので使用には注意すること)
1314  * This function can be very dangerous, use with caution!\n
1315  *\n
1316  * When actually "compacting" objects, we base the saving throw on a\n
1317  * combination of object level, distance from player, and current\n
1318  * "desperation".\n
1319  *\n
1320  * After "compacting" (if needed), we "reorder" the objects into a more\n
1321  * compact order, and we reset the allocation info, and the "live" array.\n
1322  */
1323 void compact_objects(player_type *player_ptr, int size)
1324 {
1325     object_type *o_ptr;
1326     if (size) {
1327         msg_print(_("アイテム情報を圧縮しています...", "Compacting objects..."));
1328         player_ptr->redraw |= (PR_MAP);
1329         player_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
1330     }
1331
1332     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1333     for (int num = 0, cnt = 1; num < size; cnt++) {
1334         int cur_lev = 5 * cnt;
1335         int cur_dis = 5 * (20 - cnt);
1336         for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++) {
1337             o_ptr = &floor_ptr->o_list[i];
1338
1339             if (!object_is_valid(o_ptr))
1340                 continue;
1341             if (k_info[o_ptr->k_idx].level > cur_lev)
1342                 continue;
1343
1344             POSITION y, x;
1345             if (object_is_held_monster(o_ptr)) {
1346                 monster_type *m_ptr;
1347                 m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
1348                 y = m_ptr->fy;
1349                 x = m_ptr->fx;
1350
1351                 if (randint0(100) < 90)
1352                     continue;
1353             } else {
1354                 y = o_ptr->iy;
1355                 x = o_ptr->ix;
1356             }
1357
1358             if ((cur_dis > 0) && (distance(player_ptr->y, player_ptr->x, y, x) < cur_dis))
1359                 continue;
1360
1361             int chance = 90;
1362             if ((object_is_fixed_artifact(o_ptr) || o_ptr->art_name) && (cnt < 1000))
1363                 chance = 100;
1364
1365             if (randint0(100) < chance)
1366                 continue;
1367
1368             delete_object_idx(player_ptr, i);
1369             num++;
1370         }
1371     }
1372
1373     for (OBJECT_IDX i = floor_ptr->o_max - 1; i >= 1; i--) {
1374         o_ptr = &floor_ptr->o_list[i];
1375         if (o_ptr->k_idx)
1376             continue;
1377
1378         compact_objects_aux(floor_ptr, floor_ptr->o_max - 1, i);
1379         floor_ptr->o_max--;
1380     }
1381 }
1382
1383 /*!
1384  * @brief 特殊な部屋向けに各種アイテムを配置する(vault_trapのサブセット) / Place a trap with a given displacement of point
1385  * @param y トラップを配置したいマスの中心Y座標
1386  * @param x トラップを配置したいマスの中心X座標
1387  * @param yd Y方向の配置分散マス数
1388  * @param xd X方向の配置分散マス数
1389  * @return なし
1390  * @details
1391  * Only really called by some of the "vault" routines.
1392  */
1393 static void vault_trap_aux(player_type *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd)
1394 {
1395     grid_type *g_ptr;
1396     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1397     int y1 = y, x1 = x;
1398     int dummy = 0;
1399     for (int count = 0; count <= 5; count++) {
1400         while (dummy < SAFE_MAX_ATTEMPTS) {
1401             y1 = rand_spread(y, yd);
1402             x1 = rand_spread(x, xd);
1403             dummy++;
1404             if (!in_bounds(floor_ptr, y1, x1))
1405                 continue;
1406             break;
1407         }
1408
1409         if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room) {
1410             msg_print(_("警告!地下室のトラップを配置できません!", "Warning! Could not place vault trap!"));
1411         }
1412
1413         g_ptr = &floor_ptr->grid_array[y1][x1];
1414         if (!is_floor_grid(g_ptr) || g_ptr->o_idx || g_ptr->m_idx)
1415             continue;
1416
1417         place_trap(player_ptr, y1, x1);
1418         break;
1419     }
1420 }
1421
1422 /*!
1423  * todo rooms-normal からしか呼ばれていない、要調整
1424  * @brief 特殊な部屋向けに各種アイテムを配置する(メインルーチン) / Place some traps with a given displacement of given location
1425  * @param player_ptr プレーヤーへの参照ポインタ
1426  * @param y トラップを配置したいマスの中心Y座標
1427  * @param x トラップを配置したいマスの中心X座標
1428  * @param yd Y方向の配置分散マス数
1429  * @param xd X方向の配置分散マス数
1430  * @param num 配置したいトラップの数
1431  * @return なし
1432  * @details
1433  * Only really called by some of the "vault" routines.
1434  */
1435 void vault_traps(player_type *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd, int num)
1436 {
1437     for (int i = 0; i < num; i++) {
1438         vault_trap_aux(player_ptr, y, x, yd, xd);
1439     }
1440 }
1441
1442 /*
1443  * Standard "find me a location" function
1444  *
1445  * Obtains a legal location within the given distance of the initial
1446  * location, and with "los()" from the source to destination location.
1447  *
1448  * This function is often called from inside a loop which searches for
1449  * locations while increasing the "d" distance.
1450  *
1451  * Currently the "m" parameter is unused.
1452  */
1453 void scatter(player_type *player_ptr, POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION d, BIT_FLAGS mode)
1454 {
1455     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1456     POSITION nx, ny;
1457     while (TRUE) {
1458         ny = rand_spread(y, d);
1459         nx = rand_spread(x, d);
1460
1461         if (!in_bounds(floor_ptr, ny, nx))
1462             continue;
1463         if ((d > 1) && (distance(y, x, ny, nx) > d))
1464             continue;
1465         if (mode & PROJECT_LOS) {
1466             if (los(player_ptr, y, x, ny, nx))
1467                 break;
1468             continue;
1469         }
1470
1471         if (projectable(player_ptr, y, x, ny, nx))
1472             break;
1473     }
1474
1475     *yp = ny;
1476     *xp = nx;
1477 }