OSDN Git Service

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