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.
17 #include "main/sound-definitions-table.h"
18 #include "cmd/cmd-pet.h"
19 #include "cmd/cmd-dump.h"
20 #include "player-class.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"
31 * Find the distance from (x, y) to a line.
33 POSITION dist_to_line(POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
37 POSITION ny = x2 - x1;
38 POSITION nx = y1 - y2;
39 POSITION pd = distance(y1, x1, y, x);
40 POSITION nd = distance(y1, x1, y2, x2);
42 if (pd > nd) return distance(y, x, y2, x2);
44 nd = ((nd) ? ((py * ny + px * nx) / nd) : 0);
45 return((nd >= 0) ? nd : 0 - nd);
51 * Modified version of los() for calculation of disintegration balls.
52 * Disintegration effects are stopped by permanent walls.
54 bool in_disintegration_range(floor_type *floor_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
56 POSITION delta_y = y2 - y1;
57 POSITION delta_x = x2 - x1;
58 POSITION absolute_y = ABS(delta_y);
59 POSITION absolute_x = ABS(delta_x);
60 if ((absolute_x < 2) && (absolute_y < 2)) return TRUE;
65 /* South -- check for walls */
68 for (scanner_y = y1 + 1; scanner_y < y2; scanner_y++)
70 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) return FALSE;
74 /* North -- check for walls */
77 for (scanner_y = y1 - 1; scanner_y > y2; scanner_y--)
79 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) return FALSE;
86 /* Directly East/West */
90 /* East -- check for walls */
93 for (scanner_x = x1 + 1; scanner_x < x2; scanner_x++)
95 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) return FALSE;
99 /* West -- check for walls */
102 for (scanner_x = x1 - 1; scanner_x > x2; scanner_x--)
104 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) return FALSE;
111 POSITION sign_x = (delta_x < 0) ? -1 : 1;
112 POSITION sign_y = (delta_y < 0) ? -1 : 1;
117 if (!cave_stop_disintegration(floor_ptr, y1 + sign_y, x1)) return TRUE;
120 else if (absolute_y == 1)
124 if (!cave_stop_disintegration(floor_ptr, y1, x1 + sign_x)) return TRUE;
128 POSITION scale_factor_2 = (absolute_x * absolute_y);
129 POSITION scale_factor_1 = scale_factor_2 << 1;
131 POSITION m; /* Slope, or 1/Slope, of LOS */
132 if (absolute_x >= absolute_y)
134 fraction_y = absolute_y * absolute_y;
136 scanner_x = x1 + sign_x;
137 if (fraction_y == scale_factor_2)
139 scanner_y = y1 + sign_y;
140 fraction_y -= scale_factor_1;
147 /* Note (below) the case (qy == f2), where */
148 /* the LOS exactly meets the corner of a tile. */
149 while (x2 - scanner_x)
151 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
155 if (fraction_y < scale_factor_2)
159 else if (fraction_y > scale_factor_2)
162 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
163 fraction_y -= scale_factor_1;
169 fraction_y -= scale_factor_1;
177 POSITION fraction_x = absolute_x * absolute_x;
179 scanner_y = y1 + sign_y;
180 if (fraction_x == scale_factor_2)
182 scanner_x = x1 + sign_x;
183 fraction_x -= scale_factor_1;
190 /* Note (below) the case (qx == f2), where */
191 /* the LOS exactly meets the corner of a tile. */
192 while (y2 - scanner_y)
194 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
198 if (fraction_x < scale_factor_2)
202 else if (fraction_x > scale_factor_2)
205 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
206 fraction_x -= scale_factor_1;
212 fraction_x -= scale_factor_1;
224 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)
229 int brev = rad * rad / dist;
233 int mdis = distance(y1, x1, y2, x2) + rad;
235 floor_type *floor_ptr = caster_ptr->current_floor_ptr;
238 if ((0 < dist) && (path_n < dist))
240 POSITION ny = GRID_Y(path_g[path_n]);
241 POSITION nx = GRID_X(path_g[path_n]);
242 POSITION nd = distance(ny, nx, y1, x1);
252 /* Travel from center outward */
253 for (cdis = 0; cdis <= brad; cdis++)
255 for (POSITION y = by - cdis; y <= by + cdis; y++)
257 for (POSITION x = bx - cdis; x <= bx + cdis; x++)
259 if (!in_bounds(floor_ptr, y, x)) continue;
260 if (distance(y1, x1, y, x) != bdis) continue;
261 if (distance(by, bx, y, x) != cdis) continue;
267 /* Lights are stopped by opaque terrains */
268 if (!los(caster_ptr, by, bx, y, x)) continue;
270 case GF_DISINTEGRATE:
271 /* Disintegration are stopped only by perma-walls */
272 if (!in_disintegration_range(floor_ptr, by, bx, y, x)) continue;
275 /* Ball explosions are stopped by walls */
276 if (!projectable(caster_ptr, by, bx, y, x)) continue;
287 gm[bdis + 1] = *pgrids;
288 brad = rad * (path_n + brev) / (dist + brev);
297 * @brief 鏡魔法「封魔結界」の効果処理
299 * @return 効果があったらTRUEを返す
301 bool binding_field(player_type *caster_ptr, HIT_POINT dam)
303 POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
304 int mirror_num = 0; /* 鏡の数 */
305 int msec = delay_factor * delay_factor*delay_factor;
311 /* Default target of monsterspell is player */
312 monster_target_y = caster_ptr->y;
313 monster_target_x = caster_ptr->x;
315 for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++)
317 for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++)
319 if (is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]) &&
320 distance(caster_ptr->y, caster_ptr->x, y, x) <= MAX_RANGE &&
321 distance(caster_ptr->y, caster_ptr->x, y, x) != 0 &&
322 player_has_los_bold(caster_ptr, y, x) &&
323 projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
325 mirror_y[mirror_num] = y;
326 mirror_x[mirror_num] = x;
332 if (mirror_num < 2)return FALSE;
334 point_x[0] = randint0(mirror_num);
336 point_x[1] = randint0(mirror_num);
337 } while (point_x[0] == point_x[1]);
339 point_y[0] = mirror_y[point_x[0]];
340 point_x[0] = mirror_x[point_x[0]];
341 point_y[1] = mirror_y[point_x[1]];
342 point_x[1] = mirror_x[point_x[1]];
343 point_y[2] = caster_ptr->y;
344 point_x[2] = caster_ptr->x;
346 POSITION x = point_x[0] + point_x[1] + point_x[2];
347 POSITION y = point_y[0] + point_y[1] + point_y[2];
349 POSITION centersign = (point_x[0] * 3 - x)*(point_y[1] * 3 - y)
350 - (point_y[0] * 3 - y)*(point_x[1] * 3 - x);
351 if (centersign == 0)return FALSE;
353 POSITION x1 = point_x[0] < point_x[1] ? point_x[0] : point_x[1];
354 x1 = x1 < point_x[2] ? x1 : point_x[2];
355 POSITION y1 = point_y[0] < point_y[1] ? point_y[0] : point_y[1];
356 y1 = y1 < point_y[2] ? y1 : point_y[2];
358 POSITION x2 = point_x[0] > point_x[1] ? point_x[0] : point_x[1];
359 x2 = x2 > point_x[2] ? x2 : point_x[2];
360 POSITION y2 = point_y[0] > point_y[1] ? point_y[0] : point_y[1];
361 y2 = y2 > point_y[2] ? y2 : point_y[2];
363 for (y = y1; y <= y2; y++)
365 for (x = x1; x <= x2; x++)
367 if (centersign*((point_x[0] - x)*(point_y[1] - y)
368 - (point_y[0] - y)*(point_x[1] - x)) >= 0 &&
369 centersign*((point_x[1] - x)*(point_y[2] - y)
370 - (point_y[1] - y)*(point_x[2] - x)) >= 0 &&
371 centersign*((point_x[2] - x)*(point_y[0] - y)
372 - (point_y[2] - y)*(point_x[0] - x)) >= 0)
374 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
376 if (!(caster_ptr->blind)
377 && panel_contains(y, x))
379 u16b p = bolt_pict(y, x, y, x, GF_MANA);
380 print_rel(caster_ptr, PICT_C(p), PICT_A(p), y, x);
381 move_cursor_relative(y, x);
383 Term_xtra(TERM_XTRA_DELAY, msec);
390 for (y = y1; y <= y2; y++)
392 for (x = x1; x <= x2; x++)
394 if (centersign*((point_x[0] - x)*(point_y[1] - y)
395 - (point_y[0] - y)*(point_x[1] - x)) >= 0 &&
396 centersign*((point_x[1] - x)*(point_y[2] - y)
397 - (point_y[1] - y)*(point_x[2] - x)) >= 0 &&
398 centersign*((point_x[2] - x)*(point_y[0] - y)
399 - (point_y[2] - y)*(point_x[0] - x)) >= 0)
401 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
403 (void)affect_feature(caster_ptr, 0, 0, y, x, dam, GF_MANA);
409 for (y = y1; y <= y2; y++)
411 for (x = x1; x <= x2; x++)
413 if (centersign*((point_x[0] - x)*(point_y[1] - y)
414 - (point_y[0] - y)*(point_x[1] - x)) >= 0 &&
415 centersign*((point_x[1] - x)*(point_y[2] - y)
416 - (point_y[1] - y)*(point_x[2] - x)) >= 0 &&
417 centersign*((point_x[2] - x)*(point_y[0] - y)
418 - (point_y[2] - y)*(point_x[0] - x)) >= 0)
420 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
422 (void)affect_item(caster_ptr, 0, 0, y, x, dam, GF_MANA);
428 for (y = y1; y <= y2; y++)
430 for (x = x1; x <= x2; x++)
432 if (centersign*((point_x[0] - x)*(point_y[1] - y)
433 - (point_y[0] - y)*(point_x[1] - x)) >= 0 &&
434 centersign*((point_x[1] - x)*(point_y[2] - y)
435 - (point_y[1] - y)*(point_x[2] - x)) >= 0 &&
436 centersign*((point_x[2] - x)*(point_y[0] - y)
437 - (point_y[2] - y)*(point_x[0] - x)) >= 0)
439 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
441 (void)affect_monster(caster_ptr, 0, 0, y, x, dam, GF_MANA,
442 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), TRUE);
450 msg_print(_("鏡が結界に耐えきれず、壊れてしまった。", "The field broke a mirror"));
451 remove_mirror(caster_ptr, point_y[0], point_x[0]);
459 * @brief 鏡魔法「鏡の封印」の効果処理
461 * @return 効果があったらTRUEを返す
463 void seal_of_mirror(player_type *caster_ptr, HIT_POINT dam)
465 for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++)
467 for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++)
469 if (!is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]))
472 if (!affect_monster(caster_ptr, 0, 0, y, x, dam, GF_GENOCIDE,
473 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), TRUE))
476 if (!caster_ptr->current_floor_ptr->grid_array[y][x].m_idx)
478 remove_mirror(caster_ptr, y, x);
486 * @brief 領域魔法に応じて技能の名称を返す。
487 * @param tval 魔法書のtval
488 * @return 領域魔法の技能名称を保管した文字列ポインタ
490 concptr spell_category_name(OBJECT_TYPE_VALUE tval)
494 case TV_HISSATSU_BOOK:
495 return _("必殺技", "art");
497 return _("祈り", "prayer");
499 return _("歌", "song");
501 return _("呪文", "spell");