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/equipment-info.h"
37 #include "player-status/player-energy.h"
38 #include "player/player-class.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 "spell/spell-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 "util/buffer-shaper.h"
51 #include "util/enum-converter.h"
52 #include "view/display-messages.h"
55 * @brief 職業別特殊技能の処理用構造体
57 typedef struct cm_type {
58 mind_kind_type use_mind; //!< 使った職業技能構造体
59 concptr mind_explanation; //!< 特殊技能の説明
60 SPELL_IDX n; //!< 職業種別毎ID
61 int b; //!< 失敗時チャート用乱数
62 PERCENTAGE chance; //!< 失敗率
63 PERCENTAGE minfail; //!< 最低失敗率
64 PLAYER_LEVEL plev; //!< 取得レベル
65 int old_csp; //!< 行使前のMP
66 mind_type spell; //!< 職業技能の基本設定構造体
68 int mana_cost; //!< 最終算出消費MP
69 bool on_mirror; //!< 鏡の上に乗っているどうかの判定
73 * @brief 職業技能処理構造体の初期化
75 static cm_type *initialize_cm_type(player_type *caster_ptr, cm_type *cm_ptr)
80 cm_ptr->plev = caster_ptr->lev;
81 cm_ptr->old_csp = caster_ptr->csp;
82 cm_ptr->on_mirror = false;
87 * @brief 職業別の行使可能な技能種別を構造体に付加する
89 static void switch_mind_kind(player_type *caster_ptr, cm_type *cm_ptr)
91 switch (caster_ptr->pclass) {
92 case CLASS_MINDCRAFTER:
93 cm_ptr->use_mind = mind_kind_type::MINDCRAFTER;
94 cm_ptr->mind_explanation = _("精神", "skill");
96 case CLASS_FORCETRAINER:
97 cm_ptr->use_mind = mind_kind_type::KI;
98 cm_ptr->mind_explanation = _("気", "skill");
100 case CLASS_BERSERKER:
101 cm_ptr->use_mind = mind_kind_type::BERSERKER;
102 cm_ptr->mind_explanation = _("怒り", "skill");
104 case CLASS_MIRROR_MASTER:
105 cm_ptr->use_mind = mind_kind_type::MIRROR_MASTER;
106 cm_ptr->mind_explanation = _("鏡魔法", "skill");
109 cm_ptr->use_mind = mind_kind_type::NINJUTSU;
110 cm_ptr->mind_explanation = _("精神", "skill");
113 cm_ptr->use_mind = (mind_kind_type)0;
114 cm_ptr->mind_explanation = _("超能力", "skill");
119 static void decide_mind_ki_chance(player_type *caster_ptr, cm_type *cm_ptr)
121 if (cm_ptr->use_mind != mind_kind_type::KI)
124 if (heavy_armor(caster_ptr))
125 cm_ptr->chance += 20;
127 if (caster_ptr->is_icky_wield[0])
128 cm_ptr->chance += 20;
129 else if (has_melee_weapon(caster_ptr, INVEN_MAIN_HAND))
130 cm_ptr->chance += 10;
132 if (caster_ptr->is_icky_wield[1])
133 cm_ptr->chance += 20;
134 else if (has_melee_weapon(caster_ptr, INVEN_SUB_HAND))
135 cm_ptr->chance += 10;
138 for (int j = 0; j < get_current_ki(caster_ptr) / 50; j++)
139 cm_ptr->mana_cost += (j + 1) * 3 / 2;
142 static bool check_mind_hp_mp_sufficiency(player_type *caster_ptr, cm_type *cm_ptr)
144 if ((cm_ptr->use_mind == mind_kind_type::BERSERKER) || (cm_ptr->use_mind == mind_kind_type::NINJUTSU)) {
145 if (cm_ptr->mana_cost > caster_ptr->chp) {
146 msg_print(_("HPが足りません。", "You do not have enough hp to use this power."));
153 if (cm_ptr->mana_cost <= caster_ptr->csp)
156 msg_print(_("MPが足りません。", "You do not have enough mana to use this power."));
160 return get_check(_("それでも挑戦しますか? ", "Attempt it anyway? "));
163 static void decide_mind_chance(player_type *caster_ptr, cm_type *cm_ptr)
165 if (cm_ptr->chance == 0)
168 cm_ptr->chance -= 3 * (cm_ptr->plev - cm_ptr->spell.min_lev);
169 cm_ptr->chance += caster_ptr->to_m_chance;
170 cm_ptr->chance -= 3 * (adj_mag_stat[caster_ptr->stat_index[mp_ptr->spell_stat]] - 1);
171 if ((cm_ptr->mana_cost > caster_ptr->csp) && (cm_ptr->use_mind != mind_kind_type::BERSERKER) && (cm_ptr->use_mind != mind_kind_type::NINJUTSU))
172 cm_ptr->chance += 5 * (cm_ptr->mana_cost - caster_ptr->csp);
174 cm_ptr->minfail = adj_mag_fail[caster_ptr->stat_index[mp_ptr->spell_stat]];
175 if (cm_ptr->chance < cm_ptr->minfail)
176 cm_ptr->chance = cm_ptr->minfail;
178 if (caster_ptr->stun > 50)
179 cm_ptr->chance += 25;
180 else if (caster_ptr->stun)
181 cm_ptr->chance += 15;
183 if (cm_ptr->use_mind != mind_kind_type::KI)
186 if (heavy_armor(caster_ptr))
189 if (caster_ptr->is_icky_wield[0])
192 if (caster_ptr->is_icky_wield[1])
196 static void check_mind_mindcrafter(player_type *caster_ptr, cm_type *cm_ptr)
198 if (cm_ptr->use_mind != mind_kind_type::MINDCRAFTER)
202 msg_print(_("なんてこった!頭の中が真っ白になった!", "Oh, no! Your mind has gone blank!"));
203 lose_all_info(caster_ptr);
207 if (cm_ptr->b < 15) {
208 msg_print(_("奇妙な光景が目の前で踊っている...", "Weird visions seem to dance before your eyes..."));
209 set_image(caster_ptr, caster_ptr->image + 5 + randint1(10));
213 if (cm_ptr->b < 45) {
214 msg_print(_("あなたの頭は混乱した!", "Your brain is addled!"));
215 set_confused(caster_ptr, caster_ptr->confused + randint1(8));
219 if (cm_ptr->b < 90) {
220 set_stun(caster_ptr, caster_ptr->stun + randint1(8));
224 msg_format(_("%sの力が制御できない氾流となって解放された!", "Your mind unleashes its power in an uncontrollable storm!"), cm_ptr->mind_explanation);
225 project(caster_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + cm_ptr->plev / 10, caster_ptr->y, caster_ptr->x, cm_ptr->plev * 2, GF_MANA,
226 PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
227 caster_ptr->csp = MAX(0, caster_ptr->csp - cm_ptr->plev * MAX(1, cm_ptr->plev / 10));
230 static void check_mind_mirror_master(player_type *caster_ptr, cm_type *cm_ptr)
232 if (cm_ptr->use_mind != mind_kind_type::MIRROR_MASTER)
238 if (cm_ptr->b < 81) {
239 msg_print(_("鏡の世界の干渉を受けた!", "Weird visions seem to dance before your eyes..."));
240 teleport_player(caster_ptr, 10, TELEPORT_PASSIVE);
244 if (cm_ptr->b < 96) {
245 msg_print(_("まわりのものがキラキラ輝いている!", "Your brain is addled!"));
246 set_image(caster_ptr, caster_ptr->image + 5 + randint1(10));
250 msg_format(_("%sの力が制御できない氾流となって解放された!", "Your mind unleashes its power in an uncontrollable storm!"), cm_ptr->mind_explanation);
251 project(caster_ptr, PROJECT_WHO_UNCTRL_POWER, 2 + cm_ptr->plev / 10, caster_ptr->y, caster_ptr->x, cm_ptr->plev * 2, GF_MANA,
252 PROJECT_JUMP | PROJECT_KILL | PROJECT_GRID | PROJECT_ITEM);
253 caster_ptr->csp = MAX(0, caster_ptr->csp - cm_ptr->plev * MAX(1, cm_ptr->plev / 10));
256 static void check_mind_class(player_type *caster_ptr, cm_type *cm_ptr)
258 if ((cm_ptr->use_mind == mind_kind_type::BERSERKER) || (cm_ptr->use_mind == mind_kind_type::NINJUTSU))
261 if ((cm_ptr->use_mind == mind_kind_type::KI) && (cm_ptr->n != 5) && get_current_ki(caster_ptr)) {
262 msg_print(_("気が散ってしまった...", "Your improved Force has gone away..."));
263 set_current_ki(caster_ptr, true, 0);
266 if (randint1(100) >= (cm_ptr->chance / 2))
269 cm_ptr->b = randint1(100);
270 check_mind_mindcrafter(caster_ptr, cm_ptr);
271 check_mind_mirror_master(caster_ptr, cm_ptr);
274 static bool switch_mind_class(player_type *caster_ptr, cm_type *cm_ptr)
276 switch (cm_ptr->use_mind) {
277 case mind_kind_type::MINDCRAFTER:
278 cm_ptr->cast = cast_mindcrafter_spell(caster_ptr, static_cast<mind_mindcrafter_type>(cm_ptr->n));
280 case mind_kind_type::KI:
281 cm_ptr->cast = cast_force_spell(caster_ptr, static_cast<mind_force_trainer_type>(cm_ptr->n));
283 case mind_kind_type::BERSERKER:
284 cm_ptr->cast = cast_berserk_spell(caster_ptr, static_cast<mind_berserker_type>(cm_ptr->n));
286 case mind_kind_type::MIRROR_MASTER:
287 if (caster_ptr->current_floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].is_mirror())
288 cm_ptr->on_mirror = true;
290 cm_ptr->cast = cast_mirror_spell(caster_ptr, static_cast<mind_mirror_master_type>(cm_ptr->n));
292 case mind_kind_type::NINJUTSU:
293 cm_ptr->cast = cast_ninja_spell(caster_ptr, static_cast<mind_ninja_type>(cm_ptr->n));
296 msg_format(_("謎の能力:%d, %d", "Mystery power:%d, %d"), cm_ptr->use_mind, cm_ptr->n);
301 static void mind_turn_passing(player_type *caster_ptr, cm_type *cm_ptr)
303 PlayerEnergy energy(caster_ptr);
304 if (cm_ptr->on_mirror && (caster_ptr->pclass == CLASS_MIRROR_MASTER)) {
305 if (cm_ptr->n == 3 || cm_ptr->n == 5 || cm_ptr->n == 7 || cm_ptr->n == 16) {
306 energy.set_player_turn_energy(50);
311 energy.set_player_turn_energy(100);
314 static bool judge_mind_chance(player_type *caster_ptr, cm_type *cm_ptr)
316 if (randint0(100) >= cm_ptr->chance) {
318 return switch_mind_class(caster_ptr, cm_ptr) && cm_ptr->cast;
324 msg_format(_("%sの集中に失敗した!", "You failed to concentrate hard enough for %s!"), cm_ptr->mind_explanation);
326 check_mind_class(caster_ptr, cm_ptr);
330 static void mind_reflection(player_type *caster_ptr, cm_type *cm_ptr)
332 int oops = cm_ptr->mana_cost - cm_ptr->old_csp;
333 if ((caster_ptr->csp - cm_ptr->mana_cost) < 0)
334 caster_ptr->csp_frac = 0;
336 caster_ptr->csp = MAX(0, caster_ptr->csp - cm_ptr->mana_cost);
337 msg_format(_("%sを集中しすぎて気を失ってしまった!", "You faint from the effort!"), cm_ptr->mind_explanation);
338 (void)set_paralyzed(caster_ptr, caster_ptr->paralyzed + randint1(5 * oops + 1));
339 if (randint0(100) >= 50)
342 bool perm = randint0(100) < 25;
343 msg_print(_("自分の精神を攻撃してしまった!", "You have damaged your mind!"));
344 (void)dec_stat(caster_ptr, A_WIS, 15 + randint1(10), perm);
347 static void process_hard_concentration(player_type *caster_ptr, cm_type *cm_ptr)
349 if ((cm_ptr->use_mind == mind_kind_type::BERSERKER) || (cm_ptr->use_mind == mind_kind_type::NINJUTSU)) {
350 take_hit(caster_ptr, DAMAGE_USELIFE, cm_ptr->mana_cost, _("過度の集中", "concentrating too hard"));
351 caster_ptr->redraw |= PR_HP;
355 if (cm_ptr->mana_cost > cm_ptr->old_csp) {
356 mind_reflection(caster_ptr, cm_ptr);
360 caster_ptr->csp -= cm_ptr->mana_cost;
361 if (caster_ptr->csp < 0)
364 if ((cm_ptr->use_mind == mind_kind_type::MINDCRAFTER) && (cm_ptr->n == 13)) {
366 caster_ptr->csp_frac = 0;
371 * @brief 特殊技能コマンドのメインルーチン /
373 void do_cmd_mind(player_type *caster_ptr)
376 cm_type *cm_ptr = initialize_cm_type(caster_ptr, &tmp_cm);
377 if (cmd_limit_confused(caster_ptr) || !MindPowerGetter(caster_ptr).get_mind_power(&cm_ptr->n, false))
380 switch_mind_kind(caster_ptr, cm_ptr);
381 cm_ptr->spell = mind_powers[enum2i(cm_ptr->use_mind)].info[cm_ptr->n];
382 cm_ptr->chance = cm_ptr->spell.fail;
383 cm_ptr->mana_cost = cm_ptr->spell.mana_cost;
384 decide_mind_ki_chance(caster_ptr, cm_ptr);
385 if (!check_mind_hp_mp_sufficiency(caster_ptr, cm_ptr))
388 decide_mind_chance(caster_ptr, cm_ptr);
389 if (cm_ptr->chance > 95)
392 if (!judge_mind_chance(caster_ptr, cm_ptr))
395 mind_turn_passing(caster_ptr, cm_ptr);
396 process_hard_concentration(caster_ptr, cm_ptr);
397 caster_ptr->redraw |= PR_MANA;
398 caster_ptr->window_flags |= PW_PLAYER;
399 caster_ptr->window_flags |= PW_SPELL;
402 static mind_kind_type decide_use_mind_browse(player_type *caster_ptr)
404 switch (caster_ptr->pclass) {
405 case CLASS_MINDCRAFTER:
406 return mind_kind_type::MINDCRAFTER;
407 case CLASS_FORCETRAINER:
408 return mind_kind_type::KI;
409 case CLASS_BERSERKER:
410 return mind_kind_type::BERSERKER;
412 return mind_kind_type::NINJUTSU;
413 case CLASS_MIRROR_MASTER:
414 return mind_kind_type::MIRROR_MASTER;
416 return (mind_kind_type)0; // 実質CLASS_MINDCRAFTERと同じ.
421 * @brief 現在プレイヤーが使用可能な特殊技能の一覧表示 /
423 void do_cmd_mind_browse(player_type *caster_ptr)
427 mind_kind_type use_mind = decide_use_mind_browse(caster_ptr);
430 if (!MindPowerGetter(caster_ptr).get_mind_power(&n, true)) {
435 term_erase(12, 21, 255);
436 term_erase(12, 20, 255);
437 term_erase(12, 19, 255);
438 term_erase(12, 18, 255);
439 term_erase(12, 17, 255);
440 term_erase(12, 16, 255);
441 shape_buffer(mind_tips[(int)use_mind][n], 62, temp, sizeof(temp));
442 for (int j = 0, line = 17; temp[j]; j += (1 + strlen(&temp[j]))) {
443 prt(&temp[j], line, 15);
448 case mind_kind_type::MIRROR_MASTER:
449 case mind_kind_type::NINJUTSU:
450 prt(_("何かキーを押して下さい。", "Hit any key."), 0, 0);