OSDN Git Service

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