OSDN Git Service

[Refactor] #38844 Continued removing inclusion of monster-race.h in angband.h
[hengband/hengband.git] / src / spell / process-effect.c
1 #include "spell/process-effect.h"
2 #include "core/stuff-handler.h"
3 #include "effect/effect-characteristics.h"
4 #include "effect/effect-feature.h"
5 #include "effect/effect-item.h"
6 #include "effect/effect-monster.h"
7 #include "effect/effect-player.h"
8 #include "effect/spells-effect-util.h"
9 #include "floor/floor.h"
10 #include "game-option/special-options.h"
11 #include "main/sound-definitions-table.h"
12 #include "main/sound-of-music.h"
13 #include "monster-race/monster-race.h"
14 #include "monster-race/race-flags2.h"
15 #include "monster-race/race-indice-types.h"
16 #include "monster/monster-describer.h"
17 #include "monster/monster-description-types.h"
18 #include "monster/monster-info.h"
19 #include "pet/pet-fall-off.h"
20 #include "spell/spell-types.h"
21 #include "spell/range-calc.h"
22 #include "term/gameterm.h"
23 #include "util/bit-flags-calculator.h"
24 #include "view/display-main-window.h" // 暫定、後で消すかも.
25 #include "view/display-messages.h"
26
27 /*!
28  * @brief 配置した鏡リストの次を取得する /
29  * Get another mirror. for SEEKER
30  * @param next_y 次の鏡のy座標を返す参照ポインタ
31  * @param next_x 次の鏡のx座標を返す参照ポインタ
32  * @param cury 現在の鏡のy座標
33  * @param curx 現在の鏡のx座標
34  */
35 static void next_mirror(player_type *creature_ptr, POSITION *next_y, POSITION *next_x, POSITION cury, POSITION curx)
36 {
37     POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
38     int mirror_num = 0; /* 鏡の数 */
39     for (POSITION x = 0; x < creature_ptr->current_floor_ptr->width; x++) {
40         for (POSITION y = 0; y < creature_ptr->current_floor_ptr->height; y++) {
41             if (is_mirror_grid(&creature_ptr->current_floor_ptr->grid_array[y][x])) {
42                 mirror_y[mirror_num] = y;
43                 mirror_x[mirror_num] = x;
44                 mirror_num++;
45             }
46         }
47     }
48
49     if (mirror_num) {
50         int num = randint0(mirror_num);
51         *next_y = mirror_y[num];
52         *next_x = mirror_x[num];
53         return;
54     }
55
56     *next_y = cury + randint0(5) - 2;
57     *next_x = curx + randint0(5) - 2;
58 }
59
60 /*!
61  * todo 似たような処理が山ほど並んでいる、何とかならないものか
62  * todo 引数にそのまま再代入していてカオスすぎる。直すのは簡単ではない
63  * @brief 汎用的なビーム/ボルト/ボール系処理のルーチン Generic
64  * "beam"/"bolt"/"ball" projection routine.
65  * @param who 魔法を発動したモンスター(0ならばプレイヤー) / Index of "source"
66  * monster (zero for "player")
67  * @param rad 効果半径(ビーム/ボルト = 0 / ボール = 1以上) / Radius of explosion
68  * (0 = beam/bolt, 1 to 9 = ball)
69  * @param y 目標Y座標 / Target y location (or location to travel "towards")
70  * @param x 目標X座標 / Target x location (or location to travel "towards")
71  * @param dam 基本威力 / Base damage roll to apply to affected monsters (or
72  * player)
73  * @param typ 効果属性 / Type of damage to apply to monsters (and objects)
74  * @param flag 効果フラグ / Extra bit flags (see PROJECT_xxxx)
75  * @param monspell 効果元のモンスター魔法ID
76  * @return 何か一つでも効力があればTRUEを返す / TRUE if any "effects" of the
77  * projection were observed, else FALSE
78  */
79 bool project(player_type *caster_ptr, MONSTER_IDX who, POSITION rad, POSITION y, POSITION x, HIT_POINT dam, EFFECT_ID typ, BIT_FLAGS flag, int monspell)
80 {
81     int dist;
82     POSITION y1, x1;
83     POSITION y2, x2;
84
85     /* For reflecting monsters */
86     POSITION y_saver;
87     POSITION x_saver;
88     int msec = delay_factor * delay_factor * delay_factor;
89     bool notice = FALSE;
90     bool visual = FALSE;
91     bool drawn = FALSE;
92     bool breath = FALSE;
93     bool blind = caster_ptr->blind != 0;
94     bool old_hide = FALSE;
95     int path_n = 0;
96     u16b path_g[512];
97     int grids = 0;
98     POSITION gx[1024];
99     POSITION gy[1024];
100     POSITION gm[32];
101     POSITION gm_rad = rad;
102     bool jump = FALSE;
103     GAME_TEXT who_name[MAX_NLEN];
104     bool see_s_msg = TRUE;
105     who_name[0] = '\0';
106     rakubadam_p = 0;
107     rakubadam_m = 0;
108     monster_target_y = caster_ptr->y;
109     monster_target_x = caster_ptr->x;
110
111     if (flag & (PROJECT_JUMP)) {
112         x1 = x;
113         y1 = y;
114         flag &= ~(PROJECT_JUMP);
115         jump = TRUE;
116     } else if (who <= 0) {
117         x1 = caster_ptr->x;
118         y1 = caster_ptr->y;
119     } else if (who > 0) {
120         x1 = caster_ptr->current_floor_ptr->m_list[who].fx;
121         y1 = caster_ptr->current_floor_ptr->m_list[who].fy;
122         monster_desc(caster_ptr, who_name, &caster_ptr->current_floor_ptr->m_list[who], MD_WRONGDOER_NAME);
123     } else {
124         x1 = x;
125         y1 = y;
126     }
127
128     y_saver = y1;
129     x_saver = x1;
130     y2 = y;
131     x2 = x;
132
133     if (flag & (PROJECT_THRU)) {
134         if ((x1 == x2) && (y1 == y2)) {
135             flag &= ~(PROJECT_THRU);
136         }
137     }
138
139     if (rad < 0) {
140         rad = 0 - rad;
141         breath = TRUE;
142         if (flag & PROJECT_HIDE)
143             old_hide = TRUE;
144         flag |= PROJECT_HIDE;
145     }
146
147     for (dist = 0; dist < 32; dist++)
148         gm[dist] = 0;
149
150     y = y1;
151     x = x1;
152     dist = 0;
153     if (flag & (PROJECT_BEAM)) {
154         gy[grids] = y;
155         gx[grids] = x;
156         grids++;
157     }
158
159     switch (typ) {
160     case GF_LITE:
161     case GF_LITE_WEAK:
162         if (breath || (flag & PROJECT_BEAM))
163             flag |= (PROJECT_LOS);
164         break;
165     case GF_DISINTEGRATE:
166         flag |= (PROJECT_GRID);
167         if (breath || (flag & PROJECT_BEAM))
168             flag |= (PROJECT_DISI);
169         break;
170     }
171
172     /* Calculate the projection path */
173     path_n = project_path(caster_ptr, path_g, (project_length ? project_length : MAX_RANGE), y1, x1, y2, x2, flag);
174     handle_stuff(caster_ptr);
175
176     if (typ == GF_SEEKER) {
177         int j;
178         int last_i = 0;
179         project_m_n = 0;
180         project_m_x = 0;
181         project_m_y = 0;
182         for (int i = 0; i < path_n; ++i) {
183             POSITION oy = y;
184             POSITION ox = x;
185             POSITION ny = GRID_Y(path_g[i]);
186             POSITION nx = GRID_X(path_g[i]);
187             y = ny;
188             x = nx;
189             gy[grids] = y;
190             gx[grids] = x;
191             grids++;
192
193             if (!blind && !(flag & (PROJECT_HIDE))) {
194                 if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
195                     u16b p = bolt_pict(oy, ox, y, x, typ);
196                     TERM_COLOR a = PICT_A(p);
197                     SYMBOL_CODE c = PICT_C(p);
198                     print_rel(caster_ptr, c, a, y, x);
199                     move_cursor_relative(y, x);
200                     Term_fresh();
201                     Term_xtra(TERM_XTRA_DELAY, msec);
202                     lite_spot(caster_ptr, y, x);
203                     Term_fresh();
204                     if (flag & (PROJECT_BEAM)) {
205                         p = bolt_pict(y, x, y, x, typ);
206                         a = PICT_A(p);
207                         c = PICT_C(p);
208                         print_rel(caster_ptr, c, a, y, x);
209                     }
210
211                     visual = TRUE;
212                 } else if (visual) {
213                     Term_xtra(TERM_XTRA_DELAY, msec);
214                 }
215             }
216
217             if (affect_item(caster_ptr, 0, 0, y, x, dam, GF_SEEKER))
218                 notice = TRUE;
219             if (!is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]))
220                 continue;
221
222             monster_target_y = y;
223             monster_target_x = x;
224             remove_mirror(caster_ptr, y, x);
225             next_mirror(caster_ptr, &oy, &ox, y, x);
226             path_n = i + project_path(caster_ptr, &(path_g[i + 1]), (project_length ? project_length : MAX_RANGE), y, x, oy, ox, flag);
227             for (j = last_i; j <= i; j++) {
228                 y = GRID_Y(path_g[j]);
229                 x = GRID_X(path_g[j]);
230                 if (affect_monster(caster_ptr, 0, 0, y, x, dam, GF_SEEKER, flag, TRUE))
231                     notice = TRUE;
232                 if (!who && (project_m_n == 1) && !jump && (caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx > 0)) {
233                     monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx];
234                     if (m_ptr->ml) {
235                         if (!caster_ptr->image)
236                             monster_race_track(caster_ptr, m_ptr->ap_r_idx);
237                         health_track(caster_ptr, caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx);
238                     }
239                 }
240
241                 (void)affect_feature(caster_ptr, 0, 0, y, x, dam, GF_SEEKER);
242             }
243
244             last_i = i;
245         }
246
247         for (int i = last_i; i < path_n; i++) {
248             POSITION py, px;
249             py = GRID_Y(path_g[i]);
250             px = GRID_X(path_g[i]);
251             if (affect_monster(caster_ptr, 0, 0, py, px, dam, GF_SEEKER, flag, TRUE))
252                 notice = TRUE;
253             if (!who && (project_m_n == 1) && !jump) {
254                 if (caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx > 0) {
255                     monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx];
256
257                     if (m_ptr->ml) {
258                         if (!caster_ptr->image)
259                             monster_race_track(caster_ptr, m_ptr->ap_r_idx);
260                         health_track(caster_ptr, caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx);
261                     }
262                 }
263             }
264
265             (void)affect_feature(caster_ptr, 0, 0, py, px, dam, GF_SEEKER);
266         }
267
268         return notice;
269     } else if (typ == GF_SUPER_RAY) {
270         int j;
271         int second_step = 0;
272         project_m_n = 0;
273         project_m_x = 0;
274         project_m_y = 0;
275         for (int i = 0; i < path_n; ++i) {
276             POSITION oy = y;
277             POSITION ox = x;
278             POSITION ny = GRID_Y(path_g[i]);
279             POSITION nx = GRID_X(path_g[i]);
280             y = ny;
281             x = nx;
282             gy[grids] = y;
283             gx[grids] = x;
284             grids++;
285             {
286                 if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
287                     u16b p;
288                     TERM_COLOR a;
289                     SYMBOL_CODE c;
290                     p = bolt_pict(oy, ox, y, x, typ);
291                     a = PICT_A(p);
292                     c = PICT_C(p);
293                     print_rel(caster_ptr, c, a, y, x);
294                     move_cursor_relative(y, x);
295                     Term_fresh();
296                     Term_xtra(TERM_XTRA_DELAY, msec);
297                     lite_spot(caster_ptr, y, x);
298                     Term_fresh();
299                     if (flag & (PROJECT_BEAM)) {
300                         p = bolt_pict(y, x, y, x, typ);
301                         a = PICT_A(p);
302                         c = PICT_C(p);
303                         print_rel(caster_ptr, c, a, y, x);
304                     }
305
306                     visual = TRUE;
307                 } else if (visual) {
308                     Term_xtra(TERM_XTRA_DELAY, msec);
309                 }
310             }
311
312             if (affect_item(caster_ptr, 0, 0, y, x, dam, GF_SUPER_RAY))
313                 notice = TRUE;
314             if (!cave_have_flag_bold(caster_ptr->current_floor_ptr, y, x, FF_PROJECT)) {
315                 if (second_step)
316                     continue;
317                 break;
318             }
319
320             if (is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]) && !second_step) {
321                 monster_target_y = y;
322                 monster_target_x = x;
323                 remove_mirror(caster_ptr, y, x);
324                 for (j = 0; j <= i; j++) {
325                     y = GRID_Y(path_g[j]);
326                     x = GRID_X(path_g[j]);
327                     (void)affect_feature(caster_ptr, 0, 0, y, x, dam, GF_SUPER_RAY);
328                 }
329
330                 path_n = i;
331                 second_step = i + 1;
332                 path_n += project_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : MAX_RANGE), y, x, y - 1, x - 1, flag);
333                 path_n += project_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : MAX_RANGE), y, x, y - 1, x, flag);
334                 path_n += project_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : MAX_RANGE), y, x, y - 1, x + 1, flag);
335                 path_n += project_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : MAX_RANGE), y, x, y, x - 1, flag);
336                 path_n += project_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : MAX_RANGE), y, x, y, x + 1, flag);
337                 path_n += project_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : MAX_RANGE), y, x, y + 1, x - 1, flag);
338                 path_n += project_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : MAX_RANGE), y, x, y + 1, x, flag);
339                 path_n += project_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : MAX_RANGE), y, x, y + 1, x + 1, flag);
340             }
341         }
342
343         for (int i = 0; i < path_n; i++) {
344             POSITION py = GRID_Y(path_g[i]);
345             POSITION px = GRID_X(path_g[i]);
346             (void)affect_monster(caster_ptr, 0, 0, py, px, dam, GF_SUPER_RAY, flag, TRUE);
347             if (!who && (project_m_n == 1) && !jump) {
348                 if (caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx > 0) {
349                     monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx];
350
351                     if (m_ptr->ml) {
352                         if (!caster_ptr->image)
353                             monster_race_track(caster_ptr, m_ptr->ap_r_idx);
354                         health_track(caster_ptr, caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx);
355                     }
356                 }
357             }
358
359             (void)affect_feature(caster_ptr, 0, 0, py, px, dam, GF_SUPER_RAY);
360         }
361
362         return notice;
363     }
364
365     int k;
366     for (k = 0; k < path_n; ++k) {
367         POSITION oy = y;
368         POSITION ox = x;
369         POSITION ny = GRID_Y(path_g[k]);
370         POSITION nx = GRID_X(path_g[k]);
371         if (flag & PROJECT_DISI) {
372             if (cave_stop_disintegration(caster_ptr->current_floor_ptr, ny, nx) && (rad > 0))
373                 break;
374         } else if (flag & PROJECT_LOS) {
375             if (!cave_los_bold(caster_ptr->current_floor_ptr, ny, nx) && (rad > 0))
376                 break;
377         } else {
378             if (!cave_have_flag_bold(caster_ptr->current_floor_ptr, ny, nx, FF_PROJECT) && (rad > 0))
379                 break;
380         }
381
382         y = ny;
383         x = nx;
384         if (flag & (PROJECT_BEAM)) {
385             gy[grids] = y;
386             gx[grids] = x;
387             grids++;
388         }
389
390         if (!blind && !(flag & (PROJECT_HIDE | PROJECT_FAST))) {
391             if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
392                 u16b p;
393                 TERM_COLOR a;
394                 SYMBOL_CODE c;
395                 p = bolt_pict(oy, ox, y, x, typ);
396                 a = PICT_A(p);
397                 c = PICT_C(p);
398                 print_rel(caster_ptr, c, a, y, x);
399                 move_cursor_relative(y, x);
400                 Term_fresh();
401                 Term_xtra(TERM_XTRA_DELAY, msec);
402                 lite_spot(caster_ptr, y, x);
403                 Term_fresh();
404                 if (flag & (PROJECT_BEAM)) {
405                     p = bolt_pict(y, x, y, x, typ);
406                     a = PICT_A(p);
407                     c = PICT_C(p);
408                     print_rel(caster_ptr, c, a, y, x);
409                 }
410
411                 visual = TRUE;
412             } else if (visual) {
413                 Term_xtra(TERM_XTRA_DELAY, msec);
414             }
415         }
416     }
417
418     path_n = k;
419     POSITION by = y;
420     POSITION bx = x;
421     if (breath && !path_n) {
422         breath = FALSE;
423         gm_rad = rad;
424         if (!old_hide) {
425             flag &= ~(PROJECT_HIDE);
426         }
427     }
428
429     gm[0] = 0;
430     gm[1] = grids;
431     dist = path_n;
432     int dist_hack = dist;
433     project_length = 0;
434
435     /* If we found a "target", explode there */
436     if (dist <= MAX_RANGE) {
437         if ((flag & (PROJECT_BEAM)) && (grids > 0))
438             grids--;
439
440         /*
441          * Create a conical breath attack
442          *
443          *       ***
444          *   ********
445          * D********@**
446          *   ********
447          *       ***
448          */
449         if (breath) {
450             flag &= ~(PROJECT_HIDE);
451             breath_shape(caster_ptr, path_g, dist, &grids, gx, gy, gm, &gm_rad, rad, y1, x1, by, bx, typ);
452         } else {
453             for (dist = 0; dist <= rad; dist++) {
454                 for (y = by - dist; y <= by + dist; y++) {
455                     for (x = bx - dist; x <= bx + dist; x++) {
456                         if (!in_bounds2(caster_ptr->current_floor_ptr, y, x))
457                             continue;
458                         if (distance(by, bx, y, x) != dist)
459                             continue;
460
461                         switch (typ) {
462                         case GF_LITE:
463                         case GF_LITE_WEAK:
464                             if (!los(caster_ptr, by, bx, y, x))
465                                 continue;
466                             break;
467                         case GF_DISINTEGRATE:
468                             if (!in_disintegration_range(caster_ptr->current_floor_ptr, by, bx, y, x))
469                                 continue;
470                             break;
471                         default:
472                             if (!projectable(caster_ptr, by, bx, y, x))
473                                 continue;
474                             break;
475                         }
476
477                         gy[grids] = y;
478                         gx[grids] = x;
479                         grids++;
480                     }
481                 }
482
483                 gm[dist + 1] = grids;
484             }
485         }
486     }
487
488     if (!grids)
489         return FALSE;
490
491     if (!blind && !(flag & (PROJECT_HIDE))) {
492         for (int t = 0; t <= gm_rad; t++) {
493             for (int i = gm[t]; i < gm[t + 1]; i++) {
494                 y = gy[i];
495                 x = gx[i];
496                 if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
497                     u16b p;
498                     TERM_COLOR a;
499                     SYMBOL_CODE c;
500                     drawn = TRUE;
501                     p = bolt_pict(y, x, y, x, typ);
502                     a = PICT_A(p);
503                     c = PICT_C(p);
504                     print_rel(caster_ptr, c, a, y, x);
505                 }
506             }
507
508             move_cursor_relative(by, bx);
509             Term_fresh();
510             if (visual || drawn) {
511                 Term_xtra(TERM_XTRA_DELAY, msec);
512             }
513         }
514
515         if (drawn) {
516             for (int i = 0; i < grids; i++) {
517                 y = gy[i];
518                 x = gx[i];
519                 if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
520                     lite_spot(caster_ptr, y, x);
521                 }
522             }
523
524             move_cursor_relative(by, bx);
525             Term_fresh();
526         }
527     }
528
529     update_creature(caster_ptr);
530
531     if (flag & PROJECT_KILL) {
532         see_s_msg = (who > 0) ? is_seen(caster_ptr, &caster_ptr->current_floor_ptr->m_list[who])
533                               : (!who ? TRUE : (player_can_see_bold(caster_ptr, y1, x1) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y1, x1)));
534     }
535
536     if (flag & (PROJECT_GRID)) {
537         dist = 0;
538         for (int i = 0; i < grids; i++) {
539             if (gm[dist + 1] == i)
540                 dist++;
541             y = gy[i];
542             x = gx[i];
543             if (breath) {
544                 int d = dist_to_line(y, x, y1, x1, by, bx);
545                 if (affect_feature(caster_ptr, who, d, y, x, dam, typ))
546                     notice = TRUE;
547             } else {
548                 if (affect_feature(caster_ptr, who, dist, y, x, dam, typ))
549                     notice = TRUE;
550             }
551         }
552     }
553
554     update_creature(caster_ptr);
555     if (flag & (PROJECT_ITEM)) {
556         dist = 0;
557         for (int i = 0; i < grids; i++) {
558             if (gm[dist + 1] == i)
559                 dist++;
560
561             y = gy[i];
562             x = gx[i];
563             if (breath) {
564                 int d = dist_to_line(y, x, y1, x1, by, bx);
565                 if (affect_item(caster_ptr, who, d, y, x, dam, typ))
566                     notice = TRUE;
567             } else {
568                 if (affect_item(caster_ptr, who, dist, y, x, dam, typ))
569                     notice = TRUE;
570             }
571         }
572     }
573
574     if (flag & (PROJECT_KILL)) {
575         project_m_n = 0;
576         project_m_x = 0;
577         project_m_y = 0;
578         dist = 0;
579         for (int i = 0; i < grids; i++) {
580             int effective_dist;
581             if (gm[dist + 1] == i)
582                 dist++;
583
584             y = gy[i];
585             x = gx[i];
586             if (grids <= 1) {
587                 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[y][x].m_idx];
588                 monster_race *ref_ptr = &r_info[m_ptr->r_idx];
589                 if ((flag & PROJECT_REFLECTABLE) && caster_ptr->current_floor_ptr->grid_array[y][x].m_idx && (ref_ptr->flags2 & RF2_REFLECTING)
590                     && ((caster_ptr->current_floor_ptr->grid_array[y][x].m_idx != caster_ptr->riding) || !(flag & PROJECT_PLAYER)) && (!who || dist_hack > 1)
591                     && !one_in_(10)) {
592                     POSITION t_y, t_x;
593                     int max_attempts = 10;
594                     do {
595                         t_y = y_saver - 1 + randint1(3);
596                         t_x = x_saver - 1 + randint1(3);
597                         max_attempts--;
598                     } while (max_attempts && in_bounds2u(caster_ptr->current_floor_ptr, t_y, t_x) && !projectable(caster_ptr, y, x, t_y, t_x));
599
600                     if (max_attempts < 1) {
601                         t_y = y_saver;
602                         t_x = x_saver;
603                     }
604
605                     sound(SOUND_REFLECT);
606                     if (is_seen(caster_ptr, m_ptr)) {
607                         if ((m_ptr->r_idx == MON_KENSHIROU) || (m_ptr->r_idx == MON_RAOU))
608                             msg_print(_("「北斗神拳奥義・二指真空把!」", "The attack bounces!"));
609                         else if (m_ptr->r_idx == MON_DIO)
610                             msg_print(_("ディオ・ブランドーは指一本で攻撃を弾き返した!", "The attack bounces!"));
611                         else
612                             msg_print(_("攻撃は跳ね返った!", "The attack bounces!"));
613                     }
614
615                     if (is_original_ap_and_seen(caster_ptr, m_ptr))
616                         ref_ptr->r_flags2 |= RF2_REFLECTING;
617
618                     if (player_bold(caster_ptr, y, x) || one_in_(2))
619                         flag &= ~(PROJECT_PLAYER);
620                     else
621                         flag |= PROJECT_PLAYER;
622
623                     project(caster_ptr, caster_ptr->current_floor_ptr->grid_array[y][x].m_idx, 0, t_y, t_x, dam, typ, flag, monspell);
624                     continue;
625                 }
626             }
627
628             /* Find the closest point in the blast */
629             if (breath) {
630                 effective_dist = dist_to_line(y, x, y1, x1, by, bx);
631             } else {
632                 effective_dist = dist;
633             }
634
635             if (caster_ptr->riding && player_bold(caster_ptr, y, x)) {
636                 if (flag & PROJECT_PLAYER) {
637                     if (flag & (PROJECT_BEAM | PROJECT_REFLECTABLE | PROJECT_AIMED)) {
638                         /*
639                          * A beam or bolt is well aimed
640                          * at the PLAYER!
641                          * So don't affects the mount.
642                          */
643                         continue;
644                     } else {
645                         /*
646                          * The spell is not well aimed,
647                          * So partly affect the mount too.
648                          */
649                         effective_dist++;
650                     }
651                 }
652
653                 /*
654                  * This grid is the original target.
655                  * Or aimed on your horse.
656                  */
657                 else if (((y == y2) && (x == x2)) || (flag & PROJECT_AIMED)) {
658                     /* Hit the mount with full damage */
659                 }
660
661                 /*
662                  * Otherwise this grid is not the
663                  * original target, it means that line
664                  * of fire is obstructed by this
665                  * monster.
666                  */
667                 /*
668                  * A beam or bolt will hit either
669                  * player or mount.  Choose randomly.
670                  */
671                 else if (flag & (PROJECT_BEAM | PROJECT_REFLECTABLE)) {
672                     if (one_in_(2)) {
673                         /* Hit the mount with full damage */
674                     } else {
675                         flag |= PROJECT_PLAYER;
676                         continue;
677                     }
678                 }
679
680                 /*
681                  * The spell is not well aimed, so
682                  * partly affect both player and
683                  * mount.
684                  */
685                 else {
686                     effective_dist++;
687                 }
688             }
689
690             if (affect_monster(caster_ptr, who, effective_dist, y, x, dam, typ, flag, see_s_msg))
691                 notice = TRUE;
692         }
693
694         /* Player affected one monster (without "jumping") */
695         if (!who && (project_m_n == 1) && !jump) {
696             x = project_m_x;
697             y = project_m_y;
698             if (caster_ptr->current_floor_ptr->grid_array[y][x].m_idx > 0) {
699                 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[y][x].m_idx];
700
701                 if (m_ptr->ml) {
702                     if (!caster_ptr->image)
703                         monster_race_track(caster_ptr, m_ptr->ap_r_idx);
704                     health_track(caster_ptr, caster_ptr->current_floor_ptr->grid_array[y][x].m_idx);
705                 }
706             }
707         }
708     }
709
710     if (flag & (PROJECT_KILL)) {
711         dist = 0;
712         for (int i = 0; i < grids; i++) {
713             int effective_dist;
714             if (gm[dist + 1] == i)
715                 dist++;
716
717             y = gy[i];
718             x = gx[i];
719             if (!player_bold(caster_ptr, y, x))
720                 continue;
721
722             /* Find the closest point in the blast */
723             if (breath) {
724                 effective_dist = dist_to_line(y, x, y1, x1, by, bx);
725             } else {
726                 effective_dist = dist;
727             }
728
729             if (caster_ptr->riding) {
730                 if (flag & PROJECT_PLAYER) {
731                     /* Hit the player with full damage */
732                 }
733
734                 /*
735                  * Hack -- When this grid was not the
736                  * original target, a beam or bolt
737                  * would hit either player or mount,
738                  * and should be choosen randomly.
739                  *
740                  * But already choosen to hit the
741                  * mount at this point.
742                  *
743                  * Or aimed on your horse.
744                  */
745                 else if (flag & (PROJECT_BEAM | PROJECT_REFLECTABLE | PROJECT_AIMED)) {
746                     /*
747                      * A beam or bolt is well aimed
748                      * at the mount!
749                      * So don't affects the player.
750                      */
751                     continue;
752                 } else {
753                     /*
754                      * The spell is not well aimed,
755                      * So partly affect the player too.
756                      */
757                     effective_dist++;
758                 }
759             }
760
761             if (affect_player(who, caster_ptr, who_name, effective_dist, y, x, dam, typ, flag, monspell, project))
762                 notice = TRUE;
763         }
764     }
765
766     if (caster_ptr->riding) {
767         GAME_TEXT m_name[MAX_NLEN];
768         monster_desc(caster_ptr, m_name, &caster_ptr->current_floor_ptr->m_list[caster_ptr->riding], 0);
769         if (rakubadam_m > 0) {
770             if (process_fall_off_horse(caster_ptr, rakubadam_m, FALSE)) {
771                 msg_format(_("%^sに振り落とされた!", "%^s has thrown you off!"), m_name);
772             }
773         }
774
775         if (caster_ptr->riding && rakubadam_p > 0) {
776             if (process_fall_off_horse(caster_ptr, rakubadam_p, FALSE)) {
777                 msg_format(_("%^sから落ちてしまった!", "You have fallen from %s."), m_name);
778             }
779         }
780     }
781
782     return (notice);
783 }