OSDN Git Service

[Refactor] #40413 Separated asking-player.c/h from util.c/h
[hengband/hengband.git] / src / cmd-action / cmd-attack.c
1 /*!
2  * @brief 攻撃コマンド処理
3  * @date 2020/05/23
4  * @author Hourier
5  */
6
7 #include "cmd-action/cmd-attack.h"
8 #include "art-definition/art-sword-types.h"
9 #include "combat/attack-accuracy.h"
10 #include "combat/attack-criticality.h"
11 #include "core/asking-player.h"
12 #include "dungeon/dungeon.h"
13 #include "effect/effect-characteristics.h"
14 #include "main/sound-definitions-table.h"
15 #include "main/sound-of-music.h"
16 #include "monster-race/race-flags1.h"
17 #include "monster-race/race-flags2.h"
18 #include "monster-race/race-flags3.h"
19 #include "monster/monster-describer.h"
20 #include "monster/monster-info.h"
21 #include "monster/monster-status.h"
22 #include "object/item-use-flags.h"
23 #include "player-attack/player-attack.h"
24 #include "player/avatar.h"
25 #include "player/player-damage.h"
26 #include "player/player-effects.h"
27 #include "player/player-move.h"
28 #include "player/player-skill.h"
29 #include "spell/process-effect.h"
30 #include "spell/spell-types.h"
31 #include "view/display-main-window.h"
32 #include "view/display-messages.h"
33
34 /*!
35  * @brief プレイヤーの変異要素による打撃処理
36  * @param attacker_ptr プレーヤーへの参照ポインタ
37  * @param m_idx 攻撃目標となったモンスターの参照ID
38  * @param attack 変異要素による攻撃要素の種類
39  * @param fear 攻撃を受けたモンスターが恐慌状態に陥ったかを返す参照ポインタ
40  * @param mdeath 攻撃を受けたモンスターが死亡したかを返す参照ポインタ
41  * @return なし
42  */
43 static void natural_attack(player_type *attacker_ptr, MONSTER_IDX m_idx, int attack, bool *fear, bool *mdeath)
44 {
45     WEIGHT n_weight = 0;
46     monster_type *m_ptr = &attacker_ptr->current_floor_ptr->m_list[m_idx];
47     monster_race *r_ptr = &r_info[m_ptr->r_idx];
48
49     int dice_num, dice_side;
50     concptr atk_desc;
51     switch (attack) {
52     case MUT2_SCOR_TAIL:
53         dice_num = 3;
54         dice_side = 7;
55         n_weight = 5;
56         atk_desc = _("尻尾", "tail");
57         break;
58     case MUT2_HORNS:
59         dice_num = 2;
60         dice_side = 6;
61         n_weight = 15;
62         atk_desc = _("角", "horns");
63         break;
64     case MUT2_BEAK:
65         dice_num = 2;
66         dice_side = 4;
67         n_weight = 5;
68         atk_desc = _("クチバシ", "beak");
69         break;
70     case MUT2_TRUNK:
71         dice_num = 1;
72         dice_side = 4;
73         n_weight = 35;
74         atk_desc = _("象の鼻", "trunk");
75         break;
76     case MUT2_TENTACLES:
77         dice_num = 2;
78         dice_side = 5;
79         n_weight = 5;
80         atk_desc = _("触手", "tentacles");
81         break;
82     default:
83         dice_num = dice_side = n_weight = 1;
84         atk_desc = _("未定義の部位", "undefined body part");
85     }
86
87     GAME_TEXT m_name[MAX_NLEN];
88     monster_desc(attacker_ptr, m_name, m_ptr, 0);
89
90     int bonus = attacker_ptr->to_h_m + (attacker_ptr->lev * 6 / 5);
91     int chance = (attacker_ptr->skill_thn + (bonus * BTH_PLUS_ADJ));
92
93     bool is_hit = ((r_ptr->flags2 & RF2_QUANTUM) == 0) || !randint0(2);
94     is_hit &= test_hit_norm(attacker_ptr, chance, r_ptr->ac, m_ptr->ml);
95     if (!is_hit) {
96         sound(SOUND_MISS);
97         msg_format(_("ミス! %sにかわされた。", "You miss %s."), m_name);
98         return;
99     }
100
101     sound(SOUND_HIT);
102     msg_format(_("%sを%sで攻撃した。", "You hit %s with your %s."), m_name, atk_desc);
103
104     HIT_POINT k = damroll(dice_num, dice_side);
105     k = critical_norm(attacker_ptr, n_weight, bonus, k, (s16b)bonus, 0);
106     k += attacker_ptr->to_d_m;
107     if (k < 0)
108         k = 0;
109
110     k = mon_damage_mod(attacker_ptr, m_ptr, k, FALSE);
111     msg_format_wizard(CHEAT_MONSTER, _("%dのダメージを与えた。(残りHP %d/%d(%d))", "You do %d damage. (left HP %d/%d(%d))"), k, m_ptr->hp - k, m_ptr->maxhp,
112         m_ptr->max_maxhp);
113     if (k > 0)
114         anger_monster(attacker_ptr, m_ptr);
115
116     switch (attack) {
117     case MUT2_SCOR_TAIL:
118         project(attacker_ptr, 0, 0, m_ptr->fy, m_ptr->fx, k, GF_POIS, PROJECT_KILL, -1);
119         *mdeath = (m_ptr->r_idx == 0);
120         break;
121     case MUT2_HORNS:
122         *mdeath = mon_take_hit(attacker_ptr, m_idx, k, fear, NULL);
123         break;
124     case MUT2_BEAK:
125         *mdeath = mon_take_hit(attacker_ptr, m_idx, k, fear, NULL);
126         break;
127     case MUT2_TRUNK:
128         *mdeath = mon_take_hit(attacker_ptr, m_idx, k, fear, NULL);
129         break;
130     case MUT2_TENTACLES:
131         *mdeath = mon_take_hit(attacker_ptr, m_idx, k, fear, NULL);
132         break;
133     default:
134         *mdeath = mon_take_hit(attacker_ptr, m_idx, k, fear, NULL);
135     }
136
137     touch_zap_player(m_ptr, attacker_ptr);
138 }
139
140 /*!
141  * @brief プレイヤーの打撃処理メインルーチン
142  * @param y 攻撃目標のY座標
143  * @param x 攻撃目標のX座標
144  * @param mode 発動中の剣術ID
145  * @return 実際に攻撃処理が行われた場合TRUEを返す。
146  * @details
147  * If no "weapon" is available, then "punch" the monster one time.
148  */
149 bool do_cmd_attack(player_type *attacker_ptr, POSITION y, POSITION x, combat_options mode)
150 {
151     grid_type *g_ptr = &attacker_ptr->current_floor_ptr->grid_array[y][x];
152     monster_type *m_ptr = &attacker_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
153     monster_race *r_ptr = &r_info[m_ptr->r_idx];
154     GAME_TEXT m_name[MAX_NLEN];
155
156     disturb(attacker_ptr, FALSE, TRUE);
157
158     take_turn(attacker_ptr, 100);
159
160     if (!attacker_ptr->migite && !attacker_ptr->hidarite && !(attacker_ptr->muta2 & (MUT2_HORNS | MUT2_BEAK | MUT2_SCOR_TAIL | MUT2_TRUNK | MUT2_TENTACLES))) {
161         msg_format(_("%s攻撃できない。", "You cannot do attacking."), (empty_hands(attacker_ptr, FALSE) == EMPTY_HAND_NONE) ? _("両手がふさがって", "") : "");
162         return FALSE;
163     }
164
165     monster_desc(attacker_ptr, m_name, m_ptr, 0);
166
167     if (m_ptr->ml) {
168         if (!attacker_ptr->image)
169             monster_race_track(attacker_ptr, m_ptr->ap_r_idx);
170
171         health_track(attacker_ptr, g_ptr->m_idx);
172     }
173
174     if ((r_ptr->flags1 & RF1_FEMALE) && !(attacker_ptr->stun || attacker_ptr->confused || attacker_ptr->image || !m_ptr->ml)) {
175         if ((attacker_ptr->inventory_list[INVEN_RARM].name1 == ART_ZANTETSU) || (attacker_ptr->inventory_list[INVEN_LARM].name1 == ART_ZANTETSU)) {
176             msg_print(_("拙者、おなごは斬れぬ!", "I can not attack women!"));
177             return FALSE;
178         }
179     }
180
181     if (d_info[attacker_ptr->dungeon_idx].flags1 & DF1_NO_MELEE) {
182         msg_print(_("なぜか攻撃することができない。", "Something prevents you from attacking."));
183         return FALSE;
184     }
185
186     bool stormbringer = FALSE;
187     if (!is_hostile(m_ptr) && !(attacker_ptr->stun || attacker_ptr->confused || attacker_ptr->image || attacker_ptr->shero || !m_ptr->ml)) {
188         if (attacker_ptr->inventory_list[INVEN_RARM].name1 == ART_STORMBRINGER)
189             stormbringer = TRUE;
190         if (attacker_ptr->inventory_list[INVEN_LARM].name1 == ART_STORMBRINGER)
191             stormbringer = TRUE;
192         if (stormbringer) {
193             msg_format(_("黒い刃は強欲に%sを攻撃した!", "Your black blade greedily attacks %s!"), m_name);
194             chg_virtue(attacker_ptr, V_INDIVIDUALISM, 1);
195             chg_virtue(attacker_ptr, V_HONOUR, -1);
196             chg_virtue(attacker_ptr, V_JUSTICE, -1);
197             chg_virtue(attacker_ptr, V_COMPASSION, -1);
198         } else if (attacker_ptr->pclass != CLASS_BERSERKER) {
199             if (get_check(_("本当に攻撃しますか?", "Really hit it? "))) {
200                 chg_virtue(attacker_ptr, V_INDIVIDUALISM, 1);
201                 chg_virtue(attacker_ptr, V_HONOUR, -1);
202                 chg_virtue(attacker_ptr, V_JUSTICE, -1);
203                 chg_virtue(attacker_ptr, V_COMPASSION, -1);
204             } else {
205                 msg_format(_("%sを攻撃するのを止めた。", "You stop to avoid hitting %s."), m_name);
206                 return FALSE;
207             }
208         }
209     }
210
211     if (attacker_ptr->afraid) {
212         if (m_ptr->ml)
213             msg_format(_("恐くて%sを攻撃できない!", "You are too afraid to attack %s!"), m_name);
214         else
215             msg_format(_("そっちには何か恐いものがいる!", "There is something scary in your way!"));
216
217         (void)set_monster_csleep(attacker_ptr, g_ptr->m_idx, 0);
218         return FALSE;
219     }
220
221     if (monster_csleep_remaining(m_ptr)) {
222         if (!(r_ptr->flags3 & RF3_EVIL) || one_in_(5))
223             chg_virtue(attacker_ptr, V_COMPASSION, -1);
224         if (!(r_ptr->flags3 & RF3_EVIL) || one_in_(5))
225             chg_virtue(attacker_ptr, V_HONOUR, -1);
226     }
227
228     if (attacker_ptr->migite && attacker_ptr->hidarite) {
229         if ((attacker_ptr->skill_exp[GINOU_NITOURYU] < s_info[attacker_ptr->pclass].s_max[GINOU_NITOURYU])
230             && ((attacker_ptr->skill_exp[GINOU_NITOURYU] - 1000) / 200 < r_ptr->level)) {
231             if (attacker_ptr->skill_exp[GINOU_NITOURYU] < WEAPON_EXP_BEGINNER)
232                 attacker_ptr->skill_exp[GINOU_NITOURYU] += 80;
233             else if (attacker_ptr->skill_exp[GINOU_NITOURYU] < WEAPON_EXP_SKILLED)
234                 attacker_ptr->skill_exp[GINOU_NITOURYU] += 4;
235             else if (attacker_ptr->skill_exp[GINOU_NITOURYU] < WEAPON_EXP_EXPERT)
236                 attacker_ptr->skill_exp[GINOU_NITOURYU] += 1;
237             else if (attacker_ptr->skill_exp[GINOU_NITOURYU] < WEAPON_EXP_MASTER)
238                 if (one_in_(3))
239                     attacker_ptr->skill_exp[GINOU_NITOURYU] += 1;
240             attacker_ptr->update |= (PU_BONUS);
241         }
242     }
243
244     if (attacker_ptr->riding) {
245         int cur = attacker_ptr->skill_exp[GINOU_RIDING];
246         int max = s_info[attacker_ptr->pclass].s_max[GINOU_RIDING];
247
248         if (cur < max) {
249             DEPTH ridinglevel = r_info[attacker_ptr->current_floor_ptr->m_list[attacker_ptr->riding].r_idx].level;
250             DEPTH targetlevel = r_ptr->level;
251             int inc = 0;
252
253             if ((cur / 200 - 5) < targetlevel)
254                 inc += 1;
255
256             if ((cur / 100) < ridinglevel) {
257                 if ((cur / 100 + 15) < ridinglevel)
258                     inc += 1 + (ridinglevel - (cur / 100 + 15));
259                 else
260                     inc += 1;
261             }
262
263             attacker_ptr->skill_exp[GINOU_RIDING] = MIN(max, cur + inc);
264             attacker_ptr->update |= (PU_BONUS);
265         }
266     }
267
268     attacker_ptr->riding_t_m_idx = g_ptr->m_idx;
269     bool fear = FALSE;
270     bool mdeath = FALSE;
271     if (attacker_ptr->migite)
272         exe_player_attack_to_monster(attacker_ptr, y, x, &fear, &mdeath, 0, mode);
273     if (attacker_ptr->hidarite && !mdeath)
274         exe_player_attack_to_monster(attacker_ptr, y, x, &fear, &mdeath, 1, mode);
275
276     if (!mdeath) {
277         if ((attacker_ptr->muta2 & MUT2_HORNS) && !mdeath)
278             natural_attack(attacker_ptr, g_ptr->m_idx, MUT2_HORNS, &fear, &mdeath);
279         if ((attacker_ptr->muta2 & MUT2_BEAK) && !mdeath)
280             natural_attack(attacker_ptr, g_ptr->m_idx, MUT2_BEAK, &fear, &mdeath);
281         if ((attacker_ptr->muta2 & MUT2_SCOR_TAIL) && !mdeath)
282             natural_attack(attacker_ptr, g_ptr->m_idx, MUT2_SCOR_TAIL, &fear, &mdeath);
283         if ((attacker_ptr->muta2 & MUT2_TRUNK) && !mdeath)
284             natural_attack(attacker_ptr, g_ptr->m_idx, MUT2_TRUNK, &fear, &mdeath);
285         if ((attacker_ptr->muta2 & MUT2_TENTACLES) && !mdeath)
286             natural_attack(attacker_ptr, g_ptr->m_idx, MUT2_TENTACLES, &fear, &mdeath);
287     }
288
289     if (fear && m_ptr->ml && !mdeath) {
290         sound(SOUND_FLEE);
291         msg_format(_("%^sは恐怖して逃げ出した!", "%^s flees in terror!"), m_name);
292     }
293
294     if ((attacker_ptr->special_defense & KATA_IAI) && ((mode != HISSATSU_IAI) || mdeath)) {
295         set_action(attacker_ptr, ACTION_NONE);
296     }
297
298     return mdeath;
299 }