OSDN Git Service

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