OSDN Git Service

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