OSDN Git Service

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