2 * @brief モンスターからプレイヤーへの直接攻撃をその種別において振り分ける
5 * @details 長い処理はインクルード先の別ファイルにて行っている
8 #include "monster-attack/monster-attack-switcher.h"
9 #include "inventory/inventory-slot-types.h"
10 #include "mind/drs-types.h"
11 #include "mind/mind-mirror-master.h"
12 #include "monster-attack/monster-attack-lose.h"
13 #include "monster-attack/monster-attack-player.h"
14 #include "monster-attack/monster-attack-status.h"
15 #include "monster-attack/monster-attack-table.h"
16 #include "monster-attack/monster-eating.h"
17 #include "monster/monster-status.h"
18 #include "monster/monster-update.h"
19 #include "player/player-damage.h"
20 #include "player/player-status-flags.h"
21 #include "player/player-status-resist.h"
22 #include "player/player-status.h"
23 #include "spell-kind/earthquake.h"
24 #include "spell-kind/spells-equipment.h"
25 #include "status/bad-status-setter.h"
26 #include "status/base-status.h"
27 #include "status/element-resistance.h"
28 #include "status/experience.h"
29 #include "system/monster-type-definition.h"
30 #include "system/object-type-definition.h"
31 #include "system/player-type-definition.h"
32 #include "timed-effect/player-acceleration.h"
33 #include "timed-effect/timed-effects.h"
34 #include "view/display-messages.h"
38 * @param player_ptr プレイヤーへの参照ポインタ
39 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
40 * @details 減衰の計算式がpoisではなくnukeなのは仕様 (1/3では減衰が強すぎると判断したため)
42 static void calc_blow_poison(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
44 if (monap_ptr->explode) {
48 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)) {
49 monap_ptr->obvious = true;
52 monap_ptr->damage = monap_ptr->damage * calc_nuke_damage_rate(player_ptr) / 100;
53 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
54 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_POIS);
58 * @brief 劣化ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
59 * @param player_ptr プレイヤーへの参照ポインタ
60 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
62 static void calc_blow_disenchant(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
64 if (monap_ptr->explode) {
68 if (!has_resist_disen(player_ptr) && !check_multishadow(player_ptr) && apply_disenchant(player_ptr, 0)) {
69 update_creature(player_ptr);
70 monap_ptr->obvious = true;
73 if (has_resist_disen(player_ptr)) {
74 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
77 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
78 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_DISEN);
82 * @brief 魔道具吸収ダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-7.5%)
83 * @param player_ptr プレイヤーへの参照ポインタ
84 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
85 * @detals 魔道具使用能力向上フラグがあれば、吸収対象のアイテムをスキャンされる回数が半分で済む
87 static void calc_blow_un_power(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
89 int damage_ratio = 1000;
90 if (has_dec_mana(player_ptr)) {
94 if (has_easy_spell(player_ptr)) {
98 bool is_magic_mastery = has_magic_mastery(player_ptr) != 0;
99 if (is_magic_mastery) {
103 monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
104 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
105 if (player_ptr->is_dead || check_multishadow(player_ptr)) {
109 int max_draining_item = is_magic_mastery ? 5 : 10;
110 for (int i = 0; i < max_draining_item; i++) {
111 INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
112 monap_ptr->o_ptr = &player_ptr->inventory_list[i_idx];
113 if (monap_ptr->o_ptr->k_idx == 0) {
117 if (process_un_power(player_ptr, monap_ptr)) {
124 * @brief 盲目ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
125 * @param player_ptr プレイヤーへの参照ポインタ
126 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
128 static void calc_blow_blind(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
130 if (has_resist_blind(player_ptr)) {
131 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
134 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
135 if (player_ptr->is_dead) {
139 process_blind_attack(player_ptr, monap_ptr);
140 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_BLIND);
144 * @brief 混乱ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
145 * @param player_ptr プレイヤーへの参照ポインタ
146 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
148 static void calc_blow_confusion(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
150 if (monap_ptr->explode) {
154 if (has_resist_conf(player_ptr)) {
155 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
158 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
159 if (player_ptr->is_dead) {
163 if (!has_resist_conf(player_ptr) && !check_multishadow(player_ptr) && BadStatusSetter(player_ptr).mod_confusion(3 + randint1(monap_ptr->rlev))) {
164 monap_ptr->obvious = true;
167 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_CONF);
171 * @brief 恐怖ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
172 * @param player_ptr プレイヤーへの参照ポインタ
173 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
175 static void calc_blow_fear(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
177 if (has_resist_fear(player_ptr)) {
178 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
181 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
182 if (player_ptr->is_dead) {
186 process_terrify_attack(player_ptr, monap_ptr);
187 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FEAR);
191 * @brief 麻痺ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
192 * @param player_ptr プレイヤーへの参照ポインタ
193 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
195 static void calc_blow_paralysis(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
197 if (has_free_act(player_ptr)) {
198 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
201 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
202 if (player_ptr->is_dead) {
206 process_paralyze_attack(player_ptr, monap_ptr);
207 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FREE);
211 * @brief 経験値吸収ダメージを計算する (経験値保持と地獄耐性があれば、それぞれ-7.5%)
212 * @param player_ptr プレイヤーへの参照ポインタ
213 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
215 static void calc_blow_drain_exp(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr, const int drain_value, const int hold_exp_prob)
217 int32_t d = damroll(drain_value, 6) + (player_ptr->exp / 100) * MON_DRAIN_LIFE;
218 monap_ptr->obvious = true;
219 int damage_ratio = 1000;
220 if (has_hold_exp(player_ptr)) {
224 if (has_resist_neth(player_ptr)) {
228 monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
229 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
230 if (player_ptr->is_dead || check_multishadow(player_ptr)) {
234 (void)drain_exp(player_ptr, d, d / 10, hold_exp_prob);
238 * @brief 時間逆転ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
239 * @param player_ptr プレイヤーへの参照ポインタ
240 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
242 static void calc_blow_time(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
244 if (monap_ptr->explode) {
248 process_monster_attack_time(player_ptr, monap_ptr);
249 if (has_resist_time(player_ptr)) {
250 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
253 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
257 * @brief 生命力吸収ダメージを計算する (経験値維持があれば9/10になる)
258 * @param player_ptr プレイヤーへの参照ポインタ
259 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
261 static void calc_blow_drain_life(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
263 int32_t d = damroll(60, 6) + (player_ptr->exp / 100) * MON_DRAIN_LIFE;
264 monap_ptr->obvious = true;
265 if (player_ptr->hold_exp) {
266 monap_ptr->damage = monap_ptr->damage * 9 / 10;
269 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
270 if (player_ptr->is_dead || check_multishadow(player_ptr)) {
274 bool resist_drain = check_drain_hp(player_ptr, d);
275 process_drain_life(player_ptr, monap_ptr, resist_drain);
279 * @brief MPダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-5%)
280 * @param player_ptr プレイヤーへの参照ポインタ
281 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
283 static void calc_blow_drain_mana(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
285 monap_ptr->obvious = true;
286 int damage_ratio = 100;
287 if (has_dec_mana(player_ptr)) {
291 if (has_easy_spell(player_ptr)) {
295 if (has_magic_mastery(player_ptr)) {
299 monap_ptr->damage = monap_ptr->damage * damage_ratio / 100;
300 process_drain_mana(player_ptr, monap_ptr);
301 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_MANA);
304 static void calc_blow_inertia(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
306 if (player_ptr->effects()->acceleration()->is_fast() || (player_ptr->pspeed >= 130)) {
307 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
310 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
311 if (player_ptr->is_dead || check_multishadow(player_ptr)) {
315 if (BadStatusSetter(player_ptr).mod_slowness(4 + randint0(monap_ptr->rlev / 10), false)) {
316 monap_ptr->obvious = true;
321 * @brief 空腹進行度を計算する (急速回復があれば+100%、遅消化があれば-50%)
323 static void calc_blow_hungry(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
325 if (player_ptr->regenerate) {
326 monap_ptr->damage = monap_ptr->damage * 2;
328 if (player_ptr->slow_digest) {
329 monap_ptr->damage = monap_ptr->damage / 2;
332 process_monster_attack_hungry(player_ptr, monap_ptr);
335 void switch_monster_blow_to_player(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
337 switch (monap_ptr->effect) {
338 case RaceBlowEffectType::NONE:
339 // ここには来ないはずだが、何らかのバグで来た場合はプレイヤーの不利益に
340 // ならないようダメージを 0 にしておく。
341 monap_ptr->damage = 0;
343 case RaceBlowEffectType::SUPERHURT: { /* AC軽減あり / Player armor reduces total damage */
344 if (((randint1(monap_ptr->rlev * 2 + 300) > (monap_ptr->ac + 200)) || one_in_(13)) && !check_multishadow(player_ptr)) {
345 monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
346 msg_print(_("痛恨の一撃!", "It was a critical hit!"));
347 monap_ptr->damage = std::max(monap_ptr->damage, monap_ptr->damage * 2);
348 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
353 case RaceBlowEffectType::HURT: { /* AC軽減あり / Player armor reduces total damage */
354 monap_ptr->obvious = true;
355 monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
356 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
359 case RaceBlowEffectType::POISON:
360 calc_blow_poison(player_ptr, monap_ptr);
362 case RaceBlowEffectType::UN_BONUS:
363 calc_blow_disenchant(player_ptr, monap_ptr);
365 case RaceBlowEffectType::UN_POWER:
366 calc_blow_un_power(player_ptr, monap_ptr);
368 case RaceBlowEffectType::EAT_GOLD:
369 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
370 if (monster_confused_remaining(monap_ptr->m_ptr) || player_ptr->is_dead || check_multishadow(player_ptr)) {
374 monap_ptr->obvious = true;
375 process_eat_gold(player_ptr, monap_ptr);
377 case RaceBlowEffectType::EAT_ITEM: {
378 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
379 if (!check_eat_item(player_ptr, monap_ptr)) {
383 process_eat_item(player_ptr, monap_ptr);
387 case RaceBlowEffectType::EAT_FOOD: {
388 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
389 if (player_ptr->is_dead || check_multishadow(player_ptr)) {
393 process_eat_food(player_ptr, monap_ptr);
396 case RaceBlowEffectType::EAT_LITE: {
397 monap_ptr->o_ptr = &player_ptr->inventory_list[INVEN_LITE];
398 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
399 if (player_ptr->is_dead || check_multishadow(player_ptr)) {
403 process_eat_lite(player_ptr, monap_ptr);
406 case RaceBlowEffectType::ACID: {
407 if (monap_ptr->explode) {
411 monap_ptr->obvious = true;
412 msg_print(_("酸を浴びせられた!", "You are covered in acid!"));
413 monap_ptr->get_damage += acid_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
414 update_creature(player_ptr);
415 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_ACID);
418 case RaceBlowEffectType::ELEC: {
419 if (monap_ptr->explode) {
423 monap_ptr->obvious = true;
424 msg_print(_("電撃を浴びせられた!", "You are struck by electricity!"));
425 monap_ptr->get_damage += elec_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
426 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_ELEC);
429 case RaceBlowEffectType::FIRE: {
430 if (monap_ptr->explode) {
434 monap_ptr->obvious = true;
435 msg_print(_("全身が炎に包まれた!", "You are enveloped in flames!"));
436 monap_ptr->get_damage += fire_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
437 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FIRE);
440 case RaceBlowEffectType::COLD: {
441 if (monap_ptr->explode) {
445 monap_ptr->obvious = true;
446 msg_print(_("全身が冷気で覆われた!", "You are covered with frost!"));
447 monap_ptr->get_damage += cold_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
448 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_COLD);
451 case RaceBlowEffectType::BLIND:
452 calc_blow_blind(player_ptr, monap_ptr);
454 case RaceBlowEffectType::CONFUSE:
455 calc_blow_confusion(player_ptr, monap_ptr);
457 case RaceBlowEffectType::TERRIFY:
458 calc_blow_fear(player_ptr, monap_ptr);
460 case RaceBlowEffectType::PARALYZE:
461 calc_blow_paralysis(player_ptr, monap_ptr);
463 case RaceBlowEffectType::LOSE_STR:
464 calc_blow_lose_strength(player_ptr, monap_ptr);
466 case RaceBlowEffectType::LOSE_INT:
467 calc_blow_lose_intelligence(player_ptr, monap_ptr);
469 case RaceBlowEffectType::LOSE_WIS:
470 calc_blow_lose_wisdom(player_ptr, monap_ptr);
472 case RaceBlowEffectType::LOSE_DEX:
473 calc_blow_lose_dexterity(player_ptr, monap_ptr);
475 case RaceBlowEffectType::LOSE_CON:
476 calc_blow_lose_constitution(player_ptr, monap_ptr);
478 case RaceBlowEffectType::LOSE_CHR:
479 calc_blow_lose_charisma(player_ptr, monap_ptr);
481 case RaceBlowEffectType::LOSE_ALL:
482 calc_blow_lose_all(player_ptr, monap_ptr);
484 case RaceBlowEffectType::SHATTER: { /* AC軽減あり / Player armor reduces total damage */
485 monap_ptr->obvious = true;
486 monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
487 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
488 if (monap_ptr->damage > 23 || monap_ptr->explode) {
489 earthquake(player_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, 8, monap_ptr->m_idx);
494 case RaceBlowEffectType::EXP_10:
495 calc_blow_drain_exp(player_ptr, monap_ptr, 10, 95);
497 case RaceBlowEffectType::EXP_20:
498 calc_blow_drain_exp(player_ptr, monap_ptr, 20, 90);
500 case RaceBlowEffectType::EXP_40:
501 calc_blow_drain_exp(player_ptr, monap_ptr, 40, 75);
503 case RaceBlowEffectType::EXP_80:
504 calc_blow_drain_exp(player_ptr, monap_ptr, 80, 50);
506 case RaceBlowEffectType::DISEASE:
507 calc_blow_disease(player_ptr, monap_ptr);
509 case RaceBlowEffectType::TIME:
510 calc_blow_time(player_ptr, monap_ptr);
512 case RaceBlowEffectType::DR_LIFE:
513 calc_blow_drain_life(player_ptr, monap_ptr);
515 case RaceBlowEffectType::DR_MANA:
516 calc_blow_drain_mana(player_ptr, monap_ptr);
518 case RaceBlowEffectType::INERTIA:
519 calc_blow_inertia(player_ptr, monap_ptr);
521 case RaceBlowEffectType::STUN:
522 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
523 if (player_ptr->is_dead) {
526 process_stun_attack(player_ptr, monap_ptr);
528 case RaceBlowEffectType::FLAVOR:
529 // フレーバー打撃は自明かつダメージ 0。
530 monap_ptr->obvious = true;
531 monap_ptr->damage = 0;
533 case RaceBlowEffectType::HUNGRY:
534 calc_blow_hungry(player_ptr, monap_ptr);
537 case RaceBlowEffectType::MAX: