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/player-redraw-types.h"
17 #include "core/window-redrawer.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-info/class-info.h"
37 #include "player-info/equipment-info.h"
38 #include "player-status/player-energy.h"
39 #include "player/player-damage.h"
40 #include "player/player-status-table.h"
41 #include "player/player-status.h"
42 #include "spell-kind/spells-teleport.h"
43 #include "effect/attribute-types.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 "term/screen-processor.h"
50 #include "timed-effect/player-stun.h"
51 #include "timed-effect/timed-effects.h"
52 #include "util/buffer-shaper.h"
53 #include "util/enum-converter.h"
54 #include "view/display-messages.h"
57 * @brief 職業別特殊技能の処理用構造体
59 typedef struct cm_type {
60 MindKindType use_mind; //!< 使った職業技能構造体
61 concptr mind_explanation; //!< 特殊技能の説明
62 SPELL_IDX n; //!< 職業種別毎ID
63 int b; //!< 失敗時チャート用乱数
64 PERCENTAGE chance; //!< 失敗率
65 PERCENTAGE minfail; //!< 最低失敗率
66 PLAYER_LEVEL plev; //!< 取得レベル
67 int old_csp; //!< 行使前のMP
68 mind_type spell; //!< 職業技能の基本設定構造体
70 int mana_cost; //!< 最終算出消費MP
71 bool on_mirror; //!< 鏡の上に乗っているどうかの判定
75 * @brief 職業技能処理構造体の初期化
77 static cm_type *initialize_cm_type(PlayerType *player_ptr, cm_type *cm_ptr)
82 cm_ptr->plev = player_ptr->lev;
83 cm_ptr->old_csp = player_ptr->csp;
84 cm_ptr->on_mirror = false;
89 * @brief 職業別の行使可能な技能種別を構造体に付加する
91 static void switch_mind_kind(PlayerType *player_ptr, cm_type *cm_ptr)
93 switch (player_ptr->pclass) {
94 case PlayerClassType::MINDCRAFTER:
95 cm_ptr->use_mind = MindKindType::MINDCRAFTER;
96 cm_ptr->mind_explanation = _("精神", "skill");
98 case PlayerClassType::FORCETRAINER:
99 cm_ptr->use_mind = MindKindType::KI;
100 cm_ptr->mind_explanation = _("気", "skill");
102 case PlayerClassType::BERSERKER:
103 cm_ptr->use_mind = MindKindType::BERSERKER;
104 cm_ptr->mind_explanation = _("怒り", "skill");
106 case PlayerClassType::MIRROR_MASTER:
107 cm_ptr->use_mind = MindKindType::MIRROR_MASTER;
108 cm_ptr->mind_explanation = _("鏡魔法", "skill");
110 case PlayerClassType::NINJA:
111 cm_ptr->use_mind = MindKindType::NINJUTSU;
112 cm_ptr->mind_explanation = _("精神", "skill");
115 cm_ptr->use_mind = (MindKindType)0;
116 cm_ptr->mind_explanation = _("超能力", "skill");
121 static void decide_mind_ki_chance(PlayerType *player_ptr, cm_type *cm_ptr)
123 if (cm_ptr->use_mind != MindKindType::KI)
126 if (heavy_armor(player_ptr))
127 cm_ptr->chance += 20;
129 if (player_ptr->is_icky_wield[0])
130 cm_ptr->chance += 20;
131 else if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND))
132 cm_ptr->chance += 10;
134 if (player_ptr->is_icky_wield[1])
135 cm_ptr->chance += 20;
136 else if (has_melee_weapon(player_ptr, INVEN_SUB_HAND))
137 cm_ptr->chance += 10;
140 for (int j = 0; j < get_current_ki(player_ptr) / 50; j++)
141 cm_ptr->mana_cost += (j + 1) * 3 / 2;
144 static bool check_mind_hp_mp_sufficiency(PlayerType *player_ptr, cm_type *cm_ptr)
146 if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU)) {
147 if (cm_ptr->mana_cost > player_ptr->chp) {
148 msg_print(_("HPが足りません。", "You do not have enough hp to use this power."));
155 if (cm_ptr->mana_cost <= player_ptr->csp)
158 msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
162 return get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
165 static void decide_mind_chance(PlayerType *player_ptr, cm_type *cm_ptr)
167 if (cm_ptr->chance == 0)
170 cm_ptr->chance -= 3 * (cm_ptr->plev - cm_ptr->spell.min_lev);
171 cm_ptr->chance += player_ptr->to_m_chance;
172 cm_ptr->chance -= 3 * (adj_mag_stat[player_ptr->stat_index[mp_ptr->spell_stat]] - 1);
173 if ((cm_ptr->mana_cost > player_ptr->csp) && (cm_ptr->use_mind != MindKindType::BERSERKER) && (cm_ptr->use_mind != MindKindType::NINJUTSU))
174 cm_ptr->chance += 5 * (cm_ptr->mana_cost - player_ptr->csp);
176 cm_ptr->minfail = adj_mag_fail[player_ptr->stat_index[mp_ptr->spell_stat]];
177 if (cm_ptr->chance < cm_ptr->minfail)
178 cm_ptr->chance = cm_ptr->minfail;
180 auto player_stun = player_ptr->effects()->stun();
181 cm_ptr->chance += player_stun->get_magic_chance_penalty();
183 if (cm_ptr->use_mind != MindKindType::KI)
186 if (heavy_armor(player_ptr))
189 if (player_ptr->is_icky_wield[0])
192 if (player_ptr->is_icky_wield[1])
196 static void check_mind_mindcrafter(PlayerType *player_ptr, cm_type *cm_ptr)
198 if (cm_ptr->use_mind != MindKindType::MINDCRAFTER)
202 msg_print(_("なんてこった!頭の中が真っ白になった!", "Oh, no! Your mind has gone blank!"));
203 lose_all_info(player_ptr);
207 BadStatusSetter bss(player_ptr);
208 if (cm_ptr->b < 15) {
209 msg_print(_("奇妙な光景が目の前で踊っている...", "Weird visions seem to dance before your eyes..."));
210 (void)bss.mod_hallucination(5 + randint1(10));
214 if (cm_ptr->b < 45) {
215 msg_print(_("あなたの頭は混乱した!", "Your brain is addled!"));
216 (void)bss.mod_confusion(randint1(8));
220 if (cm_ptr->b < 90) {
221 (void)bss.mod_stun(randint1(8));
225 msg_format(_("%sの力が制御できない氾流となって解放された!", "Your mind unleashes its power in an uncontrollable storm!"), cm_ptr->mind_explanation);
226 project(player_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + cm_ptr->plev / 10, player_ptr->y, player_ptr->x, cm_ptr->plev * 2, AttributeType::MANA,
227 PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
228 player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->plev * std::max(1, cm_ptr->plev / 10));
231 static void check_mind_mirror_master(PlayerType *player_ptr, cm_type *cm_ptr)
233 if (cm_ptr->use_mind != MindKindType::MIRROR_MASTER)
239 if (cm_ptr->b < 81) {
240 msg_print(_("鏡の世界の干渉を受けた!", "Weird visions seem to dance before your eyes..."));
241 teleport_player(player_ptr, 10, TELEPORT_PASSIVE);
245 if (cm_ptr->b < 96) {
246 msg_print(_("まわりのものがキラキラ輝いている!", "Your brain is addled!"));
247 (void)BadStatusSetter(player_ptr).mod_hallucination(5 + randint1(10));
251 msg_format(_("%sの力が制御できない氾流となって解放された!", "Your mind unleashes its power in an uncontrollable storm!"), cm_ptr->mind_explanation);
252 project(player_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + cm_ptr->plev / 10, player_ptr->y, player_ptr->x, cm_ptr->plev * 2, AttributeType::MANA,
253 PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
254 player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->plev * std::max(1, cm_ptr->plev / 10));
257 static void check_mind_class(PlayerType *player_ptr, cm_type *cm_ptr)
259 if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU))
262 if ((cm_ptr->use_mind == MindKindType::KI) && (cm_ptr->n != 5) && get_current_ki(player_ptr)) {
263 msg_print(_("気が散ってしまった...", "Your improved Force has gone away..."));
264 set_current_ki(player_ptr, true, 0);
267 if (randint1(100) >= (cm_ptr->chance / 2))
270 cm_ptr->b = randint1(100);
271 check_mind_mindcrafter(player_ptr, cm_ptr);
272 check_mind_mirror_master(player_ptr, cm_ptr);
275 static bool switch_mind_class(PlayerType *player_ptr, cm_type *cm_ptr)
277 switch (cm_ptr->use_mind) {
278 case MindKindType::MINDCRAFTER:
279 cm_ptr->cast = cast_mindcrafter_spell(player_ptr, i2enum<mind_mindcrafter_type>(cm_ptr->n));
281 case MindKindType::KI:
282 cm_ptr->cast = cast_force_spell(player_ptr, i2enum<mind_force_trainer_type>(cm_ptr->n));
284 case MindKindType::BERSERKER:
285 cm_ptr->cast = cast_berserk_spell(player_ptr, i2enum<mind_berserker_type>(cm_ptr->n));
287 case MindKindType::MIRROR_MASTER:
288 if (player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].is_mirror())
289 cm_ptr->on_mirror = true;
291 cm_ptr->cast = cast_mirror_spell(player_ptr, i2enum<mind_mirror_master_type>(cm_ptr->n));
293 case MindKindType::NINJUTSU:
294 cm_ptr->cast = cast_ninja_spell(player_ptr, i2enum<mind_ninja_type>(cm_ptr->n));
297 msg_format(_("謎の能力:%d, %d", "Mystery power:%d, %d"), cm_ptr->use_mind, cm_ptr->n);
302 static void mind_turn_passing(PlayerType *player_ptr, cm_type *cm_ptr)
304 PlayerEnergy energy(player_ptr);
305 if (cm_ptr->on_mirror && (player_ptr->pclass == PlayerClassType::MIRROR_MASTER)) {
306 if (cm_ptr->n == 3 || cm_ptr->n == 5 || cm_ptr->n == 7 || cm_ptr->n == 16) {
307 energy.set_player_turn_energy(50);
312 energy.set_player_turn_energy(100);
315 static bool judge_mind_chance(PlayerType *player_ptr, cm_type *cm_ptr)
317 if (randint0(100) >= cm_ptr->chance) {
319 return switch_mind_class(player_ptr, cm_ptr) && cm_ptr->cast;
325 msg_format(_("%sの集中に失敗した!", "You failed to concentrate hard enough for %s!"), cm_ptr->mind_explanation);
327 check_mind_class(player_ptr, cm_ptr);
331 static void mind_reflection(PlayerType *player_ptr, cm_type *cm_ptr)
333 int oops = cm_ptr->mana_cost - cm_ptr->old_csp;
334 if ((player_ptr->csp - cm_ptr->mana_cost) < 0)
335 player_ptr->csp_frac = 0;
337 player_ptr->csp = std::max(0, player_ptr->csp - cm_ptr->mana_cost);
338 msg_format(_("%sを集中しすぎて気を失ってしまった!", "You faint from the effort!"), cm_ptr->mind_explanation);
339 (void)BadStatusSetter(player_ptr).mod_paralysis(randint1(5 * oops + 1));
340 if (randint0(100) >= 50)
343 bool perm = randint0(100) < 25;
344 msg_print(_("自分の精神を攻撃してしまった!", "You have damaged your mind!"));
345 (void)dec_stat(player_ptr, A_WIS, 15 + randint1(10), perm);
348 static void process_hard_concentration(PlayerType *player_ptr, cm_type *cm_ptr)
350 if ((cm_ptr->use_mind == MindKindType::BERSERKER) || (cm_ptr->use_mind == MindKindType::NINJUTSU)) {
351 take_hit(player_ptr, DAMAGE_USELIFE, cm_ptr->mana_cost, _("過度の集中", "concentrating too hard"));
352 player_ptr->redraw |= PR_HP;
356 if (cm_ptr->mana_cost > cm_ptr->old_csp) {
357 mind_reflection(player_ptr, cm_ptr);
361 player_ptr->csp -= cm_ptr->mana_cost;
362 if (player_ptr->csp < 0)
365 if ((cm_ptr->use_mind == MindKindType::MINDCRAFTER) && (cm_ptr->n == 13)) {
367 player_ptr->csp_frac = 0;
372 * @brief 特殊技能コマンドのメインルーチン /
374 void do_cmd_mind(PlayerType *player_ptr)
377 cm_type *cm_ptr = initialize_cm_type(player_ptr, &tmp_cm);
378 if (cmd_limit_confused(player_ptr) || !MindPowerGetter(player_ptr).get_mind_power(&cm_ptr->n, false))
381 switch_mind_kind(player_ptr, cm_ptr);
382 cm_ptr->spell = mind_powers[enum2i(cm_ptr->use_mind)].info[cm_ptr->n];
383 cm_ptr->chance = cm_ptr->spell.fail;
384 cm_ptr->mana_cost = cm_ptr->spell.mana_cost;
385 decide_mind_ki_chance(player_ptr, cm_ptr);
386 if (!check_mind_hp_mp_sufficiency(player_ptr, cm_ptr))
389 decide_mind_chance(player_ptr, cm_ptr);
390 if (cm_ptr->chance > 95)
393 if (!judge_mind_chance(player_ptr, cm_ptr))
396 mind_turn_passing(player_ptr, cm_ptr);
397 process_hard_concentration(player_ptr, cm_ptr);
398 player_ptr->redraw |= PR_MANA;
399 player_ptr->window_flags |= PW_PLAYER;
400 player_ptr->window_flags |= PW_SPELL;
403 static MindKindType decide_use_mind_browse(PlayerType *player_ptr)
405 switch (player_ptr->pclass) {
406 case PlayerClassType::MINDCRAFTER:
407 return MindKindType::MINDCRAFTER;
408 case PlayerClassType::FORCETRAINER:
409 return MindKindType::KI;
410 case PlayerClassType::BERSERKER:
411 return MindKindType::BERSERKER;
412 case PlayerClassType::NINJA:
413 return MindKindType::NINJUTSU;
414 case PlayerClassType::MIRROR_MASTER:
415 return MindKindType::MIRROR_MASTER;
417 return (MindKindType)0; // 実質PlayerClassType::MINDCRAFTERと同じ.
422 * @brief 現在プレイヤーが使用可能な特殊技能の一覧表示 /
424 void do_cmd_mind_browse(PlayerType *player_ptr)
428 MindKindType use_mind = decide_use_mind_browse(player_ptr);
431 if (!MindPowerGetter(player_ptr).get_mind_power(&n, true)) {
436 term_erase(12, 21, 255);
437 term_erase(12, 20, 255);
438 term_erase(12, 19, 255);
439 term_erase(12, 18, 255);
440 term_erase(12, 17, 255);
441 term_erase(12, 16, 255);
442 shape_buffer(mind_tips[(int)use_mind][n], 62, temp, sizeof(temp));
443 for (int j = 0, line = 17; temp[j]; j += (1 + strlen(&temp[j]))) {
444 prt(&temp[j], line, 15);
449 case MindKindType::MIRROR_MASTER:
450 case MindKindType::NINJUTSU:
451 prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);