OSDN Git Service

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