OSDN Git Service

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