OSDN Git Service

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