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-status.h"
14 #include "monster-attack/monster-attack-util.h"
15 #include "monster-attack/monster-eating.h"
16 #include "monster/monster-status.h"
17 #include "monster/monster-update.h"
18 #include "player/player-damage.h"
19 #include "player/player-status-flags.h"
20 #include "player/player-status-resist.h"
21 #include "player/player-status.h"
22 #include "spell-kind/earthquake.h"
23 #include "spell-kind/spells-equipment.h"
24 #include "status/bad-status-setter.h"
25 #include "status/base-status.h"
26 #include "status/element-resistance.h"
27 #include "status/experience.h"
28 #include "system/monster-type-definition.h"
29 #include "system/object-type-definition.h"
30 #include "system/player-type-definition.h"
31 #include "view/display-messages.h"
35 * @param player_ptr プレイヤーへの参照ポインタ
36 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
37 * @details 減衰の計算式がpoisではなくnukeなのは仕様 (1/3では減衰が強すぎると判断したため)
39 static void calc_blow_poison(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
41 if (monap_ptr->explode)
44 if (!(has_resist_pois(player_ptr) || is_oppose_pois(player_ptr)) && !check_multishadow(player_ptr)
45 && BadStatusSetter(player_ptr).mod_poison(randint1(monap_ptr->rlev) + 5))
46 monap_ptr->obvious = true;
48 monap_ptr->damage = monap_ptr->damage * calc_nuke_damage_rate(player_ptr) / 100;
49 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
50 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_POIS);
54 * @brief 劣化ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
55 * @param player_ptr プレイヤーへの参照ポインタ
56 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
58 static void calc_blow_disenchant(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
60 if (monap_ptr->explode)
63 if (!has_resist_disen(player_ptr) && !check_multishadow(player_ptr) && apply_disenchant(player_ptr, 0)) {
64 update_creature(player_ptr);
65 monap_ptr->obvious = true;
68 if (has_resist_disen(player_ptr))
69 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
71 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
72 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_DISEN);
76 * @brief 魔道具吸収ダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-7.5%)
77 * @param player_ptr プレイヤーへの参照ポインタ
78 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
79 * @detals 魔道具使用能力向上フラグがあれば、吸収対象のアイテムをスキャンされる回数が半分で済む
81 static void calc_blow_un_power(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
83 int damage_ratio = 1000;
84 if (has_dec_mana(player_ptr))
87 if (has_easy_spell(player_ptr))
90 bool is_magic_mastery = has_magic_mastery(player_ptr) != 0;
94 monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
95 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
96 if (player_ptr->is_dead || check_multishadow(player_ptr))
99 int max_draining_item = is_magic_mastery ? 5 : 10;
100 for (int i = 0; i < max_draining_item; i++) {
101 INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
102 monap_ptr->o_ptr = &player_ptr->inventory_list[i_idx];
103 if (monap_ptr->o_ptr->k_idx == 0)
106 if (process_un_power(player_ptr, monap_ptr))
112 * @brief 盲目ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
113 * @param player_ptr プレイヤーへの参照ポインタ
114 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
116 static void calc_blow_blind(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
118 if (has_resist_blind(player_ptr))
119 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
121 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
122 if (player_ptr->is_dead)
125 process_blind_attack(player_ptr, monap_ptr);
126 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_BLIND);
130 * @brief 混乱ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
131 * @param player_ptr プレイヤーへの参照ポインタ
132 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
134 static void calc_blow_confusion(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
136 if (monap_ptr->explode) {
140 if (has_resist_conf(player_ptr)) {
141 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
144 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
145 if (player_ptr->is_dead) {
149 if (!has_resist_conf(player_ptr) && !check_multishadow(player_ptr) && BadStatusSetter(player_ptr).mod_confusion(3 + randint1(monap_ptr->rlev))) {
150 monap_ptr->obvious = true;
153 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_CONF);
157 * @brief 恐怖ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
158 * @param player_ptr プレイヤーへの参照ポインタ
159 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
161 static void calc_blow_fear(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
163 if (has_resist_fear(player_ptr))
164 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
166 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
167 if (player_ptr->is_dead)
170 process_terrify_attack(player_ptr, monap_ptr);
171 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FEAR);
175 * @brief 麻痺ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
176 * @param player_ptr プレイヤーへの参照ポインタ
177 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
179 static void calc_blow_paralysis(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
181 if (has_free_act(player_ptr))
182 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
184 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
185 if (player_ptr->is_dead)
188 process_paralyze_attack(player_ptr, monap_ptr);
189 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FREE);
193 * @brief 経験値吸収ダメージを計算する (経験値保持と地獄耐性があれば、それぞれ-7.5%)
194 * @param player_ptr プレイヤーへの参照ポインタ
195 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
197 static void calc_blow_drain_exp(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr, const int drain_value, const int hold_exp_prob)
199 int32_t d = damroll(drain_value, 6) + (player_ptr->exp / 100) * MON_DRAIN_LIFE;
200 monap_ptr->obvious = true;
201 int damage_ratio = 1000;
202 if (has_hold_exp(player_ptr))
205 if (has_resist_neth(player_ptr))
208 monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
209 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
210 if (player_ptr->is_dead || check_multishadow(player_ptr))
213 (void)drain_exp(player_ptr, d, d / 10, hold_exp_prob);
217 * @brief 時間逆転ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
218 * @param player_ptr プレイヤーへの参照ポインタ
219 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
221 static void calc_blow_time(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
223 if (monap_ptr->explode)
226 process_monster_attack_time(player_ptr, monap_ptr);
227 if (has_resist_time(player_ptr))
228 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
230 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
234 * @brief 生命力吸収ダメージを計算する (経験値維持があれば9/10になる)
235 * @param player_ptr プレイヤーへの参照ポインタ
236 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
238 static void calc_blow_drain_life(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
240 int32_t d = damroll(60, 6) + (player_ptr->exp / 100) * MON_DRAIN_LIFE;
241 monap_ptr->obvious = true;
242 if (player_ptr->hold_exp)
243 monap_ptr->damage = monap_ptr->damage * 9 / 10;
245 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
246 if (player_ptr->is_dead || check_multishadow(player_ptr))
249 bool resist_drain = check_drain_hp(player_ptr, d);
250 process_drain_life(player_ptr, monap_ptr, resist_drain);
254 * @brief MPダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-5%)
255 * @param player_ptr プレイヤーへの参照ポインタ
256 * @param monap_ptr モンスターからプレイヤーへの直接攻撃構造体への参照ポインタ
258 static void calc_blow_drain_mana(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
260 monap_ptr->obvious = true;
261 int damage_ratio = 100;
262 if (has_dec_mana(player_ptr))
265 if (has_easy_spell(player_ptr))
268 if (has_magic_mastery(player_ptr))
271 monap_ptr->damage = monap_ptr->damage * damage_ratio / 100;
272 process_drain_mana(player_ptr, monap_ptr);
273 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_MANA);
276 static void calc_blow_inertia(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
278 if ((player_ptr->fast > 0) || (player_ptr->pspeed >= 130))
279 monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
281 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
282 if (player_ptr->is_dead || check_multishadow(player_ptr))
285 if (BadStatusSetter(player_ptr).mod_slowness(4 + randint0(monap_ptr->rlev / 10), false))
286 monap_ptr->obvious = true;
290 * @brief 空腹進行度を計算する (急速回復があれば+100%、遅消化があれば-50%)
292 static void calc_blow_hungry(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
294 if (player_ptr->regenerate)
295 monap_ptr->damage = monap_ptr->damage * 2;
296 if (player_ptr->slow_digest)
297 monap_ptr->damage = monap_ptr->damage / 2;
299 process_monster_attack_hungry(player_ptr, monap_ptr);
302 void switch_monster_blow_to_player(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
304 switch (monap_ptr->effect) {
305 case RaceBlowEffectType::NONE:
306 // ここには来ないはずだが、何らかのバグで来た場合はプレイヤーの不利益に
307 // ならないようダメージを 0 にしておく。
308 monap_ptr->damage = 0;
310 case RaceBlowEffectType::SUPERHURT: { /* AC軽減あり / Player armor reduces total damage */
311 if (((randint1(monap_ptr->rlev * 2 + 300) > (monap_ptr->ac + 200)) || one_in_(13)) && !check_multishadow(player_ptr)) {
312 monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
313 msg_print(_("痛恨の一撃!", "It was a critical hit!"));
314 monap_ptr->damage = std::max(monap_ptr->damage, monap_ptr->damage * 2);
315 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
320 case RaceBlowEffectType::HURT: { /* AC軽減あり / Player armor reduces total damage */
321 monap_ptr->obvious = true;
322 monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
323 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
326 case RaceBlowEffectType::POISON:
327 calc_blow_poison(player_ptr, monap_ptr);
329 case RaceBlowEffectType::UN_BONUS:
330 calc_blow_disenchant(player_ptr, monap_ptr);
332 case RaceBlowEffectType::UN_POWER:
333 calc_blow_un_power(player_ptr, monap_ptr);
335 case RaceBlowEffectType::EAT_GOLD:
336 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
337 if (monster_confused_remaining(monap_ptr->m_ptr) || player_ptr->is_dead || check_multishadow(player_ptr))
340 monap_ptr->obvious = true;
341 process_eat_gold(player_ptr, monap_ptr);
343 case RaceBlowEffectType::EAT_ITEM: {
344 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
345 if (!check_eat_item(player_ptr, monap_ptr))
348 process_eat_item(player_ptr, monap_ptr);
352 case RaceBlowEffectType::EAT_FOOD: {
353 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
354 if (player_ptr->is_dead || check_multishadow(player_ptr))
357 process_eat_food(player_ptr, monap_ptr);
360 case RaceBlowEffectType::EAT_LITE: {
361 monap_ptr->o_ptr = &player_ptr->inventory_list[INVEN_LITE];
362 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
363 if (player_ptr->is_dead || check_multishadow(player_ptr))
366 process_eat_lite(player_ptr, monap_ptr);
369 case RaceBlowEffectType::ACID: {
370 if (monap_ptr->explode)
373 monap_ptr->obvious = true;
374 msg_print(_("酸を浴びせられた!", "You are covered in acid!"));
375 monap_ptr->get_damage += acid_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
376 update_creature(player_ptr);
377 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_ACID);
380 case RaceBlowEffectType::ELEC: {
381 if (monap_ptr->explode)
384 monap_ptr->obvious = true;
385 msg_print(_("電撃を浴びせられた!", "You are struck by electricity!"));
386 monap_ptr->get_damage += elec_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
387 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_ELEC);
390 case RaceBlowEffectType::FIRE: {
391 if (monap_ptr->explode)
394 monap_ptr->obvious = true;
395 msg_print(_("全身が炎に包まれた!", "You are enveloped in flames!"));
396 monap_ptr->get_damage += fire_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
397 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_FIRE);
400 case RaceBlowEffectType::COLD: {
401 if (monap_ptr->explode)
404 monap_ptr->obvious = true;
405 msg_print(_("全身が冷気で覆われた!", "You are covered with frost!"));
406 monap_ptr->get_damage += cold_dam(player_ptr, monap_ptr->damage, monap_ptr->ddesc, false);
407 update_smart_learn(player_ptr, monap_ptr->m_idx, DRS_COLD);
410 case RaceBlowEffectType::BLIND:
411 calc_blow_blind(player_ptr, monap_ptr);
413 case RaceBlowEffectType::CONFUSE:
414 calc_blow_confusion(player_ptr, monap_ptr);
416 case RaceBlowEffectType::TERRIFY:
417 calc_blow_fear(player_ptr, monap_ptr);
419 case RaceBlowEffectType::PARALYZE:
420 calc_blow_paralysis(player_ptr, monap_ptr);
422 case RaceBlowEffectType::LOSE_STR:
423 calc_blow_lose_strength(player_ptr, monap_ptr);
425 case RaceBlowEffectType::LOSE_INT:
426 calc_blow_lose_intelligence(player_ptr, monap_ptr);
428 case RaceBlowEffectType::LOSE_WIS:
429 calc_blow_lose_wisdom(player_ptr, monap_ptr);
431 case RaceBlowEffectType::LOSE_DEX:
432 calc_blow_lose_dexterity(player_ptr, monap_ptr);
434 case RaceBlowEffectType::LOSE_CON:
435 calc_blow_lose_constitution(player_ptr, monap_ptr);
437 case RaceBlowEffectType::LOSE_CHR:
438 calc_blow_lose_charisma(player_ptr, monap_ptr);
440 case RaceBlowEffectType::LOSE_ALL:
441 calc_blow_lose_all(player_ptr, monap_ptr);
443 case RaceBlowEffectType::SHATTER: { /* AC軽減あり / Player armor reduces total damage */
444 monap_ptr->obvious = true;
445 monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
446 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
447 if (monap_ptr->damage > 23 || monap_ptr->explode)
448 earthquake(player_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, 8, monap_ptr->m_idx);
452 case RaceBlowEffectType::EXP_10:
453 calc_blow_drain_exp(player_ptr, monap_ptr, 10, 95);
455 case RaceBlowEffectType::EXP_20:
456 calc_blow_drain_exp(player_ptr, monap_ptr, 20, 90);
458 case RaceBlowEffectType::EXP_40:
459 calc_blow_drain_exp(player_ptr, monap_ptr, 40, 75);
461 case RaceBlowEffectType::EXP_80:
462 calc_blow_drain_exp(player_ptr, monap_ptr, 80, 50);
464 case RaceBlowEffectType::DISEASE:
465 calc_blow_disease(player_ptr, monap_ptr);
467 case RaceBlowEffectType::TIME:
468 calc_blow_time(player_ptr, monap_ptr);
470 case RaceBlowEffectType::DR_LIFE:
471 calc_blow_drain_life(player_ptr, monap_ptr);
473 case RaceBlowEffectType::DR_MANA:
474 calc_blow_drain_mana(player_ptr, monap_ptr);
476 case RaceBlowEffectType::INERTIA:
477 calc_blow_inertia(player_ptr, monap_ptr);
479 case RaceBlowEffectType::STUN:
480 monap_ptr->get_damage += take_hit(player_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc);
481 if (player_ptr->is_dead)
483 process_stun_attack(player_ptr, monap_ptr);
485 case RaceBlowEffectType::FLAVOR:
486 // フレーバー打撃は自明かつダメージ 0。
487 monap_ptr->obvious = true;
488 monap_ptr->damage = 0;
490 case RaceBlowEffectType::HUNGRY:
491 calc_blow_hungry(player_ptr, monap_ptr);
494 case RaceBlowEffectType::MAX: