OSDN Git Service

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