OSDN Git Service

[Refactor] #1389 Changed monap_type from struct to class MonsterAttackPlayer
[hengbandforosx/hengbandosx.git] / src / mind / mind-samurai.cpp
1 /*!
2  * @brief 剣術家のレイシャルパワー処理
3  * @date 2020/05/16
4  * @author Hourier
5  */
6
7 #include "mind/mind-samurai.h"
8 #include "action/action-limited.h"
9 #include "avatar/avatar.h"
10 #include "cmd-action/cmd-attack.h"
11 #include "core/player-redraw-types.h"
12 #include "core/player-update-types.h"
13 #include "inventory/inventory-slot-types.h"
14 #include "io/input-key-acceptor.h"
15 #include "mind/stances-table.h"
16 #include "monster-attack/monster-attack-util.h"
17 #include "monster-race/monster-race-hook.h"
18 #include "monster-race/monster-race.h"
19 #include "monster-race/race-flags-resistance.h"
20 #include "monster-race/race-flags3.h"
21 #include "monster/monster-describer.h"
22 #include "monster/monster-info.h"
23 #include "monster/monster-status-setter.h"
24 #include "monster/monster-status.h"
25 #include "object-enchant/tr-types.h"
26 #include "pet/pet-util.h"
27 #include "player-attack/player-attack-util.h"
28 #include "player-base/player-class.h"
29 #include "player-info/samurai-data-type.h"
30 #include "player/attack-defense-types.h"
31 #include "status/action-setter.h"
32 #include "system/grid-type-definition.h"
33 #include "system/monster-race-definition.h"
34 #include "system/monster-type-definition.h"
35 #include "system/object-type-definition.h"
36 #include "system/player-type-definition.h"
37 #include "term/screen-processor.h"
38 #include "timed-effect/player-cut.h"
39 #include "timed-effect/player-stun.h"
40 #include "timed-effect/timed-effects.h"
41 #include "util/bit-flags-calculator.h"
42 #include "util/int-char-converter.h"
43 #include "view/display-messages.h"
44
45 typedef struct samurai_slaying_type {
46     MULTIPLY mult;
47     TrFlags flags;
48     monster_type *m_ptr;
49     combat_options mode;
50     monster_race *r_ptr;
51 } samurai_slaying_type;
52
53 static samurai_slaying_type *initialize_samurai_slaying_type(
54     samurai_slaying_type *samurai_slaying_ptr, MULTIPLY mult, const TrFlags &flags, monster_type *m_ptr, combat_options mode, monster_race *r_ptr)
55 {
56     samurai_slaying_ptr->mult = mult;
57     samurai_slaying_ptr->flags = flags;
58     samurai_slaying_ptr->m_ptr = m_ptr;
59     samurai_slaying_ptr->mode = mode;
60     samurai_slaying_ptr->r_ptr = r_ptr;
61     return samurai_slaying_ptr;
62 }
63
64 /*!
65  * @nrief 焔霊 (焼棄スレイ)
66  * @param player_ptr プレイヤーへの参照ポインタ
67  * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
68  */
69 static void hissatsu_burning_strike(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
70 {
71     if (samurai_slaying_ptr->mode != HISSATSU_FIRE)
72         return;
73
74     /* Notice immunity */
75     if (samurai_slaying_ptr->r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK) {
76         if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
77             samurai_slaying_ptr->r_ptr->r_flagsr |= (samurai_slaying_ptr->r_ptr->flagsr & RFR_EFF_IM_FIRE_MASK);
78
79         return;
80     }
81
82     /* Otherwise, take the damage */
83     if (samurai_slaying_ptr->flags.has(TR_BRAND_FIRE)) {
84         if (samurai_slaying_ptr->r_ptr->flags3 & RF3_HURT_FIRE) {
85             if (samurai_slaying_ptr->mult < 70)
86                 samurai_slaying_ptr->mult = 70;
87
88             if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
89                 samurai_slaying_ptr->r_ptr->r_flags3 |= RF3_HURT_FIRE;
90
91         } else if (samurai_slaying_ptr->mult < 35)
92             samurai_slaying_ptr->mult = 35;
93
94         return;
95     }
96
97     if (samurai_slaying_ptr->r_ptr->flags3 & RF3_HURT_FIRE) {
98         if (samurai_slaying_ptr->mult < 50)
99             samurai_slaying_ptr->mult = 50;
100
101         if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
102             samurai_slaying_ptr->r_ptr->r_flags3 |= RF3_HURT_FIRE;
103     } else if (samurai_slaying_ptr->mult < 25)
104         samurai_slaying_ptr->mult = 25;
105 }
106
107 /*!
108  * @brief サーペンツタン (毒殺スレイ)
109  * @param player_ptr プレイヤーへの参照ポインタ
110  * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
111  */
112 static void hissatsu_serpent_tongue(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
113 {
114     if (samurai_slaying_ptr->mode != HISSATSU_POISON)
115         return;
116
117     /* Notice immunity */
118     if (samurai_slaying_ptr->r_ptr->flagsr & RFR_EFF_IM_POIS_MASK) {
119         if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
120             samurai_slaying_ptr->r_ptr->r_flagsr |= (samurai_slaying_ptr->r_ptr->flagsr & RFR_EFF_IM_POIS_MASK);
121
122         return;
123     }
124
125     /* Otherwise, take the damage */
126     if (samurai_slaying_ptr->flags.has(TR_BRAND_POIS)) {
127         if (samurai_slaying_ptr->mult < 35)
128             samurai_slaying_ptr->mult = 35;
129     } else if (samurai_slaying_ptr->mult < 25)
130         samurai_slaying_ptr->mult = 25;
131 }
132
133 /*!
134  * @brief 二重の極み^h^h^h^h^h 斬魔剣弐の太刀 (邪悪無生命スレイ)
135  * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
136  */
137 static void hissatsu_zanma_ken(samurai_slaying_type *samurai_slaying_ptr)
138 {
139     if (samurai_slaying_ptr->mode != HISSATSU_ZANMA)
140         return;
141
142     if (!monster_living(samurai_slaying_ptr->m_ptr->r_idx) && (samurai_slaying_ptr->r_ptr->flags3 & RF3_EVIL)) {
143         if (samurai_slaying_ptr->mult < 15)
144             samurai_slaying_ptr->mult = 25;
145         else if (samurai_slaying_ptr->mult < 50)
146             samurai_slaying_ptr->mult = std::min<short>(50, samurai_slaying_ptr->mult + 20);
147     }
148 }
149
150 /*!
151  * @brief 破岩斬 (岩石スレイ)
152  * @param player_ptr プレイヤーへの参照ポインタ
153  * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
154  */
155 static void hissatsu_rock_smash(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
156 {
157     if (samurai_slaying_ptr->mode != HISSATSU_HAGAN)
158         return;
159
160     if (samurai_slaying_ptr->r_ptr->flags3 & RF3_HURT_ROCK) {
161         if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
162             samurai_slaying_ptr->r_ptr->r_flags3 |= RF3_HURT_ROCK;
163
164         if (samurai_slaying_ptr->mult == 10)
165             samurai_slaying_ptr->mult = 40;
166         else if (samurai_slaying_ptr->mult < 60)
167             samurai_slaying_ptr->mult = 60;
168     }
169 }
170
171 /*!
172  * @brief 乱れ雪月花 (冷気スレイ)
173  * @param player_ptr プレイヤーへの参照ポインタ
174  * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
175  */
176 static void hissatsu_midare_setsugetsuka(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
177 {
178     if (samurai_slaying_ptr->mode != HISSATSU_COLD)
179         return;
180
181     /* Notice immunity */
182     if (samurai_slaying_ptr->r_ptr->flagsr & RFR_EFF_IM_COLD_MASK) {
183         if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
184             samurai_slaying_ptr->r_ptr->r_flagsr |= (samurai_slaying_ptr->r_ptr->flagsr & RFR_EFF_IM_COLD_MASK);
185
186         return;
187     }
188
189     /* Otherwise, take the damage */
190     if (samurai_slaying_ptr->flags.has(TR_BRAND_COLD)) {
191         if (samurai_slaying_ptr->r_ptr->flags3 & RF3_HURT_COLD) {
192             if (samurai_slaying_ptr->mult < 70)
193                 samurai_slaying_ptr->mult = 70;
194
195             if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
196                 samurai_slaying_ptr->r_ptr->r_flags3 |= RF3_HURT_COLD;
197         } else if (samurai_slaying_ptr->mult < 35)
198             samurai_slaying_ptr->mult = 35;
199
200         return;
201     }
202
203     if (samurai_slaying_ptr->r_ptr->flags3 & RF3_HURT_COLD) {
204         if (samurai_slaying_ptr->mult < 50)
205             samurai_slaying_ptr->mult = 50;
206
207         if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
208             samurai_slaying_ptr->r_ptr->r_flags3 |= RF3_HURT_COLD;
209     } else if (samurai_slaying_ptr->mult < 25)
210         samurai_slaying_ptr->mult = 25;
211 }
212
213 /*!
214  * @brief 雷撃鷲爪斬
215  * @param player_ptr プレイヤーへの参照ポインタ
216  * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
217  */
218 static void hissatsu_lightning_eagle(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
219 {
220     if (samurai_slaying_ptr->mode != HISSATSU_ELEC)
221         return;
222
223     /* Notice immunity */
224     if (samurai_slaying_ptr->r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK) {
225         if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr))
226             samurai_slaying_ptr->r_ptr->r_flagsr |= (samurai_slaying_ptr->r_ptr->flagsr & RFR_EFF_IM_ELEC_MASK);
227
228         return;
229     }
230
231     /* Otherwise, take the damage */
232     if (samurai_slaying_ptr->flags.has(TR_BRAND_ELEC)) {
233         if (samurai_slaying_ptr->mult < 70)
234             samurai_slaying_ptr->mult = 70;
235     } else if (samurai_slaying_ptr->mult < 50)
236         samurai_slaying_ptr->mult = 50;
237 }
238
239 /*!
240  * @brief 赤流渦 (ペインバッカー)
241  * @param player_ptr プレイヤーへの参照ポインタ
242  * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
243  */
244 static void hissatsu_bloody_maelstroem(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
245 {
246     auto player_cut = player_ptr->effects()->cut();
247     if ((samurai_slaying_ptr->mode == HISSATSU_SEKIRYUKA) && player_cut->is_cut() && monster_living(samurai_slaying_ptr->m_ptr->r_idx)) {
248         auto tmp = std::min<short>(100, std::max<short>(10, player_cut->current() / 10));
249         if (samurai_slaying_ptr->mult < tmp)
250             samurai_slaying_ptr->mult = tmp;
251     }
252 }
253
254 /*!
255  * @brief 慶雲鬼忍剣 (アンデッドスレイ)
256  * @param player_ptr プレイヤーへの参照ポインタ
257  * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
258  */
259 static void hissatsu_keiun_kininken(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
260 {
261     if (samurai_slaying_ptr->mode != HISSATSU_UNDEAD)
262         return;
263
264     if (samurai_slaying_ptr->r_ptr->flags3 & RF3_UNDEAD)
265         if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
266             samurai_slaying_ptr->r_ptr->r_flags3 |= RF3_UNDEAD;
267
268             if (samurai_slaying_ptr->mult == 10)
269                 samurai_slaying_ptr->mult = 70;
270             else if (samurai_slaying_ptr->mult < 140)
271                 samurai_slaying_ptr->mult = std::min<short>(140, samurai_slaying_ptr->mult + 60);
272         }
273
274     if (samurai_slaying_ptr->mult == 10)
275         samurai_slaying_ptr->mult = 40;
276     else if (samurai_slaying_ptr->mult < 60)
277         samurai_slaying_ptr->mult = std::min<short>(60, samurai_slaying_ptr->mult + 30);
278 }
279
280 /*!
281  * @brief 剣術のスレイ倍率計算を行う /
282  * Calcurate magnification of hissatsu technics
283  * @param mult 剣術のスレイ効果以前に算出している多要素の倍率(/10倍)
284  * @param flags 剣術に使用する武器のスレイフラグ配列
285  * @param m_ptr 目標となるモンスターの構造体参照ポインタ
286  * @param mode 剣術のスレイ型ID
287  * @return スレイの倍率(/10倍)
288  */
289 MULTIPLY mult_hissatsu(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags, monster_type *m_ptr, combat_options mode)
290 {
291     monster_race *r_ptr = &r_info[m_ptr->r_idx];
292     samurai_slaying_type tmp_slaying;
293     samurai_slaying_type *samurai_slaying_ptr = initialize_samurai_slaying_type(&tmp_slaying, mult, flags, m_ptr, mode, r_ptr);
294     hissatsu_burning_strike(player_ptr, samurai_slaying_ptr);
295     hissatsu_serpent_tongue(player_ptr, samurai_slaying_ptr);
296     hissatsu_zanma_ken(samurai_slaying_ptr);
297     hissatsu_rock_smash(player_ptr, samurai_slaying_ptr);
298     hissatsu_midare_setsugetsuka(player_ptr, samurai_slaying_ptr);
299     hissatsu_lightning_eagle(player_ptr, samurai_slaying_ptr);
300     hissatsu_bloody_maelstroem(player_ptr, samurai_slaying_ptr);
301     hissatsu_keiun_kininken(player_ptr, samurai_slaying_ptr);
302
303     if (samurai_slaying_ptr->mult > 150)
304         samurai_slaying_ptr->mult = 150;
305
306     return samurai_slaying_ptr->mult;
307 }
308
309 void concentration(PlayerType *player_ptr)
310 {
311     int max_csp = std::max(player_ptr->msp * 4, player_ptr->lev * 5 + 5);
312
313     if (total_friends) {
314         msg_print(_("今はペットを操ることに集中していないと。", "Your pets demand all of your attention."));
315         return;
316     }
317
318     if (!PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::NONE)) {
319         msg_print(_("今は構えに集中している。", "You're already concentrating on your stance."));
320         return;
321     }
322
323     msg_print(_("精神を集中して気合いを溜めた。", "You concentrate to charge your power."));
324
325     player_ptr->csp += player_ptr->msp / 2;
326     if (player_ptr->csp >= max_csp) {
327         player_ptr->csp = max_csp;
328         player_ptr->csp_frac = 0;
329     }
330
331     player_ptr->redraw |= PR_MANA;
332 }
333
334 /*!
335  * @brief 剣術家の型設定処理
336  * @return 型を変化させたらTRUE、型の構え不能かキャンセルしたらFALSEを返す。
337  */
338 bool choose_samurai_stance(PlayerType *player_ptr)
339 {
340     char choice;
341     char buf[80];
342
343     if (cmd_limit_confused(player_ptr))
344         return false;
345
346     auto effects = player_ptr->effects();
347     if (effects->stun()->is_stunned()) {
348         msg_print(_("意識がはっきりとしない。", "You are not clear-headed"));
349         return false;
350     }
351
352     if (player_ptr->afraid) {
353         msg_print(_("体が震えて構えられない!", "You are trembling with fear!"));
354         return false;
355     }
356
357     screen_save();
358     prt(_(" a) 型を崩す", " a) No Form"), 2, 20);
359     for (auto i = 0U; i < samurai_stances.size(); i++) {
360         if (player_ptr->lev >= samurai_stances[i].min_level) {
361             sprintf(buf, _(" %c) %sの型    %s", " %c) Stance of %-12s  %s"), I2A(i + 1), samurai_stances[i].desc, samurai_stances[i].info);
362             prt(buf, 3 + i, 20);
363         }
364     }
365
366     prt("", 1, 0);
367     prt(_("        どの型で構えますか?", "        Choose Stance: "), 1, 14);
368
369     SamuraiStanceType new_stance = SamuraiStanceType::NONE;
370     while (true) {
371         choice = inkey();
372
373         if (choice == ESCAPE) {
374             screen_load();
375             return false;
376         } else if ((choice == 'a') || (choice == 'A')) {
377             if (player_ptr->action == ACTION_SAMURAI_STANCE) {
378                 set_action(player_ptr, ACTION_NONE);
379             } else
380                 msg_print(_("もともと構えていない。", "You are not in a special stance."));
381             screen_load();
382             return true;
383         } else if ((choice == 'b') || (choice == 'B')) {
384             new_stance = SamuraiStanceType::IAI;
385             break;
386         } else if (((choice == 'c') || (choice == 'C')) && (player_ptr->lev > 29)) {
387             new_stance = SamuraiStanceType::FUUJIN;
388             break;
389         } else if (((choice == 'd') || (choice == 'D')) && (player_ptr->lev > 34)) {
390             new_stance = SamuraiStanceType::KOUKIJIN;
391             break;
392         } else if (((choice == 'e') || (choice == 'E')) && (player_ptr->lev > 39)) {
393             new_stance = SamuraiStanceType::MUSOU;
394             break;
395         }
396     }
397
398     set_action(player_ptr, ACTION_SAMURAI_STANCE);
399     if (PlayerClass(player_ptr).samurai_stance_is(new_stance)) {
400         msg_print(_("構え直した。", "You reassume a stance."));
401     } else {
402         player_ptr->update |= (PU_BONUS | PU_MONSTERS);
403         msg_format(_("%sの型で構えた。", "You assume the %s stance."), samurai_stances[enum2i(new_stance) - 1].desc);
404         PlayerClass(player_ptr).set_samurai_stance(new_stance);
405     }
406
407     player_ptr->redraw |= (PR_STATE | PR_STATUS);
408     screen_load();
409     return true;
410 }
411
412 /*!
413  * @brief 剣術家限定で、型等に応じて命中率を高める
414  * @param player_ptr プレイヤーへの参照ポインタ
415  * @param pa_ptr 直接攻撃構造体への参照ポインタ
416  * @return 上昇後の命中率
417  */
418 int calc_attack_quality(PlayerType *player_ptr, player_attack_type *pa_ptr)
419 {
420     object_type *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + pa_ptr->hand];
421     int bonus = player_ptr->to_h[pa_ptr->hand] + o_ptr->to_h;
422     int chance = (player_ptr->skill_thn + (bonus * BTH_PLUS_ADJ));
423     if (pa_ptr->mode == HISSATSU_IAI)
424         chance += 60;
425
426     if (PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::KOUKIJIN)) {
427         chance += 150;
428     }
429
430     if (player_ptr->sutemi)
431         chance = std::max(chance * 3 / 2, chance + 60);
432
433     int vir = virtue_number(player_ptr, V_VALOUR);
434     if (vir != 0)
435         chance += (player_ptr->virtues[vir - 1] / 10);
436
437     return chance;
438 }
439
440 /*!
441  * @brief 峰打ちの効果処理
442  * @param player_ptr プレイヤーへの参照ポインタ
443  * @param pa_ptr 直接攻撃構造体への参照ポインタ
444  */
445 void mineuchi(PlayerType *player_ptr, player_attack_type *pa_ptr)
446 {
447     if (pa_ptr->mode != HISSATSU_MINEUCHI)
448         return;
449
450     pa_ptr->attack_damage = 0;
451     anger_monster(player_ptr, pa_ptr->m_ptr);
452
453     monster_race *r_ptr = &r_info[pa_ptr->m_ptr->r_idx];
454     if ((r_ptr->flags3 & (RF3_NO_STUN))) {
455         msg_format(_("%s には効果がなかった。", "%s is not effected."), pa_ptr->m_name);
456         return;
457     }
458
459     int tmp = (10 + randint1(15) + player_ptr->lev / 5);
460     if (monster_stunned_remaining(pa_ptr->m_ptr)) {
461         msg_format(_("%sはひどくもうろうとした。", "%s is more dazed."), pa_ptr->m_name);
462         tmp /= 2;
463     } else
464         msg_format(_("%s はもうろうとした。", "%s is dazed."), pa_ptr->m_name);
465
466     (void)set_monster_stunned(player_ptr, pa_ptr->g_ptr->m_idx, monster_stunned_remaining(pa_ptr->m_ptr) + tmp);
467 }
468
469 /*!
470  * @brief 無想による反撃処理
471  * @param player_ptr プレイヤーへの参照ポインタ
472  * @param pa_ptr 直接攻撃構造体への参照ポインタ
473  */
474 void musou_counterattack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
475 {
476     if ((!player_ptr->counter && !PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::MUSOU)) || !monap_ptr->alive || player_ptr->is_dead || !monap_ptr->m_ptr->ml
477         || (player_ptr->csp <= 7))
478         return;
479
480     char m_target_name[MAX_NLEN];
481     monster_desc(player_ptr, m_target_name, monap_ptr->m_ptr, 0);
482     player_ptr->csp -= 7;
483     msg_format(_("%^sに反撃した!", "You counterattacked %s!"), m_target_name);
484     do_cmd_attack(player_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, HISSATSU_COUNTER);
485     monap_ptr->fear = false;
486     player_ptr->redraw |= (PR_MANA);
487 }