OSDN Git Service

[Fix] #37285 ここまでの関数名差異を修正. / Fix difference of functions name.
[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 (!(target_ptr->resist_pois || 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 (!target_ptr->resist_disen && !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 盲目ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
75  * @param target_ptr プレーヤーへの参照ポインタ
76  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
77  * @return なし
78  */
79 static void calc_blow_blind(player_type *target_ptr, monap_type *monap_ptr)
80 {
81     if (has_resist_blind(target_ptr))
82         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
83
84     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
85     if (target_ptr->is_dead)
86         return;
87
88     process_blind_attack(target_ptr, monap_ptr);
89     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_BLIND);
90 }
91
92 /*!
93  * @brief 混乱ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
94  * @param target_ptr プレーヤーへの参照ポインタ
95  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
96  * @return なし
97  */
98 static void calc_blow_confusion(player_type *target_ptr, monap_type *monap_ptr)
99 {
100     if (monap_ptr->explode)
101         return;
102
103     if (has_resist_conf(target_ptr))
104         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
105
106     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
107     if (target_ptr->is_dead)
108         return;
109
110     if (!target_ptr->resist_conf && !check_multishadow(target_ptr) && set_confused(target_ptr, target_ptr->confused + 3 + randint1(monap_ptr->rlev)))
111         monap_ptr->obvious = TRUE;
112
113     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_CONF);
114 }
115
116 /*!
117  * @brief 恐怖ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
118  * @param target_ptr プレーヤーへの参照ポインタ
119  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
120  * @return なし
121  */
122 static void calc_blow_fear(player_type *target_ptr, monap_type *monap_ptr)
123 {
124     if (has_resist_fear(target_ptr))
125         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
126
127     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
128     if (target_ptr->is_dead)
129         return;
130
131     process_terrify_attack(target_ptr, monap_ptr);
132     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FEAR);
133 }
134
135 /*!
136  * @brief 麻痺ダメージを計算する (耐性があれば、(1d4 + 3) / 8になる)
137  * @param target_ptr プレーヤーへの参照ポインタ
138  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
139  * @return なし
140  */
141 static void calc_blow_paralysis(player_type *target_ptr, monap_type *monap_ptr)
142 {
143     if (has_free_act(target_ptr))
144         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 3) / 8;
145
146     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
147     if (target_ptr->is_dead)
148         return;
149
150     process_paralyze_attack(target_ptr, monap_ptr);
151     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FREE);
152 }
153
154 /*!
155  * @brief 経験値吸収ダメージを計算する (経験値保持と地獄耐性があれば、それぞれ-7.5%)
156  * @param target_ptr プレーヤーへの参照ポインタ
157  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
158  * @return なし
159  */
160 static void calc_blow_drain_exp(player_type *target_ptr, monap_type *monap_ptr, const int drain_value, const int hold_exp_prob)
161 {
162     s32b d = damroll(drain_value, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
163     monap_ptr->obvious = TRUE;
164     int damage_ratio = 1000;
165     if (has_hold_exp(target_ptr))
166         damage_ratio -= 75;
167
168     if (has_resist_neth(target_ptr))
169         damage_ratio -= 75;
170
171     monap_ptr->damage = monap_ptr->damage * damage_ratio / 1000;
172     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
173     if (target_ptr->is_dead || check_multishadow(target_ptr))
174         return;
175
176     (void)drain_exp(target_ptr, d, d / 10, hold_exp_prob);
177 }
178
179 /*!
180  * @brief 時間逆転ダメージを計算する (耐性があれば、(1d4 + 4) / 9になる)
181  * @param target_ptr プレーヤーへの参照ポインタ
182  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
183  * @return なし
184  */
185 static void calc_blow_time(player_type *target_ptr, monap_type *monap_ptr)
186 {
187     if (monap_ptr->explode)
188         return;
189
190     process_monster_attack_time(target_ptr, monap_ptr);
191     if (has_resist_time(target_ptr))
192         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
193
194     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
195 }
196
197 /*!
198  * @brief 生命力吸収ダメージを計算する (経験値維持があれば9/10になる)
199  * @param target_ptr プレーヤーへの参照ポインタ
200  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
201  * @return なし
202  */
203 static void calc_blow_drain_life(player_type *target_ptr, monap_type *monap_ptr)
204 {
205     s32b d = damroll(60, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
206     monap_ptr->obvious = TRUE;
207     if (target_ptr->hold_exp)
208         monap_ptr->damage = monap_ptr->damage * 9 / 10;
209
210     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
211     if (target_ptr->is_dead || check_multishadow(target_ptr))
212         return;
213
214     bool resist_drain = check_drain_hp(target_ptr, d);
215     process_drain_life(target_ptr, monap_ptr, resist_drain);
216 }
217
218 /*!
219  * todo 魔道具使用能力向上フラグの取得関数は未定義、後ほど実施する
220  * @brief MPダメージを計算する (消費魔力減少、呪文失敗率減少、魔道具使用能力向上があればそれぞれ-5%)
221  * @param target_ptr プレーヤーへの参照ポインタ
222  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
223  * @return なし
224  */
225 static void calc_blow_drain_mana(player_type *target_ptr, monap_type *monap_ptr)
226 {
227     monap_ptr->obvious = TRUE;
228     int damage_ratio = 100;
229     if (has_dec_mana(target_ptr))
230         damage_ratio -= 5;
231
232     if (has_easy_spell(target_ptr))
233         damage_ratio -= 5;
234
235     monap_ptr->damage = monap_ptr->damage * damage_ratio / 100;
236     process_drain_mana(target_ptr, monap_ptr);
237     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_MANA);
238 }
239
240 static void calc_blow_inertia(player_type *target_ptr, monap_type *monap_ptr)
241 {
242     if ((target_ptr->fast > 0) || (target_ptr->pspeed >= 130))
243         monap_ptr->damage = monap_ptr->damage * (randint1(4) + 4) / 9;
244
245     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
246     if (target_ptr->is_dead || check_multishadow(target_ptr))
247         return;
248
249     if (set_slow(target_ptr, (target_ptr->slow + 4 + randint0(monap_ptr->rlev / 10)), FALSE))
250         monap_ptr->obvious = TRUE;
251 }
252
253 void switch_monster_blow_to_player(player_type *target_ptr, monap_type *monap_ptr)
254 {
255     switch (monap_ptr->effect) {
256     case RBE_NONE:
257         monap_ptr->obvious = TRUE;
258         monap_ptr->damage = 0;
259         break;
260     case RBE_SUPERHURT: { /* AC軽減あり / Player armor reduces total damage */
261         if (((randint1(monap_ptr->rlev * 2 + 300) > (monap_ptr->ac + 200)) || one_in_(13)) && !check_multishadow(target_ptr)) {
262             int tmp_damage = monap_ptr->damage - (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
263             msg_print(_("痛恨の一撃!", "It was a critical hit!"));
264             tmp_damage = MAX(monap_ptr->damage, tmp_damage * 2);
265             monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, tmp_damage, monap_ptr->ddesc, -1);
266             break;
267         }
268     }
269         /* Fall through */
270     case RBE_HURT: { /* AC軽減あり / Player armor reduces total damage */
271         monap_ptr->obvious = TRUE;
272         monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
273         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
274         break;
275     }
276     case RBE_POISON:
277         calc_blow_poison(target_ptr, monap_ptr);
278         break;
279     case RBE_UN_BONUS:
280         calc_blow_disenchant(target_ptr, monap_ptr);
281         break;
282     case RBE_UN_POWER: {
283         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
284         if (target_ptr->is_dead || check_multishadow(target_ptr))
285             break;
286
287         for (int i = 0; i < 10; i++) {
288             INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
289             monap_ptr->o_ptr = &target_ptr->inventory_list[i_idx];
290             if (monap_ptr->o_ptr->k_idx == 0)
291                 continue;
292
293             if (process_un_power(target_ptr, monap_ptr))
294                 break;
295         }
296
297         break;
298     }
299     case RBE_EAT_GOLD: {
300         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
301         if (monster_confused_remaining(monap_ptr->m_ptr))
302             break;
303
304         if (target_ptr->is_dead || check_multishadow(target_ptr))
305             break;
306
307         monap_ptr->obvious = TRUE;
308         process_eat_gold(target_ptr, monap_ptr);
309         break;
310     }
311     case RBE_EAT_ITEM: {
312         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
313         if (!check_eat_item(target_ptr, monap_ptr))
314             break;
315
316         process_eat_item(target_ptr, monap_ptr);
317         break;
318     }
319
320     case RBE_EAT_FOOD: {
321         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
322         if (target_ptr->is_dead || check_multishadow(target_ptr))
323             break;
324
325         process_eat_food(target_ptr, monap_ptr);
326         break;
327     }
328     case RBE_EAT_LITE: {
329         monap_ptr->o_ptr = &target_ptr->inventory_list[INVEN_LITE];
330         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
331         if (target_ptr->is_dead || check_multishadow(target_ptr))
332             break;
333
334         process_eat_lite(target_ptr, monap_ptr);
335         break;
336     }
337     case RBE_ACID: {
338         if (monap_ptr->explode)
339             break;
340
341         monap_ptr->obvious = TRUE;
342         msg_print(_("酸を浴びせられた!", "You are covered in acid!"));
343         monap_ptr->get_damage += acid_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
344         update_creature(target_ptr);
345         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_ACID);
346         break;
347     }
348     case RBE_ELEC: {
349         if (monap_ptr->explode)
350             break;
351
352         monap_ptr->obvious = TRUE;
353         msg_print(_("電撃を浴びせられた!", "You are struck by electricity!"));
354         monap_ptr->get_damage += elec_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
355         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_ELEC);
356         break;
357     }
358     case RBE_FIRE: {
359         if (monap_ptr->explode)
360             break;
361
362         monap_ptr->obvious = TRUE;
363         msg_print(_("全身が炎に包まれた!", "You are enveloped in flames!"));
364         monap_ptr->get_damage += fire_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
365         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FIRE);
366         break;
367     }
368     case RBE_COLD: {
369         if (monap_ptr->explode)
370             break;
371
372         monap_ptr->obvious = TRUE;
373         msg_print(_("全身が冷気で覆われた!", "You are covered with frost!"));
374         monap_ptr->get_damage += cold_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
375         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_COLD);
376         break;
377     }
378     case RBE_BLIND:
379         calc_blow_blind(target_ptr, monap_ptr);
380         break;
381     case RBE_CONFUSE:
382         calc_blow_confusion(target_ptr, monap_ptr);
383         break;
384     case RBE_TERRIFY:
385         calc_blow_fear(target_ptr, monap_ptr);
386         break;
387     case RBE_PARALYZE:
388         calc_blow_paralysis(target_ptr, monap_ptr);
389         break;
390     case RBE_LOSE_STR:
391         calc_blow_lose_strength(target_ptr, monap_ptr);
392         break;
393     case RBE_LOSE_INT:
394         calc_blow_lose_intelligence(target_ptr, monap_ptr);
395         break;
396     case RBE_LOSE_WIS:
397         calc_blow_lose_wisdom(target_ptr, monap_ptr);
398         break;
399     case RBE_LOSE_DEX:
400         calc_blow_lose_dexterity(target_ptr, monap_ptr);
401         break;
402     case RBE_LOSE_CON:
403         calc_blow_lose_constitution(target_ptr, monap_ptr);
404         break;
405     case RBE_LOSE_CHR:
406         calc_blow_lose_charisma(target_ptr, monap_ptr);
407         break;
408     case RBE_LOSE_ALL:
409         calc_blow_lose_all(target_ptr, monap_ptr);
410         break;
411     case RBE_SHATTER: { /* AC軽減あり / Player armor reduces total damage */
412         monap_ptr->obvious = TRUE;
413         monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
414         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
415         if (monap_ptr->damage > 23 || monap_ptr->explode)
416             earthquake(target_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, 8, monap_ptr->m_idx);
417
418         break;
419     }
420     case RBE_EXP_10:
421         calc_blow_drain_exp(target_ptr, monap_ptr, 10, 95);
422         break;
423     case RBE_EXP_20:
424         calc_blow_drain_exp(target_ptr, monap_ptr, 20, 90);
425         break;
426     case RBE_EXP_40:
427         calc_blow_drain_exp(target_ptr, monap_ptr, 40, 75);
428         break;
429     case RBE_EXP_80:
430         calc_blow_drain_exp(target_ptr, monap_ptr, 80, 50);
431         break;
432     case RBE_DISEASE:
433         calc_blow_disease(target_ptr, monap_ptr);
434         break;
435     case RBE_TIME:
436         calc_blow_time(target_ptr, monap_ptr);
437         break;
438     case RBE_DR_LIFE:
439         calc_blow_drain_life(target_ptr, monap_ptr);
440         break;
441     case RBE_DR_MANA:
442         calc_blow_drain_mana(target_ptr, monap_ptr);
443         break;
444     case RBE_INERTIA:
445         calc_blow_inertia(target_ptr, monap_ptr);
446         break;
447     case RBE_STUN: {
448         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
449         if (target_ptr->is_dead)
450             break;
451
452         process_stun_attack(target_ptr, monap_ptr);
453         break;
454     }
455     }
456 }