OSDN Git Service

[Refactor] #39963 Changed inclusion for spells.h to process-effect.c
[hengband/hengband.git] / src / spells1.c
1 /*!
2  * @file spells1.c
3  * @brief 魔法による遠隔処理の実装 / Spell projection
4  * @date 2014/07/10
5  * @author
6  * <pre>
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.
11  * </pre>
12  */
13
14 #include "angband.h"
15 #include "core.h"
16 #include "util.h"
17 #include "main/sound-definitions-table.h"
18 #include "cmd/cmd-pet.h"
19 #include "cmd/cmd-dump.h"
20 #include "player-class.h"
21 #include "monster.h"
22 #include "spells.h"
23 #include "gameterm.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
30 /*
31  * Find the distance from (x, y) to a line.
32  */
33 POSITION dist_to_line(POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
34 {
35         POSITION py = y1 - y;
36         POSITION px = x1 - x;
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);
41
42         if (pd > nd) return distance(y, x, y2, x2);
43
44         nd = ((nd) ? ((py * ny + px * nx) / nd) : 0);
45         return((nd >= 0) ? nd : 0 - nd);
46 }
47
48
49 /*
50  *
51  * Modified version of los() for calculation of disintegration balls.
52  * Disintegration effects are stopped by permanent walls.
53  */
54 bool in_disintegration_range(floor_type *floor_ptr, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
55 {
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;
61
62         POSITION scanner_y;
63         if (!delta_x)
64         {
65                 /* South -- check for walls */
66                 if (delta_y > 0)
67                 {
68                         for (scanner_y = y1 + 1; scanner_y < y2; scanner_y++)
69                         {
70                                 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) return FALSE;
71                         }
72                 }
73
74                 /* North -- check for walls */
75                 else
76                 {
77                         for (scanner_y = y1 - 1; scanner_y > y2; scanner_y--)
78                         {
79                                 if (cave_stop_disintegration(floor_ptr, scanner_y, x1)) return FALSE;
80                         }
81                 }
82
83                 return TRUE;
84         }
85
86         /* Directly East/West */
87         POSITION scanner_x;
88         if (!delta_y)
89         {
90                 /* East -- check for walls */
91                 if (delta_x > 0)
92                 {
93                         for (scanner_x = x1 + 1; scanner_x < x2; scanner_x++)
94                         {
95                                 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) return FALSE;
96                         }
97                 }
98
99                 /* West -- check for walls */
100                 else
101                 {
102                         for (scanner_x = x1 - 1; scanner_x > x2; scanner_x--)
103                         {
104                                 if (cave_stop_disintegration(floor_ptr, y1, scanner_x)) return FALSE;
105                         }
106                 }
107
108                 return TRUE;
109         }
110
111         POSITION sign_x = (delta_x < 0) ? -1 : 1;
112         POSITION sign_y = (delta_y < 0) ? -1 : 1;
113         if (absolute_x == 1)
114         {
115                 if (absolute_y == 2)
116                 {
117                         if (!cave_stop_disintegration(floor_ptr, y1 + sign_y, x1)) return TRUE;
118                 }
119         }
120         else if (absolute_y == 1)
121         {
122                 if (absolute_x == 2)
123                 {
124                         if (!cave_stop_disintegration(floor_ptr, y1, x1 + sign_x)) return TRUE;
125                 }
126         }
127
128         POSITION scale_factor_2 = (absolute_x * absolute_y);
129         POSITION scale_factor_1 = scale_factor_2 << 1;
130         POSITION fraction_y;
131         POSITION m; /* Slope, or 1/Slope, of LOS */
132         if (absolute_x >= absolute_y)
133         {
134                 fraction_y = absolute_y * absolute_y;
135                 m = fraction_y << 1;
136                 scanner_x = x1 + sign_x;
137                 if (fraction_y == scale_factor_2)
138                 {
139                         scanner_y = y1 + sign_y;
140                         fraction_y -= scale_factor_1;
141                 }
142                 else
143                 {
144                         scanner_y = y1;
145                 }
146
147                 /* Note (below) the case (qy == f2), where */
148                 /* the LOS exactly meets the corner of a tile. */
149                 while (x2 - scanner_x)
150                 {
151                         if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
152
153                         fraction_y += m;
154
155                         if (fraction_y < scale_factor_2)
156                         {
157                                 scanner_x += sign_x;
158                         }
159                         else if (fraction_y > scale_factor_2)
160                         {
161                                 scanner_y += sign_y;
162                                 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
163                                 fraction_y -= scale_factor_1;
164                                 scanner_x += sign_x;
165                         }
166                         else
167                         {
168                                 scanner_y += sign_y;
169                                 fraction_y -= scale_factor_1;
170                                 scanner_x += sign_x;
171                         }
172                 }
173
174                 return TRUE;
175         }
176
177         POSITION fraction_x = absolute_x * absolute_x;
178         m = fraction_x << 1;
179         scanner_y = y1 + sign_y;
180         if (fraction_x == scale_factor_2)
181         {
182                 scanner_x = x1 + sign_x;
183                 fraction_x -= scale_factor_1;
184         }
185         else
186         {
187                 scanner_x = x1;
188         }
189
190         /* Note (below) the case (qx == f2), where */
191         /* the LOS exactly meets the corner of a tile. */
192         while (y2 - scanner_y)
193         {
194                 if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
195
196                 fraction_x += m;
197
198                 if (fraction_x < scale_factor_2)
199                 {
200                         scanner_y += sign_y;
201                 }
202                 else if (fraction_x > scale_factor_2)
203                 {
204                         scanner_x += sign_x;
205                         if (cave_stop_disintegration(floor_ptr, scanner_y, scanner_x)) return FALSE;
206                         fraction_x -= scale_factor_1;
207                         scanner_y += sign_y;
208                 }
209                 else
210                 {
211                         scanner_x += sign_x;
212                         fraction_x -= scale_factor_1;
213                         scanner_y += sign_y;
214                 }
215         }
216
217         return TRUE;
218 }
219
220
221 /*
222  * breath shape
223  */
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)
225 {
226         POSITION by = y1;
227         POSITION bx = x1;
228         int brad = 0;
229         int brev = rad * rad / dist;
230         int bdis = 0;
231         int cdis;
232         int path_n = 0;
233         int mdis = distance(y1, x1, y2, x2) + rad;
234
235         floor_type *floor_ptr = caster_ptr->current_floor_ptr;
236         while (bdis <= mdis)
237         {
238                 if ((0 < dist) && (path_n < dist))
239                 {
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);
243
244                         if (bdis >= nd)
245                         {
246                                 by = ny;
247                                 bx = nx;
248                                 path_n++;
249                         }
250                 }
251
252                 /* Travel from center outward */
253                 for (cdis = 0; cdis <= brad; cdis++)
254                 {
255                         for (POSITION y = by - cdis; y <= by + cdis; y++)
256                         {
257                                 for (POSITION x = bx - cdis; x <= bx + cdis; x++)
258                                 {
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;
262
263                                         switch (typ)
264                                         {
265                                         case GF_LITE:
266                                         case GF_LITE_WEAK:
267                                                 /* Lights are stopped by opaque terrains */
268                                                 if (!los(caster_ptr, by, bx, y, x)) continue;
269                                                 break;
270                                         case GF_DISINTEGRATE:
271                                                 /* Disintegration are stopped only by perma-walls */
272                                                 if (!in_disintegration_range(floor_ptr, by, bx, y, x)) continue;
273                                                 break;
274                                         default:
275                                                 /* Ball explosions are stopped by walls */
276                                                 if (!projectable(caster_ptr, by, bx, y, x)) continue;
277                                                 break;
278                                         }
279
280                                         gy[*pgrids] = y;
281                                         gx[*pgrids] = x;
282                                         (*pgrids)++;
283                                 }
284                         }
285                 }
286
287                 gm[bdis + 1] = *pgrids;
288                 brad = rad * (path_n + brev) / (dist + brev);
289                 bdis++;
290         }
291
292         *pgm_rad = bdis;
293 }
294
295
296 /*!
297  * @brief 鏡魔法「封魔結界」の効果処理
298  * @param dam ダメージ量
299  * @return 効果があったらTRUEを返す
300  */
301 bool binding_field(player_type *caster_ptr, HIT_POINT dam)
302 {
303         POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
304         int mirror_num = 0;     /* 鏡の数 */
305         int msec = delay_factor * delay_factor*delay_factor;
306
307         /* 三角形の頂点 */
308         POSITION point_x[3];
309         POSITION point_y[3];
310
311         /* Default target of monsterspell is player */
312         monster_target_y = caster_ptr->y;
313         monster_target_x = caster_ptr->x;
314
315         for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++)
316         {
317                 for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++)
318                 {
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))
324                         {
325                                 mirror_y[mirror_num] = y;
326                                 mirror_x[mirror_num] = x;
327                                 mirror_num++;
328                         }
329                 }
330         }
331
332         if (mirror_num < 2)return FALSE;
333
334         point_x[0] = randint0(mirror_num);
335         do {
336                 point_x[1] = randint0(mirror_num);
337         } while (point_x[0] == point_x[1]);
338
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;
345
346         POSITION x = point_x[0] + point_x[1] + point_x[2];
347         POSITION y = point_y[0] + point_y[1] + point_y[2];
348
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;
352
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];
357
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];
362
363         for (y = y1; y <= y2; y++)
364         {
365                 for (x = x1; x <= x2; x++)
366                 {
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)
373                         {
374                                 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
375                                 {
376                                         if (!(caster_ptr->blind)
377                                                 && panel_contains(y, x))
378                                         {
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);
382                                                 Term_fresh();
383                                                 Term_xtra(TERM_XTRA_DELAY, msec);
384                                         }
385                                 }
386                         }
387                 }
388         }
389
390         for (y = y1; y <= y2; y++)
391         {
392                 for (x = x1; x <= x2; x++)
393                 {
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)
400                         {
401                                 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
402                                 {
403                                         (void)affect_feature(caster_ptr, 0, 0, y, x, dam, GF_MANA);
404                                 }
405                         }
406                 }
407         }
408
409         for (y = y1; y <= y2; y++)
410         {
411                 for (x = x1; x <= x2; x++)
412                 {
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)
419                         {
420                                 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
421                                 {
422                                         (void)affect_item(caster_ptr, 0, 0, y, x, dam, GF_MANA);
423                                 }
424                         }
425                 }
426         }
427
428         for (y = y1; y <= y2; y++)
429         {
430                 for (x = x1; x <= x2; x++)
431                 {
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)
438                         {
439                                 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
440                                 {
441                                         (void)affect_monster(caster_ptr, 0, 0, y, x, dam, GF_MANA,
442                                                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), TRUE);
443                                 }
444                         }
445                 }
446         }
447
448         if (one_in_(7))
449         {
450                 msg_print(_("鏡が結界に耐えきれず、壊れてしまった。", "The field broke a mirror"));
451                 remove_mirror(caster_ptr, point_y[0], point_x[0]);
452         }
453
454         return TRUE;
455 }
456
457
458 /*!
459  * @brief 鏡魔法「鏡の封印」の効果処理
460  * @param dam ダメージ量
461  * @return 効果があったらTRUEを返す
462  */
463 void seal_of_mirror(player_type *caster_ptr, HIT_POINT dam)
464 {
465         for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++)
466         {
467                 for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++)
468                 {
469                         if (!is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]))
470                                 continue;
471
472                         if (!affect_monster(caster_ptr, 0, 0, y, x, dam, GF_GENOCIDE,
473                                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), TRUE))
474                                 continue;
475
476                         if (!caster_ptr->current_floor_ptr->grid_array[y][x].m_idx)
477                         {
478                                 remove_mirror(caster_ptr, y, x);
479                         }
480                 }
481         }
482 }
483
484
485 /*!
486  * @brief 領域魔法に応じて技能の名称を返す。
487  * @param tval 魔法書のtval
488  * @return 領域魔法の技能名称を保管した文字列ポインタ
489  */
490 concptr spell_category_name(OBJECT_TYPE_VALUE tval)
491 {
492         switch (tval)
493         {
494         case TV_HISSATSU_BOOK:
495                 return _("必殺技", "art");
496         case TV_LIFE_BOOK:
497                 return _("祈り", "prayer");
498         case TV_MUSIC_BOOK:
499                 return _("歌", "song");
500         default:
501                 return _("呪文", "spell");
502         }
503 }