2 * @brief 剣術家のレイシャルパワー処理
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/item-entity.h"
35 #include "system/monster-entity.h"
36 #include "system/monster-race-info.h"
37 #include "system/player-type-definition.h"
38 #include "term/screen-processor.h"
39 #include "term/z-form.h"
40 #include "timed-effect/player-cut.h"
41 #include "timed-effect/player-fear.h"
42 #include "timed-effect/player-stun.h"
43 #include "timed-effect/timed-effects.h"
44 #include "util/bit-flags-calculator.h"
45 #include "util/int-char-converter.h"
46 #include "view/display-messages.h"
48 struct samurai_slaying_type {
53 MonsterRaceInfo *r_ptr;
56 static samurai_slaying_type *initialize_samurai_slaying_type(
57 samurai_slaying_type *samurai_slaying_ptr, MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr, combat_options mode, MonsterRaceInfo *r_ptr)
59 samurai_slaying_ptr->mult = mult;
60 samurai_slaying_ptr->flags = flags;
61 samurai_slaying_ptr->m_ptr = m_ptr;
62 samurai_slaying_ptr->mode = mode;
63 samurai_slaying_ptr->r_ptr = r_ptr;
64 return samurai_slaying_ptr;
69 * @param player_ptr プレイヤーへの参照ポインタ
70 * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
72 static void hissatsu_burning_strike(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
74 if (samurai_slaying_ptr->mode != HISSATSU_FIRE) {
79 if (samurai_slaying_ptr->r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_FIRE_MASK)) {
80 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
81 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(samurai_slaying_ptr->r_ptr->resistance_flags & RFR_EFF_IM_FIRE_MASK);
87 /* Otherwise, take the damage */
88 if (samurai_slaying_ptr->flags.has(TR_BRAND_FIRE)) {
89 if (samurai_slaying_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::HURT_FIRE)) {
90 if (samurai_slaying_ptr->mult < 70) {
91 samurai_slaying_ptr->mult = 70;
94 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
95 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::HURT_FIRE);
98 } else if (samurai_slaying_ptr->mult < 35) {
99 samurai_slaying_ptr->mult = 35;
105 if (samurai_slaying_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::HURT_FIRE)) {
106 if (samurai_slaying_ptr->mult < 50) {
107 samurai_slaying_ptr->mult = 50;
110 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
111 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::HURT_FIRE);
113 } else if (samurai_slaying_ptr->mult < 25) {
114 samurai_slaying_ptr->mult = 25;
119 * @brief サーペンツタン (毒殺スレイ)
120 * @param player_ptr プレイヤーへの参照ポインタ
121 * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
123 static void hissatsu_serpent_tongue(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
125 if (samurai_slaying_ptr->mode != HISSATSU_POISON) {
129 /* Notice immunity */
130 if (samurai_slaying_ptr->r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_POISON_MASK)) {
131 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
132 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(samurai_slaying_ptr->r_ptr->resistance_flags & RFR_EFF_IM_POISON_MASK);
138 /* Otherwise, take the damage */
139 if (samurai_slaying_ptr->flags.has(TR_BRAND_POIS)) {
140 if (samurai_slaying_ptr->mult < 35) {
141 samurai_slaying_ptr->mult = 35;
143 } else if (samurai_slaying_ptr->mult < 25) {
144 samurai_slaying_ptr->mult = 25;
149 * @brief 二重の極み^h^h^h^h^h 斬魔剣弐の太刀 (邪悪無生命スレイ)
150 * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
152 static void hissatsu_zanma_ken(samurai_slaying_type *samurai_slaying_ptr)
154 if (samurai_slaying_ptr->mode != HISSATSU_ZANMA) {
158 if (!monster_living(samurai_slaying_ptr->m_ptr->r_idx) && samurai_slaying_ptr->r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
159 if (samurai_slaying_ptr->mult < 15) {
160 samurai_slaying_ptr->mult = 25;
161 } else if (samurai_slaying_ptr->mult < 50) {
162 samurai_slaying_ptr->mult = std::min<short>(50, samurai_slaying_ptr->mult + 20);
169 * @param player_ptr プレイヤーへの参照ポインタ
170 * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
172 static void hissatsu_rock_smash(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
174 if (samurai_slaying_ptr->mode != HISSATSU_HAGAN) {
178 if (samurai_slaying_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::HURT_ROCK)) {
179 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
180 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::HURT_ROCK);
183 if (samurai_slaying_ptr->mult == 10) {
184 samurai_slaying_ptr->mult = 40;
185 } else if (samurai_slaying_ptr->mult < 60) {
186 samurai_slaying_ptr->mult = 60;
192 * @brief 乱れ雪月花 (冷気スレイ)
193 * @param player_ptr プレイヤーへの参照ポインタ
194 * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
196 static void hissatsu_midare_setsugetsuka(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
198 if (samurai_slaying_ptr->mode != HISSATSU_COLD) {
202 /* Notice immunity */
203 if (samurai_slaying_ptr->r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_COLD_MASK)) {
204 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
205 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(samurai_slaying_ptr->r_ptr->resistance_flags & RFR_EFF_IM_COLD_MASK);
211 /* Otherwise, take the damage */
212 if (samurai_slaying_ptr->flags.has(TR_BRAND_COLD)) {
213 if (samurai_slaying_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::HURT_COLD)) {
214 if (samurai_slaying_ptr->mult < 70) {
215 samurai_slaying_ptr->mult = 70;
218 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
219 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::HURT_COLD);
221 } else if (samurai_slaying_ptr->mult < 35) {
222 samurai_slaying_ptr->mult = 35;
228 if (samurai_slaying_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::HURT_COLD)) {
229 if (samurai_slaying_ptr->mult < 50) {
230 samurai_slaying_ptr->mult = 50;
233 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
234 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::HURT_COLD);
236 } else if (samurai_slaying_ptr->mult < 25) {
237 samurai_slaying_ptr->mult = 25;
243 * @param player_ptr プレイヤーへの参照ポインタ
244 * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
246 static void hissatsu_lightning_eagle(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
248 if (samurai_slaying_ptr->mode != HISSATSU_ELEC) {
252 /* Notice immunity */
253 if (samurai_slaying_ptr->r_ptr->resistance_flags.has_any_of(RFR_EFF_IM_ELEC_MASK)) {
254 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
255 samurai_slaying_ptr->r_ptr->r_resistance_flags.set(samurai_slaying_ptr->r_ptr->resistance_flags & RFR_EFF_IM_ELEC_MASK);
261 /* Otherwise, take the damage */
262 if (samurai_slaying_ptr->flags.has(TR_BRAND_ELEC)) {
263 if (samurai_slaying_ptr->mult < 70) {
264 samurai_slaying_ptr->mult = 70;
266 } else if (samurai_slaying_ptr->mult < 50) {
267 samurai_slaying_ptr->mult = 50;
272 * @brief 赤流渦 (ペインバッカー)
273 * @param player_ptr プレイヤーへの参照ポインタ
274 * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
276 static void hissatsu_bloody_maelstroem(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
278 auto player_cut = player_ptr->effects()->cut();
279 if ((samurai_slaying_ptr->mode == HISSATSU_SEKIRYUKA) && player_cut->is_cut() && monster_living(samurai_slaying_ptr->m_ptr->r_idx)) {
280 auto tmp = std::min<short>(100, std::max<short>(10, player_cut->current() / 10));
281 if (samurai_slaying_ptr->mult < tmp) {
282 samurai_slaying_ptr->mult = tmp;
288 * @brief 慶雲鬼忍剣 (アンデッドスレイ)
289 * @param player_ptr プレイヤーへの参照ポインタ
290 * @param samurai_slaying_ptr スレイ計算に必要なパラメータ群への参照ポインタ
292 static void hissatsu_keiun_kininken(PlayerType *player_ptr, samurai_slaying_type *samurai_slaying_ptr)
294 if (samurai_slaying_ptr->mode != HISSATSU_UNDEAD) {
298 if (samurai_slaying_ptr->r_ptr->kind_flags.has(MonsterKindType::UNDEAD)) {
299 if (is_original_ap_and_seen(player_ptr, samurai_slaying_ptr->m_ptr)) {
300 samurai_slaying_ptr->r_ptr->r_kind_flags.set(MonsterKindType::UNDEAD);
302 if (samurai_slaying_ptr->mult == 10) {
303 samurai_slaying_ptr->mult = 70;
304 } else if (samurai_slaying_ptr->mult < 140) {
305 samurai_slaying_ptr->mult = std::min<short>(140, samurai_slaying_ptr->mult + 60);
310 if (samurai_slaying_ptr->mult == 10) {
311 samurai_slaying_ptr->mult = 40;
312 } else if (samurai_slaying_ptr->mult < 60) {
313 samurai_slaying_ptr->mult = std::min<short>(60, samurai_slaying_ptr->mult + 30);
318 * @brief 剣術のスレイ倍率計算を行う /
319 * Calcurate magnification of hissatsu technics
320 * @param mult 剣術のスレイ効果以前に算出している多要素の倍率(/10倍)
321 * @param flags 剣術に使用する武器のスレイフラグ配列
322 * @param m_ptr 目標となるモンスターの構造体参照ポインタ
323 * @param mode 剣術のスレイ型ID
324 * @return スレイの倍率(/10倍)
326 MULTIPLY mult_hissatsu(PlayerType *player_ptr, MULTIPLY mult, const TrFlags &flags, MonsterEntity *m_ptr, combat_options mode)
328 auto *r_ptr = &monraces_info[m_ptr->r_idx];
329 samurai_slaying_type tmp_slaying;
330 samurai_slaying_type *samurai_slaying_ptr = initialize_samurai_slaying_type(&tmp_slaying, mult, flags, m_ptr, mode, r_ptr);
331 hissatsu_burning_strike(player_ptr, samurai_slaying_ptr);
332 hissatsu_serpent_tongue(player_ptr, samurai_slaying_ptr);
333 hissatsu_zanma_ken(samurai_slaying_ptr);
334 hissatsu_rock_smash(player_ptr, samurai_slaying_ptr);
335 hissatsu_midare_setsugetsuka(player_ptr, samurai_slaying_ptr);
336 hissatsu_lightning_eagle(player_ptr, samurai_slaying_ptr);
337 hissatsu_bloody_maelstroem(player_ptr, samurai_slaying_ptr);
338 hissatsu_keiun_kininken(player_ptr, samurai_slaying_ptr);
340 if (samurai_slaying_ptr->mult > 150) {
341 samurai_slaying_ptr->mult = 150;
344 return samurai_slaying_ptr->mult;
347 void concentration(PlayerType *player_ptr)
349 int max_csp = std::max(player_ptr->msp * 4, player_ptr->lev * 5 + 5);
352 msg_print(_("今はペットを操ることに集中していないと。", "Your pets demand all of your attention."));
356 if (!PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::NONE)) {
357 msg_print(_("今は構えに集中している。", "You're already concentrating on your stance."));
361 msg_print(_("精神を集中して気合いを溜めた。", "You concentrate to charge your power."));
363 player_ptr->csp += player_ptr->msp / 2;
364 if (player_ptr->csp >= max_csp) {
365 player_ptr->csp = max_csp;
366 player_ptr->csp_frac = 0;
369 player_ptr->redraw |= PR_MANA;
374 * @return 型を変化させたらTRUE、型の構え不能かキャンセルしたらFALSEを返す。
376 bool choose_samurai_stance(PlayerType *player_ptr)
381 if (cmd_limit_confused(player_ptr)) {
385 auto effects = player_ptr->effects();
386 if (effects->stun()->is_stunned()) {
387 msg_print(_("意識がはっきりとしない。", "You are not clear-headed"));
391 if (effects->fear()->is_fearful()) {
392 msg_print(_("体が震えて構えられない!", "You are trembling with fear!"));
397 prt(_(" a) 型を崩す", " a) No Form"), 2, 20);
398 for (auto i = 0U; i < samurai_stances.size(); i++) {
399 if (player_ptr->lev >= samurai_stances[i].min_level) {
400 strnfmt(buf, sizeof(buf), _(" %c) %sの型 %s", " %c) Stance of %-12s %s"), I2A(i + 1), samurai_stances[i].desc, samurai_stances[i].info);
406 prt(_(" どの型で構えますか?", " Choose Stance: "), 1, 14);
408 SamuraiStanceType new_stance = SamuraiStanceType::NONE;
412 if (choice == ESCAPE) {
415 } else if ((choice == 'a') || (choice == 'A')) {
416 if (player_ptr->action == ACTION_SAMURAI_STANCE) {
417 set_action(player_ptr, ACTION_NONE);
419 msg_print(_("もともと構えていない。", "You are not in a special stance."));
423 } else if ((choice == 'b') || (choice == 'B')) {
424 new_stance = SamuraiStanceType::IAI;
426 } else if (((choice == 'c') || (choice == 'C')) && (player_ptr->lev > 29)) {
427 new_stance = SamuraiStanceType::FUUJIN;
429 } else if (((choice == 'd') || (choice == 'D')) && (player_ptr->lev > 34)) {
430 new_stance = SamuraiStanceType::KOUKIJIN;
432 } else if (((choice == 'e') || (choice == 'E')) && (player_ptr->lev > 39)) {
433 new_stance = SamuraiStanceType::MUSOU;
438 set_action(player_ptr, ACTION_SAMURAI_STANCE);
439 if (PlayerClass(player_ptr).samurai_stance_is(new_stance)) {
440 msg_print(_("構え直した。", "You reassume a stance."));
442 player_ptr->update |= (PU_BONUS | PU_MONSTERS);
443 msg_format(_("%sの型で構えた。", "You assume the %s stance."), samurai_stances[enum2i(new_stance) - 1].desc);
444 PlayerClass(player_ptr).set_samurai_stance(new_stance);
447 player_ptr->redraw |= (PR_STATE | PR_STATUS);
453 * @brief 剣術家限定で、型等に応じて命中率を高める
454 * @param player_ptr プレイヤーへの参照ポインタ
455 * @param pa_ptr 直接攻撃構造体への参照ポインタ
458 int calc_attack_quality(PlayerType *player_ptr, player_attack_type *pa_ptr)
460 auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + pa_ptr->hand];
461 int bonus = player_ptr->to_h[pa_ptr->hand] + o_ptr->to_h;
462 int chance = (player_ptr->skill_thn + (bonus * BTH_PLUS_ADJ));
463 if (pa_ptr->mode == HISSATSU_IAI) {
467 if (PlayerClass(player_ptr).samurai_stance_is(SamuraiStanceType::KOUKIJIN)) {
471 if (player_ptr->sutemi) {
472 chance = std::max(chance * 3 / 2, chance + 60);
475 int vir = virtue_number(player_ptr, V_VALOUR);
477 chance += (player_ptr->virtues[vir - 1] / 10);
485 * @param player_ptr プレイヤーへの参照ポインタ
486 * @param pa_ptr 直接攻撃構造体への参照ポインタ
488 void mineuchi(PlayerType *player_ptr, player_attack_type *pa_ptr)
490 if (pa_ptr->mode != HISSATSU_MINEUCHI) {
494 pa_ptr->attack_damage = 0;
495 anger_monster(player_ptr, pa_ptr->m_ptr);
497 auto *r_ptr = &monraces_info[pa_ptr->m_ptr->r_idx];
498 if ((r_ptr->flags3 & (RF3_NO_STUN))) {
499 msg_format(_("%s には効果がなかった。", "%s is not effected."), pa_ptr->m_name);
503 int tmp = (10 + randint1(15) + player_ptr->lev / 5);
504 if (pa_ptr->m_ptr->get_remaining_stun()) {
505 msg_format(_("%sはひどくもうろうとした。", "%s is more dazed."), pa_ptr->m_name);
508 msg_format(_("%s はもうろうとした。", "%s is dazed."), pa_ptr->m_name);
511 (void)set_monster_stunned(player_ptr, pa_ptr->g_ptr->m_idx, pa_ptr->m_ptr->get_remaining_stun() + tmp);
516 * @param player_ptr プレイヤーへの参照ポインタ
517 * @param pa_ptr 直接攻撃構造体への参照ポインタ
519 void musou_counterattack(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
521 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)) {
525 char m_target_name[MAX_NLEN];
526 monster_desc(player_ptr, m_target_name, monap_ptr->m_ptr, 0);
527 player_ptr->csp -= 7;
528 msg_format(_("%^sに反撃した!", "You counterattacked %s!"), m_target_name);
529 do_cmd_attack(player_ptr, monap_ptr->m_ptr->fy, monap_ptr->m_ptr->fx, HISSATSU_COUNTER);
530 monap_ptr->fear = false;
531 player_ptr->redraw |= (PR_MANA);