OSDN Git Service

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