2 * @brief 各職業の特殊技能実装 / Special magics
5 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke\n
6 * This software may be copied and distributed for educational, research,\n
7 * and not for profit purposes provided that this copyright and statement\n
8 * are included in all such copies. Other copyrights may also apply.\n
10 * 2014 Deskull rearranged comment for Doxygen.\n
13 #include "cmd-action/cmd-mind.h"
14 #include "action/action-limited.h"
15 #include "core/asking-player.h"
16 #include "core/window-redrawer.h"
17 #include "effect/attribute-types.h"
18 #include "effect/effect-characteristics.h"
19 #include "effect/effect-processor.h"
20 #include "game-option/disturbance-options.h"
21 #include "game-option/input-options.h"
22 #include "grid/grid.h"
23 #include "inventory/inventory-slot-types.h"
24 #include "io/input-key-acceptor.h"
25 #include "main/sound-definitions-table.h"
26 #include "main/sound-of-music.h"
27 #include "mind/mind-berserker.h"
28 #include "mind/mind-explanations-table.h"
29 #include "mind/mind-force-trainer.h"
30 #include "mind/mind-mindcrafter.h"
31 #include "mind/mind-mirror-master.h"
32 #include "mind/mind-ninja.h"
33 #include "mind/mind-numbers.h"
34 #include "mind/mind-power-getter.h"
35 #include "mind/mind-types.h"
36 #include "player-base/player-class.h"
37 #include "player-info/class-info.h"
38 #include "player-info/equipment-info.h"
39 #include "player-status/player-energy.h"
40 #include "player/player-damage.h"
41 #include "player/player-status-table.h"
42 #include "player/player-status.h"
43 #include "spell-kind/spells-teleport.h"
44 #include "status/bad-status-setter.h"
45 #include "status/base-status.h"
46 #include "system/floor-type-definition.h"
47 #include "system/grid-type-definition.h"
48 #include "system/player-type-definition.h"
49 #include "system/redrawing-flags-updater.h"
50 #include "term/screen-processor.h"
51 #include "timed-effect/player-stun.h"
52 #include "timed-effect/timed-effects.h"
53 #include "util/enum-converter.h"
54 #include "view/display-messages.h"
55 #include "view/display-util.h"
58 * @brief 職業別特殊技能の処理用構造体
61 MindKindType use_mind; //!< 使った職業技能構造体
62 concptr mind_explanation; //!< 特殊技能の説明
63 SPELL_IDX n; //!< 職業種別毎ID
64 int b; //!< 失敗時チャート用乱数
65 PERCENTAGE chance; //!< 失敗率
66 PERCENTAGE minfail; //!< 最低失敗率
67 PLAYER_LEVEL plev; //!< 取得レベル
68 int old_csp; //!< 行使前のMP
69 mind_type spell; //!< 職業技能の基本設定構造体
71 int mana_cost; //!< 最終算出消費MP
72 bool on_mirror; //!< 鏡の上に乗っているどうかの判定
76 * @brief 職業技能処理構造体の初期化
78 static cm_type *initialize_cm_type(PlayerType *player_ptr, cm_type *cm_ptr)
83 cm_ptr->plev = player_ptr->lev;
84 cm_ptr->old_csp = player_ptr->csp;
85 cm_ptr->on_mirror = false;
90 * @brief 職業別の行使可能な技能種別を構造体に付加する
92 static void switch_mind_kind(PlayerType *player_ptr, cm_type *cm_ptr)
94 switch (player_ptr->pclass) {
95 case PlayerClassType::MINDCRAFTER:
96 cm_ptr->use_mind = MindKindType::MINDCRAFTER;
97 cm_ptr->mind_explanation = _("精神", "skill");
99 case PlayerClassType::FORCETRAINER:
100 cm_ptr->use_mind = MindKindType::KI;
101 cm_ptr->mind_explanation = _("気", "skill");
103 case PlayerClassType::BERSERKER:
104 cm_ptr->use_mind = MindKindType::BERSERKER;
105 cm_ptr->mind_explanation = _("怒り", "skill");
107 case PlayerClassType::MIRROR_MASTER:
108 cm_ptr->use_mind = MindKindType::MIRROR_MASTER;
109 cm_ptr->mind_explanation = _("鏡魔法", "skill");
111 case PlayerClassType::NINJA:
112 cm_ptr->use_mind = MindKindType::NINJUTSU;
113 cm_ptr->mind_explanation = _("精神", "skill");
116 cm_ptr->use_mind = (MindKindType)0;
117 cm_ptr->mind_explanation = _("超能力", "skill");
122 static void decide_mind_ki_chance(PlayerType *player_ptr, cm_type *cm_ptr)
124 if (cm_ptr->use_mind != MindKindType::KI) {
128 if (heavy_armor(player_ptr)) {
129 cm_ptr->chance += 20;
132 if (player_ptr->is_icky_wield[0]) {
133 cm_ptr->chance += 20;
134 } else if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND)) {
135 cm_ptr->chance += 10;
138 if (player_ptr->is_icky_wield[1]) {
139 cm_ptr->chance += 20;
140 } else if (has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
141 cm_ptr->chance += 10;
144 if (cm_ptr->n == 5) {
145 for (int j = 0; j < get_current_ki(player_ptr) / 50; j++) {
146 cm_ptr->mana_cost += (j + 1) * 3 / 2;
151 static bool check_mind_hp_mp_sufficiency(PlayerType *player_ptr, cm_type *cm_ptr)
153 if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU)) {
154 if (cm_ptr->mana_cost > player_ptr->chp) {
155 msg_print(_("HPが足りません。", "You do not have enough hp to use this power."));
162 if (cm_ptr->mana_cost <= player_ptr->csp) {
166 msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
171 return input_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
174 static void decide_mind_chance(PlayerType *player_ptr, cm_type *cm_ptr)
176 if (cm_ptr->chance == 0) {
180 cm_ptr->chance -= 3 * (cm_ptr->plev - cm_ptr->spell.min_lev);
181 cm_ptr->chance += player_ptr->to_m_chance;
182 cm_ptr->chance -= 3 * (adj_mag_stat[player_ptr->stat_index[mp_ptr->spell_stat]] - 1);
183 if ((cm_ptr->mana_cost > player_ptr->csp) && (cm_ptr->use_mind != MindKindType::BERSERKER) && (cm_ptr->use_mind != MindKindType::NINJUTSU)) {
184 cm_ptr->chance += 5 * (cm_ptr->mana_cost - player_ptr->csp);
187 cm_ptr->minfail = adj_mag_fail[player_ptr->stat_index[mp_ptr->spell_stat]];
188 if (cm_ptr->chance < cm_ptr->minfail) {
189 cm_ptr->chance = cm_ptr->minfail;
192 auto player_stun = player_ptr->effects()->stun();
193 cm_ptr->chance += player_stun->get_magic_chance_penalty();
195 if (cm_ptr->use_mind != MindKindType::KI) {
199 if (heavy_armor(player_ptr)) {
203 if (player_ptr->is_icky_wield[0]) {
207 if (player_ptr->is_icky_wield[1]) {
212 static void check_mind_mindcrafter(PlayerType *player_ptr, cm_type *cm_ptr)
214 if (cm_ptr->use_mind != MindKindType::MINDCRAFTER) {
219 msg_print(_("なんてこった!頭の中が真っ白になった!", "Oh, no! Your mind has gone blank!"));
220 lose_all_info(player_ptr);
224 BadStatusSetter bss(player_ptr);
225 if (cm_ptr->b < 15) {
226 msg_print(_("奇妙な光景が目の前で踊っている...", "Weird visions seem to dance before your eyes..."));
227 (void)bss.mod_hallucination(5 + randint1(10));
231 if (cm_ptr->b < 45) {
232 msg_print(_("あなたの頭は混乱した!", "Your brain is addled!"));
233 (void)bss.mod_confusion(randint1(8));
237 if (cm_ptr->b < 90) {
238 (void)bss.mod_stun(randint1(8));
242 msg_print(_(format("%sの力が制御できない氾流となって解放された!", cm_ptr->mind_explanation), "Your mind unleashes its power in an uncontrollable storm!"));
243 project(player_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + cm_ptr->plev / 10, player_ptr->y, player_ptr->x, cm_ptr->plev * 2, AttributeType::MANA,
244 PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
245 player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->plev * std::max(1, cm_ptr->plev / 10));
248 static void check_mind_mirror_master(PlayerType *player_ptr, cm_type *cm_ptr)
250 if (cm_ptr->use_mind != MindKindType::MIRROR_MASTER) {
254 if (cm_ptr->b < 51) {
258 if (cm_ptr->b < 81) {
259 msg_print(_("鏡の世界の干渉を受けた!", "Weird visions seem to dance before your eyes..."));
260 teleport_player(player_ptr, 10, TELEPORT_PASSIVE);
264 if (cm_ptr->b < 96) {
265 msg_print(_("まわりのものがキラキラ輝いている!", "Your brain is addled!"));
266 (void)BadStatusSetter(player_ptr).mod_hallucination(5 + randint1(10));
270 msg_print(_(format("%sの力が制御できない氾流となって解放された!", cm_ptr->mind_explanation), "Your mind unleashes its power in an uncontrollable storm!"));
271 project(player_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + cm_ptr->plev / 10, player_ptr->y, player_ptr->x, cm_ptr->plev * 2, AttributeType::MANA,
272 PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
273 player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->plev * std::max(1, cm_ptr->plev / 10));
276 static void check_mind_class(PlayerType *player_ptr, cm_type *cm_ptr)
278 if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU)) {
282 if ((cm_ptr->use_mind == MindKindType::KI) && (cm_ptr->n != 5) && get_current_ki(player_ptr)) {
283 msg_print(_("気が散ってしまった...", "Your improved Force has gone away..."));
284 set_current_ki(player_ptr, true, 0);
287 if (randint1(100) >= (cm_ptr->chance / 2)) {
291 cm_ptr->b = randint1(100);
292 check_mind_mindcrafter(player_ptr, cm_ptr);
293 check_mind_mirror_master(player_ptr, cm_ptr);
296 static bool switch_mind_class(PlayerType *player_ptr, cm_type *cm_ptr)
298 switch (cm_ptr->use_mind) {
299 case MindKindType::MINDCRAFTER:
300 cm_ptr->cast = cast_mindcrafter_spell(player_ptr, i2enum<MindMindcrafterType>(cm_ptr->n));
302 case MindKindType::KI:
303 cm_ptr->cast = cast_force_spell(player_ptr, i2enum<MindForceTrainerType>(cm_ptr->n));
305 case MindKindType::BERSERKER:
306 cm_ptr->cast = cast_berserk_spell(player_ptr, i2enum<MindBerserkerType>(cm_ptr->n));
308 case MindKindType::MIRROR_MASTER:
309 if (player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].is_mirror()) {
310 cm_ptr->on_mirror = true;
313 cm_ptr->cast = cast_mirror_spell(player_ptr, i2enum<MindMirrorMasterType>(cm_ptr->n));
315 case MindKindType::NINJUTSU:
316 cm_ptr->cast = cast_ninja_spell(player_ptr, i2enum<MindNinjaType>(cm_ptr->n));
319 msg_format(_("謎の能力:%d, %d", "Mystery power:%d, %d"), enum2i(cm_ptr->use_mind), cm_ptr->n);
324 static void mind_turn_passing(PlayerType *player_ptr, cm_type *cm_ptr)
326 PlayerEnergy energy(player_ptr);
327 if (cm_ptr->on_mirror && PlayerClass(player_ptr).equals(PlayerClassType::MIRROR_MASTER)) {
328 if (cm_ptr->n == 3 || cm_ptr->n == 5 || cm_ptr->n == 7 || cm_ptr->n == 16) {
329 energy.set_player_turn_energy(50);
334 energy.set_player_turn_energy(100);
337 static bool judge_mind_chance(PlayerType *player_ptr, cm_type *cm_ptr)
339 if (randint0(100) >= cm_ptr->chance) {
341 return switch_mind_class(player_ptr, cm_ptr) && cm_ptr->cast;
348 msg_format(_("%sの集中に失敗した!", "You failed to concentrate hard enough for %s!"), cm_ptr->mind_explanation);
350 check_mind_class(player_ptr, cm_ptr);
354 static void mind_reflection(PlayerType *player_ptr, cm_type *cm_ptr)
356 int oops = cm_ptr->mana_cost - cm_ptr->old_csp;
357 if ((player_ptr->csp - cm_ptr->mana_cost) < 0) {
358 player_ptr->csp_frac = 0;
361 player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->mana_cost);
362 msg_print(_(format("%sを集中しすぎて気を失ってしまった!", cm_ptr->mind_explanation), "You faint from the effort!"));
363 (void)BadStatusSetter(player_ptr).mod_paralysis(randint1(5 * oops + 1));
364 if (randint0(100) >= 50) {
368 bool perm = randint0(100) < 25;
369 msg_print(_("自分の精神を攻撃してしまった!", "You have damaged your mind!"));
370 (void)dec_stat(player_ptr, A_WIS, 15 + randint1(10), perm);
373 static void process_hard_concentration(PlayerType *player_ptr, cm_type *cm_ptr)
375 if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU)) {
376 take_hit(player_ptr, DAMAGE_USELIFE, cm_ptr->mana_cost, _("過度の集中", "concentrating too hard"));
377 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::HP);
381 if (cm_ptr->mana_cost > cm_ptr->old_csp) {
382 mind_reflection(player_ptr, cm_ptr);
386 player_ptr->csp -= cm_ptr->mana_cost;
387 if (player_ptr->csp < 0) {
391 if ((cm_ptr->use_mind == MindKindType::MINDCRAFTER) && (cm_ptr->n == 13)) {
393 player_ptr->csp_frac = 0;
398 * @brief 特殊技能コマンドのメインルーチン /
400 void do_cmd_mind(PlayerType *player_ptr)
403 cm_type *cm_ptr = initialize_cm_type(player_ptr, &tmp_cm);
404 if (cmd_limit_confused(player_ptr) || !MindPowerGetter(player_ptr).get_mind_power(&cm_ptr->n, false)) {
408 switch_mind_kind(player_ptr, cm_ptr);
409 cm_ptr->spell = mind_powers[enum2i(cm_ptr->use_mind)].info[cm_ptr->n];
410 cm_ptr->chance = cm_ptr->spell.fail;
411 cm_ptr->mana_cost = cm_ptr->spell.mana_cost;
412 decide_mind_ki_chance(player_ptr, cm_ptr);
413 if (!check_mind_hp_mp_sufficiency(player_ptr, cm_ptr)) {
417 decide_mind_chance(player_ptr, cm_ptr);
418 if (cm_ptr->chance > 95) {
422 if (!judge_mind_chance(player_ptr, cm_ptr)) {
426 mind_turn_passing(player_ptr, cm_ptr);
427 process_hard_concentration(player_ptr, cm_ptr);
428 auto &rfu = RedrawingFlagsUpdater::get_instance();
429 rfu.set_flag(MainWindowRedrawingFlag::MP);
430 static constexpr auto flags = {
431 SubWindowRedrawingFlag::PLAYER,
432 SubWindowRedrawingFlag::SPELL,
434 rfu.set_flags(flags);
437 static MindKindType decide_use_mind_browse(PlayerType *player_ptr)
439 switch (player_ptr->pclass) {
440 case PlayerClassType::MINDCRAFTER:
441 return MindKindType::MINDCRAFTER;
442 case PlayerClassType::FORCETRAINER:
443 return MindKindType::KI;
444 case PlayerClassType::BERSERKER:
445 return MindKindType::BERSERKER;
446 case PlayerClassType::NINJA:
447 return MindKindType::NINJUTSU;
448 case PlayerClassType::MIRROR_MASTER:
449 return MindKindType::MIRROR_MASTER;
451 return (MindKindType)0; // 実質PlayerClassType::MINDCRAFTERと同じ.
456 * @brief 現在プレイヤーが使用可能な特殊技能の一覧表示 /
458 void do_cmd_mind_browse(PlayerType *player_ptr)
461 MindKindType use_mind = decide_use_mind_browse(player_ptr);
464 if (!MindPowerGetter(player_ptr).get_mind_power(&n, true)) {
475 display_wrap_around(mind_tips[enum2i(use_mind)][n], 62, 17, 15);
478 case MindKindType::MIRROR_MASTER:
479 case MindKindType::NINJUTSU:
480 prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);