OSDN Git Service

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