OSDN Git Service

Merge branch 'macos-develop' into macos-3-0-0
[hengbandforosx/hengbandosx.git] / src / monster-attack / monster-attack-switcher.cpp
1 /*!
2  * @brief モンスターからプレイヤーへの直接攻撃をその種別において振り分ける
3  * @date 2020/05/31
4  * @author Hourier
5  * @details 長い処理はインクルード先の別ファイルにて行っている
6  */
7
8 #include "monster-attack/monster-attack-switcher.h"
9 #include "dungeon/quest.h"
10 #include "inventory/inventory-slot-types.h"
11 #include "mind/drs-types.h"
12 #include "mind/mind-mirror-master.h"
13 #include "monster-attack/monster-attack-lose.h"
14 #include "monster-attack/monster-attack-player.h"
15 #include "monster-attack/monster-attack-status.h"
16 #include "monster-attack/monster-attack-table.h"
17 #include "monster-attack/monster-eating.h"
18 #include "monster/monster-status.h"
19 #include "monster/monster-update.h"
20 #include "mutation/mutation-investor-remover.h"
21 #include "player/player-damage.h"
22 #include "player/player-status-flags.h"
23 #include "player/player-status-resist.h"
24 #include "player/player-status.h"
25 #include "spell-kind/earthquake.h"
26 #include "spell-kind/spells-equipment.h"
27 #include "spell-kind/spells-teleport.h"
28 #include "status/bad-status-setter.h"
29 #include "status/base-status.h"
30 #include "status/element-resistance.h"
31 #include "status/experience.h"
32 #include "system/floor-type-definition.h"
33 #include "system/item-entity.h"
34 #include "system/monster-entity.h"
35 #include "system/player-type-definition.h"
36 #include "timed-effect/player-acceleration.h"
37 #include "timed-effect/timed-effects.h"
38 #include "view/display-messages.h"
39
40 /*!
41  * @brief 毒ダメージを計算する
42  * @param player_ptr プレイヤーへの参照ポインタ
43  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
44  * @details 減衰の計算式がpoisではなくnukeなのは仕様 (1/3では減衰が強すぎると判断したため)
45  */
46 static void calc_blow_poison(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
47 {
48     if (monap_ptr->explode) {
49         return;
50     }
51
52     if (!(has_resist_pois(player_ptr) || is_oppose_pois(player_ptr)) && !check_multishadow(player_ptr) && BadStatusSetter(player_ptr).mod_poison(randint1(monap_ptr->rlev) + 5)) {
53         monap_ptr->obvious = true;
54     }
55
56     monap_ptr->damage = monap_ptr->damage * calc_nuke_damage_rate(player_ptr) / 100;
57     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
58     update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_POIS);
59 }
60
61 /*!
62  * @brief 劣化ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
63  * @param player_ptr プレイヤーへの参照ポインタ
64  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
65  */
66 static void calc_blow_disenchant(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
67 {
68     if (monap_ptr->explode) {
69         return;
70     }
71
72     if (!has_resist_disen(player_ptr) && !check_multishadow(player_ptr) && apply_disenchant(player_ptr, 0)) {
73         update_creature(player_ptr);
74         monap_ptr->obvious = true;
75     }
76
77     if (has_resist_disen(player_ptr)) {
78         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
79     }
80
81     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
82     update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_DISEN);
83 }
84
85 /*!
86  * @brief 魔道具吸収ダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-7.5%)
87  * @param player_ptr プレイヤーへの参照ポインタ
88  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
89  * @detals 魔道具使用能力向上フラグがあれば、吸収対象のアイテムをスキャンされる回数が半分で済む
90  */
91 static void calc_blow_un_power(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
92 {
93     int damage_ratio = 1000;
94     if (has_dec_mana(player_ptr)) {
95         damage_ratio -= 75;
96     }
97
98     if (has_easy_spell(player_ptr)) {
99         damage_ratio -= 75;
100     }
101
102     bool is_magic_mastery = has_magic_mastery(player_ptr) != 0;
103     if (is_magic_mastery) {
104         damage_ratio -= 75;
105     }
106
107     monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
108     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
109     if (player_ptr->is_dead || check_multishadow(player_ptr)) {
110         return;
111     }
112
113     int max_draining_item = is_magic_mastery ? 5 : 10;
114     for (int i = 0; i < max_draining_item; i++) {
115         INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
116         monap_ptr->o_ptr = &player_ptr->inventory_list[i_idx];
117         if (!monap_ptr->o_ptr->is_valid()) {
118             continue;
119         }
120
121         if (process_un_power(player_ptr, monap_ptr)) {
122             break;
123         }
124     }
125 }
126
127 /*!
128  * @brief 盲目ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
129  * @param player_ptr プレイヤーへの参照ポインタ
130  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
131  */
132 static void calc_blow_blind(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
133 {
134     if (has_resist_blind(player_ptr)) {
135         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
136     }
137
138     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
139     if (player_ptr->is_dead) {
140         return;
141     }
142
143     process_blind_attack(player_ptr, monap_ptr);
144     update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_BLIND);
145 }
146
147 /*!
148  * @brief 混乱ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
149  * @param player_ptr プレイヤーへの参照ポインタ
150  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
151  */
152 static void calc_blow_confusion(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
153 {
154     if (monap_ptr->explode) {
155         return;
156     }
157
158     if (has_resist_conf(player_ptr)) {
159         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
160     }
161
162     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
163     if (player_ptr->is_dead) {
164         return;
165     }
166
167     if (!has_resist_conf(player_ptr) && !check_multishadow(player_ptr) && BadStatusSetter(player_ptr).mod_confusion(3 + randint1(monap_ptr->rlev))) {
168         monap_ptr->obvious = true;
169     }
170
171     update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_CONF);
172 }
173
174 /*!
175  * @brief 恐怖ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
176  * @param player_ptr プレイヤーへの参照ポインタ
177  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
178  */
179 static void calc_blow_fear(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
180 {
181     if (has_resist_fear(player_ptr)) {
182         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
183     }
184
185     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
186     if (player_ptr->is_dead) {
187         return;
188     }
189
190     process_terrify_attack(player_ptr, monap_ptr);
191     update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FEAR);
192 }
193
194 /*!
195  * @brief 麻痺ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
196  * @param player_ptr プレイヤーへの参照ポインタ
197  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
198  */
199 static void calc_blow_paralysis(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
200 {
201     if (has_free_act(player_ptr)) {
202         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
203     }
204
205     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
206     if (player_ptr->is_dead) {
207         return;
208     }
209
210     process_paralyze_attack(player_ptr, monap_ptr);
211     update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FREE);
212 }
213
214 /*!
215  * @brief 経験値吸収ダメージを計算する (経験値保持と地獄耐性があれば、それぞれ-7.5%)
216  * @param player_ptr プレイヤーへの参照ポインタ
217  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
218  */
219 static void calc_blow_drain_exp(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr, const int drain_value, const int hold_exp_prob)
220 {
221     int32_t d = damroll(drain_value, 6) + (player_ptr->exp / 100) * MON_DRAIN_LIFE;
222     monap_ptr->obvious = true;
223     int damage_ratio = 1000;
224     if (has_hold_exp(player_ptr)) {
225         damage_ratio -= 75;
226     }
227
228     if (has_resist_neth(player_ptr)) {
229         damage_ratio -= 75;
230     }
231
232     monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
233     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
234     if (player_ptr->is_dead || check_multishadow(player_ptr)) {
235         return;
236     }
237
238     (void)drain_exp(player_ptr, d, d / 10, hold_exp_prob);
239 }
240
241 /*!
242  * @brief 時間逆転ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
243  * @param player_ptr プレイヤーへの参照ポインタ
244  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
245  */
246 static void calc_blow_time(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
247 {
248     if (monap_ptr->explode) {
249         return;
250     }
251
252     process_monster_attack_time(player_ptr);
253     if (has_resist_time(player_ptr)) {
254         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
255     }
256
257     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
258 }
259
260 /*!
261  * @brief 生命力吸収ダメージを計算する (経験値維持があれば9/10になる)
262  * @param player_ptr プレイヤーへの参照ポインタ
263  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
264  */
265 static void calc_blow_drain_life(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
266 {
267     int32_t d = damroll(60, 6) + (player_ptr->exp / 100) * MON_DRAIN_LIFE;
268     monap_ptr->obvious = true;
269     if (player_ptr->hold_exp) {
270         monap_ptr->damage = monap_ptr->damage * 9 / 10;
271     }
272
273     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
274     if (player_ptr->is_dead || check_multishadow(player_ptr)) {
275         return;
276     }
277
278     bool resist_drain = check_drain_hp(player_ptr, d);
279     process_drain_life(player_ptr, monap_ptr, resist_drain);
280 }
281
282 /*!
283  * @brief MPダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-5%)
284  * @param player_ptr プレイヤーへの参照ポインタ
285  * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
286  */
287 static void calc_blow_drain_mana(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
288 {
289     monap_ptr->obvious = true;
290     int damage_ratio = 100;
291     if (has_dec_mana(player_ptr)) {
292         damage_ratio -= 5;
293     }
294
295     if (has_easy_spell(player_ptr)) {
296         damage_ratio -= 5;
297     }
298
299     if (has_magic_mastery(player_ptr)) {
300         damage_ratio -= 5;
301     }
302
303     monap_ptr->damage = monap_ptr->damage * damage_ratio / 100;
304     process_drain_mana(player_ptr, monap_ptr);
305     update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_MANA);
306 }
307
308 static void calc_blow_inertia(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
309 {
310     if (player_ptr->effects()->acceleration()->is_fast() || (player_ptr->pspeed >= 130)) {
311         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
312     }
313
314     monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
315     if (player_ptr->is_dead || check_multishadow(player_ptr)) {
316         return;
317     }
318
319     if (BadStatusSetter(player_ptr).mod_deceleration(4 + randint0(monap_ptr->rlev / 10), false)) {
320         monap_ptr->obvious = true;
321     }
322 }
323
324 /*!
325  * @brief 空腹進行度を計算する (急速回復があれば+100%、遅消化があれば-50%)
326  */
327 static void calc_blow_hungry(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
328 {
329     if (player_ptr->regenerate) {
330         monap_ptr->damage = monap_ptr->damage * 2;
331     }
332     if (player_ptr->slow_digest) {
333         monap_ptr->damage = monap_ptr->damage / 2;
334     }
335
336     process_monster_attack_hungry(player_ptr, monap_ptr);
337 }
338
339 void switch_monster_blow_to_player(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
340 {
341     switch (monap_ptr->effect) {
342     case RaceBlowEffectType::NONE:
343         // ここには来ないはずだが、何らかのバグで来た場合はプレイヤーの不利益に
344         // ならないようダメージを 0 にしておく。
345         monap_ptr->damage = 0;
346         break;
347     case RaceBlowEffectType::SUPERHURT: { /* AC軽減あり / Player armor reduces total damage */
348         if (((randint1(monap_ptr->rlev * 2 + 300) > (monap_ptr->ac + 200)) || one_in_(13)) && !check_multishadow(player_ptr)) {
349             monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
350             msg_print(_("痛恨の一撃!", "It was a critical hit!"));
351             monap_ptr->damage = std::max(monap_ptr->damage, monap_ptr->damage * 2);
352             monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
353             break;
354         }
355     }
356         [[fallthrough]];
357     case RaceBlowEffectType::HURT: { /* AC軽減あり / Player armor reduces total damage */
358         monap_ptr->obvious = true;
359         monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
360         monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
361         break;
362     }
363     case RaceBlowEffectType::POISON:
364         calc_blow_poison(player_ptr, monap_ptr);
365         break;
366     case RaceBlowEffectType::UN_BONUS:
367         calc_blow_disenchant(player_ptr, monap_ptr);
368         break;
369     case RaceBlowEffectType::UN_POWER:
370         calc_blow_un_power(player_ptr, monap_ptr);
371         break;
372     case RaceBlowEffectType::EAT_GOLD:
373         monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
374         if (monap_ptr->m_ptr->is_confused() || player_ptr->is_dead || check_multishadow(player_ptr)) {
375             break;
376         }
377
378         monap_ptr->obvious = true;
379         process_eat_gold(player_ptr, monap_ptr);
380         break;
381     case RaceBlowEffectType::EAT_ITEM: {
382         monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
383         if (!check_eat_item(player_ptr, monap_ptr)) {
384             break;
385         }
386
387         process_eat_item(player_ptr, monap_ptr);
388         break;
389     }
390
391     case RaceBlowEffectType::EAT_FOOD: {
392         monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
393         if (player_ptr->is_dead || check_multishadow(player_ptr)) {
394             break;
395         }
396
397         process_eat_food(player_ptr, monap_ptr);
398         break;
399     }
400     case RaceBlowEffectType::EAT_LITE: {
401         monap_ptr->o_ptr = &player_ptr->inventory_list[INVEN_LITE];
402         monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
403         if (player_ptr->is_dead || check_multishadow(player_ptr)) {
404             break;
405         }
406
407         process_eat_lite(player_ptr, monap_ptr);
408         break;
409     }
410     case RaceBlowEffectType::ACID: {
411         if (monap_ptr->explode) {
412             break;
413         }
414
415         monap_ptr->obvious = true;
416         msg_print(_("酸を浴びせられた!", "You are covered in acid!"));
417         monap_ptr->get_damage += acid_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
418         update_creature(player_ptr);
419         update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_ACID);
420         break;
421     }
422     case RaceBlowEffectType::ELEC: {
423         if (monap_ptr->explode) {
424             break;
425         }
426
427         monap_ptr->obvious = true;
428         msg_print(_("電撃を浴びせられた!", "You are struck by electricity!"));
429         monap_ptr->get_damage += elec_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
430         update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_ELEC);
431         break;
432     }
433     case RaceBlowEffectType::FIRE: {
434         if (monap_ptr->explode) {
435             break;
436         }
437
438         monap_ptr->obvious = true;
439         msg_print(_("全身が炎に包まれた!", "You are enveloped in flames!"));
440         monap_ptr->get_damage += fire_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
441         update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FIRE);
442         break;
443     }
444     case RaceBlowEffectType::COLD: {
445         if (monap_ptr->explode) {
446             break;
447         }
448
449         monap_ptr->obvious = true;
450         msg_print(_("全身が冷気で覆われた!", "You are covered with frost!"));
451         monap_ptr->get_damage += cold_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
452         update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_COLD);
453         break;
454     }
455     case RaceBlowEffectType::BLIND:
456         calc_blow_blind(player_ptr, monap_ptr);
457         break;
458     case RaceBlowEffectType::CONFUSE:
459         calc_blow_confusion(player_ptr, monap_ptr);
460         break;
461     case RaceBlowEffectType::TERRIFY:
462         calc_blow_fear(player_ptr, monap_ptr);
463         break;
464     case RaceBlowEffectType::PARALYZE:
465         calc_blow_paralysis(player_ptr, monap_ptr);
466         break;
467     case RaceBlowEffectType::LOSE_STR:
468         calc_blow_lose_strength(player_ptr, monap_ptr);
469         break;
470     case RaceBlowEffectType::LOSE_INT:
471         calc_blow_lose_intelligence(player_ptr, monap_ptr);
472         break;
473     case RaceBlowEffectType::LOSE_WIS:
474         calc_blow_lose_wisdom(player_ptr, monap_ptr);
475         break;
476     case RaceBlowEffectType::LOSE_DEX:
477         calc_blow_lose_dexterity(player_ptr, monap_ptr);
478         break;
479     case RaceBlowEffectType::LOSE_CON:
480         calc_blow_lose_constitution(player_ptr, monap_ptr);
481         break;
482     case RaceBlowEffectType::LOSE_CHR:
483         calc_blow_lose_charisma(player_ptr, monap_ptr);
484         break;
485     case RaceBlowEffectType::LOSE_ALL:
486         calc_blow_lose_all(player_ptr, monap_ptr);
487         break;
488     case RaceBlowEffectType::SHATTER: { /* AC軽減あり / Player armor reduces total damage */
489         monap_ptr->obvious = true;
490         monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
491         monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
492         if (monap_ptr->damage > 23 || monap_ptr->explode) {
493             earthquake(player_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, 8, monap_ptr->m_idx);
494         }
495
496         break;
497     }
498     case RaceBlowEffectType::EXP_10:
499         calc_blow_drain_exp(player_ptr, monap_ptr, 10, 95);
500         break;
501     case RaceBlowEffectType::EXP_20:
502         calc_blow_drain_exp(player_ptr, monap_ptr, 20, 90);
503         break;
504     case RaceBlowEffectType::EXP_40:
505         calc_blow_drain_exp(player_ptr, monap_ptr, 40, 75);
506         break;
507     case RaceBlowEffectType::EXP_80:
508         calc_blow_drain_exp(player_ptr, monap_ptr, 80, 50);
509         break;
510     case RaceBlowEffectType::DISEASE:
511         calc_blow_disease(player_ptr, monap_ptr);
512         break;
513     case RaceBlowEffectType::TIME:
514         calc_blow_time(player_ptr, monap_ptr);
515         break;
516     case RaceBlowEffectType::DR_LIFE:
517         calc_blow_drain_life(player_ptr, monap_ptr);
518         break;
519     case RaceBlowEffectType::DR_MANA:
520         calc_blow_drain_mana(player_ptr, monap_ptr);
521         break;
522     case RaceBlowEffectType::INERTIA:
523         calc_blow_inertia(player_ptr, monap_ptr);
524         break;
525     case RaceBlowEffectType::STUN:
526         monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
527         if (player_ptr->is_dead) {
528             break;
529         }
530         process_stun_attack(player_ptr, monap_ptr);
531         break;
532     case RaceBlowEffectType::FLAVOR:
533         // フレーバー打撃は自明かつダメージ 0。
534         monap_ptr->obvious = true;
535         monap_ptr->damage = 0;
536         break;
537     case RaceBlowEffectType::HUNGRY:
538         calc_blow_hungry(player_ptr, monap_ptr);
539         break;
540     case RaceBlowEffectType::CHAOS: {
541         update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_CHAOS);
542         monap_ptr->damage = monap_ptr->damage * calc_chaos_damage_rate(player_ptr, CALC_RAND) / 100;
543         monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
544
545         const auto has_chaos_resist = has_resist_chaos(player_ptr);
546
547         if (!has_chaos_resist) {
548             monap_ptr->obvious = true;
549         }
550         if (randint1(5) < 3) {
551             monap_ptr->obvious = true;
552             if (!has_chaos_resist) {
553                 if (player_ptr->is_dead || check_multishadow(player_ptr)) {
554                     return;
555                 }
556
557                 int32_t d = damroll(60, 6) + (player_ptr->exp / 100) * MON_DRAIN_LIFE;
558
559                 bool resist_drain = check_drain_hp(player_ptr, d);
560                 process_drain_life(player_ptr, monap_ptr, resist_drain);
561             }
562             break;
563         }
564         if (one_in_(250)) {
565             monap_ptr->obvious = true;
566             const auto *floor_ptr = player_ptr->current_floor_ptr;
567             if (floor_ptr->is_in_dungeon() && (!floor_ptr->is_in_quest() || !QuestType::is_fixed(floor_ptr->quest_number))) {
568                 if (monap_ptr->damage > 23 || monap_ptr->explode) {
569                     msg_print(_("カオスの力でダンジョンが崩れ始める!", "The dungeon tumbles by the chaotic power!"));
570                     earthquake(player_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, 8, monap_ptr->m_idx);
571                     break;
572                 }
573             }
574         }
575         if (!one_in_(10)) {
576             if (player_ptr->is_dead) {
577                 return;
578             }
579             monap_ptr->obvious = true;
580
581             if (!has_chaos_resist && !has_resist_conf(player_ptr) && !check_multishadow(player_ptr) && BadStatusSetter(player_ptr).mod_confusion(3 + randint1(monap_ptr->rlev))) {
582                 monap_ptr->obvious = true;
583             }
584             break;
585         }
586
587         if (one_in_(2)) {
588             if (player_ptr->is_dead) {
589                 return;
590             }
591             monap_ptr->obvious = true;
592
593             if (!has_chaos_resist && player_ptr->anti_tele == 0) {
594                 msg_print(_("突然体が浮きだした!", "Your body floats suddenly!"));
595                 teleport_player(player_ptr, 50, TELEPORT_PASSIVE);
596             }
597         } else if (!has_chaos_resist) {
598             if (player_ptr->is_dead) {
599                 return;
600             }
601             monap_ptr->obvious = true;
602
603             msg_print(_("あなたの身体はカオスの力で捻じ曲げられた!", "Your body is twisted by chaos!"));
604             (void)gain_mutation(player_ptr, 0);
605         }
606     } break;
607
608     case RaceBlowEffectType::MAX:
609         break;
610     }
611 }