OSDN Git Service

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