OSDN Git Service

[Refactor] #40014 Separated smart-learn-types.h from monster.h
[hengband/hengband.git] / src / monster-attack / monster-attack-player.c
1 /*!
2  * @brief モンスターからプレーヤーへの直接攻撃処理
3  * @date 2020/05/23
4  * @author Hourier
5  */
6
7 #include "monster-attack/monster-attack-player.h"
8 #include "cmd-action/cmd-attack.h"
9 #include "cmd-action/cmd-pet.h"
10 #include "combat/attack-accuracy.h"
11 #include "combat/attack-criticality.h"
12 #include "combat/combat-options-type.h"
13 #include "combat/hallucination-attacks-table.h"
14 #include "monster-attack/monster-attack-describer.h"
15 #include "monster-attack/monster-attack-effect.h"
16 #include "monster-attack/monster-attack-switcher.h"
17 #include "monster-attack/monster-attack-util.h"
18 #include "combat/aura-counterattack.h"
19 #include "dungeon/dungeon.h"
20 #include "effect/effect-characteristics.h"
21 #include "main/sound-definitions-table.h"
22 #include "mind/mind-ninja.h"
23 #include "mind/mind-samurai.h"
24 #include "monster/monster-status.h"
25 #include "monster/smart-learn-types.h"
26 #include "pet/pet-fall-off.h"
27 #include "object/object-hook.h"
28 #include "player/player-damage.h"
29 #include "player/player-effects.h"
30 #include "player/player-move.h"
31 #include "player/player-skill.h"
32 #include "realm/realm-hex-numbers.h"
33 #include "spell/process-effect.h"
34 #include "spell-realm/spells-hex.h"
35 #include "spell-kind/spells-teleport.h"
36 #include "spell/spells-type.h"
37
38 static bool check_no_blow(player_type *target_ptr, monap_type *monap_ptr)
39 {
40     monster_race *r_ptr = &r_info[monap_ptr->m_ptr->r_idx];
41     if (r_ptr->flags1 & (RF1_NEVER_BLOW))
42         return FALSE;
43
44     if (d_info[target_ptr->dungeon_idx].flags1 & DF1_NO_MELEE)
45         return FALSE;
46
47     if (!is_hostile(monap_ptr->m_ptr))
48         return FALSE;
49
50     return TRUE;
51 }
52
53 /*!
54  * @brief プレーヤー死亡等でモンスターからプレーヤーへの直接攻撃処理を途中で打ち切るかどうかを判定する
55  * @param target_ptr プレーヤーへの参照ポインタ
56  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
57  * @return 攻撃続行ならばTRUE、打ち切りになったらFALSE
58  */
59 static bool check_monster_attack_terminated(player_type *target_ptr, monap_type *monap_ptr)
60 {
61     if (!monster_is_valid(monap_ptr->m_ptr))
62         return FALSE;
63
64     if (monap_ptr->method == RBM_NONE)
65         return FALSE;
66
67     monster_race *r_ptr = &r_info[monap_ptr->m_ptr->r_idx];
68     if (is_pet(monap_ptr->m_ptr) && (r_ptr->flags1 & RF1_UNIQUE) && (monap_ptr->method == RBM_EXPLODE)) {
69         monap_ptr->method = RBM_HIT;
70         monap_ptr->d_dice /= 10;
71     }
72
73     if (!target_ptr->playing || target_ptr->is_dead || (distance(target_ptr->y, target_ptr->x, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx) > 1)
74         || target_ptr->leaving)
75         return FALSE;
76
77     return TRUE;
78 }
79
80 /*!
81  * @brief 対邪悪結界が効いている状態で邪悪なモンスターから直接攻撃を受けた時の処理
82  * @param target_ptr プレーヤーへの参照ポインタ
83  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
84  * @return briefに書いた条件+確率が満たされたらTRUE、それ以外はFALSE
85  */
86 static bool effect_protecion_from_evil(player_type *target_ptr, monap_type *monap_ptr)
87 {
88     monster_race *r_ptr = &r_info[monap_ptr->m_ptr->r_idx];
89     if ((target_ptr->protevil <= 0) || ((r_ptr->flags3 & RF3_EVIL) == 0) || (target_ptr->lev < monap_ptr->rlev) || ((randint0(100) + target_ptr->lev) <= 50))
90         return FALSE;
91
92     if (is_original_ap_and_seen(target_ptr, monap_ptr->m_ptr))
93         r_ptr->r_flags3 |= RF3_EVIL;
94
95 #ifdef JP
96     if (monap_ptr->abbreviate)
97         msg_format("撃退した。");
98     else
99         msg_format("%^sは撃退された。", monap_ptr->m_name);
100
101     monap_ptr->abbreviate = 1; /* 2回目以降は省略 */
102 #else
103     msg_format("%^s is repelled.", monap_ptr->m_name);
104 #endif
105
106     return TRUE;
107 }
108
109 static void describe_silly_attacks(monap_type *monap_ptr)
110 {
111     if (monap_ptr->act == NULL)
112         return;
113
114     if (monap_ptr->do_silly_attack) {
115 #ifdef JP
116         monap_ptr->abbreviate = -1;
117 #endif
118         monap_ptr->act = silly_attacks[randint0(MAX_SILLY_ATTACK)];
119     }
120
121 #ifdef JP
122     if (monap_ptr->abbreviate == 0)
123         msg_format("%^sに%s", monap_ptr->m_name, monap_ptr->act);
124     else if (monap_ptr->abbreviate == 1)
125         msg_format("%s", monap_ptr->act);
126     else /* if (monap_ptr->abbreviate == -1) */
127         msg_format("%^s%s", monap_ptr->m_name, monap_ptr->act);
128
129     monap_ptr->abbreviate = 1; /*2回目以降は省略 */
130 #else
131     msg_format("%^s %s%s", monap_ptr->m_name, monap_ptr->act, monap_ptr->do_silly_attack ? " you." : "");
132 #endif
133 }
134
135 /*!
136  * @brief 切り傷と朦朧が同時に発生した時、片方を無効にする
137  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
138  * @return なし
139  */
140 static void select_cut_stun(monap_type *monap_ptr)
141 {
142     if ((monap_ptr->do_cut == 0) || (monap_ptr->do_stun == 0))
143         return;
144
145     if (randint0(100) < 50)
146         monap_ptr->do_cut = 0;
147     else
148         monap_ptr->do_stun = 0;
149 }
150
151 static void calc_player_cut(player_type *target_ptr, monap_type *monap_ptr)
152 {
153     if (monap_ptr->do_cut == 0)
154         return;
155
156     int cut_plus = 0;
157     int criticality = calc_monster_critical(monap_ptr->d_dice, monap_ptr->d_side, monap_ptr->damage);
158     switch (criticality) {
159     case 0:
160         cut_plus = 0;
161         break;
162     case 1:
163         cut_plus = randint1(5);
164         break;
165     case 2:
166         cut_plus = randint1(5) + 5;
167         break;
168     case 3:
169         cut_plus = randint1(20) + 20;
170         break;
171     case 4:
172         cut_plus = randint1(50) + 50;
173         break;
174     case 5:
175         cut_plus = randint1(100) + 100;
176         break;
177     case 6:
178         cut_plus = 300;
179         break;
180     default:
181         cut_plus = 500;
182         break;
183     }
184
185     if (cut_plus > 0)
186         (void)set_cut(target_ptr, target_ptr->cut + cut_plus);
187 }
188
189 static void calc_player_stun(player_type *target_ptr, monap_type *monap_ptr)
190 {
191     if (monap_ptr->do_stun == 0)
192         return;
193
194     int stun_plus = 0;
195     int criticality = calc_monster_critical(monap_ptr->d_dice, monap_ptr->d_side, monap_ptr->damage);
196     switch (criticality) {
197     case 0:
198         stun_plus = 0;
199         break;
200     case 1:
201         stun_plus = randint1(5);
202         break;
203     case 2:
204         stun_plus = randint1(5) + 10;
205         break;
206     case 3:
207         stun_plus = randint1(10) + 20;
208         break;
209     case 4:
210         stun_plus = randint1(15) + 30;
211         break;
212     case 5:
213         stun_plus = randint1(20) + 40;
214         break;
215     case 6:
216         stun_plus = 80;
217         break;
218     default:
219         stun_plus = 150;
220         break;
221     }
222
223     if (stun_plus > 0)
224         (void)set_stun(target_ptr, target_ptr->stun + stun_plus);
225 }
226
227 static void monster_explode(player_type *target_ptr, monap_type *monap_ptr)
228 {
229     if (!monap_ptr->explode)
230         return;
231
232     sound(SOUND_EXPLODE);
233     if (mon_take_hit(target_ptr, monap_ptr->m_idx, monap_ptr->m_ptr->hp + 1, &monap_ptr->fear, NULL)) {
234         monap_ptr->blinked = FALSE;
235         monap_ptr->alive = FALSE;
236     }
237 }
238
239 static void describe_attack_evasion(player_type *target_ptr, monap_type *monap_ptr)
240 {
241     if (!monap_ptr->m_ptr->ml)
242         return;
243
244     disturb(target_ptr, TRUE, TRUE);
245 #ifdef JP
246     if (monap_ptr->abbreviate)
247         msg_format("%sかわした。", (target_ptr->special_attack & ATTACK_SUIKEN) ? "奇妙な動きで" : "");
248     else
249         msg_format("%s%^sの攻撃をかわした。", (target_ptr->special_attack & ATTACK_SUIKEN) ? "奇妙な動きで" : "", monap_ptr->m_name);
250
251     monap_ptr->abbreviate = 1; /* 2回目以降は省略 */
252 #else
253     msg_format("%^s misses you.", monap_ptr->m_name);
254 #endif
255 }
256
257 static void gain_armor_exp(player_type *target_ptr, monap_type *monap_ptr)
258 {
259     if (!object_is_armour(&target_ptr->inventory_list[INVEN_RARM]) && !object_is_armour(&target_ptr->inventory_list[INVEN_LARM]))
260         return;
261
262     int cur = target_ptr->skill_exp[GINOU_SHIELD];
263     int max = s_info[target_ptr->pclass].s_max[GINOU_SHIELD];
264     if (cur >= max)
265         return;
266
267     monster_race *r_ptr = &r_info[monap_ptr->m_ptr->r_idx];
268     DEPTH targetlevel = r_ptr->level;
269     int inc = 0;
270     if ((cur / 100) < targetlevel) {
271         if ((cur / 100 + 15) < targetlevel)
272             inc += 1 + (targetlevel - (cur / 100 + 15));
273         else
274             inc += 1;
275     }
276
277     target_ptr->skill_exp[GINOU_SHIELD] = MIN(max, cur + inc);
278     target_ptr->update |= (PU_BONUS);
279 }
280
281 /*!
282  * @brief モンスターから直接攻撃を1回受けた時の処理
283  * @return 対邪悪結界により攻撃が当たらなかったらFALSE、それ以外はTRUE
284  * @param target_ptr プレーヤーへの参照ポインタ
285  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
286  * @details 最大4 回/モンスター/ターン、このルーチンを通る
287  */
288 static bool process_monster_attack_hit(player_type *target_ptr, monap_type *monap_ptr)
289 {
290     disturb(target_ptr, TRUE, TRUE);
291     if (effect_protecion_from_evil(target_ptr, monap_ptr))
292         return FALSE;
293
294     monap_ptr->do_cut = 0;
295     monap_ptr->do_stun = 0;
296     describe_monster_attack_method(monap_ptr);
297     describe_silly_attacks(monap_ptr);
298     monap_ptr->obvious = TRUE;
299     monap_ptr->damage = damroll(monap_ptr->d_dice, monap_ptr->d_side);
300     if (monap_ptr->explode)
301         monap_ptr->damage = 0;
302
303     switch_monster_blow_to_player(target_ptr, monap_ptr);
304     select_cut_stun(monap_ptr);
305     calc_player_cut(target_ptr, monap_ptr);
306     calc_player_stun(target_ptr, monap_ptr);
307     monster_explode(target_ptr, monap_ptr);
308     process_aura_counterattack(target_ptr, monap_ptr);
309     return TRUE;
310 }
311
312 /*!
313  * @brief 一部の打撃種別の場合のみ、避けた旨のメッセージ表示と盾技能スキル向上を行う
314  * @param target_ptr プレーヤーへの参照ポインタ
315  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
316  * @return なし
317  */
318 static void process_monster_attack_evasion(player_type *target_ptr, monap_type *monap_ptr)
319 {
320     switch (monap_ptr->method) {
321     case RBM_HIT:
322     case RBM_TOUCH:
323     case RBM_PUNCH:
324     case RBM_KICK:
325     case RBM_CLAW:
326     case RBM_BITE:
327     case RBM_STING:
328     case RBM_SLASH:
329     case RBM_BUTT:
330     case RBM_CRUSH:
331     case RBM_ENGULF:
332     case RBM_CHARGE:
333         describe_attack_evasion(target_ptr, monap_ptr);
334         gain_armor_exp(target_ptr, monap_ptr);
335         monap_ptr->damage = 0;
336         return;
337     default:
338         return;
339     }
340 }
341
342 static void increase_blow_type_seen(player_type *target_ptr, monap_type *monap_ptr)
343 {
344     if (!is_original_ap_and_seen(target_ptr, monap_ptr->m_ptr) || monap_ptr->do_silly_attack)
345         return;
346
347     monster_race *r_ptr = &r_info[monap_ptr->m_ptr->r_idx];
348     if (!monap_ptr->obvious && (monap_ptr->damage == 0) && (r_ptr->r_blows[monap_ptr->ap_cnt] <= 10))
349         return;
350
351     if (r_ptr->r_blows[monap_ptr->ap_cnt] < MAX_UCHAR)
352         r_ptr->r_blows[monap_ptr->ap_cnt]++;
353 }
354
355 static bool process_monster_blows(player_type *target_ptr, monap_type *monap_ptr)
356 {
357     monster_race *r_ptr = &r_info[monap_ptr->m_ptr->r_idx];
358     for (monap_ptr->ap_cnt = 0; monap_ptr->ap_cnt < 4; monap_ptr->ap_cnt++) {
359         monap_ptr->obvious = FALSE;
360         HIT_POINT power = 0;
361         monap_ptr->damage = 0;
362         monap_ptr->act = NULL;
363         monap_ptr->effect = r_ptr->blow[monap_ptr->ap_cnt].effect;
364         monap_ptr->method = r_ptr->blow[monap_ptr->ap_cnt].method;
365         monap_ptr->d_dice = r_ptr->blow[monap_ptr->ap_cnt].d_dice;
366         monap_ptr->d_side = r_ptr->blow[monap_ptr->ap_cnt].d_side;
367
368         if (!check_monster_attack_terminated(target_ptr, monap_ptr))
369             break;
370
371         if (monap_ptr->method == RBM_SHOOT)
372             continue;
373
374         power = mbe_info[monap_ptr->effect].power;
375         monap_ptr->ac = target_ptr->ac + target_ptr->to_a;
376         if ((monap_ptr->effect == RBE_NONE) || check_hit_from_monster_to_player(target_ptr, power, monap_ptr->rlev, MON_STUNNED(monap_ptr->m_ptr)))
377             if (!process_monster_attack_hit(target_ptr, monap_ptr))
378                 continue;
379             else
380                 process_monster_attack_evasion(target_ptr, monap_ptr);
381
382         increase_blow_type_seen(target_ptr, monap_ptr);
383         check_fall_off_horse(target_ptr, monap_ptr);
384         if (target_ptr->special_defense & NINJA_KAWARIMI) {
385             if (kawarimi(target_ptr, FALSE))
386                 return TRUE;
387         }
388     }
389
390     return FALSE;
391 }
392
393 /*!
394  * @brief 呪術「目には目を」の効果処理
395  * @param target_ptr プレーヤーへの参照ポインタ
396  * @param monap_ptr モンスターからプレーヤーへの直接攻撃構造体への参照ポインタ
397  * @return なし
398  */
399 static void eyes_on_eyes(player_type *target_ptr, monap_type *monap_ptr)
400 {
401     if (((target_ptr->tim_eyeeye == 0) && !hex_spelling(target_ptr, HEX_EYE_FOR_EYE)) || (monap_ptr->get_damage == 0) || target_ptr->is_dead)
402         return;
403
404 #ifdef JP
405     msg_format("攻撃が%s自身を傷つけた!", monap_ptr->m_name);
406 #else
407     GAME_TEXT m_name_self[80];
408     monster_desc(target_ptr, m_name_self, monap_ptr->m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE | MD_OBJECTIVE);
409     msg_format("The attack of %s has wounded %s!", monap_ptr->m_name, m_name_self);
410 #endif
411     project(target_ptr, 0, 0, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, monap_ptr->get_damage, GF_MISSILE, PROJECT_KILL, -1);
412     if (target_ptr->tim_eyeeye)
413         set_tim_eyeeye(target_ptr, target_ptr->tim_eyeeye - 5, TRUE);
414 }
415
416 static void thief_teleport(player_type *target_ptr, monap_type *monap_ptr)
417 {
418     if (!monap_ptr->blinked || !monap_ptr->alive || target_ptr->is_dead)
419         return;
420
421     if (teleport_barrier(target_ptr, monap_ptr->m_idx)) {
422         msg_print(_("泥棒は笑って逃げ...ようとしたがバリアに防がれた。", "The thief flees laughing...? But a magic barrier obstructs it."));
423     } else {
424         msg_print(_("泥棒は笑って逃げた!", "The thief flees laughing!"));
425         teleport_away(target_ptr, monap_ptr->m_idx, MAX_SIGHT * 2 + 5, TELEPORT_SPONTANEOUS);
426     }
427 }
428
429 static void postprocess_monster_blows(player_type *target_ptr, monap_type *monap_ptr)
430 {
431     revenge_store(target_ptr, monap_ptr->get_damage);
432     eyes_on_eyes(target_ptr, monap_ptr);
433     musou_counterattack(target_ptr, monap_ptr);
434     thief_teleport(target_ptr, monap_ptr);
435     monster_race *r_ptr = &r_info[monap_ptr->m_ptr->r_idx];
436     if (target_ptr->is_dead && (r_ptr->r_deaths < MAX_SHORT) && !target_ptr->current_floor_ptr->inside_arena)
437         r_ptr->r_deaths++;
438
439     if (monap_ptr->m_ptr->ml && monap_ptr->fear && monap_ptr->alive && !target_ptr->is_dead) {
440         sound(SOUND_FLEE);
441         msg_format(_("%^sは恐怖で逃げ出した!", "%^s flees in terror!"), monap_ptr->m_name);
442     }
443
444     if (target_ptr->special_defense & KATA_IAI)
445         set_action(target_ptr, ACTION_NONE);
446 }
447
448 /*!
449  * @brief モンスターからプレイヤーへの打撃処理 / Attack the player via physical attacks.
450  * @param m_idx 打撃を行うモンスターのID
451  * @return 実際に攻撃処理を行った場合TRUEを返す
452  */
453 bool make_attack_normal(player_type *target_ptr, MONSTER_IDX m_idx)
454 {
455     monap_type tmp_monap;
456     monap_type *monap_ptr = initialize_monap_type(target_ptr, &tmp_monap, m_idx);
457     check_no_blow(target_ptr, monap_ptr);
458
459     monster_race *r_ptr = &r_info[monap_ptr->m_ptr->r_idx];
460     monap_ptr->rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);
461     monster_desc(target_ptr, monap_ptr->m_name, monap_ptr->m_ptr, 0);
462     monster_desc(target_ptr, monap_ptr->ddesc, monap_ptr->m_ptr, MD_WRONGDOER_NAME);
463     if (target_ptr->special_defense & KATA_IAI) {
464         msg_format(_("相手が襲いかかる前に素早く武器を振るった。", "You took sen, drew and cut in one motion before %s moved."), monap_ptr->m_name);
465         if (do_cmd_attack(target_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, HISSATSU_IAI))
466             return TRUE;
467     }
468
469     if ((target_ptr->special_defense & NINJA_KAWARIMI) && (randint0(55) < (target_ptr->lev * 3 / 5 + 20))) {
470         if (kawarimi(target_ptr, TRUE))
471             return TRUE;
472     }
473
474     monap_ptr->blinked = FALSE;
475     if (process_monster_blows(target_ptr, monap_ptr))
476         return TRUE;
477
478     postprocess_monster_blows(target_ptr, monap_ptr);
479     return TRUE;
480 }