OSDN Git Service

[Fix] 対邪悪結界で打撃を撃退した際は落馬/変わり身処理を行わない
[hengbandforosx/hengbandosx.git] / src / mind / mind-ninja.c
1 #include "mind/mind-ninja.h"
2 #include "cmd-action/cmd-attack.h"
3 #include "cmd-item/cmd-throw.h"
4 #include "combat/combat-options-type.h"
5 #include "core/disturbance.h"
6 #include "core/player-redraw-types.h"
7 #include "effect/effect-characteristics.h"
8 #include "effect/effect-processor.h"
9 #include "effect/spells-effect-util.h"
10 #include "floor/cave.h"
11 #include "floor/floor-object.h"
12 #include "floor/floor-util.h"
13 #include "game-option/disturbance-options.h"
14 #include "grid/feature.h"
15 #include "inventory/inventory-slot-types.h"
16 #include "mind/mind-mirror-master.h"
17 #include "mind/mind-numbers.h"
18 #include "mind/mind-warrior.h"
19 #include "monster-race/monster-race.h"
20 #include "monster-race/race-flags-resistance.h"
21 #include "monster-race/race-indice-types.h"
22 #include "monster/monster-describer.h"
23 #include "monster/monster-status.h"
24 #include "monster/monster-update.h"
25 #include "object-enchant/trc-types.h"
26 #include "object/object-generator.h"
27 #include "object/object-kind-hook.h"
28 #include "player/attack-defense-types.h"
29 #include "player/player-status-flags.h"
30 #include "player/special-defense-types.h"
31 #include "spell-kind/spells-detection.h"
32 #include "spell-kind/spells-fetcher.h"
33 #include "spell-kind/spells-floor.h"
34 #include "spell-kind/spells-grid.h"
35 #include "spell-kind/spells-launcher.h"
36 #include "spell-kind/spells-lite.h"
37 #include "spell-kind/spells-perception.h"
38 #include "spell-kind/spells-teleport.h"
39 #include "spell/spell-types.h"
40 #include "spell/spells-status.h"
41 #include "status/action-setter.h"
42 #include "status/body-improvement.h"
43 #include "status/element-resistance.h"
44 #include "status/temporary-resistance.h"
45 #include "system/floor-type-definition.h"
46 #include "target/projection-path-calculator.h"
47 #include "target/target-checker.h"
48 #include "target/target-getter.h"
49 #include "util/bit-flags-calculator.h"
50 #include "view/display-messages.h"
51
52 /*!
53  * @brief 変わり身処理
54  * @param caster_ptr プレーヤーへの参照ポインタ
55  * @param success 判定成功上の処理ならばTRUE
56  * @return 作用が実際にあった場合TRUEを返す
57  */
58 bool kawarimi(player_type *caster_ptr, bool success)
59 {
60     object_type forge;
61     object_type *q_ptr = &forge;
62
63     if (caster_ptr->is_dead)
64         return FALSE;
65     if (caster_ptr->confused || caster_ptr->blind || caster_ptr->paralyzed || caster_ptr->image)
66         return FALSE;
67     if (randint0(200) < caster_ptr->stun)
68         return FALSE;
69
70     if (!success && one_in_(3)) {
71         msg_print(_("失敗!逃げられなかった。", "Failed! You couldn't run away."));
72         caster_ptr->special_defense &= ~(NINJA_KAWARIMI);
73         caster_ptr->redraw |= (PR_STATUS);
74         return FALSE;
75     }
76
77     POSITION y = caster_ptr->y;
78     POSITION x = caster_ptr->x;
79
80     teleport_player(caster_ptr, 10 + randint1(90), TELEPORT_SPONTANEOUS);
81     object_wipe(q_ptr);
82     const int SV_WOODEN_STATUE = 0;
83     object_prep(caster_ptr, q_ptr, lookup_kind(TV_STATUE, SV_WOODEN_STATUE));
84
85     q_ptr->pval = MON_NINJA;
86     (void)drop_near(caster_ptr, q_ptr, -1, y, x);
87
88     if (success)
89         msg_print(_("攻撃を受ける前に素早く身をひるがえした。", "You have turned around just before the attack hit you."));
90     else
91         msg_print(_("失敗!攻撃を受けてしまった。", "Failed! You are hit by the attack."));
92
93     caster_ptr->special_defense &= ~(NINJA_KAWARIMI);
94     caster_ptr->redraw |= (PR_STATUS);
95     return TRUE;
96 }
97
98 /*!
99  * @brief 入身処理 / "Rush Attack" routine for Samurai or Ninja
100  * @param caster_ptr プレーヤーへの参照ポインタ
101  * @param mdeath 目標モンスターが死亡したかを返す
102  * @return 作用が実際にあった場合TRUEを返す /  Return value is for checking "done"
103  */
104 bool rush_attack(player_type *attacker_ptr, bool *mdeath)
105 {
106     if (mdeath)
107         *mdeath = FALSE;
108
109     project_length = 5;
110     DIRECTION dir;
111     if (!get_aim_dir(attacker_ptr, &dir))
112         return FALSE;
113
114     int tx = attacker_ptr->x + project_length * ddx[dir];
115     int ty = attacker_ptr->y + project_length * ddy[dir];
116
117     if ((dir == 5) && target_okay(attacker_ptr)) {
118         tx = target_col;
119         ty = target_row;
120     }
121
122     int tm_idx = 0;
123     floor_type *floor_ptr = attacker_ptr->current_floor_ptr;
124     if (in_bounds(floor_ptr, ty, tx))
125         tm_idx = floor_ptr->grid_array[ty][tx].m_idx;
126
127     u16b path_g[32];
128     int path_n = projection_path(attacker_ptr, path_g, project_length, attacker_ptr->y, attacker_ptr->x, ty, tx, PROJECT_STOP | PROJECT_KILL);
129     project_length = 0;
130     if (!path_n)
131         return TRUE;
132
133     ty = attacker_ptr->y;
134     tx = attacker_ptr->x;
135     bool tmp_mdeath = FALSE;
136     bool moved = FALSE;
137     for (int i = 0; i < path_n; i++) {
138         monster_type *m_ptr;
139
140         int ny = get_grid_y(path_g[i]);
141         int nx = get_grid_x(path_g[i]);
142
143         if (is_cave_empty_bold(attacker_ptr, ny, nx) && player_can_enter(attacker_ptr, floor_ptr->grid_array[ny][nx].feat, 0)) {
144             ty = ny;
145             tx = nx;
146             continue;
147         }
148
149         if (!floor_ptr->grid_array[ny][nx].m_idx) {
150             if (tm_idx) {
151                 msg_print(_("失敗!", "Failed!"));
152             } else {
153                 msg_print(_("ここには入身では入れない。", "You can't move to that place."));
154             }
155
156             break;
157         }
158
159         if (!player_bold(attacker_ptr, ty, tx))
160             teleport_player_to(attacker_ptr, ty, tx, TELEPORT_NONMAGICAL);
161         update_monster(attacker_ptr, floor_ptr->grid_array[ny][nx].m_idx, TRUE);
162
163         m_ptr = &floor_ptr->m_list[floor_ptr->grid_array[ny][nx].m_idx];
164         if (tm_idx != floor_ptr->grid_array[ny][nx].m_idx) {
165 #ifdef JP
166             msg_format("%s%sが立ちふさがっている!", tm_idx ? "別の" : "", m_ptr->ml ? "モンスター" : "何か");
167 #else
168             msg_format("There is %s in the way!", m_ptr->ml ? (tm_idx ? "another monster" : "a monster") : "someone");
169 #endif
170         } else if (!player_bold(attacker_ptr, ty, tx)) {
171             GAME_TEXT m_name[MAX_NLEN];
172             monster_desc(attacker_ptr, m_name, m_ptr, 0);
173             msg_format(_("素早く%sの懐に入り込んだ!", "You quickly jump in and attack %s!"), m_name);
174         }
175
176         if (!player_bold(attacker_ptr, ty, tx))
177             teleport_player_to(attacker_ptr, ty, tx, TELEPORT_NONMAGICAL);
178         moved = TRUE;
179         tmp_mdeath = do_cmd_attack(attacker_ptr, ny, nx, HISSATSU_NYUSIN);
180
181         break;
182     }
183
184     if (!moved && !player_bold(attacker_ptr, ty, tx))
185         teleport_player_to(attacker_ptr, ty, tx, TELEPORT_NONMAGICAL);
186
187     if (mdeath)
188         *mdeath = tmp_mdeath;
189     return TRUE;
190 }
191
192 /*!
193  * @brief 盗賊と忍者における不意打ち
194  * @param attacker_ptr プレーヤーへの参照ポインタ
195  * @param pa_ptr 直接攻撃構造体への参照ポインタ
196  * @return なし
197  */
198 void process_surprise_attack(player_type *attacker_ptr, player_attack_type *pa_ptr)
199 {
200     monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
201     if (!has_melee_weapon(attacker_ptr, INVEN_MAIN_HAND + pa_ptr->hand) || attacker_ptr->icky_wield[pa_ptr->hand])
202         return;
203
204     int tmp = attacker_ptr->lev * 6 + (attacker_ptr->skill_stl + 10) * 4;
205     if (attacker_ptr->monlite && (pa_ptr->mode != HISSATSU_NYUSIN))
206         tmp /= 3;
207     if (has_aggravate(attacker_ptr))
208         tmp /= 2;
209     if (r_ptr->level > (attacker_ptr->lev * attacker_ptr->lev / 20 + 10))
210         tmp /= 3;
211     if (monster_csleep_remaining(pa_ptr->m_ptr) && pa_ptr->m_ptr->ml) {
212         /* Can't backstab creatures that we can't see, right? */
213         pa_ptr->backstab = TRUE;
214     } else if ((attacker_ptr->special_defense & NINJA_S_STEALTH) && (randint0(tmp) > (r_ptr->level + 20)) && pa_ptr->m_ptr->ml
215         && !(r_ptr->flagsr & RFR_RES_ALL)) {
216         pa_ptr->surprise_attack = TRUE;
217     } else if (monster_fear_remaining(pa_ptr->m_ptr) && pa_ptr->m_ptr->ml) {
218         pa_ptr->stab_fleeing = TRUE;
219     }
220 }
221
222 void print_surprise_attack(player_attack_type *pa_ptr)
223 {
224     if (pa_ptr->backstab)
225         msg_format(_("あなたは冷酷にも眠っている無力な%sを突き刺した!", "You cruelly stab the helpless, sleeping %s!"), pa_ptr->m_name);
226     else if (pa_ptr->surprise_attack)
227         msg_format(_("不意を突いて%sに強烈な一撃を喰らわせた!", "You make surprise attack, and hit %s with a powerful blow!"), pa_ptr->m_name);
228     else if (pa_ptr->stab_fleeing)
229         msg_format(_("逃げる%sを背中から突き刺した!", "You backstab the fleeing %s!"), pa_ptr->m_name);
230     else if (!pa_ptr->monk_attack)
231         msg_format(_("%sを攻撃した。", "You hit %s."), pa_ptr->m_name);
232 }
233
234 /*!
235  * @brief 盗賊と忍者における不意打ちのダメージ計算
236  * @param attacker_ptr プレーヤーへの参照ポインタ
237  * @param pa_ptr 直接攻撃構造体への参照ポインタ
238  * @return なし
239  */
240 void calc_surprise_attack_damage(player_type *attacker_ptr, player_attack_type *pa_ptr)
241 {
242     if (pa_ptr->backstab) {
243         pa_ptr->attack_damage *= (3 + (attacker_ptr->lev / 20));
244         return;
245     }
246
247     if (pa_ptr->surprise_attack) {
248         pa_ptr->attack_damage = pa_ptr->attack_damage * (5 + (attacker_ptr->lev * 2 / 25)) / 2;
249         return;
250     }
251
252     if (pa_ptr->stab_fleeing)
253         pa_ptr->attack_damage = (3 * pa_ptr->attack_damage) / 2;
254 }
255
256 /*!
257  * @brief 速駆け処理
258  * @param creature_ptr プレーヤーへの参照ポインタ
259  * @return 常にTRUE
260  */
261 bool hayagake(player_type *creature_ptr)
262 {
263     if (creature_ptr->action == ACTION_HAYAGAKE) {
264         set_action(creature_ptr, ACTION_NONE);
265         creature_ptr->energy_use = 0;
266         return TRUE;
267     }
268
269     grid_type *g_ptr = &creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x];
270     feature_type *f_ptr = &f_info[g_ptr->feat];
271
272     if (!has_flag(f_ptr->flags, FF_PROJECT) || (!creature_ptr->levitation && has_flag(f_ptr->flags, FF_DEEP))) {
273         msg_print(_("ここでは素早く動けない。", "You cannot run in here."));
274     } else {
275         set_action(creature_ptr, ACTION_HAYAGAKE);
276     }
277
278     creature_ptr->energy_use = 0;
279     return TRUE;
280 }
281
282 /*!
283  * @brief 超隠密状態をセットする
284  * @param set TRUEならば超隠密状態になる。
285  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
286  */
287 bool set_superstealth(player_type *creature_ptr, bool set)
288 {
289     bool notice = FALSE;
290
291     if (creature_ptr->is_dead)
292         return FALSE;
293
294     if (set) {
295         if (!(creature_ptr->special_defense & NINJA_S_STEALTH)) {
296             if (creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].info & CAVE_MNLT) {
297                 msg_print(_("敵の目から薄い影の中に覆い隠された。", "You are mantled in weak shadow from ordinary eyes."));
298                 creature_ptr->monlite = creature_ptr->old_monlite = TRUE;
299             } else {
300                 msg_print(_("敵の目から影の中に覆い隠された!", "You are mantled in shadow from ordinary eyes!"));
301                 creature_ptr->monlite = creature_ptr->old_monlite = FALSE;
302             }
303
304             notice = TRUE;
305             creature_ptr->special_defense |= NINJA_S_STEALTH;
306         }
307     } else {
308         if (creature_ptr->special_defense & NINJA_S_STEALTH) {
309             msg_print(_("再び敵の目にさらされるようになった。", "You are exposed to common sight once more."));
310             notice = TRUE;
311             creature_ptr->special_defense &= ~(NINJA_S_STEALTH);
312         }
313     }
314
315     if (!notice)
316         return FALSE;
317     creature_ptr->redraw |= (PR_STATUS);
318
319     if (disturb_state)
320         disturb(creature_ptr, FALSE, FALSE);
321     return TRUE;
322 }
323
324 /*!
325  * @brief 忍術の発動 /
326  * do_cmd_cast calls this function if the player's class is 'ninja'.
327  * @param caster_ptr プレーヤーへの参照ポインタ
328  * @param spell 発動する特殊技能のID
329  * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
330  */
331 bool cast_ninja_spell(player_type *caster_ptr, mind_ninja_type spell)
332 {
333     POSITION x = 0, y = 0;
334     DIRECTION dir;
335     PLAYER_LEVEL plev = caster_ptr->lev;
336     switch (spell) {
337     case DARKNESS_CREATION:
338         (void)unlite_area(caster_ptr, 0, 3);
339         break;
340     case DETECT_NEAR:
341         if (plev > 44)
342             wiz_lite(caster_ptr, TRUE);
343
344         detect_monsters_normal(caster_ptr, DETECT_RAD_DEFAULT);
345         if (plev > 4) {
346             detect_traps(caster_ptr, DETECT_RAD_DEFAULT, TRUE);
347             detect_doors(caster_ptr, DETECT_RAD_DEFAULT);
348             detect_stairs(caster_ptr, DETECT_RAD_DEFAULT);
349         }
350
351         if (plev > 14)
352             detect_objects_normal(caster_ptr, DETECT_RAD_DEFAULT);
353
354         break;
355     case HIDE_LEAVES:
356         teleport_player(caster_ptr, 10, TELEPORT_SPONTANEOUS);
357         break;
358     case KAWARIMI:
359         if (!(caster_ptr->special_defense & NINJA_KAWARIMI)) {
360             msg_print(_("敵の攻撃に対して敏感になった。", "You are now prepared to evade any attacks."));
361             caster_ptr->special_defense |= NINJA_KAWARIMI;
362             caster_ptr->redraw |= (PR_STATUS);
363         }
364
365         break;
366     case ABSCONDING:
367         teleport_player(caster_ptr, caster_ptr->lev * 5, TELEPORT_SPONTANEOUS);
368         break;
369     case HIT_AND_AWAY:
370         if (!hit_and_away(caster_ptr))
371             return FALSE;
372
373         break;
374     case BIND_MONSTER:
375         if (!get_aim_dir(caster_ptr, &dir))
376             return FALSE;
377
378         (void)stasis_monster(caster_ptr, dir);
379         break;
380     case ANCIENT_KNOWLEDGE:
381         return ident_spell(caster_ptr, FALSE, 0);
382     case FLOATING:
383         set_tim_levitation(caster_ptr, randint1(20) + 20, FALSE);
384         break;
385     case HIDE_FLAMES:
386         fire_ball(caster_ptr, GF_FIRE, 0, 50 + plev, plev / 10 + 2);
387         teleport_player(caster_ptr, 30, TELEPORT_SPONTANEOUS);
388         set_oppose_fire(caster_ptr, (TIME_EFFECT)plev, FALSE);
389         break;
390     case NYUSIN:
391         return rush_attack(caster_ptr, NULL);
392     case SYURIKEN_SPREADING: {
393         for (int i = 0; i < 8; i++) {
394             OBJECT_IDX slot;
395
396             for (slot = 0; slot < INVEN_PACK; slot++) {
397                 if (caster_ptr->inventory_list[slot].tval == TV_SPIKE)
398                     break;
399             }
400
401             if (slot == INVEN_PACK) {
402                 if (!i)
403                     msg_print(_("くさびを持っていない。", "You have no Iron Spikes."));
404                 else
405                     msg_print(_("くさびがなくなった。", "You have no more Iron Spikes."));
406
407                 return FALSE;
408             }
409
410             do_cmd_throw(caster_ptr, 1, FALSE, slot);
411             take_turn(caster_ptr, 100);
412         }
413
414         break;
415     }
416     case CHAIN_HOOK:
417         (void)fetch_monster(caster_ptr);
418         break;
419     case SMOKE_BALL:
420         if (!get_aim_dir(caster_ptr, &dir))
421             return FALSE;
422
423         fire_ball(caster_ptr, GF_OLD_CONF, dir, plev * 3, 3);
424         break;
425     case SWAP_POSITION:
426         project_length = -1;
427         if (!get_aim_dir(caster_ptr, &dir)) {
428             project_length = 0;
429             return FALSE;
430         }
431
432         project_length = 0;
433         (void)teleport_swap(caster_ptr, dir);
434         break;
435     case EXPLOSION_GLYPH:
436         explosive_rune(caster_ptr, caster_ptr->y, caster_ptr->x);
437         break;
438     case HIDE_MUD:
439         (void)set_pass_wall(caster_ptr, randint1(plev / 2) + plev / 2, FALSE);
440         set_oppose_acid(caster_ptr, (TIME_EFFECT)plev, FALSE);
441         break;
442     case HIDE_MIST:
443         fire_ball(caster_ptr, GF_POIS, 0, 75 + plev * 2 / 3, plev / 5 + 2);
444         fire_ball(caster_ptr, GF_HYPODYNAMIA, 0, 75 + plev * 2 / 3, plev / 5 + 2);
445         fire_ball(caster_ptr, GF_CONFUSION, 0, 75 + plev * 2 / 3, plev / 5 + 2);
446         teleport_player(caster_ptr, 30, TELEPORT_SPONTANEOUS);
447         break;
448     case PURGATORY_FLAME: {
449         int num = damroll(3, 9);
450         for (int k = 0; k < num; k++) {
451             EFFECT_ID typ = one_in_(2) ? GF_FIRE : one_in_(3) ? GF_NETHER : GF_PLASMA;
452             int attempts = 1000;
453             while (attempts--) {
454                 scatter(caster_ptr, &y, &x, caster_ptr->y, caster_ptr->x, 4, PROJECT_NONE);
455                 if (!player_bold(caster_ptr, y, x))
456                     break;
457             }
458
459             project(caster_ptr, 0, 0, y, x, damroll(6 + plev / 8, 10), typ, (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_KILL), -1);
460         }
461
462         break;
463     }
464     case ALTER_EGO:
465         set_multishadow(caster_ptr, 6 + randint1(6), FALSE);
466         break;
467     default:
468         msg_print(_("なに?", "Zap?"));
469         break;
470     }
471     return TRUE;
472 }