OSDN Git Service

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