OSDN Git Service

[Refactor] #40577 Separated projection-path-calculator.c/h from floor.c/h
[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/floor.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 = GRID_Y(path_g[i]);
192             POSITION nx = 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                     term_fresh();
207                     term_xtra(TERM_XTRA_DELAY, msec);
208                     lite_spot(caster_ptr, y, x);
209                     term_fresh();
210                     if (flag & (PROJECT_BEAM)) {
211                         p = bolt_pict(y, x, y, x, typ);
212                         a = PICT_A(p);
213                         c = PICT_C(p);
214                         print_rel(caster_ptr, c, a, y, x);
215                     }
216
217                     visual = TRUE;
218                 } else if (visual) {
219                     term_xtra(TERM_XTRA_DELAY, msec);
220                 }
221             }
222
223             if (affect_item(caster_ptr, 0, 0, y, x, dam, GF_SEEKER))
224                 notice = TRUE;
225             if (!is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]))
226                 continue;
227
228             monster_target_y = y;
229             monster_target_x = x;
230             remove_mirror(caster_ptr, y, x);
231             next_mirror(caster_ptr, &oy, &ox, y, x);
232             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);
233             for (j = last_i; j <= i; j++) {
234                 y = GRID_Y(path_g[j]);
235                 x = GRID_X(path_g[j]);
236                 if (affect_monster(caster_ptr, 0, 0, y, x, dam, GF_SEEKER, flag, TRUE))
237                     notice = TRUE;
238                 if (!who && (project_m_n == 1) && !jump && (caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx > 0)) {
239                     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];
240                     if (m_ptr->ml) {
241                         if (!caster_ptr->image)
242                             monster_race_track(caster_ptr, m_ptr->ap_r_idx);
243                         health_track(caster_ptr, caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx);
244                     }
245                 }
246
247                 (void)affect_feature(caster_ptr, 0, 0, y, x, dam, GF_SEEKER);
248             }
249
250             last_i = i;
251         }
252
253         for (int i = last_i; i < path_n; i++) {
254             POSITION py, px;
255             py = GRID_Y(path_g[i]);
256             px = GRID_X(path_g[i]);
257             if (affect_monster(caster_ptr, 0, 0, py, px, dam, GF_SEEKER, flag, TRUE))
258                 notice = TRUE;
259             if (!who && (project_m_n == 1) && !jump) {
260                 if (caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx > 0) {
261                     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];
262
263                     if (m_ptr->ml) {
264                         if (!caster_ptr->image)
265                             monster_race_track(caster_ptr, m_ptr->ap_r_idx);
266                         health_track(caster_ptr, caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx);
267                     }
268                 }
269             }
270
271             (void)affect_feature(caster_ptr, 0, 0, py, px, dam, GF_SEEKER);
272         }
273
274         return notice;
275     } else if (typ == GF_SUPER_RAY) {
276         int j;
277         int second_step = 0;
278         project_m_n = 0;
279         project_m_x = 0;
280         project_m_y = 0;
281         for (int i = 0; i < path_n; ++i) {
282             POSITION oy = y;
283             POSITION ox = x;
284             POSITION ny = GRID_Y(path_g[i]);
285             POSITION nx = GRID_X(path_g[i]);
286             y = ny;
287             x = nx;
288             gy[grids] = y;
289             gx[grids] = x;
290             grids++;
291             {
292                 if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
293                     u16b p;
294                     TERM_COLOR a;
295                     SYMBOL_CODE c;
296                     p = bolt_pict(oy, ox, y, x, typ);
297                     a = PICT_A(p);
298                     c = PICT_C(p);
299                     print_rel(caster_ptr, c, a, y, x);
300                     move_cursor_relative(y, x);
301                     term_fresh();
302                     term_xtra(TERM_XTRA_DELAY, msec);
303                     lite_spot(caster_ptr, y, x);
304                     term_fresh();
305                     if (flag & (PROJECT_BEAM)) {
306                         p = bolt_pict(y, x, y, x, typ);
307                         a = PICT_A(p);
308                         c = PICT_C(p);
309                         print_rel(caster_ptr, c, a, y, x);
310                     }
311
312                     visual = TRUE;
313                 } else if (visual) {
314                     term_xtra(TERM_XTRA_DELAY, msec);
315                 }
316             }
317
318             if (affect_item(caster_ptr, 0, 0, y, x, dam, GF_SUPER_RAY))
319                 notice = TRUE;
320             if (!cave_have_flag_bold(caster_ptr->current_floor_ptr, y, x, FF_PROJECT)) {
321                 if (second_step)
322                     continue;
323                 break;
324             }
325
326             if (is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]) && !second_step) {
327                 monster_target_y = y;
328                 monster_target_x = x;
329                 remove_mirror(caster_ptr, y, x);
330                 for (j = 0; j <= i; j++) {
331                     y = GRID_Y(path_g[j]);
332                     x = GRID_X(path_g[j]);
333                     (void)affect_feature(caster_ptr, 0, 0, y, x, dam, GF_SUPER_RAY);
334                 }
335
336                 path_n = i;
337                 second_step = i + 1;
338                 path_n
339                     += projection_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : get_max_range(caster_ptr)), y, x, y - 1, x - 1, flag);
340                 path_n += projection_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : get_max_range(caster_ptr)), y, x, y - 1, x, flag);
341                 path_n
342                     += projection_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : get_max_range(caster_ptr)), y, x, y - 1, x + 1, flag);
343                 path_n += projection_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : get_max_range(caster_ptr)), y, x, y, x - 1, flag);
344                 path_n += projection_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : get_max_range(caster_ptr)), y, x, y, x + 1, flag);
345                 path_n
346                     += projection_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : get_max_range(caster_ptr)), y, x, y + 1, x - 1, flag);
347                 path_n += projection_path(caster_ptr, &(path_g[path_n + 1]), (project_length ? project_length : get_max_range(caster_ptr)), y, x, y + 1, x, 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 + 1, x + 1, flag);
350             }
351         }
352
353         for (int i = 0; i < path_n; i++) {
354             POSITION py = GRID_Y(path_g[i]);
355             POSITION px = GRID_X(path_g[i]);
356             (void)affect_monster(caster_ptr, 0, 0, py, px, dam, GF_SUPER_RAY, flag, TRUE);
357             if (!who && (project_m_n == 1) && !jump) {
358                 if (caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx > 0) {
359                     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];
360
361                     if (m_ptr->ml) {
362                         if (!caster_ptr->image)
363                             monster_race_track(caster_ptr, m_ptr->ap_r_idx);
364                         health_track(caster_ptr, caster_ptr->current_floor_ptr->grid_array[project_m_y][project_m_x].m_idx);
365                     }
366                 }
367             }
368
369             (void)affect_feature(caster_ptr, 0, 0, py, px, dam, GF_SUPER_RAY);
370         }
371
372         return notice;
373     }
374
375     int k;
376     for (k = 0; k < path_n; ++k) {
377         POSITION oy = y;
378         POSITION ox = x;
379         POSITION ny = GRID_Y(path_g[k]);
380         POSITION nx = GRID_X(path_g[k]);
381         if (flag & PROJECT_DISI) {
382             if (cave_stop_disintegration(caster_ptr->current_floor_ptr, ny, nx) && (rad > 0))
383                 break;
384         } else if (flag & PROJECT_LOS) {
385             if (!cave_los_bold(caster_ptr->current_floor_ptr, ny, nx) && (rad > 0))
386                 break;
387         } else {
388             if (!cave_have_flag_bold(caster_ptr->current_floor_ptr, ny, nx, FF_PROJECT) && (rad > 0))
389                 break;
390         }
391
392         y = ny;
393         x = nx;
394         if (flag & (PROJECT_BEAM)) {
395             gy[grids] = y;
396             gx[grids] = x;
397             grids++;
398         }
399
400         if (!blind && !(flag & (PROJECT_HIDE | PROJECT_FAST))) {
401             if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
402                 u16b p;
403                 TERM_COLOR a;
404                 SYMBOL_CODE c;
405                 p = bolt_pict(oy, ox, y, x, typ);
406                 a = PICT_A(p);
407                 c = PICT_C(p);
408                 print_rel(caster_ptr, c, a, y, x);
409                 move_cursor_relative(y, x);
410                 term_fresh();
411                 term_xtra(TERM_XTRA_DELAY, msec);
412                 lite_spot(caster_ptr, y, x);
413                 term_fresh();
414                 if (flag & (PROJECT_BEAM)) {
415                     p = bolt_pict(y, x, y, x, typ);
416                     a = PICT_A(p);
417                     c = PICT_C(p);
418                     print_rel(caster_ptr, c, a, y, x);
419                 }
420
421                 visual = TRUE;
422             } else if (visual) {
423                 term_xtra(TERM_XTRA_DELAY, msec);
424             }
425         }
426     }
427
428     path_n = k;
429     POSITION by = y;
430     POSITION bx = x;
431     if (breath && !path_n) {
432         breath = FALSE;
433         gm_rad = rad;
434         if (!old_hide) {
435             flag &= ~(PROJECT_HIDE);
436         }
437     }
438
439     gm[0] = 0;
440     gm[1] = grids;
441     dist = path_n;
442     int dist_hack = dist;
443     project_length = 0;
444
445     /* If we found a "target", explode there */
446     if (dist <= get_max_range(caster_ptr)) {
447         if ((flag & (PROJECT_BEAM)) && (grids > 0))
448             grids--;
449
450         /*
451          * Create a conical breath attack
452          *
453          *       ***
454          *   ********
455          * D********@**
456          *   ********
457          *       ***
458          */
459         if (breath) {
460             flag &= ~(PROJECT_HIDE);
461             breath_shape(caster_ptr, path_g, dist, &grids, gx, gy, gm, &gm_rad, rad, y1, x1, by, bx, typ);
462         } else {
463             for (dist = 0; dist <= rad; dist++) {
464                 for (y = by - dist; y <= by + dist; y++) {
465                     for (x = bx - dist; x <= bx + dist; x++) {
466                         if (!in_bounds2(caster_ptr->current_floor_ptr, y, x))
467                             continue;
468                         if (distance(by, bx, y, x) != dist)
469                             continue;
470
471                         switch (typ) {
472                         case GF_LITE:
473                         case GF_LITE_WEAK:
474                             if (!los(caster_ptr, by, bx, y, x))
475                                 continue;
476                             break;
477                         case GF_DISINTEGRATE:
478                             if (!in_disintegration_range(caster_ptr->current_floor_ptr, by, bx, y, x))
479                                 continue;
480                             break;
481                         default:
482                             if (!projectable(caster_ptr, by, bx, y, x))
483                                 continue;
484                             break;
485                         }
486
487                         gy[grids] = y;
488                         gx[grids] = x;
489                         grids++;
490                     }
491                 }
492
493                 gm[dist + 1] = grids;
494             }
495         }
496     }
497
498     if (!grids)
499         return FALSE;
500
501     if (!blind && !(flag & (PROJECT_HIDE))) {
502         for (int t = 0; t <= gm_rad; t++) {
503             for (int i = gm[t]; i < gm[t + 1]; i++) {
504                 y = gy[i];
505                 x = gx[i];
506                 if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
507                     u16b p;
508                     TERM_COLOR a;
509                     SYMBOL_CODE c;
510                     drawn = TRUE;
511                     p = bolt_pict(y, x, y, x, typ);
512                     a = PICT_A(p);
513                     c = PICT_C(p);
514                     print_rel(caster_ptr, c, a, y, x);
515                 }
516             }
517
518             move_cursor_relative(by, bx);
519             term_fresh();
520             if (visual || drawn) {
521                 term_xtra(TERM_XTRA_DELAY, msec);
522             }
523         }
524
525         if (drawn) {
526             for (int i = 0; i < grids; i++) {
527                 y = gy[i];
528                 x = gx[i];
529                 if (panel_contains(y, x) && player_has_los_bold(caster_ptr, y, x)) {
530                     lite_spot(caster_ptr, y, x);
531                 }
532             }
533
534             move_cursor_relative(by, bx);
535             term_fresh();
536         }
537     }
538
539     update_creature(caster_ptr);
540
541     if (flag & PROJECT_KILL) {
542         see_s_msg = (who > 0) ? is_seen(caster_ptr, &caster_ptr->current_floor_ptr->m_list[who])
543                               : (!who ? TRUE : (player_can_see_bold(caster_ptr, y1, x1) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y1, x1)));
544     }
545
546     if (flag & (PROJECT_GRID)) {
547         dist = 0;
548         for (int i = 0; i < grids; i++) {
549             if (gm[dist + 1] == i)
550                 dist++;
551             y = gy[i];
552             x = gx[i];
553             if (breath) {
554                 int d = dist_to_line(y, x, y1, x1, by, bx);
555                 if (affect_feature(caster_ptr, who, d, y, x, dam, typ))
556                     notice = TRUE;
557             } else {
558                 if (affect_feature(caster_ptr, who, dist, y, x, dam, typ))
559                     notice = TRUE;
560             }
561         }
562     }
563
564     update_creature(caster_ptr);
565     if (flag & (PROJECT_ITEM)) {
566         dist = 0;
567         for (int i = 0; i < grids; i++) {
568             if (gm[dist + 1] == i)
569                 dist++;
570
571             y = gy[i];
572             x = gx[i];
573             if (breath) {
574                 int d = dist_to_line(y, x, y1, x1, by, bx);
575                 if (affect_item(caster_ptr, who, d, y, x, dam, typ))
576                     notice = TRUE;
577             } else {
578                 if (affect_item(caster_ptr, who, dist, y, x, dam, typ))
579                     notice = TRUE;
580             }
581         }
582     }
583
584     if (flag & (PROJECT_KILL)) {
585         project_m_n = 0;
586         project_m_x = 0;
587         project_m_y = 0;
588         dist = 0;
589         for (int i = 0; i < grids; i++) {
590             int effective_dist;
591             if (gm[dist + 1] == i)
592                 dist++;
593
594             y = gy[i];
595             x = gx[i];
596             if (grids <= 1) {
597                 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[y][x].m_idx];
598                 monster_race *ref_ptr = &r_info[m_ptr->r_idx];
599                 if ((flag & PROJECT_REFLECTABLE) && caster_ptr->current_floor_ptr->grid_array[y][x].m_idx && (ref_ptr->flags2 & RF2_REFLECTING)
600                     && ((caster_ptr->current_floor_ptr->grid_array[y][x].m_idx != caster_ptr->riding) || !(flag & PROJECT_PLAYER)) && (!who || dist_hack > 1)
601                     && !one_in_(10)) {
602                     POSITION t_y, t_x;
603                     int max_attempts = 10;
604                     do {
605                         t_y = y_saver - 1 + randint1(3);
606                         t_x = x_saver - 1 + randint1(3);
607                         max_attempts--;
608                     } while (max_attempts && in_bounds2u(caster_ptr->current_floor_ptr, t_y, t_x) && !projectable(caster_ptr, y, x, t_y, t_x));
609
610                     if (max_attempts < 1) {
611                         t_y = y_saver;
612                         t_x = x_saver;
613                     }
614
615                     sound(SOUND_REFLECT);
616                     if (is_seen(caster_ptr, m_ptr)) {
617                         if ((m_ptr->r_idx == MON_KENSHIROU) || (m_ptr->r_idx == MON_RAOU))
618                             msg_print(_("「北斗神拳奥義・二指真空把!」", "The attack bounces!"));
619                         else if (m_ptr->r_idx == MON_DIO)
620                             msg_print(_("ディオ・ブランドーは指一本で攻撃を弾き返した!", "The attack bounces!"));
621                         else
622                             msg_print(_("攻撃は跳ね返った!", "The attack bounces!"));
623                     }
624
625                     if (is_original_ap_and_seen(caster_ptr, m_ptr))
626                         ref_ptr->r_flags2 |= RF2_REFLECTING;
627
628                     if (player_bold(caster_ptr, y, x) || one_in_(2))
629                         flag &= ~(PROJECT_PLAYER);
630                     else
631                         flag |= PROJECT_PLAYER;
632
633                     project(caster_ptr, caster_ptr->current_floor_ptr->grid_array[y][x].m_idx, 0, t_y, t_x, dam, typ, flag, monspell);
634                     continue;
635                 }
636             }
637
638             /* Find the closest point in the blast */
639             if (breath) {
640                 effective_dist = dist_to_line(y, x, y1, x1, by, bx);
641             } else {
642                 effective_dist = dist;
643             }
644
645             if (caster_ptr->riding && player_bold(caster_ptr, y, x)) {
646                 if (flag & PROJECT_PLAYER) {
647                     if (flag & (PROJECT_BEAM | PROJECT_REFLECTABLE | PROJECT_AIMED)) {
648                         /*
649                          * A beam or bolt is well aimed
650                          * at the PLAYER!
651                          * So don't affects the mount.
652                          */
653                         continue;
654                     } else {
655                         /*
656                          * The spell is not well aimed,
657                          * So partly affect the mount too.
658                          */
659                         effective_dist++;
660                     }
661                 }
662
663                 /*
664                  * This grid is the original target.
665                  * Or aimed on your horse.
666                  */
667                 else if (((y == y2) && (x == x2)) || (flag & PROJECT_AIMED)) {
668                     /* Hit the mount with full damage */
669                 }
670
671                 /*
672                  * Otherwise this grid is not the
673                  * original target, it means that line
674                  * of fire is obstructed by this
675                  * monster.
676                  */
677                 /*
678                  * A beam or bolt will hit either
679                  * player or mount.  Choose randomly.
680                  */
681                 else if (flag & (PROJECT_BEAM | PROJECT_REFLECTABLE)) {
682                     if (one_in_(2)) {
683                         /* Hit the mount with full damage */
684                     } else {
685                         flag |= PROJECT_PLAYER;
686                         continue;
687                     }
688                 }
689
690                 /*
691                  * The spell is not well aimed, so
692                  * partly affect both player and
693                  * mount.
694                  */
695                 else {
696                     effective_dist++;
697                 }
698             }
699
700             if (affect_monster(caster_ptr, who, effective_dist, y, x, dam, typ, flag, see_s_msg))
701                 notice = TRUE;
702         }
703
704         /* Player affected one monster (without "jumping") */
705         if (!who && (project_m_n == 1) && !jump) {
706             x = project_m_x;
707             y = project_m_y;
708             if (caster_ptr->current_floor_ptr->grid_array[y][x].m_idx > 0) {
709                 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[caster_ptr->current_floor_ptr->grid_array[y][x].m_idx];
710
711                 if (m_ptr->ml) {
712                     if (!caster_ptr->image)
713                         monster_race_track(caster_ptr, m_ptr->ap_r_idx);
714                     health_track(caster_ptr, caster_ptr->current_floor_ptr->grid_array[y][x].m_idx);
715                 }
716             }
717         }
718     }
719
720     if (flag & (PROJECT_KILL)) {
721         dist = 0;
722         for (int i = 0; i < grids; i++) {
723             int effective_dist;
724             if (gm[dist + 1] == i)
725                 dist++;
726
727             y = gy[i];
728             x = gx[i];
729             if (!player_bold(caster_ptr, y, x))
730                 continue;
731
732             /* Find the closest point in the blast */
733             if (breath) {
734                 effective_dist = dist_to_line(y, x, y1, x1, by, bx);
735             } else {
736                 effective_dist = dist;
737             }
738
739             if (caster_ptr->riding) {
740                 if (flag & PROJECT_PLAYER) {
741                     /* Hit the player with full damage */
742                 }
743
744                 /*
745                  * Hack -- When this grid was not the
746                  * original target, a beam or bolt
747                  * would hit either player or mount,
748                  * and should be choosen randomly.
749                  *
750                  * But already choosen to hit the
751                  * mount at this point.
752                  *
753                  * Or aimed on your horse.
754                  */
755                 else if (flag & (PROJECT_BEAM | PROJECT_REFLECTABLE | PROJECT_AIMED)) {
756                     /*
757                      * A beam or bolt is well aimed
758                      * at the mount!
759                      * So don't affects the player.
760                      */
761                     continue;
762                 } else {
763                     /*
764                      * The spell is not well aimed,
765                      * So partly affect the player too.
766                      */
767                     effective_dist++;
768                 }
769             }
770
771             if (affect_player(who, caster_ptr, who_name, effective_dist, y, x, dam, typ, flag, monspell, project))
772                 notice = TRUE;
773         }
774     }
775
776     if (caster_ptr->riding) {
777         GAME_TEXT m_name[MAX_NLEN];
778         monster_desc(caster_ptr, m_name, &caster_ptr->current_floor_ptr->m_list[caster_ptr->riding], 0);
779         if (rakubadam_m > 0) {
780             if (process_fall_off_horse(caster_ptr, rakubadam_m, FALSE)) {
781                 msg_format(_("%^sに振り落とされた!", "%^s has thrown you off!"), m_name);
782             }
783         }
784
785         if (caster_ptr->riding && rakubadam_p > 0) {
786             if (process_fall_off_horse(caster_ptr, rakubadam_p, FALSE)) {
787                 msg_format(_("%^sから落ちてしまった!", "You have fallen from %s."), m_name);
788             }
789         }
790     }
791
792     return (notice);
793 }