OSDN Git Service

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