OSDN Git Service

[Fix] 玄武の構えによるAC修正の計算を適切な位置へ移動
[hengband/hengband.git] / src / monster-attack / monster-attack-switcher.c
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 "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-eating.h"
15 #include "monster/monster-status.h"
16 #include "monster/monster-update.h"
17 #include "player/player-damage.h"
18 #include "player/player-status-flags.h"
19 #include "player/player-status-resist.h"
20 #include "spell-kind/earthquake.h"
21 #include "spell-kind/spells-equipment.h"
22 #include "status/bad-status-setter.h"
23 #include "status/base-status.h"
24 #include "status/element-resistance.h"
25 #include "status/experience.h"
26 #include "system/object-type-definition.h"
27 #include "view/display-messages.h"
28
29 /*!
30  * @brief 毒ダメージを計算する
31  * @param target_ptr プレーヤーへの参照ポインタ
32  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
33  * @return なし
34  * @detail 減衰の計算式がpoisではなくnukeなのは仕様 (1/3では減衰が強すぎると判断したため)
35  */
36 static void calc_blow_poison(player_type *target_ptr, monap_type *monap_ptr)
37 {
38     if (monap_ptr->explode)
39         return;
40
41     if (!(has_resist_pois(target_ptr) || is_oppose_pois(target_ptr)) && !check_multishadow(target_ptr)
42         && set_poisoned(target_ptr, target_ptr->poisoned + randint1(monap_ptr->rlev) + 5))
43         monap_ptr->obvious = TRUE;
44
45     monap_ptr->damage = monap_ptr->damage * calc_nuke_damage_rate(target_ptr) / 100;
46     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
47     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_POIS);
48 }
49
50 /*!
51  * @brief 劣化ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
52  * @param target_ptr プレーヤーへの参照ポインタ
53  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
54  * @return なし
55  */
56 static void calc_blow_disenchant(player_type *target_ptr, monap_type *monap_ptr)
57 {
58     if (monap_ptr->explode)
59         return;
60
61     if (!has_resist_disen(target_ptr) && !check_multishadow(target_ptr) && apply_disenchant(target_ptr, 0)) {
62         update_creature(target_ptr);
63         monap_ptr->obvious = TRUE;
64     }
65
66     if (has_resist_disen(target_ptr))
67         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
68
69     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
70     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_DISEN);
71 }
72
73 /*!
74  * @brief 魔道具吸収ダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-7.5%)
75  * @param target_ptr プレーヤーへの参照ポインタ
76  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
77  * @return なし
78  * @detals 魔道具使用能力向上フラグがあれば、吸収対象のアイテムをスキャンされる回数が半分で済む
79  */
80 static void calc_blow_un_power(player_type *target_ptr, monap_type *monap_ptr)
81 {
82     int damage_ratio = 1000;
83     if (has_dec_mana(target_ptr))
84         damage_ratio -= 75;
85
86     if (has_easy_spell(target_ptr))
87         damage_ratio -= 75;
88
89     bool is_magic_mastery = has_magic_mastery(target_ptr) != 0;
90     if (is_magic_mastery)
91         damage_ratio -= 75;
92
93     monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
94     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
95     if (target_ptr->is_dead || check_multishadow(target_ptr))
96         return;
97
98     int max_draining_item = is_magic_mastery ? 5 : 10;
99     for (int i = 0; i < max_draining_item; i++) {
100         INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
101         monap_ptr->o_ptr = &target_ptr->inventory_list[i_idx];
102         if (monap_ptr->o_ptr->k_idx == 0)
103             continue;
104
105         if (process_un_power(target_ptr, monap_ptr))
106             break;
107     }
108 }
109
110 /*!
111  * @brief 盲目ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
112  * @param target_ptr プレーヤーへの参照ポインタ
113  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
114  * @return なし
115  */
116 static void calc_blow_blind(player_type *target_ptr, monap_type *monap_ptr)
117 {
118     if (has_resist_blind(target_ptr))
119         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
120
121     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
122     if (target_ptr->is_dead)
123         return;
124
125     process_blind_attack(target_ptr, monap_ptr);
126     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_BLIND);
127 }
128
129 /*!
130  * @brief 混乱ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
131  * @param target_ptr プレーヤーへの参照ポインタ
132  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
133  * @return なし
134  */
135 static void calc_blow_confusion(player_type *target_ptr, monap_type *monap_ptr)
136 {
137     if (monap_ptr->explode)
138         return;
139
140     if (has_resist_conf(target_ptr))
141         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
142
143     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
144     if (target_ptr->is_dead)
145         return;
146
147     if (!has_resist_conf(target_ptr) && !check_multishadow(target_ptr) && set_confused(target_ptr, target_ptr->confused + 3 + randint1(monap_ptr->rlev)))
148         monap_ptr->obvious = TRUE;
149
150     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_CONF);
151 }
152
153 /*!
154  * @brief 恐怖ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
155  * @param target_ptr プレーヤーへの参照ポインタ
156  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
157  * @return なし
158  */
159 static void calc_blow_fear(player_type *target_ptr, monap_type *monap_ptr)
160 {
161     if (has_resist_fear(target_ptr))
162         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
163
164     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
165     if (target_ptr->is_dead)
166         return;
167
168     process_terrify_attack(target_ptr, monap_ptr);
169     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FEAR);
170 }
171
172 /*!
173  * @brief 麻痺ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
174  * @param target_ptr プレーヤーへの参照ポインタ
175  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
176  * @return なし
177  */
178 static void calc_blow_paralysis(player_type *target_ptr, monap_type *monap_ptr)
179 {
180     if (has_free_act(target_ptr))
181         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
182
183     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
184     if (target_ptr->is_dead)
185         return;
186
187     process_paralyze_attack(target_ptr, monap_ptr);
188     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FREE);
189 }
190
191 /*!
192  * @brief 経験値吸収ダメージを計算する (経験値保持と地獄耐性があれば、それぞれ-7.5%)
193  * @param target_ptr プレーヤーへの参照ポインタ
194  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
195  * @return なし
196  */
197 static void calc_blow_drain_exp(player_type *target_ptr, monap_type *monap_ptr, const int drain_value, const int hold_exp_prob)
198 {
199     s32b d = damroll(drain_value, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
200     monap_ptr->obvious = TRUE;
201     int damage_ratio = 1000;
202     if (has_hold_exp(target_ptr))
203         damage_ratio -= 75;
204
205     if (has_resist_neth(target_ptr))
206         damage_ratio -= 75;
207
208     monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
209     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
210     if (target_ptr->is_dead || check_multishadow(target_ptr))
211         return;
212
213     (void)drain_exp(target_ptr, d, d / 10, hold_exp_prob);
214 }
215
216 /*!
217  * @brief 時間逆転ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
218  * @param target_ptr プレーヤーへの参照ポインタ
219  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
220  * @return なし
221  */
222 static void calc_blow_time(player_type *target_ptr, monap_type *monap_ptr)
223 {
224     if (monap_ptr->explode)
225         return;
226
227     process_monster_attack_time(target_ptr, monap_ptr);
228     if (has_resist_time(target_ptr))
229         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
230
231     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
232 }
233
234 /*!
235  * @brief 生命力吸収ダメージを計算する (経験値維持があれば9/10になる)
236  * @param target_ptr プレーヤーへの参照ポインタ
237  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
238  * @return なし
239  */
240 static void calc_blow_drain_life(player_type *target_ptr, monap_type *monap_ptr)
241 {
242     s32b d = damroll(60, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
243     monap_ptr->obvious = TRUE;
244     if (target_ptr->hold_exp)
245         monap_ptr->damage = monap_ptr->damage * 9 / 10;
246
247     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
248     if (target_ptr->is_dead || check_multishadow(target_ptr))
249         return;
250
251     bool resist_drain = check_drain_hp(target_ptr, d);
252     process_drain_life(target_ptr, monap_ptr, resist_drain);
253 }
254
255 /*!
256  * @brief MPダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-5%)
257  * @param target_ptr プレーヤーへの参照ポインタ
258  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
259  * @return なし
260  */
261 static void calc_blow_drain_mana(player_type *target_ptr, monap_type *monap_ptr)
262 {
263     monap_ptr->obvious = TRUE;
264     int damage_ratio = 100;
265     if (has_dec_mana(target_ptr))
266         damage_ratio -= 5;
267
268     if (has_easy_spell(target_ptr))
269         damage_ratio -= 5;
270
271     if (has_magic_mastery(target_ptr))
272         damage_ratio -= 5;
273
274     monap_ptr->damage = monap_ptr->damage * damage_ratio / 100;
275     process_drain_mana(target_ptr, monap_ptr);
276     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_MANA);
277 }
278
279 static void calc_blow_inertia(player_type *target_ptr, monap_type *monap_ptr)
280 {
281     if ((target_ptr->fast > 0) || (target_ptr->pspeed >= 130))
282         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
283
284     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
285     if (target_ptr->is_dead || check_multishadow(target_ptr))
286         return;
287
288     if (set_slow(target_ptr, (target_ptr->slow + 4 + randint0(monap_ptr->rlev / 10)), FALSE))
289         monap_ptr->obvious = TRUE;
290 }
291
292 void switch_monster_blow_to_player(player_type *target_ptr, monap_type *monap_ptr)
293 {
294     switch (monap_ptr->effect) {
295     case RBE_NONE:
296         monap_ptr->obvious = TRUE;
297         monap_ptr->damage = 0;
298         break;
299     case RBE_SUPERHURT: { /* AC軽減あり / Player armor reduces total damage */
300         if (((randint1(monap_ptr->rlev * 2 + 300) > (monap_ptr->ac + 200)) || one_in_(13)) && !check_multishadow(target_ptr)) {
301             int tmp_damage = monap_ptr->damage - (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
302             msg_print(_("痛恨の一撃!", "It was a critical hit!"));
303             tmp_damage = MAX(monap_ptr->damage, tmp_damage * 2);
304             monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, tmp_damage, monap_ptr->ddesc, -1);
305             break;
306         }
307     }
308         /* Fall through */
309     case RBE_HURT: { /* AC軽減あり / Player armor reduces total damage */
310         monap_ptr->obvious = TRUE;
311         monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
312         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
313         break;
314     }
315     case RBE_POISON:
316         calc_blow_poison(target_ptr, monap_ptr);
317         break;
318     case RBE_UN_BONUS:
319         calc_blow_disenchant(target_ptr, monap_ptr);
320         break;
321     case RBE_UN_POWER:
322         calc_blow_un_power(target_ptr, monap_ptr);
323         break;
324     case RBE_EAT_GOLD:
325         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
326         if (monster_confused_remaining(monap_ptr->m_ptr) || target_ptr->is_dead || check_multishadow(target_ptr))
327             break;
328
329         monap_ptr->obvious = TRUE;
330         process_eat_gold(target_ptr, monap_ptr);
331         break;
332     case RBE_EAT_ITEM: {
333         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
334         if (!check_eat_item(target_ptr, monap_ptr))
335             break;
336
337         process_eat_item(target_ptr, monap_ptr);
338         break;
339     }
340
341     case RBE_EAT_FOOD: {
342         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
343         if (target_ptr->is_dead || check_multishadow(target_ptr))
344             break;
345
346         process_eat_food(target_ptr, monap_ptr);
347         break;
348     }
349     case RBE_EAT_LITE: {
350         monap_ptr->o_ptr = &target_ptr->inventory_list[INVEN_LITE];
351         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
352         if (target_ptr->is_dead || check_multishadow(target_ptr))
353             break;
354
355         process_eat_lite(target_ptr, monap_ptr);
356         break;
357     }
358     case RBE_ACID: {
359         if (monap_ptr->explode)
360             break;
361
362         monap_ptr->obvious = TRUE;
363         msg_print(_("酸を浴びせられた!", "You are covered in acid!"));
364         monap_ptr->get_damage += acid_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
365         update_creature(target_ptr);
366         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_ACID);
367         break;
368     }
369     case RBE_ELEC: {
370         if (monap_ptr->explode)
371             break;
372
373         monap_ptr->obvious = TRUE;
374         msg_print(_("電撃を浴びせられた!", "You are struck by electricity!"));
375         monap_ptr->get_damage += elec_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
376         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_ELEC);
377         break;
378     }
379     case RBE_FIRE: {
380         if (monap_ptr->explode)
381             break;
382
383         monap_ptr->obvious = TRUE;
384         msg_print(_("全身が炎に包まれた!", "You are enveloped in flames!"));
385         monap_ptr->get_damage += fire_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
386         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FIRE);
387         break;
388     }
389     case RBE_COLD: {
390         if (monap_ptr->explode)
391             break;
392
393         monap_ptr->obvious = TRUE;
394         msg_print(_("全身が冷気で覆われた!", "You are covered with frost!"));
395         monap_ptr->get_damage += cold_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
396         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_COLD);
397         break;
398     }
399     case RBE_BLIND:
400         calc_blow_blind(target_ptr, monap_ptr);
401         break;
402     case RBE_CONFUSE:
403         calc_blow_confusion(target_ptr, monap_ptr);
404         break;
405     case RBE_TERRIFY:
406         calc_blow_fear(target_ptr, monap_ptr);
407         break;
408     case RBE_PARALYZE:
409         calc_blow_paralysis(target_ptr, monap_ptr);
410         break;
411     case RBE_LOSE_STR:
412         calc_blow_lose_strength(target_ptr, monap_ptr);
413         break;
414     case RBE_LOSE_INT:
415         calc_blow_lose_intelligence(target_ptr, monap_ptr);
416         break;
417     case RBE_LOSE_WIS:
418         calc_blow_lose_wisdom(target_ptr, monap_ptr);
419         break;
420     case RBE_LOSE_DEX:
421         calc_blow_lose_dexterity(target_ptr, monap_ptr);
422         break;
423     case RBE_LOSE_CON:
424         calc_blow_lose_constitution(target_ptr, monap_ptr);
425         break;
426     case RBE_LOSE_CHR:
427         calc_blow_lose_charisma(target_ptr, monap_ptr);
428         break;
429     case RBE_LOSE_ALL:
430         calc_blow_lose_all(target_ptr, monap_ptr);
431         break;
432     case RBE_SHATTER: { /* AC軽減あり / Player armor reduces total damage */
433         monap_ptr->obvious = TRUE;
434         monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
435         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
436         if (monap_ptr->damage > 23 || monap_ptr->explode)
437             earthquake(target_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, 8, monap_ptr->m_idx);
438
439         break;
440     }
441     case RBE_EXP_10:
442         calc_blow_drain_exp(target_ptr, monap_ptr, 10, 95);
443         break;
444     case RBE_EXP_20:
445         calc_blow_drain_exp(target_ptr, monap_ptr, 20, 90);
446         break;
447     case RBE_EXP_40:
448         calc_blow_drain_exp(target_ptr, monap_ptr, 40, 75);
449         break;
450     case RBE_EXP_80:
451         calc_blow_drain_exp(target_ptr, monap_ptr, 80, 50);
452         break;
453     case RBE_DISEASE:
454         calc_blow_disease(target_ptr, monap_ptr);
455         break;
456     case RBE_TIME:
457         calc_blow_time(target_ptr, monap_ptr);
458         break;
459     case RBE_DR_LIFE:
460         calc_blow_drain_life(target_ptr, monap_ptr);
461         break;
462     case RBE_DR_MANA:
463         calc_blow_drain_mana(target_ptr, monap_ptr);
464         break;
465     case RBE_INERTIA:
466         calc_blow_inertia(target_ptr, monap_ptr);
467         break;
468     case RBE_STUN:
469         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
470         if (target_ptr->is_dead)
471             break;
472
473         process_stun_attack(target_ptr, monap_ptr);
474         break;
475     }
476 }