OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / player-attack / player-attack.cpp
1 /*!
2  * @brief プレイヤーからモンスターへの打撃処理
3  * @date 2020/05/22
4  * @author Hourier
5  */
6
7 #include "player-attack/player-attack.h"
8 #include "artifact/fixed-art-types.h"
9 #include "avatar/avatar.h"
10 #include "cmd-action/cmd-attack.h"
11 #include "combat/attack-accuracy.h"
12 #include "combat/attack-criticality.h"
13 #include "combat/martial-arts-table.h"
14 #include "combat/slaying.h"
15 #include "floor/cave.h"
16 #include "floor/geometry.h"
17 #include "game-option/cheat-types.h"
18 #include "grid/feature-flag-types.h"
19 #include "inventory/inventory-slot-types.h"
20 #include "main/sound-definitions-table.h"
21 #include "main/sound-of-music.h"
22 #include "mind/mind-ninja.h"
23 #include "mind/mind-samurai.h"
24 #include "mind/monk-attack.h"
25 #include "monster-race/monster-race-hook.h"
26 #include "monster-race/monster-race.h"
27 #include "monster-race/race-flags3.h"
28 #include "monster/monster-damage.h"
29 #include "monster/monster-describer.h"
30 #include "monster/monster-status-setter.h"
31 #include "monster/monster-status.h"
32 #include "object-enchant/tr-types.h"
33 #include "object-enchant/vorpal-weapon.h"
34 #include "object-hook/hook-weapon.h"
35 #include "object/object-flags.h"
36 #include "object/tval-types.h"
37 #include "player-attack/attack-chaos-effect.h"
38 #include "player-attack/blood-sucking-processor.h"
39 #include "player-base/player-class.h"
40 #include "player-info/equipment-info.h"
41 #include "player-status/player-energy.h"
42 #include "player-status/player-hand-types.h"
43 #include "player/player-damage.h"
44 #include "player/player-skill.h"
45 #include "player/player-status-flags.h"
46 #include "realm/realm-hex-numbers.h"
47 #include "spell-kind/earthquake.h"
48 #include "spell-realm/spells-hex.h"
49 #include "sv-definition/sv-weapon-types.h"
50 #include "system/floor-type-definition.h"
51 #include "system/grid-type-definition.h"
52 #include "system/item-entity.h"
53 #include "system/monster-entity.h"
54 #include "system/monster-race-info.h"
55 #include "system/player-type-definition.h"
56 #include "timed-effect/player-cut.h"
57 #include "timed-effect/timed-effects.h"
58 #include "util/bit-flags-calculator.h"
59 #include "util/string-processor.h"
60 #include "view/display-messages.h"
61 #include "wizard/wizard-messages.h"
62 #include "world/world.h"
63
64 /*! 吸血処理の最大回復HP */
65 constexpr auto MAX_VAMPIRIC_DRAIN = 50;
66
67 /*!
68  * @brief プレイヤーの攻撃情報を初期化する(コンストラクタ以外の分)
69  */
70 player_attack_type::player_attack_type(FloorType &floor, POSITION y, POSITION x, int16_t hand, combat_options mode, bool *fear, bool *mdeath)
71     : hand(hand)
72     , mode(mode)
73     , fear(fear)
74     , mdeath(mdeath)
75     , drain_left(MAX_VAMPIRIC_DRAIN)
76     , g_ptr(&floor.grid_array[y][x])
77     , chaos_effect(CE_NONE)
78     , magical_effect(MagicalBrandEffectType::NONE)
79 {
80     this->m_idx = this->g_ptr->m_idx;
81     this->m_ptr = &floor.m_list[this->g_ptr->m_idx];
82     this->r_idx = this->m_ptr->r_idx;
83     this->r_ptr = &monraces_info[this->m_ptr->r_idx];
84     this->ma_ptr = &ma_blows[0];
85 }
86
87 /*!
88  * @brief 一部職業で攻撃に倍率がかかったりすることの処理
89  * @param player_ptr プレイヤーへの参照ポインタ
90  * @param pa_ptr 直接攻撃構造体への参照ポインタ
91  */
92 static void attack_classify(PlayerType *player_ptr, player_attack_type *pa_ptr)
93 {
94     switch (player_ptr->pclass) {
95     case PlayerClassType::ROGUE:
96     case PlayerClassType::NINJA:
97         process_surprise_attack(player_ptr, pa_ptr);
98         return;
99     case PlayerClassType::MONK:
100     case PlayerClassType::FORCETRAINER:
101     case PlayerClassType::BERSERKER:
102         if ((empty_hands(player_ptr, true) & EMPTY_HAND_MAIN) && !player_ptr->riding) {
103             pa_ptr->monk_attack = true;
104         }
105         return;
106     default:
107         return;
108     }
109 }
110
111 /*!
112  * @brief マーシャルアーツの技能値を増加させる
113  * @param player_ptr プレイヤーへの参照ポインタ
114  * @param pa_ptr 直接攻撃構造体への参照ポインタ
115  */
116 static void get_bare_knuckle_exp(PlayerType *player_ptr, player_attack_type *pa_ptr)
117 {
118     auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
119     if ((r_ptr->level + 10) <= player_ptr->lev) {
120         return;
121     }
122
123     PlayerSkill(player_ptr).gain_martial_arts_skill_exp();
124 }
125
126 /*!
127  * @brief 装備している武器の技能値を増加させる
128  * @param player_ptr プレイヤーへの参照ポインタ
129  * @param pa_ptr 直接攻撃構造体への参照ポインタ
130  */
131 static void get_weapon_exp(PlayerType *player_ptr, player_attack_type *pa_ptr)
132 {
133     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
134
135     PlayerSkill(player_ptr).gain_melee_weapon_exp(o_ptr);
136 }
137
138 /*!
139  * @brief 直接攻撃に伴う技能値の上昇処理
140  * @param player_ptr プレイヤーへの参照ポインタ
141  * @param pa_ptr 直接攻撃構造体への参照ポインタ
142  */
143 static void get_attack_exp(PlayerType *player_ptr, player_attack_type *pa_ptr)
144 {
145     auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
146     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
147     if (!o_ptr->is_valid()) {
148         get_bare_knuckle_exp(player_ptr, pa_ptr);
149         return;
150     }
151
152     if (!o_ptr->is_melee_weapon() || ((r_ptr->level + 10) <= player_ptr->lev)) {
153         return;
154     }
155
156     get_weapon_exp(player_ptr, pa_ptr);
157 }
158
159 /*!
160  * @brief 攻撃回数を決定する
161  * @param player_ptr プレイヤーへの参照ポインタ
162  * @param pa_ptr 直接攻撃構造体への参照ポインタ
163  * @details 毒針は確定で1回
164  */
165 static void calc_num_blow(PlayerType *player_ptr, player_attack_type *pa_ptr)
166 {
167     if ((pa_ptr->mode == HISSATSU_KYUSHO) || (pa_ptr->mode == HISSATSU_MINEUCHI) || (pa_ptr->mode == HISSATSU_3DAN) || (pa_ptr->mode == HISSATSU_IAI)) {
168         pa_ptr->num_blow = 1;
169     } else if (pa_ptr->mode == HISSATSU_COLD) {
170         pa_ptr->num_blow = player_ptr->num_blow[pa_ptr->hand] + 2;
171     } else {
172         pa_ptr->num_blow = player_ptr->num_blow[pa_ptr->hand];
173     }
174
175     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
176     if (o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) {
177         pa_ptr->num_blow = 1;
178     }
179 }
180
181 /*!
182  * @brief 混沌属性の武器におけるカオス効果を決定する
183  * @param player_ptr プレイヤーへの参照ポインタ
184  * @param pa_ptr 直接攻撃構造体への参照ポインタ
185  * @return カオス効果
186  * @details
187  * 吸血20%、地震0.12%、混乱26.892%、テレポート・アウェイ1.494%、変身1.494% /
188  * Vampiric 20%, Quake 0.12%, Confusion 26.892%, Teleport away 1.494% and Polymorph 1.494%
189  */
190 static chaotic_effect select_chaotic_effect(PlayerType *player_ptr, player_attack_type *pa_ptr)
191 {
192     if (pa_ptr->flags.has_not(TR_CHAOTIC) || one_in_(2)) {
193         return CE_NONE;
194     }
195
196     if (one_in_(10)) {
197         chg_virtue(player_ptr, Virtue::CHANCE, 1);
198     }
199
200     if (randint1(5) < 3) {
201         return CE_VAMPIRIC;
202     }
203
204     if (one_in_(250)) {
205         return CE_QUAKE;
206     }
207
208     if (!one_in_(10)) {
209         return CE_CONFUSION;
210     }
211
212     return one_in_(2) ? CE_TELE_AWAY : CE_POLYMORPH;
213 }
214
215 /*!
216  * @brief 魔術属性による追加ダイス数を返す
217  * @param player_ptr プレイヤー情報への参照ポインタ
218  * @param pa_ptr プレイヤー攻撃情報への参照ポインタ
219  * @return 魔術属性効果
220  */
221 static MagicalBrandEffectType select_magical_brand_effect(PlayerType *player_ptr, player_attack_type *pa_ptr)
222 {
223     if (pa_ptr->flags.has_not(TR_BRAND_MAGIC)) {
224         return MagicalBrandEffectType::NONE;
225     }
226
227     if (one_in_(10)) {
228         chg_virtue(player_ptr, Virtue::CHANCE, 1);
229     }
230
231     if (one_in_(5)) {
232         return MagicalBrandEffectType::STUN;
233     }
234
235     if (one_in_(5)) {
236         return MagicalBrandEffectType::SCARE;
237     }
238
239     if (one_in_(10)) {
240         return MagicalBrandEffectType::DISPELL;
241     }
242
243     if (one_in_(16)) {
244         return MagicalBrandEffectType::PROBE;
245     }
246
247     return MagicalBrandEffectType::EXTRA;
248 }
249
250 /*!
251  * @brief 魔法属性による追加ダイス数を返す
252  * @param pa_ptr プレイヤー攻撃情報への参照ポインタ
253  * @return ダイス数
254  */
255 static DICE_NUMBER magical_brand_extra_dice(player_attack_type *pa_ptr)
256 {
257     switch (pa_ptr->magical_effect) {
258     case MagicalBrandEffectType::NONE:
259         return 0;
260     case MagicalBrandEffectType::EXTRA:
261         return 1;
262     default:
263         return 2;
264     }
265 }
266
267 /*!
268  * @brief 装備品が地震を起こすか判定
269  * @param player_ptr プレイヤー情報への参照ポインタ
270  * @param pa_ptr 直接攻撃構造体への参照ポインタ
271  * @return 地震を起こすならtrue、起こさないならfalse
272  * @details
273  * 打撃に使用する武器または武器以外の装備品が地震を起こすなら、
274  * ダメージ量が50より多いか1/7で地震を起こす
275  */
276 static bool does_equip_cause_earthquake(PlayerType *player_ptr, player_attack_type *pa_ptr)
277 {
278     if (!player_ptr->earthquake) {
279         return false;
280     }
281
282     auto do_quake = false;
283
284     auto hand = (pa_ptr->hand == 0) ? FLAG_CAUSE_INVEN_MAIN_HAND : FLAG_CAUSE_INVEN_SUB_HAND;
285     if (any_bits(player_ptr->earthquake, hand)) {
286         do_quake = true;
287     } else {
288         auto flags = player_ptr->earthquake;
289         reset_bits(flags, FLAG_CAUSE_INVEN_MAIN_HAND | FLAG_CAUSE_INVEN_SUB_HAND);
290         do_quake = flags != 0;
291     }
292
293     if (do_quake) {
294         return pa_ptr->attack_damage > 50 || one_in_(7);
295     }
296
297     return false;
298 }
299
300 /*!
301  * @brief 手にしている装備品がフラグを持つか判定
302  * @param attacker_flags 装備状況で集計されたフラグ
303  * @param pa_ptr 直接攻撃構造体への参照ポインタ
304  * @return 持つならtrue、持たないならfalse
305  */
306 static bool does_weapon_has_flag(BIT_FLAGS &attacker_flags, player_attack_type *pa_ptr)
307 {
308     if (!attacker_flags) {
309         return false;
310     }
311
312     auto hand = (pa_ptr->hand == 0) ? FLAG_CAUSE_INVEN_MAIN_HAND : FLAG_CAUSE_INVEN_SUB_HAND;
313     if (any_bits(attacker_flags, hand)) {
314         return true;
315     }
316
317     auto flags = attacker_flags;
318     reset_bits(flags, FLAG_CAUSE_INVEN_MAIN_HAND | FLAG_CAUSE_INVEN_SUB_HAND);
319     return flags != 0;
320 }
321
322 /*!
323  * @brief 武器による直接攻撃メインルーチン
324  * @param player_ptr プレイヤーへの参照ポインタ
325  * @param pa_ptr 直接攻撃構造体への参照ポインタ
326  * @param vorpal_cut メッタ斬りにできるかどうか
327  * @param vorpal_chance ヴォーパル倍率上昇の機会値
328  * @return 攻撃の結果、地震を起こすことになったらTRUE、それ以外はFALSE
329  */
330 static void process_weapon_attack(PlayerType *player_ptr, player_attack_type *pa_ptr, bool *do_quake, const bool vorpal_cut, const int vorpal_chance)
331 {
332     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
333     auto dd = o_ptr->dd + player_ptr->to_dd[pa_ptr->hand] + magical_brand_extra_dice(pa_ptr);
334     pa_ptr->attack_damage = damroll(dd, o_ptr->ds + player_ptr->to_ds[pa_ptr->hand]);
335     pa_ptr->attack_damage = calc_attack_damage_with_slay(player_ptr, o_ptr, pa_ptr->attack_damage, pa_ptr->m_ptr, pa_ptr->mode, false);
336     calc_surprise_attack_damage(player_ptr, pa_ptr);
337
338     if (does_equip_cause_earthquake(player_ptr, pa_ptr) || (pa_ptr->chaos_effect == CE_QUAKE) || (pa_ptr->mode == HISSATSU_QUAKE)) {
339         *do_quake = true;
340     }
341
342     auto do_impact = does_weapon_has_flag(player_ptr->impact, pa_ptr);
343     if ((o_ptr->bi_key != BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) && !(pa_ptr->mode == HISSATSU_KYUSHO)) {
344         pa_ptr->attack_damage = critical_norm(player_ptr, o_ptr->weight, o_ptr->to_h, pa_ptr->attack_damage, player_ptr->to_h[pa_ptr->hand], pa_ptr->mode, do_impact);
345     }
346
347     pa_ptr->drain_result = pa_ptr->attack_damage;
348     process_vorpal_attack(player_ptr, pa_ptr, vorpal_cut, vorpal_chance);
349     pa_ptr->attack_damage += o_ptr->to_d;
350     pa_ptr->drain_result += o_ptr->to_d;
351 }
352
353 /*!
354  * @brief 武器または素手による攻撃ダメージを計算する
355  * @param player_ptr プレイヤーへの参照ポインタ
356  * @param pa_ptr 直接攻撃構造体への参照ポインタ
357  * @param do_quake 攻撃の結果、地震を起こすことになったらTRUE、それ以外はFALSE
358  * @param vorpal_cut メッタ斬りにできるかどうか
359  * @param vorpal_change ヴォーパル倍率上昇の機会値
360  * @details 取り敢えず素手と仮定し1とする.
361  */
362 static void calc_attack_damage(PlayerType *player_ptr, player_attack_type *pa_ptr, bool *do_quake, const bool vorpal_cut, const int vorpal_chance)
363 {
364     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
365     pa_ptr->attack_damage = 1;
366     if (pa_ptr->monk_attack) {
367         process_monk_attack(player_ptr, pa_ptr);
368         return;
369     }
370
371     if (o_ptr->is_valid()) {
372         process_weapon_attack(player_ptr, pa_ptr, do_quake, vorpal_cut, vorpal_chance);
373     }
374 }
375
376 /*!
377  * @brief 武器のダメージボーナスや剣術家の技によってダメージにボーナスを与える
378  * @param player_ptr プレイヤーへの参照ポインタ
379  * @param pa_ptr 直接攻撃構造体への参照ポインタ
380  */
381 static void apply_damage_bonus(PlayerType *player_ptr, player_attack_type *pa_ptr)
382 {
383     pa_ptr->attack_damage += player_ptr->to_d[pa_ptr->hand];
384     pa_ptr->drain_result += player_ptr->to_d[pa_ptr->hand];
385
386     if ((pa_ptr->mode == HISSATSU_SUTEMI) || (pa_ptr->mode == HISSATSU_3DAN)) {
387         pa_ptr->attack_damage *= 2;
388     }
389
390     if ((pa_ptr->mode == HISSATSU_SEKIRYUKA) && !pa_ptr->m_ptr->has_living_flag()) {
391         pa_ptr->attack_damage = 0;
392     }
393
394     auto is_cut = player_ptr->effects()->cut()->is_cut();
395     if ((pa_ptr->mode == HISSATSU_SEKIRYUKA) && !is_cut) {
396         pa_ptr->attack_damage /= 2;
397     }
398 }
399
400 /*!
401  * @brief 特殊な条件でダメージが減ったり0になったりする処理
402  * @param player_ptr プレイヤーへの参照ポインタ
403  * @param pa_ptr 直接攻撃構造体への参照ポインタ
404  * @param is_zantetsu_nullified 斬鉄剣で切れないならばTRUE
405  * @param is_ej_nullified 蜘蛛相手ならばTRUE
406  * @details ダメージが0未満なら0に補正する
407  * @todo かなりのレアケースだが、右手に混沌属性の武器を持ち、左手にエクスカリバー・ジュニアを持ち、
408  * 右手の最終打撃で蜘蛛に変身したとしても、左手の攻撃でダメージが減らない気がする
409  * モンスターへの参照ポインタは変身時に変わるのにis_ej_nullifiedはその前に代入されて参照されるだけであるため
410  */
411 static void apply_damage_negative_effect(player_attack_type *pa_ptr, bool is_zantetsu_nullified, bool is_ej_nullified)
412 {
413     if (pa_ptr->attack_damage < 0) {
414         pa_ptr->attack_damage = 0;
415     }
416
417     auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
418     if ((pa_ptr->mode == HISSATSU_ZANMA) && !(!pa_ptr->m_ptr->has_living_flag() && r_ptr->kind_flags.has(MonsterKindType::EVIL))) {
419         pa_ptr->attack_damage = 0;
420     }
421
422     if (is_zantetsu_nullified) {
423         sound(SOUND_ATTACK_FAILED);
424         msg_print(_("こんな軟らかいものは切れん!", "You cannot cut such an elastic thing!"));
425         pa_ptr->attack_damage = 0;
426     }
427
428     if (is_ej_nullified) {
429         msg_print(_("蜘蛛は苦手だ!", "Spiders are difficult for you to deal with!"));
430         pa_ptr->attack_damage /= 2;
431     }
432 }
433
434 /*!
435  * @brief モンスターのHPを減らした後、恐怖させるか死なす (フロアから消滅させる)
436  * @param player_ptr プレイヤーへの参照ポインタ
437  * @param pa_ptr 直接攻撃構造体への参照ポインタ
438  * @return 死んだらTRUE、生きていたらFALSE
439  */
440 static bool check_fear_death(PlayerType *player_ptr, player_attack_type *pa_ptr, const int num, const bool is_lowlevel)
441 {
442     MonsterDamageProcessor mdp(player_ptr, pa_ptr->m_idx, pa_ptr->attack_damage, pa_ptr->fear, pa_ptr->attribute_flags);
443     if (!mdp.mon_take_hit("")) {
444         return false;
445     }
446
447     *(pa_ptr->mdeath) = true;
448     if (PlayerClass(player_ptr).equals(PlayerClassType::BERSERKER) && player_ptr->energy_use) {
449         PlayerEnergy energy(player_ptr);
450         if (can_attack_with_main_hand(player_ptr) && can_attack_with_sub_hand(player_ptr)) {
451             ENERGY energy_use;
452             if (pa_ptr->hand) {
453                 energy_use = player_ptr->energy_use * 3 / 5 + player_ptr->energy_use * num * 2 / (player_ptr->num_blow[pa_ptr->hand] * 5);
454             } else {
455                 energy_use = player_ptr->energy_use * num * 3 / (player_ptr->num_blow[pa_ptr->hand] * 5);
456             }
457
458             energy.set_player_turn_energy(energy_use);
459         } else {
460             auto energy_use = (ENERGY)(player_ptr->energy_use * num / player_ptr->num_blow[pa_ptr->hand]);
461             energy.set_player_turn_energy(energy_use);
462         }
463     }
464
465     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
466     if ((o_ptr->is_specific_artifact(FixedArtifactId::ZANTETSU)) && is_lowlevel) {
467         msg_print(_("またつまらぬものを斬ってしまった...", "Sigh... Another trifling thing I've cut...."));
468     }
469
470     return true;
471 }
472
473 /*!
474  * @brief 直接攻撃が当たった時の処理
475  * @param player_ptr プレイヤーへの参照ポインタ
476  * @param pa_ptr 直接攻撃構造体への参照ポインタ
477  * @param do_quake 攻撃後に地震を起こすかどうか
478  * @param is_zantetsu_nullified 斬鉄剣で切れないならばTRUE
479  * @param is_ej_nullified 蜘蛛相手ならばTRUE
480  */
481 static void apply_actual_attack(
482     PlayerType *player_ptr, player_attack_type *pa_ptr, bool *do_quake, const bool is_zantetsu_nullified, const bool is_ej_nullified)
483 {
484     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
485     int vorpal_chance = (o_ptr->is_specific_artifact(FixedArtifactId::VORPAL_BLADE) || o_ptr->is_specific_artifact(FixedArtifactId::CHAINSWORD)) ? 2 : 4;
486
487     sound(SOUND_HIT);
488     print_surprise_attack(pa_ptr);
489
490     pa_ptr->flags = object_flags(o_ptr);
491     pa_ptr->chaos_effect = select_chaotic_effect(player_ptr, pa_ptr);
492     pa_ptr->magical_effect = select_magical_brand_effect(player_ptr, pa_ptr);
493     decide_blood_sucking(player_ptr, pa_ptr);
494
495     bool vorpal_cut = (pa_ptr->flags.has(TR_VORPAL) || SpellHex(player_ptr).is_spelling_specific(HEX_RUNESWORD)) && (randint1(vorpal_chance * 3 / 2) == 1) && !is_zantetsu_nullified;
496     calc_attack_damage(player_ptr, pa_ptr, do_quake, vorpal_cut, vorpal_chance);
497     apply_damage_bonus(player_ptr, pa_ptr);
498     apply_damage_negative_effect(pa_ptr, is_zantetsu_nullified, is_ej_nullified);
499     mineuchi(player_ptr, pa_ptr);
500
501     const auto is_death_scythe = o_ptr->bi_key == BaseitemKey(ItemKindType::POLEARM, SV_DEATH_SCYTHE);
502     const auto is_berserker = PlayerClass(player_ptr).equals(PlayerClassType::BERSERKER);
503     pa_ptr->attack_damage = mon_damage_mod(player_ptr, pa_ptr->m_ptr, pa_ptr->attack_damage, is_death_scythe || (is_berserker && one_in_(2)));
504     critical_attack(player_ptr, pa_ptr);
505     msg_format_wizard(player_ptr, CHEAT_MONSTER, _("%dのダメージを与えた。(残りHP %d/%d(%d))", "You do %d damage. (left HP %d/%d(%d))"),
506         pa_ptr->attack_damage, pa_ptr->m_ptr->hp - pa_ptr->attack_damage, pa_ptr->m_ptr->maxhp, pa_ptr->m_ptr->max_maxhp);
507 }
508
509 /*!
510  * @brief 地震を起こす
511  * @param player_ptr プレイヤーへの参照ポインタ
512  * @param pa_ptr 直接攻撃構造体への参照ポインタ
513  * @param do_quake 攻撃後に地震を起こすかどうか
514  * @param y モンスターのY座標
515  * @param x モンスターのX座標
516  */
517 static void cause_earthquake(PlayerType *player_ptr, player_attack_type *pa_ptr, const bool do_quake, const POSITION y, const POSITION x)
518 {
519     if (!do_quake) {
520         return;
521     }
522
523     earthquake(player_ptr, player_ptr->y, player_ptr->x, 10, 0);
524     if (player_ptr->current_floor_ptr->grid_array[y][x].m_idx == 0) {
525         *(pa_ptr->mdeath) = true;
526     }
527 }
528
529 /*!
530  * @brief プレイヤーの打撃処理サブルーチン /
531  * Player attacks a (poor, defenseless) creature        -RAK-
532  * @param y 攻撃目標のY座標
533  * @param x 攻撃目標のX座標
534  * @param fear 攻撃を受けたモンスターが恐慌状態に陥ったかを返す参照ポインタ
535  * @param mdeath 攻撃を受けたモンスターが死亡したかを返す参照ポインタ
536  * @param hand 攻撃を行うための武器を持つ手
537  * @param mode 発動中の剣術ID
538  * @details
539  * If no "weapon" is available, then "punch" the monster one time.
540  */
541 void exe_player_attack_to_monster(PlayerType *player_ptr, POSITION y, POSITION x, bool *fear, bool *mdeath, int16_t hand, combat_options mode)
542 {
543     bool do_quake = false;
544     bool drain_msg = true;
545
546     player_attack_type tmp_attack(*player_ptr->current_floor_ptr, y, x, hand, mode, fear, mdeath);
547     auto pa_ptr = &tmp_attack;
548
549     bool is_human = (pa_ptr->r_ptr->d_char == 'p');
550     bool is_lowlevel = (pa_ptr->r_ptr->level < (player_ptr->lev - 15));
551
552     attack_classify(player_ptr, pa_ptr);
553     get_attack_exp(player_ptr, pa_ptr);
554
555     /* Disturb the monster */
556     (void)set_monster_csleep(player_ptr, pa_ptr->m_idx, 0);
557     angband_strcpy(pa_ptr->m_name, monster_desc(player_ptr, pa_ptr->m_ptr, 0), sizeof(pa_ptr->m_name));
558
559     int chance = calc_attack_quality(player_ptr, pa_ptr);
560     auto *o_ptr = &player_ptr->inventory_list[enum2i(INVEN_MAIN_HAND) + pa_ptr->hand];
561     bool is_zantetsu_nullified = (o_ptr->is_specific_artifact(FixedArtifactId::ZANTETSU) && (pa_ptr->r_ptr->d_char == 'j'));
562     bool is_ej_nullified = (o_ptr->is_specific_artifact(FixedArtifactId::EXCALIBUR_J) && (pa_ptr->r_ptr->d_char == 'S'));
563     calc_num_blow(player_ptr, pa_ptr);
564
565     /* Attack once for each legal blow */
566     int num = 0;
567     while ((num++ < pa_ptr->num_blow) && !player_ptr->is_dead) {
568         if (!process_attack_hit(player_ptr, pa_ptr, chance)) {
569             continue;
570         }
571
572         pa_ptr->attribute_flags = melee_attribute(player_ptr, o_ptr, pa_ptr->mode);
573         apply_actual_attack(player_ptr, pa_ptr, &do_quake, is_zantetsu_nullified, is_ej_nullified);
574         calc_drain(pa_ptr);
575         if (check_fear_death(player_ptr, pa_ptr, num, is_lowlevel)) {
576             break;
577         }
578
579         /* Anger the monster */
580         if (pa_ptr->attack_damage > 0) {
581             anger_monster(player_ptr, pa_ptr->m_ptr);
582         }
583
584         touch_zap_player(pa_ptr->m_ptr, player_ptr);
585         process_drain(player_ptr, pa_ptr, is_human, &drain_msg);
586         pa_ptr->can_drain = false;
587         pa_ptr->drain_result = 0;
588         change_monster_stat(player_ptr, pa_ptr, y, x, &num);
589         pa_ptr->backstab = false;
590         pa_ptr->surprise_attack = false;
591     }
592
593     if (pa_ptr->weak && !(*mdeath)) {
594         msg_format(_("%sは弱くなったようだ。", "%s^ seems weakened."), pa_ptr->m_name);
595     }
596
597     if ((pa_ptr->drain_left != MAX_VAMPIRIC_DRAIN) && one_in_(4)) {
598         chg_virtue(player_ptr, Virtue::UNLIFE, 1);
599     }
600
601     cause_earthquake(player_ptr, pa_ptr, do_quake, y, x);
602 }
603
604 /*!
605  * @brief 皆殺し(全方向攻撃)処理
606  * @param player_ptr プレイヤーへの参照ポインタ
607  */
608 void massacre(PlayerType *player_ptr)
609 {
610     grid_type *g_ptr;
611     MonsterEntity *m_ptr;
612     for (DIRECTION dir = 0; dir < 8; dir++) {
613         POSITION y = player_ptr->y + ddy_ddd[dir];
614         POSITION x = player_ptr->x + ddx_ddd[dir];
615         g_ptr = &player_ptr->current_floor_ptr->grid_array[y][x];
616         m_ptr = &player_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
617         if (g_ptr->m_idx && (m_ptr->ml || cave_has_flag_bold(player_ptr->current_floor_ptr, y, x, TerrainCharacteristics::PROJECT))) {
618             do_cmd_attack(player_ptr, y, x, HISSATSU_NONE);
619         }
620     }
621 }