OSDN Git Service

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