OSDN Git Service

[Implement] #37285 毒ダメージの減衰式を追加 / Added attenuating calculation for poison blow
[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-status.h"
13 #include "monster-attack/monster-eating.h"
14 #include "monster/monster-status.h"
15 #include "monster/monster-update.h"
16 #include "player/player-damage.h"
17 #include "player/player-status-resist.h"
18 #include "spell-kind/earthquake.h"
19 #include "spell-kind/spells-equipment.h"
20 #include "status/bad-status-setter.h"
21 #include "status/base-status.h"
22 #include "status/element-resistance.h"
23 #include "status/experience.h"
24 #include "system/object-type-definition.h"
25 #include "view/display-messages.h"
26
27 /*!
28  * @brief 毒ダメージを計算する
29  * @param target_ptr プレーヤーへの参照ポインタ
30  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
31  * @return なし
32  * @detail 減衰の計算式がpoisではなくnukeなのは仕様 (1/3では減衰が強すぎると判断したため)
33  */
34 static void calc_blow_poison(player_type *target_ptr, monap_type *monap_ptr)
35 {
36     if (monap_ptr->explode)
37         return;
38
39     if (!(target_ptr->resist_pois || is_oppose_pois(target_ptr)) && !check_multishadow(target_ptr)
40         && set_poisoned(target_ptr, target_ptr->poisoned + randint1(monap_ptr->rlev) + 5))
41         monap_ptr->obvious = TRUE;
42
43     monap_ptr->damage = monap_ptr->damage * calc_nuke_damage_rate(target_ptr) / 100;
44     monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
45     update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_POIS);
46 }
47
48 void switch_monster_blow_to_player(player_type *target_ptr, monap_type *monap_ptr)
49 {
50     switch (monap_ptr->effect) {
51     case RBE_NONE:
52         monap_ptr->obvious = TRUE;
53         monap_ptr->damage = 0;
54         break;
55     case RBE_SUPERHURT: { /* AC軽減あり / Player armor reduces total damage */
56         if (((randint1(monap_ptr->rlev * 2 + 300) > (monap_ptr->ac + 200)) || one_in_(13)) && !check_multishadow(target_ptr)) {
57             int tmp_damage = monap_ptr->damage - (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
58             msg_print(_("痛恨の一撃!", "It was a critical hit!"));
59             tmp_damage = MAX(monap_ptr->damage, tmp_damage * 2);
60             monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, tmp_damage, monap_ptr->ddesc, -1);
61             break;
62         }
63     }
64         /* Fall through */
65     case RBE_HURT: { /* AC軽減あり / Player armor reduces total damage */
66         monap_ptr->obvious = TRUE;
67         monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
68         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
69         break;
70     }
71     case RBE_POISON:
72         calc_blow_poison(target_ptr, monap_ptr);
73         break;
74     case RBE_UN_BONUS: {
75         if (monap_ptr->explode)
76             break;
77
78         if (!target_ptr->resist_disen && !check_multishadow(target_ptr)) {
79             if (apply_disenchant(target_ptr, 0)) {
80                 update_creature(target_ptr);
81                 monap_ptr->obvious = TRUE;
82             }
83         }
84
85         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
86         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_DISEN);
87         break;
88     }
89     case RBE_UN_POWER: {
90         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
91         if (target_ptr->is_dead || check_multishadow(target_ptr))
92             break;
93
94         for (int i = 0; i < 10; i++) {
95             INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
96             monap_ptr->o_ptr = &target_ptr->inventory_list[i_idx];
97             if (monap_ptr->o_ptr->k_idx == 0)
98                 continue;
99
100             if (process_un_power(target_ptr, monap_ptr))
101                 break;
102         }
103
104         break;
105     }
106     case RBE_EAT_GOLD: {
107         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
108         if (monster_confused_remaining(monap_ptr->m_ptr))
109             break;
110
111         if (target_ptr->is_dead || check_multishadow(target_ptr))
112             break;
113
114         monap_ptr->obvious = TRUE;
115         process_eat_gold(target_ptr, monap_ptr);
116         break;
117     }
118     case RBE_EAT_ITEM: {
119         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
120         if (!check_eat_item(target_ptr, monap_ptr))
121             break;
122
123         process_eat_item(target_ptr, monap_ptr);
124         break;
125     }
126
127     case RBE_EAT_FOOD: {
128         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
129         if (target_ptr->is_dead || check_multishadow(target_ptr))
130             break;
131
132         process_eat_food(target_ptr, monap_ptr);
133         break;
134     }
135     case RBE_EAT_LITE: {
136         monap_ptr->o_ptr = &target_ptr->inventory_list[INVEN_LITE];
137         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
138         if (target_ptr->is_dead || check_multishadow(target_ptr))
139             break;
140
141         process_eat_lite(target_ptr, monap_ptr);
142         break;
143     }
144     case RBE_ACID: {
145         if (monap_ptr->explode)
146             break;
147
148         monap_ptr->obvious = TRUE;
149         msg_print(_("酸を浴びせられた!", "You are covered in acid!"));
150         monap_ptr->get_damage += acid_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
151         update_creature(target_ptr);
152         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_ACID);
153         break;
154     }
155     case RBE_ELEC: {
156         if (monap_ptr->explode)
157             break;
158         monap_ptr->obvious = TRUE;
159         msg_print(_("電撃を浴びせられた!", "You are struck by electricity!"));
160         monap_ptr->get_damage += elec_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
161         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_ELEC);
162         break;
163     }
164     case RBE_FIRE: {
165         if (monap_ptr->explode)
166             break;
167         monap_ptr->obvious = TRUE;
168         msg_print(_("全身が炎に包まれた!", "You are enveloped in flames!"));
169         monap_ptr->get_damage += fire_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
170         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FIRE);
171         break;
172     }
173     case RBE_COLD: {
174         if (monap_ptr->explode)
175             break;
176         monap_ptr->obvious = TRUE;
177         msg_print(_("全身が冷気で覆われた!", "You are covered with frost!"));
178         monap_ptr->get_damage += cold_dam(target_ptr, monap_ptr->damage, monap_ptr->ddesc, -1, FALSE);
179         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_COLD);
180         break;
181     }
182     case RBE_BLIND: {
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             break;
186
187         process_blind_attack(target_ptr, monap_ptr);
188         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_BLIND);
189         break;
190     }
191     case RBE_CONFUSE: {
192         if (monap_ptr->explode)
193             break;
194
195         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
196         if (target_ptr->is_dead)
197             break;
198
199         if (!target_ptr->resist_conf && !check_multishadow(target_ptr)) {
200             if (set_confused(target_ptr, target_ptr->confused + 3 + randint1(monap_ptr->rlev))) {
201                 monap_ptr->obvious = TRUE;
202             }
203         }
204
205         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_CONF);
206         break;
207     }
208     case RBE_TERRIFY: {
209         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
210         if (target_ptr->is_dead)
211             break;
212
213         process_terrify_attack(target_ptr, monap_ptr);
214         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FEAR);
215         break;
216     }
217     case RBE_PARALYZE: {
218         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
219
220         if (target_ptr->is_dead)
221             break;
222
223         process_paralyze_attack(target_ptr, monap_ptr);
224         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_FREE);
225         break;
226     }
227     case RBE_LOSE_STR: {
228         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
229         if (target_ptr->is_dead || check_multishadow(target_ptr))
230             break;
231
232         if (do_dec_stat(target_ptr, A_STR))
233             monap_ptr->obvious = TRUE;
234
235         break;
236     }
237     case RBE_LOSE_INT: {
238         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
239         if (target_ptr->is_dead || check_multishadow(target_ptr))
240             break;
241
242         if (do_dec_stat(target_ptr, A_INT))
243             monap_ptr->obvious = TRUE;
244
245         break;
246     }
247     case RBE_LOSE_WIS: {
248         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
249         if (target_ptr->is_dead || check_multishadow(target_ptr))
250             break;
251
252         if (do_dec_stat(target_ptr, A_WIS))
253             monap_ptr->obvious = TRUE;
254
255         break;
256     }
257     case RBE_LOSE_DEX: {
258         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
259         if (target_ptr->is_dead || check_multishadow(target_ptr))
260             break;
261
262         if (do_dec_stat(target_ptr, A_DEX))
263             monap_ptr->obvious = TRUE;
264
265         break;
266     }
267     case RBE_LOSE_CON: {
268         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
269         if (target_ptr->is_dead || check_multishadow(target_ptr))
270             break;
271
272         if (do_dec_stat(target_ptr, A_CON))
273             monap_ptr->obvious = TRUE;
274
275         break;
276     }
277     case RBE_LOSE_CHR: {
278         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
279         if (target_ptr->is_dead || check_multishadow(target_ptr))
280             break;
281
282         if (do_dec_stat(target_ptr, A_CHR))
283             monap_ptr->obvious = TRUE;
284
285         break;
286     }
287     case RBE_LOSE_ALL: {
288         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
289         if (target_ptr->is_dead || check_multishadow(target_ptr))
290             break;
291
292         process_lose_all_attack(target_ptr, monap_ptr);
293         break;
294     }
295     case RBE_SHATTER: { /* AC軽減あり / Player armor reduces total damage */
296         monap_ptr->obvious = TRUE;
297         monap_ptr->damage -= (monap_ptr->damage * ((monap_ptr->ac < 150) ? monap_ptr->ac : 150) / 250);
298         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
299         if (monap_ptr->damage > 23 || monap_ptr->explode)
300             earthquake(target_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, 8, monap_ptr->m_idx);
301
302         break;
303     }
304     case RBE_EXP_10: {
305         s32b d = damroll(10, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
306         monap_ptr->obvious = TRUE;
307         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
308         if (target_ptr->is_dead || check_multishadow(target_ptr))
309             break;
310
311         (void)drain_exp(target_ptr, d, d / 10, 95);
312         break;
313     }
314     case RBE_EXP_20: {
315         s32b d = damroll(20, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
316         monap_ptr->obvious = TRUE;
317         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
318         if (target_ptr->is_dead || check_multishadow(target_ptr))
319             break;
320
321         (void)drain_exp(target_ptr, d, d / 10, 90);
322         break;
323     }
324     case RBE_EXP_40: {
325         s32b d = damroll(40, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
326         monap_ptr->obvious = TRUE;
327         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
328         if (target_ptr->is_dead || check_multishadow(target_ptr))
329             break;
330
331         (void)drain_exp(target_ptr, d, d / 10, 75);
332         break;
333     }
334     case RBE_EXP_80: {
335         s32b d = damroll(80, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
336         monap_ptr->obvious = TRUE;
337         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
338         if (target_ptr->is_dead || check_multishadow(target_ptr))
339             break;
340
341         (void)drain_exp(target_ptr, d, d / 10, 50);
342         break;
343     }
344     case RBE_DISEASE: {
345         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
346         if (target_ptr->is_dead || check_multishadow(target_ptr))
347             break;
348
349         if (!(target_ptr->resist_pois || is_oppose_pois(target_ptr))) {
350             if (set_poisoned(target_ptr, target_ptr->poisoned + randint1(monap_ptr->rlev) + 5)) {
351                 monap_ptr->obvious = TRUE;
352             }
353         }
354
355         if ((randint1(100) < 11) && (target_ptr->prace != RACE_ANDROID)) {
356             bool perm = one_in_(10);
357             if (dec_stat(target_ptr, A_CON, randint1(10), perm)) {
358                 msg_print(_("病があなたを蝕んでいる気がする。", "You feel sickly."));
359                 monap_ptr->obvious = TRUE;
360             }
361         }
362
363         break;
364     }
365     case RBE_TIME: {
366         if (monap_ptr->explode)
367             break;
368
369         process_monster_attack_time(target_ptr, monap_ptr);
370         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
371         break;
372     }
373     case RBE_DR_LIFE: {
374         s32b d = damroll(60, 6) + (target_ptr->exp / 100) * MON_DRAIN_LIFE;
375         monap_ptr->obvious = TRUE;
376         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
377         if (target_ptr->is_dead || check_multishadow(target_ptr))
378             break;
379
380         bool resist_drain = check_drain_hp(target_ptr, d);
381         process_drain_life(target_ptr, monap_ptr, resist_drain);
382         break;
383     }
384     case RBE_DR_MANA: {
385         monap_ptr->obvious = TRUE;
386         process_drain_mana(target_ptr, monap_ptr);
387         update_smart_learn(target_ptr, monap_ptr->m_idx, DRS_MANA);
388         break;
389     }
390     case RBE_INERTIA: {
391         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
392         if (target_ptr->is_dead)
393             break;
394
395         if (check_multishadow(target_ptr)) {
396             /* Do nothing */
397         } else {
398             if (set_slow(target_ptr, (target_ptr->slow + 4 + randint0(monap_ptr->rlev / 10)), FALSE)) {
399                 monap_ptr->obvious = TRUE;
400             }
401         }
402
403         break;
404     }
405     case RBE_STUN: {
406         monap_ptr->get_damage += take_hit(target_ptr, DAMAGE_ATTACK, monap_ptr->damage, monap_ptr->ddesc, -1);
407         if (target_ptr->is_dead)
408             break;
409
410         process_stun_attack(target_ptr, monap_ptr);
411         break;
412     }
413     }
414 }