OSDN Git Service

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