3 * @brief 魔法による遠隔処理の実装 / Spell projection
7 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
8 * This software may be copied and distributed for educational, research,
9 * and not for profit purposes provided that this copyright and statement
10 * are included in all such copies. Other copyrights may also apply.
14 #include "system/angband.h"
15 #include "system/system-variables.h"
17 #include "main/sound-definitions-table.h"
18 #include "cmd/cmd-pet.h"
19 #include "cmd/cmd-dump.h"
20 #include "player/player-class.h"
21 #include "monster/monster.h"
22 #include "spell/spells1.h"
24 #include "view/display-main-window.h"
25 #include "effect/spells-effect-util.h"
26 #include "effect/effect-feature.h"
27 #include "effect/effect-item.h"
28 #include "effect/effect-monster.h"
29 #include "effect/effect-characteristics.h"
32 * Find the distance from (x, y) to a line.
34 POSITION dist_to_line(POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
38 POSITION ny = x2 - x1;
39 POSITION nx = y1 - y2;
40 POSITION pd = distance(y1, x1, y, x);
41 POSITION nd = distance(y1, x1, y2, x2);
43 if (pd > nd) return distance(y, x, y2, x2);
45 nd = ((nd) ? ((py * ny + px * nx) / nd) : 0);
46 return((nd >= 0) ? nd : 0 - nd);
52 * Modified version of los() for calculation of disintegration balls.
53 * Disintegration effects are stopped by permanent walls.
55 bool in_disintegration_range(floor_type *floor_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
57 POSITION delta_y = y2 - y1;
58 POSITION delta_x = x2 - x1;
59 POSITION absolute_y = ABS(delta_y);
60 POSITION absolute_x = ABS(delta_x);
61 if ((absolute_x < 2) && (absolute_y < 2)) return TRUE;
66 /* South -- check for walls */
69 for (scanner_y = y1 + 1; scanner_y < y2; scanner_y++)
71 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) return FALSE;
75 /* North -- check for walls */
78 for (scanner_y = y1 - 1; scanner_y > y2; scanner_y--)
80 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) return FALSE;
87 /* Directly East/West */
91 /* East -- check for walls */
94 for (scanner_x = x1 + 1; scanner_x < x2; scanner_x++)
96 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) return FALSE;
100 /* West -- check for walls */
103 for (scanner_x = x1 - 1; scanner_x > x2; scanner_x--)
105 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) return FALSE;
112 POSITION sign_x = (delta_x < 0) ? -1 : 1;
113 POSITION sign_y = (delta_y < 0) ? -1 : 1;
118 if (!cave_stop_disintegration(floor_ptr, y1 + sign_y, x1)) return TRUE;
121 else if (absolute_y == 1)
125 if (!cave_stop_disintegration(floor_ptr, y1, x1 + sign_x)) return TRUE;
129 POSITION scale_factor_2 = (absolute_x * absolute_y);
130 POSITION scale_factor_1 = scale_factor_2 << 1;
132 POSITION m; /* Slope, or 1/Slope, of LOS */
133 if (absolute_x >= absolute_y)
135 fraction_y = absolute_y * absolute_y;
137 scanner_x = x1 + sign_x;
138 if (fraction_y == scale_factor_2)
140 scanner_y = y1 + sign_y;
141 fraction_y -= scale_factor_1;
148 /* Note (below) the case (qy == f2), where */
149 /* the LOS exactly meets the corner of a tile. */
150 while (x2 - scanner_x)
152 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
156 if (fraction_y < scale_factor_2)
160 else if (fraction_y > scale_factor_2)
163 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
164 fraction_y -= scale_factor_1;
170 fraction_y -= scale_factor_1;
178 POSITION fraction_x = absolute_x * absolute_x;
180 scanner_y = y1 + sign_y;
181 if (fraction_x == scale_factor_2)
183 scanner_x = x1 + sign_x;
184 fraction_x -= scale_factor_1;
191 /* Note (below) the case (qx == f2), where */
192 /* the LOS exactly meets the corner of a tile. */
193 while (y2 - scanner_y)
195 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
199 if (fraction_x < scale_factor_2)
203 else if (fraction_x > scale_factor_2)
206 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
207 fraction_x -= scale_factor_1;
213 fraction_x -= scale_factor_1;
225 void breath_shape(player_type *caster_ptr, u16b *path_g, int dist, int *pgrids, POSITION *gx, POSITION *gy, POSITION *gm, POSITION *pgm_rad, POSITION rad, POSITION y1, POSITION x1, POSITION y2, POSITION x2, EFFECT_ID typ)
230 int brev = rad * rad / dist;
234 int mdis = distance(y1, x1, y2, x2) + rad;
236 floor_type *floor_ptr = caster_ptr->current_floor_ptr;
239 if ((0 < dist) && (path_n < dist))
241 POSITION ny = GRID_Y(path_g[path_n]);
242 POSITION nx = GRID_X(path_g[path_n]);
243 POSITION nd = distance(ny, nx, y1, x1);
253 /* Travel from center outward */
254 for (cdis = 0; cdis <= brad; cdis++)
256 for (POSITION y = by - cdis; y <= by + cdis; y++)
258 for (POSITION x = bx - cdis; x <= bx + cdis; x++)
260 if (!in_bounds(floor_ptr, y, x)) continue;
261 if (distance(y1, x1, y, x) != bdis) continue;
262 if (distance(by, bx, y, x) != cdis) continue;
268 /* Lights are stopped by opaque terrains */
269 if (!los(caster_ptr, by, bx, y, x)) continue;
271 case GF_DISINTEGRATE:
272 /* Disintegration are stopped only by perma-walls */
273 if (!in_disintegration_range(floor_ptr, by, bx, y, x)) continue;
276 /* Ball explosions are stopped by walls */
277 if (!projectable(caster_ptr, by, bx, y, x)) continue;
288 gm[bdis + 1] = *pgrids;
289 brad = rad * (path_n + brev) / (dist + brev);
298 * @brief 鏡魔法「封魔結界」の効果処理
300 * @return 効果があったらTRUEを返す
302 bool binding_field(player_type *caster_ptr, HIT_POINT dam)
304 POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
305 int mirror_num = 0; /* 鏡の数 */
306 int msec = delay_factor * delay_factor*delay_factor;
312 /* Default target of monsterspell is player */
313 monster_target_y = caster_ptr->y;
314 monster_target_x = caster_ptr->x;
316 for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++)
318 for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++)
320 if (is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]) &&
321 distance(caster_ptr->y, caster_ptr->x, y, x) <= MAX_RANGE &&
322 distance(caster_ptr->y, caster_ptr->x, y, x) != 0 &&
323 player_has_los_bold(caster_ptr, y, x) &&
324 projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
326 mirror_y[mirror_num] = y;
327 mirror_x[mirror_num] = x;
333 if (mirror_num < 2)return FALSE;
335 point_x[0] = randint0(mirror_num);
337 point_x[1] = randint0(mirror_num);
338 } while (point_x[0] == point_x[1]);
340 point_y[0] = mirror_y[point_x[0]];
341 point_x[0] = mirror_x[point_x[0]];
342 point_y[1] = mirror_y[point_x[1]];
343 point_x[1] = mirror_x[point_x[1]];
344 point_y[2] = caster_ptr->y;
345 point_x[2] = caster_ptr->x;
347 POSITION x = point_x[0] + point_x[1] + point_x[2];
348 POSITION y = point_y[0] + point_y[1] + point_y[2];
350 POSITION centersign = (point_x[0] * 3 - x)*(point_y[1] * 3 - y)
351 - (point_y[0] * 3 - y)*(point_x[1] * 3 - x);
352 if (centersign == 0)return FALSE;
354 POSITION x1 = point_x[0] < point_x[1] ? point_x[0] : point_x[1];
355 x1 = x1 < point_x[2] ? x1 : point_x[2];
356 POSITION y1 = point_y[0] < point_y[1] ? point_y[0] : point_y[1];
357 y1 = y1 < point_y[2] ? y1 : point_y[2];
359 POSITION x2 = point_x[0] > point_x[1] ? point_x[0] : point_x[1];
360 x2 = x2 > point_x[2] ? x2 : point_x[2];
361 POSITION y2 = point_y[0] > point_y[1] ? point_y[0] : point_y[1];
362 y2 = y2 > point_y[2] ? y2 : point_y[2];
364 for (y = y1; y <= y2; y++)
366 for (x = x1; x <= x2; x++)
368 if (centersign*((point_x[0] - x)*(point_y[1] - y)
369 - (point_y[0] - y)*(point_x[1] - x)) >= 0 &&
370 centersign*((point_x[1] - x)*(point_y[2] - y)
371 - (point_y[1] - y)*(point_x[2] - x)) >= 0 &&
372 centersign*((point_x[2] - x)*(point_y[0] - y)
373 - (point_y[2] - y)*(point_x[0] - x)) >= 0)
375 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
377 if (!(caster_ptr->blind)
378 && panel_contains(y, x))
380 u16b p = bolt_pict(y, x, y, x, GF_MANA);
381 print_rel(caster_ptr, PICT_C(p), PICT_A(p), y, x);
382 move_cursor_relative(y, x);
384 Term_xtra(TERM_XTRA_DELAY, msec);
391 for (y = y1; y <= y2; y++)
393 for (x = x1; x <= x2; x++)
395 if (centersign*((point_x[0] - x)*(point_y[1] - y)
396 - (point_y[0] - y)*(point_x[1] - x)) >= 0 &&
397 centersign*((point_x[1] - x)*(point_y[2] - y)
398 - (point_y[1] - y)*(point_x[2] - x)) >= 0 &&
399 centersign*((point_x[2] - x)*(point_y[0] - y)
400 - (point_y[2] - y)*(point_x[0] - x)) >= 0)
402 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
404 (void)affect_feature(caster_ptr, 0, 0, y, x, dam, GF_MANA);
410 for (y = y1; y <= y2; y++)
412 for (x = x1; x <= x2; x++)
414 if (centersign*((point_x[0] - x)*(point_y[1] - y)
415 - (point_y[0] - y)*(point_x[1] - x)) >= 0 &&
416 centersign*((point_x[1] - x)*(point_y[2] - y)
417 - (point_y[1] - y)*(point_x[2] - x)) >= 0 &&
418 centersign*((point_x[2] - x)*(point_y[0] - y)
419 - (point_y[2] - y)*(point_x[0] - x)) >= 0)
421 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
423 (void)affect_item(caster_ptr, 0, 0, y, x, dam, GF_MANA);
429 for (y = y1; y <= y2; y++)
431 for (x = x1; x <= x2; x++)
433 if (centersign*((point_x[0] - x)*(point_y[1] - y)
434 - (point_y[0] - y)*(point_x[1] - x)) >= 0 &&
435 centersign*((point_x[1] - x)*(point_y[2] - y)
436 - (point_y[1] - y)*(point_x[2] - x)) >= 0 &&
437 centersign*((point_x[2] - x)*(point_y[0] - y)
438 - (point_y[2] - y)*(point_x[0] - x)) >= 0)
440 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
442 (void)affect_monster(caster_ptr, 0, 0, y, x, dam, GF_MANA,
443 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), TRUE);
451 msg_print(_("鏡が結界に耐えきれず、壊れてしまった。", "The field broke a mirror"));
452 remove_mirror(caster_ptr, point_y[0], point_x[0]);
460 * @brief 鏡魔法「鏡の封印」の効果処理
462 * @return 効果があったらTRUEを返す
464 void seal_of_mirror(player_type *caster_ptr, HIT_POINT dam)
466 for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++)
468 for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++)
470 if (!is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]))
473 if (!affect_monster(caster_ptr, 0, 0, y, x, dam, GF_GENOCIDE,
474 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), TRUE))
477 if (!caster_ptr->current_floor_ptr->grid_array[y][x].m_idx)
479 remove_mirror(caster_ptr, y, x);
487 * @brief 領域魔法に応じて技能の名称を返す。
488 * @param tval 魔法書のtval
489 * @return 領域魔法の技能名称を保管した文字列ポインタ
491 concptr spell_category_name(OBJECT_TYPE_VALUE tval)
495 case TV_HISSATSU_BOOK:
496 return _("必殺技", "art");
498 return _("祈り", "prayer");
500 return _("歌", "song");
502 return _("呪文", "spell");