7 * キーパッドの方向を南から反時計回り順に列挙 / Global array for looping through the "keypad directions"
9 const POSITION ddd[9] =
10 { 2, 8, 6, 4, 3, 1, 9, 7, 5 };
13 * dddで定義した順にベクトルのX軸成分を定義 / Global arrays for converting "keypad direction" into offsets
15 const POSITION ddx[10] =
16 { 0, -1, 0, 1, -1, 0, 1, -1, 0, 1 };
19 * dddで定義した順にベクトルのY軸成分を定義 / Global arrays for converting "keypad direction" into offsets
21 const POSITION ddy[10] =
22 { 0, 1, 1, 1, 0, 0, 0, -1, -1, -1 };
25 * ddd越しにベクトルのX軸成分を定義 / Global arrays for optimizing "ddx[ddd[i]]" and "ddy[ddd[i]]"
27 const POSITION ddx_ddd[9] =
28 { 0, 0, 1, -1, 1, -1, 1, -1, 0 };
31 * ddd越しにベクトルのY軸成分を定義 / Global arrays for optimizing "ddx[ddd[i]]" and "ddy[ddd[i]]"
33 const POSITION ddy_ddd[9] =
34 { 1, -1, 0, 0, 1, 1, -1, -1, 0 };
38 * キーパッドの円環状方向配列 / Circular keypad direction array
40 const POSITION cdd[8] =
41 { 2, 3, 6, 9, 8, 7, 4, 1 };
44 * cdd越しにベクトルのX軸成分を定義 / Global arrays for optimizing "ddx[cdd[i]]" and "ddy[cdd[i]]"
46 const POSITION ddx_cdd[8] =
47 { 0, 1, 1, 1, 0, -1, -1, -1 };
50 * cdd越しにベクトルのY軸成分を定義 / Global arrays for optimizing "ddx[cdd[i]]" and "ddy[cdd[i]]"
52 const POSITION ddy_cdd[8] =
53 { 1, 1, 0, -1, -1, -1, 0, 1 };
57 * @brief 2点間の距離をニュートン・ラプソン法で算出する / Distance between two points via Newton-Raphson technique
64 POSITION distance(POSITION y1, POSITION x1, POSITION y2, POSITION x2)
66 POSITION dy = (y1 > y2) ? (y1 - y2) : (y2 - y1);
67 POSITION dx = (x1 > x2) ? (x1 - x2) : (x2 - x1);
69 /* Squared distance */
70 POSITION target = (dy * dy) + (dx * dx);
72 /* Approximate distance: hypot(dy,dx) = max(dy,dx) + min(dy,dx) / 2 */
73 POSITION d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
78 if (!dy || !dx) return d;
82 /* Approximate error */
83 err = (target - d * d) / (2 * d);
85 /* No error - we are done */
96 * @brief プレイヤーから指定の座標がどの方角にあるかを返す /
97 * Convert an adjacent location to a direction.
102 DIRECTION coords_to_dir(player_type *creature_ptr, POSITION y, POSITION x)
104 DIRECTION d[3][3] = { {7, 4, 1}, {8, 5, 2}, {9, 6, 3} };
107 dy = y - creature_ptr->y;
108 dx = x - creature_ptr->x;
109 if (ABS(dx) > 1 || ABS(dy) > 1) return (0);
111 return d[dx + 1][dy + 1];
115 * @brief 始点から終点への直線経路を返す /
116 * Determine the path taken by a projection.
117 * @param gp 経路座標リストを返す参照ポインタ
127 * The projection will always start from the grid (y1,x1), and will travel
128 * towards the grid (y2,x2), touching one grid per unit of distance along
129 * the major axis, and stopping when it enters the destination grid or a
130 * wall grid, or has travelled the maximum legal distance of "range".
132 * Note that "distance" in this function (as in the "update_view()" code)
133 * is defined as "MAX(dy,dx) + MIN(dy,dx)/2", which means that the player
134 * actually has an "octagon of projection" not a "circle of projection".
136 * The path grids are saved into the grid array pointed to by "gp", and
137 * there should be room for at least "range" grids in "gp". Note that
138 * due to the way in which distance is calculated, this function normally
139 * uses fewer than "range" grids for the projection path, so the result
140 * of this function should never be compared directly to "range". Note
141 * that the initial grid (y1,x1) is never saved into the grid array, not
142 * even if the initial grid is also the final grid.
144 * The "flg" flags can be used to modify the behavior of this function.
146 * In particular, the "PROJECT_STOP" and "PROJECT_THRU" flags have the same
147 * semantics as they do for the "project" function, namely, that the path
148 * will stop as soon as it hits a monster, or that the path will continue
149 * through the destination grid, respectively.
151 * The "PROJECT_JUMP" flag, which for the "project()" function means to
152 * start at a special grid (which makes no sense in this function), means
153 * that the path should be "angled" slightly if needed to avoid any wall
154 * grids, allowing the player to "target" any grid which is in "view".
155 * This flag is non-trivial and has not yet been implemented, but could
156 * perhaps make use of the "vinfo" array (above).
158 * This function returns the number of grids (if any) in the path. This
159 * function will return zero if and only if (y1,x1) and (y2,x2) are equal.
161 * This algorithm is similar to, but slightly different from, the one used
162 * by "update_view_los()", and very different from the one used by "los()".
165 sint project_path(u16b *gp, POSITION range, POSITION y1, POSITION x1, POSITION y2, POSITION x2, BIT_FLAGS flg)
187 /* No path necessary (or allowed) */
188 if ((x1 == x2) && (y1 == y2)) return (0);
216 /* Number of "units" in one "half" grid */
219 /* Number of "units" in one "full" grid */
225 /* Let m = ((dx/dy) * full) = (dx * dx * 2) */
236 /* Advance (X) part 2 */
239 /* Advance (X) part 3 */
246 /* Create the projection path */
250 gp[n++] = GRID(y, x);
252 /* Hack -- Check maximum range */
253 if ((n + (k >> 1)) >= range) break;
255 /* Sometimes stop at destination grid */
256 if (!(flg & (PROJECT_THRU)))
258 if ((x == x2) && (y == y2)) break;
261 if (flg & (PROJECT_DISI))
263 if ((n > 0) && cave_stop_disintegration(y, x)) break;
265 else if (flg & (PROJECT_LOS))
267 if ((n > 0) && !cave_los_bold(y, x)) break;
269 else if (!(flg & (PROJECT_PATH)))
271 /* Always stop at non-initial wall grids */
272 if ((n > 0) && !cave_have_flag_bold(y, x, FF_PROJECT)) break;
275 /* Sometimes stop at non-initial monsters/players */
276 if (flg & (PROJECT_STOP))
279 (player_bold(y, x) || p_ptr->current_floor_ptr->grid_array[y][x].m_idx != 0))
283 if (!in_bounds(p_ptr->current_floor_ptr, y, x)) break;
288 /* Advance (X) part 1 */
291 /* Horizontal change */
294 /* Advance (X) part 2 */
297 /* Advance (X) part 3 */
313 /* Let m = ((dy/dx) * full) = (dy * dy * 2) */
322 /* Vertical change */
325 /* Advance (Y) part 2 */
328 /* Advance (Y) part 3 */
335 /* Create the projection path */
339 gp[n++] = GRID(y, x);
341 /* Hack -- Check maximum range */
342 if ((n + (k >> 1)) >= range) break;
344 /* Sometimes stop at destination grid */
345 if (!(flg & (PROJECT_THRU)))
347 if ((x == x2) && (y == y2)) break;
350 if (flg & (PROJECT_DISI))
352 if ((n > 0) && cave_stop_disintegration(y, x)) break;
354 else if (flg & (PROJECT_LOS))
356 if ((n > 0) && !cave_los_bold(y, x)) break;
358 else if (!(flg & (PROJECT_PATH)))
360 /* Always stop at non-initial wall grids */
361 if ((n > 0) && !cave_have_flag_bold(y, x, FF_PROJECT)) break;
364 /* Sometimes stop at non-initial monsters/players */
365 if (flg & (PROJECT_STOP))
368 (player_bold(y, x) || p_ptr->current_floor_ptr->grid_array[y][x].m_idx != 0))
372 if (!in_bounds(p_ptr->current_floor_ptr, y, x)) break;
377 /* Advance (Y) part 1 */
380 /* Vertical change */
383 /* Advance (Y) part 2 */
386 /* Advance (Y) part 3 */
406 /* Create the projection path */
410 gp[n++] = GRID(y, x);
412 /* Hack -- Check maximum range */
413 if ((n + (n >> 1)) >= range) break;
415 /* Sometimes stop at destination grid */
416 if (!(flg & (PROJECT_THRU)))
418 if ((x == x2) && (y == y2)) break;
421 if (flg & (PROJECT_DISI))
423 if ((n > 0) && cave_stop_disintegration(y, x)) break;
425 else if (flg & (PROJECT_LOS))
427 if ((n > 0) && !cave_los_bold(y, x)) break;
429 else if (!(flg & (PROJECT_PATH)))
431 /* Always stop at non-initial wall grids */
432 if ((n > 0) && !cave_have_flag_bold(y, x, FF_PROJECT)) break;
435 /* Sometimes stop at non-initial monsters/players */
436 if (flg & (PROJECT_STOP))
439 (player_bold(y, x) || p_ptr->current_floor_ptr->grid_array[y][x].m_idx != 0))
443 if (!in_bounds(p_ptr->current_floor_ptr, y, x)) break;
458 * @brief LOS(Line Of Sight / 視線が通っているか)の判定を行う。
463 * @return LOSが通っているならTRUEを返す。
465 * A simple, fast, integer-based line-of-sight algorithm. By Joseph Hall,\n
466 * 4116 Brewster Drive, Raleigh NC 27606. Email to jnh@ecemwl.ncsu.edu.\n
468 * Returns TRUE if a line of sight can be traced from (x1,y1) to (x2,y2).\n
470 * The LOS begins at the center of the tile (x1,y1) and ends at the center of\n
471 * the tile (x2,y2). If los() is to return TRUE, all of the tiles this line\n
472 * passes through must be floor tiles, except for (x1,y1) and (x2,y2).\n
474 * We assume that the "mathematical corner" of a non-floor tile does not\n
475 * block line of sight.\n
477 * Because this function uses (short) ints for all calculations, overflow may\n
478 * occur if dx and dy exceed 90.\n
480 * Once all the degenerate cases are eliminated, the values "qx", "qy", and\n
481 * "m" are multiplied by a scale factor "f1 = abs(dx * dy * 2)", so that\n
482 * we can use integer arithmetic.\n
484 * We travel from start to finish along the longer axis, starting at the border\n
485 * between the first and second tiles, where the y offset = .5 * slope, taking\n
486 * into account the scale factor. See below.\n
488 * Also note that this function and the "move towards target" code do NOT\n
489 * share the same properties. Thus, you can see someone, target them, and\n
490 * then fire a bolt at them, but the bolt may hit a wall, not them. However\n,
491 * by clever choice of target locations, you can sometimes throw a "curve".\n
493 * Note that "line of sight" is not "reflexive" in all cases.\n
495 * Use the "projectable()" routine to test "spell/missile line of sight".\n
497 * Use the "update_view()" function to determine player line-of-sight.\n
499 bool los(POSITION y1, POSITION x1, POSITION y2, POSITION x2)
519 /* Slope, or 1/Slope, of LOS */
523 /* Extract the offset */
527 /* Extract the absolute offset */
532 /* Handle adjacent (or identical) grids */
533 if ((ax < 2) && (ay < 2)) return TRUE;
536 /* Paranoia -- require "safe" origin */
537 /* if (!in_bounds(p_ptr->current_floor_ptr, y1, x1)) return FALSE; */
538 /* if (!in_bounds(p_ptr->current_floor_ptr, y2, x2)) return FALSE; */
541 /* Directly South/North */
544 /* South -- check for walls */
547 for (ty = y1 + 1; ty < y2; ty++)
549 if (!cave_los_bold(ty, x1)) return FALSE;
553 /* North -- check for walls */
556 for (ty = y1 - 1; ty > y2; ty--)
558 if (!cave_los_bold(ty, x1)) return FALSE;
566 /* Directly East/West */
569 /* East -- check for walls */
572 for (tx = x1 + 1; tx < x2; tx++)
574 if (!cave_los_bold(y1, tx)) return FALSE;
578 /* West -- check for walls */
581 for (tx = x1 - 1; tx > x2; tx--)
583 if (!cave_los_bold(y1, tx)) return FALSE;
592 /* Extract some signs */
593 sx = (dx < 0) ? -1 : 1;
594 sy = (dy < 0) ? -1 : 1;
597 /* Vertical "knights" */
602 if (cave_los_bold(y1 + sy, x1)) return TRUE;
606 /* Horizontal "knights" */
611 if (cave_los_bold(y1, x1 + sx)) return TRUE;
616 /* Calculate scale factor div 2 */
619 /* Calculate scale factor */
623 /* Travel horizontally */
626 /* Let m = dy / dx * 2 * (dy * dx) = 2 * dy * dy */
632 /* Consider the special case where slope == 1. */
643 /* Note (below) the case (qy == f2), where */
644 /* the LOS exactly meets the corner of a tile. */
647 if (!cave_los_bold(ty, tx)) return FALSE;
658 if (!cave_los_bold(ty, tx)) return FALSE;
671 /* Travel vertically */
674 /* Let m = dx / dy * 2 * (dx * dy) = 2 * dx * dx */
690 /* Note (below) the case (qx == f2), where */
691 /* the LOS exactly meets the corner of a tile. */
694 if (!cave_los_bold(ty, tx)) return FALSE;
705 if (!cave_los_bold(ty, tx)) return FALSE;
723 * Determine if a bolt spell cast from (y1,x1) to (y2,x2) will arrive
724 * at the final destination, assuming no monster gets in the way.
726 * This is slightly (but significantly) different from "los(y1,x1,y2,x2)".
728 bool projectable(POSITION y1, POSITION x1, POSITION y2, POSITION x2)
735 /* Check the projection path */
736 grid_n = project_path(grid_g, (project_length ? project_length : MAX_RANGE), y1, x1, y2, x2, 0);
739 if (!grid_n) return TRUE;
742 y = GRID_Y(grid_g[grid_n - 1]);
743 x = GRID_X(grid_g[grid_n - 1]);
745 /* May not end in an unrequested grid */
746 if ((y != y2) || (x != x2)) return (FALSE);
755 * Standard "find me a location" function
757 * Obtains a legal location within the given distance of the initial
758 * location, and with "los()" from the source to destination location.
760 * This function is often called from inside a loop which searches for
761 * locations while increasing the "d" distance.
763 * Currently the "m" parameter is unused.
765 void scatter(POSITION *yp, POSITION *xp, POSITION y, POSITION x, POSITION d, BIT_FLAGS mode)
769 /* Pick a location */
772 /* Pick a new location */
773 ny = rand_spread(y, d);
774 nx = rand_spread(x, d);
776 /* Ignore annoying locations */
777 if (!in_bounds(p_ptr->current_floor_ptr, ny, nx)) continue;
779 /* Ignore "excessively distant" locations */
780 if ((d > 1) && (distance(y, x, ny, nx) > d)) continue;
782 if (mode & PROJECT_LOS)
784 if (los(y, x, ny, nx)) break;
788 if (projectable(y, x, ny, nx)) break;
793 /* Save the location */
800 * @brief 指定された座標をプレイヤーが視覚に収められるかを返す。 / Can the player "see" the given grid in detail?
803 * @return 視覚に収められる状態ならTRUEを返す
805 * He must have vision, illumination, and line of sight.\n
807 * Note -- "CAVE_LITE" is only set if the "torch" has "los()".\n
808 * So, given "CAVE_LITE", we know that the grid is "fully visible".\n
810 * Note that "CAVE_GLOW" makes little sense for a wall, since it would mean\n
811 * that a wall is visible from any direction. That would be odd. Except\n
812 * under wizard light, which might make sense. Thus, for walls, we require\n
813 * not only that they be "CAVE_GLOW", but also, that they be adjacent to a\n
814 * grid which is not only "CAVE_GLOW", but which is a non-wall, and which is\n
815 * in line of sight of the player.\n
817 * This extra check is expensive, but it provides a more "correct" semantics.\n
819 * Note that we should not run this check on walls which are "outer walls" of\n
820 * the dungeon, or we will induce a memory fault, but actually verifying all\n
821 * of the locations would be extremely expensive.\n
823 * Thus, to speed up the function, we assume that all "perma-walls" which are\n
824 * "CAVE_GLOW" are "illuminated" from all sides. This is correct for all cases\n
825 * except "vaults" and the "buildings" in town. But the town is a hack anyway,\n
826 * and the player has more important things on his mind when he is attacking a\n
827 * monster vault. It is annoying, but an extremely important optimization.\n
829 * Note that "glowing walls" are only considered to be "illuminated" if the\n
830 * grid which is next to the wall in the direction of the player is also a\n
831 * "glowing" grid. This prevents the player from being able to "see" the\n
832 * walls of illuminated rooms from a corridor outside the room.\n
834 bool player_can_see_bold(POSITION y, POSITION x)
838 /* Blind players see nothing */
839 if (p_ptr->blind) return FALSE;
841 g_ptr = &p_ptr->current_floor_ptr->grid_array[y][x];
843 /* Note that "torch-lite" yields "illumination" */
844 if (g_ptr->info & (CAVE_LITE | CAVE_MNLT)) return TRUE;
846 /* Require line of sight to the grid */
847 if (!player_has_los_bold(y, x)) return FALSE;
849 /* Noctovision of Ninja */
850 if (p_ptr->see_nocto) return TRUE;
852 /* Require "perma-lite" of the grid */
853 if ((g_ptr->info & (CAVE_GLOW | CAVE_MNDK)) != CAVE_GLOW) return FALSE;
855 /* Feature code (applying "mimic" field) */
856 /* Floors are simple */
857 if (feat_supports_los(get_feat_mimic(g_ptr))) return TRUE;
859 /* Check for "local" illumination */
860 return check_local_illumination(y, x);
864 * Calculate "incremental motion". Used by project() and shoot().
865 * Assumes that (*y,*x) lies on the path from (y1,x1) to (y2,x2).
867 void mmove2(POSITION *y, POSITION *x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
869 POSITION dy, dx, dist, shift;
871 /* Extract the distance travelled */
872 dy = (*y < y1) ? y1 - *y : *y - y1;
873 dx = (*x < x1) ? x1 - *x : *x - x1;
875 /* Number of steps */
876 dist = (dy > dx) ? dy : dx;
878 /* We are calculating the next location */
882 /* Calculate the total distance along each axis */
883 dy = (y2 < y1) ? (y1 - y2) : (y2 - y1);
884 dx = (x2 < x1) ? (x1 - x2) : (x2 - x1);
886 /* Paranoia -- Hack -- no motion */
887 if (!dy && !dx) return;
890 /* Move mostly vertically */
893 /* Extract a shift factor */
894 shift = (dist * dx + (dy - 1) / 2) / dy;
896 /* Sometimes move along the minor axis */
897 (*x) = (x2 < x1) ? (x1 - shift) : (x1 + shift);
899 /* Always move along major axis */
900 (*y) = (y2 < y1) ? (y1 - dist) : (y1 + dist);
903 /* Move mostly horizontally */
906 /* Extract a shift factor */
907 shift = (dist * dy + (dx - 1) / 2) / dx;
909 /* Sometimes move along the minor axis */
910 (*y) = (y2 < y1) ? (y1 - shift) : (y1 + shift);
912 /* Always move along major axis */
913 (*x) = (x2 < x1) ? (x1 - dist) : (x1 + dist);