OSDN Git Service

bac1ef423db7bbbc8fb14dcccfa1774eb3bf49c3
[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-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"
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 /*!
47  * @brief 鍵のかかったドアを配置する
48  * @param player_ptr プレーヤーへの参照ポインタ
49  * @param y 配置したいフロアのY座標
50  * @param x 配置したいフロアのX座標
51  * @return なし
52  */
53 void place_locked_door(player_type *player_ptr, POSITION y, POSITION x)
54 {
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);
58         return;
59     }
60
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);
64 }
65
66 /*!
67  * @brief 隠しドアを配置する
68  * @param player_ptr プレーヤーへの参照ポインタ
69  * @param y 配置したいフロアのY座標
70  * @param x 配置したいフロアのX座標
71  * @param type DOOR_DEFAULT / DOOR_DOOR / DOOR_GLASS_DOOR / DOOR_CURTAIN のいずれか
72  * @return なし
73  */
74 void place_secret_door(player_type *player_ptr, POSITION y, POSITION x, int type)
75 {
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);
79         return;
80     }
81
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))
84             ? DOOR_CURTAIN
85             : ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
86     }
87
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)];
95             }
96
97             g_ptr->mimic = 0;
98         }
99     }
100
101     g_ptr->info &= ~(CAVE_FLOOR);
102     delete_monster(player_ptr, y, x);
103 }
104
105 static int scent_when = 0;
106
107 /*
108  * Characters leave scent trails for perceptive monsters to track.
109  *
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.
114  *
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.
119  *
120  * Whenever the age count loops, most of the scent trail is erased and
121  * the age of the remainder is recalculated.
122  */
123 void update_smell(floor_type *floor_ptr, player_type *subject_ptr)
124 {
125     /* Create a table that controls the spread of scent */
126     const int scent_adjust[5][5] = {
127         { -1, 0, 0, 0, -1 },
128         { 0, 1, 1, 1, 0 },
129         { 0, 1, 2, 1, 0 },
130         { 0, 1, 1, 1, 0 },
131         { -1, 0, 0, 0, -1 },
132     };
133
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;
139             }
140         }
141
142         scent_when = 126;
143     }
144
145     for (POSITION i = 0; i < 5; i++) {
146         for (POSITION j = 0; j < 5; j++) {
147             grid_type *g_ptr;
148             POSITION y = i + subject_ptr->y - 2;
149             POSITION x = j + subject_ptr->x - 2;
150             if (!in_bounds(floor_ptr, y, x))
151                 continue;
152
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))
155                 continue;
156             if (!player_has_los_bold(subject_ptr, y, x))
157                 continue;
158             if (scent_adjust[i][j] == -1)
159                 continue;
160
161             g_ptr->when = scent_when + scent_adjust[i][j];
162         }
163     }
164 }
165
166 /*
167  * Hack -- forget the "flow" information
168  */
169 void forget_flow(floor_type *floor_ptr)
170 {
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;
176         }
177     }
178 }
179
180 /*
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.
183  *
184  * The doors must be INSIDE the allocated region.
185  */
186 void add_door(player_type *player_ptr, POSITION x, POSITION y)
187 {
188     floor_type *floor_ptr = player_ptr->current_floor_ptr;
189     if (!is_outer_bold(floor_ptr, y, x))
190         return;
191
192     /* look at:
193      *  x#x
194      *  .#.
195      *  x#x
196      *
197      *  where x=don't care
198      *  .=floor, #=wall
199      */
200
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);
206     }
207
208     /* look at:
209      *  x#x
210      *  .#.
211      *  x#x
212      *
213      *  where x = don't care
214      *  .=floor, #=wall
215      */
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);
220     }
221 }
222
223 /*!
224  * @brief 所定の位置に上り階段か下り階段を配置する / Place an up/down staircase at given location
225  * @param player_ptr プレーヤーへの参照ポインタ
226  * @param y 配置を試みたいマスのY座標
227  * @param x 配置を試みたいマスのX座標
228  * @return なし
229  */
230 void place_random_stairs(player_type *player_ptr, POSITION y, POSITION x)
231 {
232     bool up_stairs = TRUE;
233     bool down_stairs = TRUE;
234     grid_type *g_ptr;
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)
238         return;
239
240     if (!floor_ptr->dun_level)
241         up_stairs = FALSE;
242     if (ironman_downward)
243         up_stairs = FALSE;
244     if (floor_ptr->dun_level >= d_info[player_ptr->dungeon_idx].maxdepth)
245         down_stairs = FALSE;
246     if (quest_number(player_ptr, floor_ptr->dun_level) && (floor_ptr->dun_level > 1))
247         down_stairs = FALSE;
248
249     if (down_stairs && up_stairs) {
250         if (randint0(100) < 50)
251             up_stairs = FALSE;
252         else
253             down_stairs = FALSE;
254     }
255
256     if (up_stairs)
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);
260 }
261
262 /*!
263  * @brief LOS(Line Of Sight / 視線が通っているか)の判定を行う。
264  * @param player_ptr プレーヤーへの参照ポインタ
265  * @param y1 始点のy座標
266  * @param x1 始点のx座標
267  * @param y2 終点のy座標
268  * @param x2 終点のx座標
269  * @return LOSが通っているならTRUEを返す。
270  * @details
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
273  *\n
274  * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).\n
275  *\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
279  *\n
280  * We assume that the "mathematical corner" of a non-floor tile does not\n
281  * block line of sight.\n
282  *\n
283  * Because this function uses (short) ints for all calculations, overflow may\n
284  * occur if dx and dy exceed 90.\n
285  *\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
289  *\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
293  *\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
298  *\n
299  * Note that "line of sight" is not "reflexive" in all cases.\n
300  *\n
301  * Use the "projectable()" routine to test "spell/missile line of sight".\n
302  *\n
303  * Use the "update_view()" function to determine player line-of-sight.\n
304  */
305 bool los(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
306 {
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))
312         return TRUE;
313
314     /* Directly South/North */
315     floor_type *floor_ptr = player_ptr->current_floor_ptr;
316     POSITION tx, ty;
317     if (!dx) {
318         /* South -- check for walls */
319         if (dy > 0) {
320             for (ty = y1 + 1; ty < y2; ty++) {
321                 if (!cave_los_bold(floor_ptr, ty, x1))
322                     return FALSE;
323             }
324         }
325
326         /* North -- check for walls */
327         else {
328             for (ty = y1 - 1; ty > y2; ty--) {
329                 if (!cave_los_bold(floor_ptr, ty, x1))
330                     return FALSE;
331             }
332         }
333
334         /* Assume los */
335         return TRUE;
336     }
337
338     /* Directly East/West */
339     if (!dy) {
340         /* East -- check for walls */
341         if (dx > 0) {
342             for (tx = x1 + 1; tx < x2; tx++) {
343                 if (!cave_los_bold(floor_ptr, y1, tx))
344                     return FALSE;
345             }
346         }
347
348         /* West -- check for walls */
349         else {
350             for (tx = x1 - 1; tx > x2; tx--) {
351                 if (!cave_los_bold(floor_ptr, y1, tx))
352                     return FALSE;
353             }
354         }
355
356         return TRUE;
357     }
358
359     POSITION sx = (dx < 0) ? -1 : 1;
360     POSITION sy = (dy < 0) ? -1 : 1;
361
362     if (ax == 1) {
363         if (ay == 2) {
364             if (cave_los_bold(floor_ptr, y1 + sy, x1))
365                 return TRUE;
366         }
367     } else if (ay == 1) {
368         if (ax == 2) {
369             if (cave_los_bold(floor_ptr, y1, x1 + sx))
370                 return TRUE;
371         }
372     }
373
374     POSITION f2 = (ax * ay);
375     POSITION f1 = f2 << 1;
376     POSITION qy;
377     POSITION m;
378     if (ax >= ay) {
379         qy = ay * ay;
380         m = qy << 1;
381         tx = x1 + sx;
382         if (qy == f2) {
383             ty = y1 + sy;
384             qy -= f1;
385         } else {
386             ty = y1;
387         }
388
389         /* Note (below) the case (qy == f2), where */
390         /* the LOS exactly meets the corner of a tile. */
391         while (x2 - tx) {
392             if (!cave_los_bold(floor_ptr, ty, tx))
393                 return FALSE;
394
395             qy += m;
396
397             if (qy < f2) {
398                 tx += sx;
399                 continue;
400             }
401
402             if (qy > f2) {
403                 ty += sy;
404                 if (!cave_los_bold(floor_ptr, ty, tx))
405                     return FALSE;
406                 qy -= f1;
407                 tx += sx;
408                 continue;
409             }
410
411             ty += sy;
412             qy -= f1;
413             tx += sx;
414         }
415
416         return TRUE;
417     }
418
419     /* Travel vertically */
420     POSITION qx = ax * ax;
421     m = qx << 1;
422     ty = y1 + sy;
423     if (qx == f2) {
424         tx = x1 + sx;
425         qx -= f1;
426     } else {
427         tx = x1;
428     }
429
430     /* Note (below) the case (qx == f2), where */
431     /* the LOS exactly meets the corner of a tile. */
432     while (y2 - ty) {
433         if (!cave_los_bold(floor_ptr, ty, tx))
434             return FALSE;
435
436         qx += m;
437
438         if (qx < f2) {
439             ty += sy;
440             continue;
441         }
442
443         if (qx > f2) {
444             tx += sx;
445             if (!cave_los_bold(floor_ptr, ty, tx))
446                 return FALSE;
447             qx -= f1;
448             ty += sy;
449             continue;
450         }
451
452         tx += sx;
453         qx -= f1;
454         ty += sy;
455     }
456
457     return TRUE;
458 }
459
460 /*!
461  * @briefプレイヤーの攻撃射程(マス) / Maximum range (spells, etc)
462  * @param creature_ptr プレーヤーへの参照ポインタ
463  * @return 射程
464  */
465 int get_max_range(player_type *creature_ptr) { return creature_ptr->phase_out ? 36 : 18; }
466
467 /*
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.
470  *
471  * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
472  */
473 bool projectable(player_type *player_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
474 {
475     u16b grid_g[512];
476     int grid_n = projection_path(player_ptr, grid_g, (project_length ? project_length : get_max_range(player_ptr)), y1, x1, y2, x2, 0);
477     if (!grid_n)
478         return TRUE;
479
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))
483         return FALSE;
484
485     return TRUE;
486 }
487
488 /*
489  * Grid based version of "creature_bold()"
490  */
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]; }
492
493 /*
494  * Grid based version of "cave_empty_bold()"
495  */
496 static bool is_cave_empty_grid(player_type *player_ptr, grid_type *g_ptr)
497 {
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;
502 }
503
504 /*!
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 配置したいモンスターの数
510  * @return なし
511  * @details
512  * Only really called by some of the "vault" routines.
513  */
514 void vault_monsters(player_type *player_ptr, POSITION y1, POSITION x1, int num)
515 {
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++) {
519             int d = 1;
520             POSITION y, x;
521             scatter(player_ptr, &y, &x, y1, x1, d, 0);
522             grid_type *g_ptr;
523             g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
524             if (!is_cave_empty_grid(player_ptr, g_ptr))
525                 continue;
526
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;
530         }
531     }
532 }
533
534 /*!
535  * @brief 指定された座標が地震や階段生成の対象となるマスかを返す。 / Determine if a given location may be "destroyed"
536  * @param player_ptr プレーヤーへの参照ポインタ
537  * @param y y座標
538  * @param x x座標
539  * @return 各種の変更が可能ならTRUEを返す。
540  * @details
541  * 条件は永久地形でなく、なおかつ該当のマスにアーティファクトが存在しないか、である。英語の旧コメントに反して*破壊*の抑止判定には現在使われていない。
542  */
543 bool cave_valid_bold(floor_type *floor_ptr, POSITION y, POSITION x)
544 {
545     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
546     if (cave_have_flag_grid(g_ptr, FF_PERMANENT))
547         return FALSE;
548
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) {
551         object_type *o_ptr;
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))
555             return FALSE;
556     }
557
558     return TRUE;
559 }
560
561 /*
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
564  */
565 static bool player_has_los_grid(grid_type *g_ptr) { return (g_ptr->info & CAVE_VIEW) != 0; }
566
567 /*
568  * Change the "feat" flag for a grid, and notice/redraw the grid
569  */
570 void cave_set_feat(player_type *player_ptr, POSITION y, POSITION x, FEAT_IDX feat)
571 {
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) {
576         g_ptr->mimic = 0;
577         g_ptr->feat = feat;
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))
583                     continue;
584                 floor_ptr->grid_array[yy][xx].info |= CAVE_GLOW;
585             }
586         }
587
588         return;
589     }
590
591     bool old_los = cave_have_flag_bold(floor_ptr, y, x, FF_LOS);
592     bool old_mirror = is_mirror_grid(g_ptr);
593
594     g_ptr->mimic = 0;
595     g_ptr->feat = feat;
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);
601
602         update_local_illumination(player_ptr, y, x);
603     }
604
605     if (!have_flag(f_ptr->flags, FF_REMEMBER))
606         g_ptr->info &= ~(CAVE_MARK);
607     if (g_ptr->m_idx)
608         update_monster(player_ptr, g_ptr->m_idx, FALSE);
609
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)) {
613
614 #ifdef COMPLEX_WALL_ILLUMINATION /* COMPLEX_WALL_ILLUMINATION */
615
616         update_local_illumination(player_ptr, y, x);
617
618 #endif /* COMPLEX_WALL_ILLUMINATION */
619
620         player_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE | PU_MONSTERS);
621     }
622
623     if (!have_flag(f_ptr->flags, FF_GLOW) || (d_info[player_ptr->dungeon_idx].flags1 & DF1_DARKNESS))
624         return;
625
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))
630             continue;
631
632         grid_type *cc_ptr;
633         cc_ptr = &floor_ptr->grid_array[yy][xx];
634         cc_ptr->info |= CAVE_GLOW;
635
636         if (player_has_los_grid(cc_ptr)) {
637             if (cc_ptr->m_idx)
638                 update_monster(player_ptr, cc_ptr->m_idx, FALSE);
639             note_spot(player_ptr, yy, xx);
640             lite_spot(player_ptr, yy, xx);
641         }
642
643         update_local_illumination(player_ptr, yy, xx);
644     }
645
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);
649     }
650 }
651
652 /*!
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 部屋に接している場合向けのドア生成か否か
658  * @return なし
659  */
660 void place_random_door(player_type *player_ptr, POSITION y, POSITION x, bool room)
661 {
662     floor_type *floor_ptr = player_ptr->current_floor_ptr;
663     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
664     g_ptr->mimic = 0;
665
666     if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS) {
667         place_bold(player_ptr, y, x, GB_FLOOR);
668         return;
669     }
670
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))
672         ? DOOR_CURTAIN
673         : ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
674
675     int tmp = randint0(1000);
676     FEAT_IDX feat = feat_none;
677     if (tmp < 300) {
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);
683
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)];
689                 }
690                 g_ptr->mimic = 0;
691             }
692         }
693     } else {
694         place_closed_door(player_ptr, y, x, type);
695     }
696
697     if (tmp >= 400) {
698         delete_monster(player_ptr, y, x);
699         return;
700     }
701
702     if (feat != feat_none) {
703         set_cave_feat(floor_ptr, y, x, feat);
704     } else {
705         place_bold(player_ptr, y, x, GB_FLOOR);
706     }
707
708     delete_monster(player_ptr, y, x);
709 }
710
711 /*!
712  * @brief グローバルオブジェクト配列を初期化する /
713  * Delete all the items when player leaves the level
714  * @note we do NOT visually reflect these (irrelevant) changes
715  * @details
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.
721  * @return なし
722  */
723 void wipe_o_list(floor_type *floor_ptr)
724 {
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))
728             continue;
729
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;
733             }
734         }
735
736         if (object_is_held_monster(o_ptr)) {
737             monster_type *m_ptr;
738             m_ptr = &floor_ptr->m_list[o_ptr->held_m_idx];
739             m_ptr->hold_o_idx = 0;
740             object_wipe(o_ptr);
741             continue;
742         }
743
744         grid_type *g_ptr;
745         POSITION y = o_ptr->iy;
746         POSITION x = o_ptr->ix;
747
748         g_ptr = &floor_ptr->grid_array[y][x];
749         g_ptr->o_idx = 0;
750         object_wipe(o_ptr);
751     }
752
753     floor_ptr->o_max = 1;
754     floor_ptr->o_cnt = 0;
755 }
756
757 /*!
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
763  * @return なし
764  */
765 void place_closed_door(player_type *player_ptr, POSITION y, POSITION x, int type)
766 {
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);
770         return;
771     }
772
773     int tmp = randint0(400);
774     FEAT_IDX feat = feat_none;
775     if (tmp < 300) {
776         /* Create closed door */
777         feat = feat_door[type].closed;
778     } else if (tmp < 399) {
779         feat = feat_locked_door_random(type);
780     } else {
781         feat = feat_jammed_door_random(type);
782     }
783
784     if (feat == feat_none) {
785         place_bold(player_ptr, y, x, GB_FLOOR);
786         return;
787     }
788
789     cave_set_feat(player_ptr, y, x, feat);
790     floor_ptr->grid_array[y][x].info &= ~(CAVE_MASK);
791 }
792
793 /*!
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
798  */
799 bool get_is_floor(floor_type *floor_ptr, POSITION x, POSITION y)
800 {
801     if (!in_bounds(floor_ptr, y, x)) {
802         return FALSE;
803     }
804
805     if (is_floor_bold(floor_ptr, y, x))
806         return TRUE;
807
808     return FALSE;
809 }
810
811 FEAT_IDX conv_dungeon_feat(floor_type *floor_ptr, FEAT_IDX newfeat)
812 {
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;
830         default:
831             return newfeat;
832         }
833     } else
834         return newfeat;
835 }
836
837 /*!
838  * @brief 特殊な部屋向けに各種アイテムを配置する / Create up to "num" objects near the given coordinates
839  * @param player_ptr プレーヤーへの参照ポインタ
840  * @param y 配置したい中心マスのY座標
841  * @param x 配置したい中心マスのX座標
842  * @param num 配置したい数
843  * @return なし
844  * @details
845  * Only really called by some of the "vault" routines.
846  */
847 void vault_objects(player_type *player_ptr, POSITION y, POSITION x, int num)
848 {
849     floor_type *floor_ptr = player_ptr->current_floor_ptr;
850     for (; num > 0; --num) {
851         int j = y, k = x;
852         int dummy = 0;
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);
857                 dummy++;
858                 if (!in_bounds(floor_ptr, j, k))
859                     continue;
860                 break;
861             }
862
863             if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room) {
864                 msg_print(_("警告!地下室のアイテムを配置できません!", "Warning! Could not place vault object!"));
865             }
866
867             grid_type *g_ptr;
868             g_ptr = &floor_ptr->grid_array[j][k];
869             if (!is_floor_grid(g_ptr) || g_ptr->o_idx)
870                 continue;
871
872             if (randint0(100) < 75) {
873                 place_object(player_ptr, j, k, 0L);
874             } else {
875                 place_gold(player_ptr, j, k);
876             }
877
878             break;
879         }
880     }
881 }
882
883 /*!
884  * @brief 指定のマスを床地形に変える / Set a square to be floor.  (Includes range checking.)
885  * @param player_ptr プレーヤーへの参照ポインタ
886  * @param x 地形を変えたいマスのX座標
887  * @param y 地形を変えたいマスのY座標
888  * @return なし
889  */
890 void set_floor(player_type *player_ptr, POSITION x, POSITION y)
891 {
892     floor_type *floor_ptr = player_ptr->current_floor_ptr;
893     if (!in_bounds(floor_ptr, y, x)) {
894         return;
895     }
896
897     if (floor_ptr->grid_array[y][x].info & CAVE_ROOM) {
898         return;
899     }
900
901     if (is_extra_bold(floor_ptr, y, x))
902         place_bold(player_ptr, y, x, GB_FLOOR);
903 }
904
905 /*!
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を返す。
913  * @details
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
917  */
918 void place_object(player_type *owner_ptr, POSITION y, POSITION x, BIT_FLAGS mode)
919 {
920     floor_type *floor_ptr = owner_ptr->current_floor_ptr;
921     grid_type *g_ptr = &floor_ptr->grid_array[y][x];
922     object_type forge;
923     object_type *q_ptr;
924     if (!in_bounds(floor_ptr, y, x))
925         return;
926     if (!cave_drop_bold(floor_ptr, y, x))
927         return;
928     if (g_ptr->o_idx)
929         return;
930
931     q_ptr = &forge;
932     object_wipe(q_ptr);
933     if (!make_object(owner_ptr, q_ptr, mode))
934         return;
935
936     OBJECT_IDX o_idx = o_pop(floor_ptr);
937     if (o_idx == 0) {
938         if (object_is_fixed_artifact(q_ptr)) {
939             a_info[q_ptr->name1].cur_num = 0;
940         }
941
942         return;
943     }
944
945     object_type *o_ptr;
946     o_ptr = &floor_ptr->o_list[o_idx];
947     object_copy(o_ptr, q_ptr);
948
949     o_ptr->iy = y;
950     o_ptr->ix = x;
951     o_ptr->next_o_idx = g_ptr->o_idx;
952
953     g_ptr->o_idx = o_idx;
954     note_spot(owner_ptr, y, x);
955     lite_spot(owner_ptr, y, x);
956 }
957
958 /*!
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を返す。
965  * @details
966  * The location must be a legal, clean, floor grid.
967  */
968 void place_gold(player_type *player_ptr, POSITION y, POSITION x)
969 {
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))
973         return;
974     if (!cave_drop_bold(floor_ptr, y, x))
975         return;
976     if (g_ptr->o_idx)
977         return;
978
979     object_type forge;
980     object_type *q_ptr;
981     q_ptr = &forge;
982     object_wipe(q_ptr);
983     if (!make_gold(player_ptr, q_ptr))
984         return;
985
986     OBJECT_IDX o_idx = o_pop(floor_ptr);
987     if (o_idx == 0)
988         return;
989
990     object_type *o_ptr;
991     o_ptr = &floor_ptr->o_list[o_idx];
992     object_copy(o_ptr, q_ptr);
993
994     o_ptr->iy = y;
995     o_ptr->ix = x;
996     o_ptr->next_o_idx = g_ptr->o_idx;
997
998     g_ptr->o_idx = o_idx;
999     note_spot(player_ptr, y, x);
1000     lite_spot(player_ptr, y, x);
1001 }
1002
1003 /*!
1004  * @brief 指定位置に存在するモンスターを削除する / Delete the monster, if any, at a given location
1005  * @param player_ptr プレーヤーへの参照ポインタ
1006  * @param x 削除位置x座標
1007  * @param y 削除位置y座標
1008  * @return なし
1009  */
1010 void delete_monster(player_type *player_ptr, POSITION y, POSITION x)
1011 {
1012     grid_type *g_ptr;
1013     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1014     if (!in_bounds(floor_ptr, y, x))
1015         return;
1016
1017     g_ptr = &floor_ptr->grid_array[y][x];
1018     if (g_ptr->m_idx)
1019         delete_monster_idx(player_ptr, g_ptr->m_idx);
1020 }
1021
1022 /*!
1023  * @brief グローバルオブジェクト配列に対し指定範囲のオブジェクトを整理してIDの若い順に寄せる /
1024  * Move an object from index i1 to index i2 in the object list
1025  * @param i1 整理したい配列の始点
1026  * @param i2 整理したい配列の終点
1027  * @return なし
1028  */
1029 static void compact_objects_aux(floor_type *floor_ptr, OBJECT_IDX i1, OBJECT_IDX i2)
1030 {
1031     if (i1 == i2)
1032         return;
1033
1034     object_type *o_ptr;
1035     for (OBJECT_IDX i = 1; i < floor_ptr->o_max; i++) {
1036         o_ptr = &floor_ptr->o_list[i];
1037         if (!o_ptr->k_idx)
1038             continue;
1039
1040         if (o_ptr->next_o_idx == i1) {
1041             o_ptr->next_o_idx = i2;
1042         }
1043     }
1044
1045     o_ptr = &floor_ptr->o_list[i1];
1046
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;
1052         }
1053     } else {
1054         POSITION y = o_ptr->iy;
1055         POSITION x = o_ptr->ix;
1056         grid_type *g_ptr;
1057         g_ptr = &floor_ptr->grid_array[y][x];
1058
1059         if (g_ptr->o_idx == i1) {
1060             g_ptr->o_idx = i2;
1061         }
1062     }
1063
1064     floor_ptr->o_list[i2] = floor_ptr->o_list[i1];
1065     object_wipe(o_ptr);
1066 }
1067
1068 /*!
1069  * @brief グローバルオブジェクト配列から優先度の低いものを削除し、データを圧縮する。 /
1070  * Compact and Reorder the object list.
1071  * @param player_ptr プレーヤーへの参照ポインタ
1072  * @param size 最低でも減らしたいオブジェクト数の水準
1073  * @return なし
1074  * @details
1075  * (危険なので使用には注意すること)
1076  * This function can be very dangerous, use with caution!\n
1077  *\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
1080  * "desperation".\n
1081  *\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
1084  */
1085 void compact_objects(player_type *player_ptr, int size)
1086 {
1087     object_type *o_ptr;
1088     if (size) {
1089         msg_print(_("アイテム情報を圧縮しています...", "Compacting objects..."));
1090         player_ptr->redraw |= (PR_MAP);
1091         player_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
1092     }
1093
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];
1100
1101             if (!object_is_valid(o_ptr))
1102                 continue;
1103             if (k_info[o_ptr->k_idx].level > cur_lev)
1104                 continue;
1105
1106             POSITION y, x;
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];
1110                 y = m_ptr->fy;
1111                 x = m_ptr->fx;
1112
1113                 if (randint0(100) < 90)
1114                     continue;
1115             } else {
1116                 y = o_ptr->iy;
1117                 x = o_ptr->ix;
1118             }
1119
1120             if ((cur_dis > 0) && (distance(player_ptr->y, player_ptr->x, y, x) < cur_dis))
1121                 continue;
1122
1123             int chance = 90;
1124             if ((object_is_fixed_artifact(o_ptr) || o_ptr->art_name) && (cnt < 1000))
1125                 chance = 100;
1126
1127             if (randint0(100) < chance)
1128                 continue;
1129
1130             delete_object_idx(player_ptr, i);
1131             num++;
1132         }
1133     }
1134
1135     for (OBJECT_IDX i = floor_ptr->o_max - 1; i >= 1; i--) {
1136         o_ptr = &floor_ptr->o_list[i];
1137         if (o_ptr->k_idx)
1138             continue;
1139
1140         compact_objects_aux(floor_ptr, floor_ptr->o_max - 1, i);
1141         floor_ptr->o_max--;
1142     }
1143 }
1144
1145 /*!
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方向の配置分散マス数
1151  * @return なし
1152  * @details
1153  * Only really called by some of the "vault" routines.
1154  */
1155 static void vault_trap_aux(player_type *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd)
1156 {
1157     grid_type *g_ptr;
1158     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1159     int y1 = y, x1 = x;
1160     int dummy = 0;
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);
1165             dummy++;
1166             if (!in_bounds(floor_ptr, y1, x1))
1167                 continue;
1168             break;
1169         }
1170
1171         if (dummy >= SAFE_MAX_ATTEMPTS && cheat_room) {
1172             msg_print(_("警告!地下室のトラップを配置できません!", "Warning! Could not place vault trap!"));
1173         }
1174
1175         g_ptr = &floor_ptr->grid_array[y1][x1];
1176         if (!is_floor_grid(g_ptr) || g_ptr->o_idx || g_ptr->m_idx)
1177             continue;
1178
1179         place_trap(player_ptr, y1, x1);
1180         break;
1181     }
1182 }
1183
1184 /*!
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 配置したいトラップの数
1193  * @return なし
1194  * @details
1195  * Only really called by some of the "vault" routines.
1196  */
1197 void vault_traps(player_type *player_ptr, POSITION y, POSITION x, POSITION yd, POSITION xd, int num)
1198 {
1199     for (int i = 0; i < num; i++) {
1200         vault_trap_aux(player_ptr, y, x, yd, xd);
1201     }
1202 }
1203
1204 /*
1205  * Standard "find me a location" function
1206  *
1207  * Obtains a legal location within the given distance of the initial
1208  * location, and with "los()" from the source to destination location.
1209  *
1210  * This function is often called from inside a loop which searches for
1211  * locations while increasing the "d" distance.
1212  *
1213  * Currently the "m" parameter is unused.
1214  */
1215 void scatter(player_type *player_ptr, POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION d, BIT_FLAGS mode)
1216 {
1217     floor_type *floor_ptr = player_ptr->current_floor_ptr;
1218     POSITION nx, ny;
1219     while (TRUE) {
1220         ny = rand_spread(y, d);
1221         nx = rand_spread(x, d);
1222
1223         if (!in_bounds(floor_ptr, ny, nx))
1224             continue;
1225         if ((d > 1) && (distance(y, x, ny, nx) > d))
1226             continue;
1227         if (mode & PROJECT_LOS) {
1228             if (los(player_ptr, y, x, ny, nx))
1229                 break;
1230             continue;
1231         }
1232
1233         if (projectable(player_ptr, y, x, ny, nx))
1234             break;
1235     }
1236
1237     *yp = ny;
1238     *xp = nx;
1239 }