OSDN Git Service

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