OSDN Git Service

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