1 #include "mind/mind-power-getter.h"
2 #include "core/asking-player.h"
3 #include "core/stuff-handler.h"
4 #include "core/window-redrawer.h"
5 #include "game-option/text-display-options.h"
6 #include "inventory/inventory-slot-types.h"
7 #include "io/command-repeater.h"
8 #include "io/input-key-requester.h"
9 #include "main/sound-of-music.h"
10 #include "mind/mind-explanations-table.h"
11 #include "mind/mind-force-trainer.h"
12 #include "mind/mind-info.h"
13 #include "mind/mind-types.h"
14 #include "player-info/class-info.h"
15 #include "player-info/equipment-info.h"
16 #include "player/player-status-table.h"
17 #include "system/player-type-definition.h"
18 #include "term/screen-processor.h"
19 #include "timed-effect/player-stun.h"
20 #include "timed-effect/timed-effects.h"
21 #include "util/enum-converter.h"
22 #include "util/int-char-converter.h"
24 MindPowerGetter::MindPowerGetter(PlayerType *player_ptr)
25 : player_ptr(player_ptr)
26 , menu_line(use_menu ? 1 : 0)
31 * @brief 使用可能な特殊技能を選択する /
32 * Allow user to choose a mindcrafter power.
33 * @param sn 選択した特殊技能ID、キャンセルの場合-1、不正な選択の場合-2を返す
34 * @param only_browse 一覧を見るだけの場合trueを返す
35 * @return 発動可能な魔法を選択した場合true、キャンセル処理か不正な選択が行われた場合falseを返す。
37 * If a valid spell is chosen, saves it in '*sn' and returns true\n
38 * If the user hits escape, returns false, and set '*sn' to -1\n
39 * If there are no legal choices, returns false, and sets '*sn' to -2\n
41 * The "prompt" should be "cast", "recite", or "study"\n
42 * The "known" should be true for cast/pray, false for study\n
44 * nb: This function has a (trivial) display bug which will be obvious\n
45 * when you run it. It's probably easy to fix but I haven't tried,\n
48 bool MindPowerGetter::get_mind_power(SPELL_IDX *sn, bool only_browse)
50 select_mind_description();
51 if (select_spell_index(sn)) {
55 for (this->index = 0; this->index < MAX_MIND_POWERS; this->index++) {
56 if (mind_ptr->info[this->index].min_lev <= this->player_ptr->lev) {
63 (void)strnfmt(out_val, 78, _("(%^s %c-%c, '*'で一覧, ESC) どの%sについて知りますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
64 this->mind_description, I2A(0), I2A(this->num - 1), this->mind_description);
66 (void)strnfmt(out_val, 78, _("(%^s %c-%c, '*'で一覧, ESC) どの%sを使いますか?", "(%^ss %c-%c, *=List, ESC=exit) Use which %s? "),
67 this->mind_description, I2A(0), I2A(this->num - 1), this->mind_description);
70 if (use_menu && !only_browse) {
74 this->choice = (always_show_list || use_menu) ? ESCAPE : 1;
75 decide_mind_choice(out_val, only_browse);
76 if (this->redraw && !only_browse) {
80 this->player_ptr->window_flags |= PW_SPELL;
81 handle_stuff(this->player_ptr);
87 repeat_push((COMMAND_CODE)this->index);
92 * @brief 職業ごとの特殊技能表記を取得する
94 void MindPowerGetter::select_mind_description()
96 switch (this->player_ptr->pclass)
97 case PlayerClassType::MINDCRAFTER: {
98 this->use_mind = MindKindType::MINDCRAFTER;
99 this->mind_description = _("超能力", "mindcraft");
101 case PlayerClassType::FORCETRAINER:
102 this->use_mind = MindKindType::KI;
103 this->mind_description = _("練気術", "Force");
105 case PlayerClassType::BERSERKER:
106 this->use_mind = MindKindType::BERSERKER;
107 this->mind_description = _("技", "brutal power");
109 case PlayerClassType::MIRROR_MASTER:
110 this->use_mind = MindKindType::MIRROR_MASTER;
111 this->mind_description = _("鏡魔法", "magic");
113 case PlayerClassType::NINJA:
114 this->use_mind = MindKindType::NINJUTSU;
115 this->mind_description = _("忍術", "ninjutsu");
118 this->use_mind = MindKindType::MINDCRAFTER;
119 this->mind_description = _("超能力", "mindcraft");
124 bool MindPowerGetter::select_spell_index(SPELL_IDX *sn)
127 this->mind_ptr = &mind_powers[enum2i(this->use_mind)];
129 if (!repeat_pull(&code)) {
133 *sn = (SPELL_IDX)code;
134 if (*sn == INVEN_FORCE) {
135 (void)repeat_pull(&code);
138 *sn = (SPELL_IDX)code;
139 return mind_ptr->info[*sn].min_lev <= this->player_ptr->lev;
142 bool MindPowerGetter::decide_mind_choice(char *out_val, const bool only_browse)
144 while (!this->flag) {
145 if (this->choice == ESCAPE) {
147 } else if (!get_com(out_val, &this->choice, true)) {
151 if (!interpret_mind_key_input(only_browse)) {
155 if (display_minds_chance(only_browse)) {
160 if ((this->index < 0) || (this->index >= this->num)) {
165 this->spell = &mind_ptr->info[this->index];
168 (void)strnfmt(tmp_val, 78, _("%sを使いますか?", "Use %s? "), this->spell->name);
169 if (!get_check(tmp_val)) {
180 bool MindPowerGetter::interpret_mind_key_input(const bool only_browse)
182 if (!use_menu || this->choice == ' ') {
186 switch (this->choice) {
196 this->menu_line += (this->num - 1);
207 this->index = this->menu_line - 1;
214 if (this->menu_line > this->num) {
215 this->menu_line -= this->num;
221 bool MindPowerGetter::display_minds_chance(const bool only_browse)
223 if ((this->choice != ' ') && (this->choice != '*') && (this->choice != '?') && (!use_menu || !this->ask)) {
227 if (!this->redraw || use_menu) {
229 if (!only_browse && !use_menu) {
234 put_str(_("名前", "Name"), y, x + 5);
235 put_str(format(_("Lv %s 失率 効果", "Lv %s Fail Info"),
236 ((this->use_mind == MindKindType::BERSERKER) || (this->use_mind == MindKindType::NINJUTSU)) ? "HP" : "MP"),
238 display_each_mind_chance();
239 prt("", y + this->index + 1, x);
247 this->redraw = false;
252 void MindPowerGetter::display_each_mind_chance()
255 has_weapon[0] = has_melee_weapon(this->player_ptr, INVEN_MAIN_HAND);
256 has_weapon[1] = has_melee_weapon(this->player_ptr, INVEN_SUB_HAND);
257 for (this->index = 0; this->index < MAX_MIND_POWERS; this->index++) {
258 this->spell = &mind_ptr->info[this->index];
259 if (this->spell->min_lev > this->player_ptr->lev) {
263 calculate_mind_chance(has_weapon);
265 mindcraft_info(this->player_ptr, comment, this->use_mind, this->index);
268 if (this->index == (this->menu_line - 1)) {
269 strcpy(psi_desc, _(" 》 ", " > "));
271 strcpy(psi_desc, " ");
274 sprintf(psi_desc, " %c) ", I2A(this->index));
278 format("%-30s%2d %4d%s %3d%%%s", this->spell->name, this->spell->min_lev, mana_cost,
279 (((this->use_mind == MindKindType::MINDCRAFTER) && (this->index == 13)) ? _("~", "~ ") : " "), chance, comment));
280 prt(psi_desc, y + this->index + 1, x);
284 void MindPowerGetter::calculate_mind_chance(bool *has_weapon)
286 this->chance = this->spell->fail;
287 this->mana_cost = this->spell->mana_cost;
288 if (this->chance == 0) {
292 this->chance -= 3 * (this->player_ptr->lev - this->spell->min_lev);
293 this->chance -= 3 * (adj_mag_stat[this->player_ptr->stat_index[mp_ptr->spell_stat]] - 1);
294 calculate_ki_chance(has_weapon);
295 if ((this->use_mind != MindKindType::BERSERKER) && (this->use_mind != MindKindType::NINJUTSU) && (this->mana_cost > this->player_ptr->csp)) {
296 this->chance += 5 * (this->mana_cost - this->player_ptr->csp);
299 this->chance += this->player_ptr->to_m_chance;
300 PERCENTAGE minfail = adj_mag_fail[this->player_ptr->stat_index[mp_ptr->spell_stat]];
301 if (this->chance < minfail) {
302 this->chance = minfail;
305 auto player_stun = this->player_ptr->effects()->stun();
306 this->chance += player_stun->get_magic_chance_penalty();
308 if (this->chance > 95) {
313 void MindPowerGetter::calculate_ki_chance(bool *has_weapon)
315 if (this->use_mind != MindKindType::KI) {
319 if (heavy_armor(this->player_ptr))
322 if (this->player_ptr->is_icky_wield[0]) {
324 } else if (has_weapon[0]) {
328 if (this->player_ptr->is_icky_wield[1]) {
330 } else if (has_weapon[1]) {
334 if (this->index == 5) {
335 for (auto j = 0; j < get_current_ki(this->player_ptr) / 50; j++) {
336 this->mana_cost += (j + 1) * 3 / 2;
341 void MindPowerGetter::add_ki_chance()
343 if (this->use_mind != MindKindType::KI) {
347 if (heavy_armor(this->player_ptr)) {
351 if (this->player_ptr->is_icky_wield[0]) {
355 if (this->player_ptr->is_icky_wield[1]) {
360 void MindPowerGetter::make_choice_lower()
366 this->ask = (bool)isupper(this->choice);
368 this->choice = (char)tolower(this->choice);
371 this->index = (islower(this->choice) ? A2I(this->choice) : -1);