OSDN Git Service

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