OSDN Git Service

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