2 * @brief 素手で攻撃することに補正のある職業 (修行僧、狂戦士、練気術師)の打撃処理
5 * @details 練気術師は騎乗していない時
8 #include "mind/monk-attack.h"
9 #include "cmd-action/cmd-attack.h"
10 #include "combat/attack-criticality.h"
11 #include "core/speed-table.h"
12 #include "core/stuff-handler.h"
13 #include "floor/geometry.h"
14 #include "game-option/cheat-options.h"
15 #include "main/sound-definitions-table.h"
16 #include "main/sound-of-music.h"
17 #include "mind/mind-force-trainer.h"
18 #include "monster-race/monster-race.h"
19 #include "monster-race/race-flags1.h"
20 #include "monster-race/race-flags3.h"
21 #include "monster/monster-status-setter.h"
22 #include "monster/monster-status.h"
23 #include "player-attack/player-attack-util.h"
24 #include "player/attack-defense-types.h"
25 #include "player/special-defense-types.h"
26 #include "system/floor-type-definition.h"
27 #include "system/grid-type-definition.h"
28 #include "system/monster-race-definition.h"
29 #include "system/monster-type-definition.h"
30 #include "system/player-type-definition.h"
31 #include "target/target-getter.h"
32 #include "util/string-processor.h"
33 #include "view/display-messages.h"
34 #include "world/world.h"
38 * @param pa_ptr 直接攻撃構造体への参照ポインタ
41 static int calc_stun_resistance(player_attack_type *pa_ptr)
43 monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
45 if (r_ptr->flags1 & RF1_UNIQUE)
48 if (r_ptr->flags3 & RF3_NO_STUN)
51 if (r_ptr->flags3 & RF3_NO_CONF)
54 if (r_ptr->flags3 & RF3_NO_SLEEP)
57 if ((r_ptr->flags3 & RF3_UNDEAD) || (r_ptr->flags3 & RF3_NONLIVING))
64 * @brief 技のランダム選択回数を決定する
65 * @param player_ptr プレイヤーへの参照ポインタ
67 * @details ランダム選択は一番強い技が最終的に選択されるので、回数が多いほど有利
69 static int calc_max_blow_selection_times(player_type *player_ptr)
71 if (player_ptr->special_defense & KAMAE_BYAKKO)
72 return (player_ptr->lev < 3 ? 1 : player_ptr->lev / 3);
74 if (player_ptr->special_defense & KAMAE_SUZAKU)
77 if (player_ptr->special_defense & KAMAE_GENBU)
80 return player_ptr->lev < 7 ? 1 : player_ptr->lev / 7;
84 * @brief プレイヤーのレベルと技の難度を加味しつつ、確率で一番強い技を選ぶ
85 * @param player_ptr プレイヤーへの参照ポインタ
87 * @return 技の行使に必要な最低レベル
89 static int select_blow(player_type *player_ptr, player_attack_type *pa_ptr, int max_blow_selection_times)
92 const martial_arts *old_ptr = &ma_blows[0];
93 for (int times = 0; times < max_blow_selection_times; times++) {
95 pa_ptr->ma_ptr = &ma_blows[randint0(MAX_MA)];
96 if ((player_ptr->pclass == CLASS_FORCETRAINER) && (pa_ptr->ma_ptr->min_level > 1))
97 min_level = pa_ptr->ma_ptr->min_level + 3;
99 min_level = pa_ptr->ma_ptr->min_level;
100 } while ((min_level > player_ptr->lev) || (randint1(player_ptr->lev) < pa_ptr->ma_ptr->chance));
102 if ((pa_ptr->ma_ptr->min_level <= old_ptr->min_level) || player_ptr->stun || player_ptr->confused) {
103 pa_ptr->ma_ptr = old_ptr;
107 old_ptr = pa_ptr->ma_ptr;
108 if (w_ptr->wizard && cheat_xtra)
109 msg_print(_("攻撃を再選択しました。", "Attack re-selected."));
112 if (player_ptr->pclass == CLASS_FORCETRAINER)
113 min_level = MAX(1, pa_ptr->ma_ptr->min_level - 3);
115 min_level = pa_ptr->ma_ptr->min_level;
120 static int process_monk_additional_effect(player_attack_type *pa_ptr, int *stun_effect)
122 int special_effect = 0;
123 monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
124 if (pa_ptr->ma_ptr->effect == MA_KNEE) {
125 if (r_ptr->flags1 & RF1_MALE) {
126 msg_format(_("%sに金的膝蹴りをくらわした!", "You hit %s in the groin with your knee!"), pa_ptr->m_name);
128 special_effect = MA_KNEE;
130 msg_format(pa_ptr->ma_ptr->desc, pa_ptr->m_name);
133 else if (pa_ptr->ma_ptr->effect == MA_SLOW) {
134 if (!((r_ptr->flags1 & RF1_NEVER_MOVE) || angband_strchr("~#{}.UjmeEv$,DdsbBFIJQSXclnw!=?", r_ptr->d_char))) {
135 msg_format(_("%sの足首に関節蹴りをくらわした!", "You kick %s in the ankle."), pa_ptr->m_name);
136 special_effect = MA_SLOW;
138 msg_format(pa_ptr->ma_ptr->desc, pa_ptr->m_name);
140 if (pa_ptr->ma_ptr->effect) {
141 *stun_effect = (pa_ptr->ma_ptr->effect / 2) + randint1(pa_ptr->ma_ptr->effect / 2);
144 msg_format(pa_ptr->ma_ptr->desc, pa_ptr->m_name);
147 return special_effect;
151 * @brief 攻撃の重さ (修行僧と練気術師における武器重量)を決定する
152 * @param player_ptr プレイヤーへの参照ポインタ
155 static WEIGHT calc_monk_attack_weight(player_type *player_ptr)
158 if (player_ptr->special_defense & KAMAE_SUZAKU)
161 if ((player_ptr->pclass == CLASS_FORCETRAINER) && (get_current_ki(player_ptr) != 0)) {
162 weight += (get_current_ki(player_ptr) / 30);
171 * @brief 急所攻撃による追加効果を与える
172 * @param player_ptr プレイヤーへの参照ポインタ
173 * @param pa_ptr 直接攻撃構造体への参照ポインタ
174 * @param stun_effect 朦朧の残りターン
175 * @param resist_stun 朦朧への抵抗値
176 * @param special_effect 技を繰り出した時の追加効果
178 static void process_attack_vital_spot(player_type *player_ptr, player_attack_type *pa_ptr, int *stun_effect, int *resist_stun, const int special_effect)
180 monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
181 if ((special_effect == MA_KNEE) && ((pa_ptr->attack_damage + player_ptr->to_d[pa_ptr->hand]) < pa_ptr->m_ptr->hp)) {
182 msg_format(_("%^sは苦痛にうめいている!", "%^s moans in agony!"), pa_ptr->m_name);
183 *stun_effect = 7 + randint1(13);
188 if ((special_effect == MA_SLOW) && ((pa_ptr->attack_damage + player_ptr->to_d[pa_ptr->hand]) < pa_ptr->m_ptr->hp)) {
189 if (!(r_ptr->flags1 & RF1_UNIQUE) && (randint1(player_ptr->lev) > r_ptr->level) && pa_ptr->m_ptr->mspeed > 60) {
190 msg_format(_("%^sは足をひきずり始めた。", "You've hobbled %s."), pa_ptr->m_name);
191 pa_ptr->m_ptr->mspeed -= 10;
197 * @brief 朦朧効果を受けたモンスターのステータス表示
198 * @param player_ptr プレイヤーの参照ポインタ
199 * @param pa_ptr 直接攻撃構造体への参照ポインタ
200 * @param g_ptr グリッドへの参照ポインタ
201 * @param stun_effect 朦朧の残りターン
202 * @param resist_stun 朦朧への抵抗値
204 static void print_stun_effect(player_type *player_ptr, player_attack_type *pa_ptr, const int stun_effect, const int resist_stun)
206 monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
207 if (stun_effect && ((pa_ptr->attack_damage + player_ptr->to_d[pa_ptr->hand]) < pa_ptr->m_ptr->hp)) {
208 if (player_ptr->lev > randint1(r_ptr->level + resist_stun + 10)) {
209 if (set_monster_stunned(player_ptr, pa_ptr->g_ptr->m_idx, stun_effect + monster_stunned_remaining(pa_ptr->m_ptr))) {
210 msg_format(_("%^sはフラフラになった。", "%^s is stunned."), pa_ptr->m_name);
212 msg_format(_("%^sはさらにフラフラになった。", "%^s is more stunned."), pa_ptr->m_name);
219 * @brief 強力な素手攻撃ができる職業 (修行僧、狂戦士、練気術師)の素手攻撃処理メインルーチン
220 * @param player_ptr プレイヤーの参照ポインタ
221 * @param pa_ptr 直接攻撃構造体への参照ポインタ
222 * @param g_ptr グリッドへの参照ポインタ
224 void process_monk_attack(player_type *player_ptr, player_attack_type *pa_ptr)
226 int resist_stun = calc_stun_resistance(pa_ptr);
227 int max_blow_selection_times = calc_max_blow_selection_times(player_ptr);
228 int min_level = select_blow(player_ptr, pa_ptr, max_blow_selection_times);
230 pa_ptr->attack_damage = damroll(pa_ptr->ma_ptr->dd + player_ptr->to_dd[pa_ptr->hand], pa_ptr->ma_ptr->ds + player_ptr->to_ds[pa_ptr->hand]);
231 if (player_ptr->special_attack & ATTACK_SUIKEN)
232 pa_ptr->attack_damage *= 2;
235 int special_effect = process_monk_additional_effect(pa_ptr, &stun_effect);
236 WEIGHT weight = calc_monk_attack_weight(player_ptr);
237 pa_ptr->attack_damage = critical_norm(player_ptr, player_ptr->lev * weight, min_level, pa_ptr->attack_damage, player_ptr->to_h[0], HISSATSU_NONE);
238 process_attack_vital_spot(player_ptr, pa_ptr, &stun_effect, &resist_stun, special_effect);
239 print_stun_effect(player_ptr, pa_ptr, stun_effect, resist_stun);
242 bool double_attack(player_type *player_ptr)
245 if (!get_rep_dir(player_ptr, &dir, false))
247 POSITION y = player_ptr->y + ddy[dir];
248 POSITION x = player_ptr->x + ddx[dir];
249 if (!player_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
250 msg_print(_("その方向にはモンスターはいません。", "You don't see any monster in this direction"));
256 msg_print(_("あーたたたたたたたたたたたたたたたたたたたたたた!!!", "Ahhhtatatatatatatatatatatatatatataatatatatattaaaaa!!!!"));
258 msg_print(_("無駄無駄無駄無駄無駄無駄無駄無駄無駄無駄無駄無駄!!!", "Mudamudamudamudamudamudamudamudamudamudamudamudamuda!!!!"));
260 msg_print(_("オラオラオラオラオラオラオラオラオラオラオラオラ!!!", "Oraoraoraoraoraoraoraoraoraoraoraoraoraoraoraoraora!!!!"));
262 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
263 if (player_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
264 handle_stuff(player_ptr);
265 do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
268 player_ptr->energy_need += ENERGY_NEED();