OSDN Git Service

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