3 #include "floor-save.h"
8 #include "object-hook.h"
11 * The array of floor [MAX_WID][MAX_HGT].
12 * Not completely allocated, that would be inefficient
13 * Not completely hardcoded, that would overflow memory
15 floor_type floor_info;
18 * The array of saved floors
20 saved_floor_type saved_floors[MAX_SAVED_FLOORS];
23 * @brief 鍵のかかったドアを配置する
24 * @param y 配置したいフロアのY座標
25 * @param x 配置したいフロアのX座標
28 void place_locked_door(floor_type *floor_ptr, POSITION y, POSITION x)
30 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
32 place_floor_bold(floor_ptr, y, x);
36 set_cave_feat(floor_ptr, y, x, feat_locked_door_random((d_info[p_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR));
37 floor_ptr->grid_array[y][x].info &= ~(CAVE_FLOOR);
45 * @param y 配置したいフロアのY座標
46 * @param x 配置したいフロアのX座標
47 * @param type DOOR_DEFAULT / DOOR_DOOR / DOOR_GLASS_DOOR / DOOR_CURTAIN のいずれか
50 void place_secret_door(floor_type *floor_ptr, POSITION y, POSITION x, int type)
52 if (d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_DOORS)
54 place_floor_bold(floor_ptr, y, x);
58 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
60 if (type == DOOR_DEFAULT)
62 type = ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_CURTAIN) &&
63 one_in_((d_info[floor_ptr->dungeon_idx].flags1 & DF1_NO_CAVE) ? 16 : 256)) ? DOOR_CURTAIN :
64 ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_GLASS_DOOR) ? DOOR_GLASS_DOOR : DOOR_DOOR);
67 /* Create secret door */
68 place_closed_door(y, x, type);
70 if (type != DOOR_CURTAIN)
72 /* Hide by inner wall because this is used in rooms only */
73 g_ptr->mimic = feat_wall_inner;
75 /* Floor type terrain cannot hide a door */
76 if (feat_supports_los(g_ptr->mimic) && !feat_supports_los(g_ptr->feat))
78 if (have_flag(f_info[g_ptr->mimic].flags, FF_MOVE) || have_flag(f_info[g_ptr->mimic].flags, FF_CAN_FLY))
80 g_ptr->feat = one_in_(2) ? g_ptr->mimic : feat_ground_type[randint0(100)];
86 g_ptr->info &= ~(CAVE_FLOOR);
91 static int scent_when = 0;
94 * Characters leave scent trails for perceptive monsters to track.
96 * Smell is rather more limited than sound. Many creatures cannot use
97 * it at all, it doesn't extend very far outwards from the character's
98 * current position, and monsters can use it to home in the character,
99 * but not to run away from him.
101 * Smell is valued according to age. When a character takes his turn,
102 * scent is aged by one, and new scent of the current age is laid down.
103 * Speedy characters leave more scent, true, but it also ages faster,
104 * which makes it harder to hunt them down.
106 * Whenever the age count loops, most of the scent trail is erased and
107 * the age of the remainder is recalculated.
109 void update_smell(floor_type *floor_ptr, player_type *subject_ptr)
114 /* Create a table that controls the spread of scent */
115 const int scent_adjust[5][5] =
124 /* Loop the age and adjust scent values when necessary */
125 if (++scent_when == 254)
127 /* Scan the entire dungeon */
128 for (y = 0; y < floor_ptr->height; y++)
130 for (x = 0; x < floor_ptr->width; x++)
132 int w = floor_ptr->grid_array[y][x].when;
133 floor_ptr->grid_array[y][x].when = (w > 128) ? (w - 128) : 0;
142 /* Lay down new scent */
143 for (i = 0; i < 5; i++)
145 for (j = 0; j < 5; j++)
149 /* Translate table to map grids */
150 y = i + subject_ptr->y - 2;
151 x = j + subject_ptr->x - 2;
154 if (!in_bounds(floor_ptr, y, x)) continue;
156 g_ptr = &floor_ptr->grid_array[y][x];
158 /* Walls, water, and lava cannot hold scent. */
159 if (!cave_have_flag_grid(g_ptr, FF_MOVE) && !is_closed_door(g_ptr->feat)) continue;
161 /* Grid must not be blocked by walls from the character */
162 if (!player_has_los_bold(subject_ptr, y, x)) continue;
164 /* Note grids that are too far away */
165 if (scent_adjust[i][j] == -1) continue;
167 /* Mark the grid with new scent */
168 g_ptr->when = scent_when + scent_adjust[i][j];
175 * Hack -- forget the "flow" information
177 void forget_flow(floor_type *floor_ptr)
181 /* Check the entire dungeon */
182 for (y = 0; y < floor_ptr->height; y++)
184 for (x = 0; x < floor_ptr->width; x++)
186 /* Forget the old data */
187 floor_ptr->grid_array[y][x].dist = 0;
188 floor_ptr->grid_array[y][x].cost = 0;
189 floor_ptr->grid_array[y][x].when = 0;
195 * Routine used by the random vault creators to add a door to a location
196 * Note that range checking has to be done in the calling routine.
198 * The doors must be INSIDE the allocated region.
200 void add_door(floor_type* floor_ptr, POSITION x, POSITION y)
202 /* Need to have a wall in the center square */
203 if (!is_outer_bold(floor_ptr, y, x)) return;
214 if (is_floor_bold(floor_ptr, y - 1, x) && is_floor_bold(floor_ptr, y + 1, x) &&
215 (is_outer_bold(floor_ptr, y, x - 1) && is_outer_bold(floor_ptr, y, x + 1)))
218 place_secret_door(floor_ptr, y, x, DOOR_DEFAULT);
220 /* set boundarys so don't get wide doors */
221 place_solid_bold(y, x - 1);
222 place_solid_bold(y, x + 1);
231 * where x = don't care
234 if (is_outer_bold(floor_ptr, y - 1, x) && is_outer_bold(floor_ptr, y + 1, x) &&
235 is_floor_bold(floor_ptr, y, x - 1) && is_floor_bold(floor_ptr, y, x + 1))
238 place_secret_door(floor_ptr, y, x, DOOR_DEFAULT);
240 /* set boundarys so don't get wide doors */
241 place_solid_bold(y - 1, x);
242 place_solid_bold(y + 1, x);
247 * @brief 所定の位置に上り階段か下り階段を配置する / Place an up/down staircase at given location
248 * @param y 配置を試みたいマスのY座標
249 * @param x 配置を試みたいマスのX座標
252 void place_random_stairs(floor_type *floor_ptr, POSITION y, POSITION x)
254 bool up_stairs = TRUE;
255 bool down_stairs = TRUE;
257 g_ptr = &floor_ptr->grid_array[y][x];
258 if (!is_floor_grid(g_ptr) || g_ptr->o_idx) return;
260 if (!floor_ptr->dun_level) up_stairs = FALSE;
261 if (ironman_downward) up_stairs = FALSE;
262 if (floor_ptr->dun_level >= d_info[p_ptr->dungeon_idx].maxdepth) down_stairs = FALSE;
263 if (quest_number(floor_ptr->dun_level) && (floor_ptr->dun_level > 1)) down_stairs = FALSE;
265 /* We can't place both */
266 if (down_stairs && up_stairs)
268 /* Choose a staircase randomly */
269 if (randint0(100) < 50) up_stairs = FALSE;
270 else down_stairs = FALSE;
273 /* Place the stairs */
274 if (up_stairs) set_cave_feat(floor_ptr, y, x, feat_up_stair);
275 else if (down_stairs) set_cave_feat(floor_ptr, y, x, feat_down_stair);
279 * @brief LOS(Line Of Sight / 視線が通っているか)の判定を行う。
284 * @return LOSが通っているならTRUEを返す。
286 * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall,\n
287 * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu.\n
289 * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).\n
291 * The LOS begins at the center of the tile (x1,y1) and ends at the center of\n
292 * the tile (x2,y2). If los() is to return TRUE, all of the tiles this line\n
293 * passes through must be floor tiles, except for (x1,y1) and (x2,y2).\n
295 * We assume that the "mathematical corner" of a non-floor tile does not\n
296 * block line of sight.\n
298 * Because this function uses (short) ints for all calculations, overflow may\n
299 * occur if dx and dy exceed 90.\n
301 * Once all the degenerate cases are eliminated, the values "qx", "qy", and\n
302 * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that\n
303 * we can use integer arithmetic.\n
305 * We travel from start to finish along the longer axis, starting at the border\n
306 * between the first and second tiles, where the y offset = .5 * slope, taking\n
307 * into account the scale factor. See below.\n
309 * Also note that this function and the "move towards target" code do NOT\n
310 * share the same properties. Thus, you can see someone, target them, and\n
311 * then fire a bolt at them, but the bolt may hit a wall, not them. However\n,
312 * by clever choice of target locations, you can sometimes throw a "curve".\n
314 * Note that "line of sight" is not "reflexive" in all cases.\n
316 * Use the "projectable()" routine to test "spell/missile line of sight".\n
318 * Use the "update_view()" function to determine player line-of-sight.\n
320 bool los(floor_type *floor_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
340 /* Slope, or 1/Slope, of LOS */
344 /* Extract the offset */
348 /* Extract the absolute offset */
353 /* Handle adjacent (or identical) grids */
354 if ((ax < 2) && (ay < 2)) return TRUE;
357 /* Paranoia -- require "safe" origin */
358 /* if (!in_bounds(floor_ptr, y1, x1)) return FALSE; */
359 /* if (!in_bounds(floor_ptr, y2, x2)) return FALSE; */
362 /* Directly South/North */
365 /* South -- check for walls */
368 for (ty = y1 + 1; ty < y2; ty++)
370 if (!cave_los_bold(floor_ptr, ty, x1)) return FALSE;
374 /* North -- check for walls */
377 for (ty = y1 - 1; ty > y2; ty--)
379 if (!cave_los_bold(floor_ptr, ty, x1)) return FALSE;
387 /* Directly East/West */
390 /* East -- check for walls */
393 for (tx = x1 + 1; tx < x2; tx++)
395 if (!cave_los_bold(floor_ptr, y1, tx)) return FALSE;
399 /* West -- check for walls */
402 for (tx = x1 - 1; tx > x2; tx--)
404 if (!cave_los_bold(floor_ptr, y1, tx)) return FALSE;
413 /* Extract some signs */
414 sx = (dx < 0) ? -1 : 1;
415 sy = (dy < 0) ? -1 : 1;
418 /* Vertical "knights" */
423 if (cave_los_bold(floor_ptr, y1 + sy, x1)) return TRUE;
427 /* Horizontal "knights" */
432 if (cave_los_bold(floor_ptr, y1, x1 + sx)) return TRUE;
437 /* Calculate scale factor div 2 */
440 /* Calculate scale factor */
444 /* Travel horizontally */
447 /* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */
453 /* Consider the special case where slope == 1. */
464 /* Note (below) the case (qy == f2), where */
465 /* the LOS exactly meets the corner of a tile. */
468 if (!cave_los_bold(floor_ptr, ty, tx)) return FALSE;
479 if (!cave_los_bold(floor_ptr, ty, tx)) return FALSE;
492 /* Travel vertically */
495 /* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */
511 /* Note (below) the case (qx == f2), where */
512 /* the LOS exactly meets the corner of a tile. */
515 if (!cave_los_bold(floor_ptr, ty, tx)) return FALSE;
526 if (!cave_los_bold(floor_ptr, ty, tx)) return FALSE;
545 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
546 * at the final destination, assuming no monster gets in the way.
548 * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
550 bool projectable(floor_type *floor_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
557 /* Check the projection path */
558 grid_n = project_path(grid_g, (project_length ? project_length : MAX_RANGE), y1, x1, y2, x2, 0);
561 if (!grid_n) return TRUE;
564 y = GRID_Y(grid_g[grid_n - 1]);
565 x = GRID_X(grid_g[grid_n - 1]);
567 /* May not end in an unrequested grid */
568 if ((y != y2) || (x != x2)) return (FALSE);
576 * @brief 特殊な部屋地形向けにモンスターを配置する / Hack -- Place some sleeping monsters near the given location
577 * @param y1 モンスターを配置したいマスの中心Y座標
578 * @param x1 モンスターを配置したいマスの中心X座標
579 * @param num 配置したいモンスターの数
582 * Only really called by some of the "vault" routines.
584 void vault_monsters(floor_type *floor_ptr, POSITION y1, POSITION x1, int num)
590 /* Try to summon "num" monsters "near" the given location */
591 for (k = 0; k < num; k++)
593 /* Try nine locations */
594 for (i = 0; i < 9; i++)
598 /* Pick a nearby location */
599 scatter(&y, &x, y1, x1, d, 0);
601 /* Require "empty" floor grids */
602 g_ptr = &floor_ptr->grid_array[y][x];
603 if (!cave_empty_grid(g_ptr)) continue;
605 /* Place the monster (allow groups) */
606 floor_ptr->monster_level = floor_ptr->base_level + 2;
607 (void)place_monster(y, x, (PM_ALLOW_SLEEP | PM_ALLOW_GROUP));
608 floor_ptr->monster_level = floor_ptr->base_level;
615 * @brief 指定された座標が地震や階段生成の対象となるマスかを返す。 / Determine if a given location may be "destroyed"
618 * @return 各種の変更が可能ならTRUEを返す。
620 * 条件は永久地形でなく、なおかつ該当のマスにアーティファクトが存在しないか、である。英語の旧コメントに反して*破壊*の抑止判定には現在使われていない。
622 bool cave_valid_bold(floor_type *floor_ptr, POSITION y, POSITION x)
624 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
625 OBJECT_IDX this_o_idx, next_o_idx = 0;
627 /* Forbid perma-grids */
628 if (cave_perma_grid(g_ptr)) return (FALSE);
631 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
634 o_ptr = &floor_ptr->o_list[this_o_idx];
635 next_o_idx = o_ptr->next_o_idx;
637 /* Forbid artifact grids */
638 if (object_is_artifact(o_ptr)) return (FALSE);