OSDN Git Service

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