1 #include "spell/spell-info.h"
2 #include "game-option/game-play-options.h"
3 #include "io/input-key-requester.h"
4 #include "monster-race/monster-race.h"
5 #include "player-info/class-info.h"
6 #include "player/player-skill.h"
7 #include "player/player-status-table.h"
8 #include "player/player-status.h"
9 #include "realm/realm-names-table.h"
10 #include "realm/realm-types.h"
11 #include "spell/spells-execution.h"
12 #include "system/floor-type-definition.h"
13 #include "system/monster-race-definition.h"
14 #include "system/monster-type-definition.h"
15 #include "system/player-type-definition.h"
16 #include "term/screen-processor.h"
17 #include "term/term-color-types.h"
18 #include "timed-effect/player-stun.h"
19 #include "timed-effect/timed-effects.h"
20 #include "util/bit-flags-calculator.h"
21 #include "util/int-char-converter.h"
22 #include "view/display-messages.h"
25 static const int extra_min_magic_fail_rate = 2;
29 * Modify mana consumption rate using spell exp and dec_mana
30 * @param player_ptr プレイヤーへの参照ポインタ
31 * @param need_mana 基本消費MP
36 MANA_POINT mod_need_mana(player_type *player_ptr, MANA_POINT need_mana, SPELL_IDX spell, int16_t realm)
38 #define MANA_CONST 2400
40 #define DEC_MANA_DIV 3
41 if ((realm > REALM_NONE) && (realm <= MAX_REALM)) {
42 need_mana = need_mana * (MANA_CONST + PlayerSkill::spell_exp_at(PlayerSkillRank::EXPERT) - PlayerSkill(player_ptr).exp_of_spell(realm, spell)) + (MANA_CONST - 1);
43 need_mana *= player_ptr->dec_mana ? DEC_MANA_DIV : MANA_DIV;
44 need_mana /= MANA_CONST * MANA_DIV;
48 if (player_ptr->dec_mana)
49 need_mana = (need_mana + 1) * DEC_MANA_DIV / MANA_DIV;
60 * @brief 呪文の失敗率修正処理1(呪い、消費魔力減少、呪文簡易化) /
61 * Modify spell fail rate
62 * Using to_m_chance, dec_mana, easy_spell and heavy_spell
63 * @param player_ptr プレイヤーへの参照ポインタ
64 * @param chance 修正前失敗率
68 PERCENTAGE mod_spell_chance_1(player_type *player_ptr, PERCENTAGE chance)
70 chance += player_ptr->to_m_chance;
72 if (player_ptr->heavy_spell)
75 if (player_ptr->dec_mana && player_ptr->easy_spell)
77 else if (player_ptr->easy_spell)
79 else if (player_ptr->dec_mana)
86 * @brief 呪文の失敗率修正処理2(消費魔力減少、呪い、負値修正) /
87 * Modify spell fail rate
88 * Using to_m_chance, dec_mana, easy_spell and heavy_spell
89 * @param player_ptr プレイヤーへの参照ポインタ
90 * @param chance 修正前失敗率
92 * Modify spell fail rate (as "suffix" process)
93 * Using dec_mana, easy_spell and heavy_spell
94 * Note: variable "chance" cannot be negative.
97 PERCENTAGE mod_spell_chance_2(player_type *player_ptr, PERCENTAGE chance)
99 if (player_ptr->dec_mana)
101 if (player_ptr->heavy_spell)
103 return std::max(chance, 0);
107 * @brief 呪文の失敗率計算メインルーチン /
108 * Returns spell chance of failure for spell -RAK-
109 * @param player_ptr プレイヤーへの参照ポインタ
111 * @param use_realm 魔法領域ID
114 PERCENTAGE spell_chance(player_type *player_ptr, SPELL_IDX spell, int16_t use_realm)
116 if (mp_ptr->spell_book == ItemKindType::NONE)
118 if (use_realm == REALM_HISSATSU)
121 const magic_type *s_ptr;
122 if (!is_magic(use_realm)) {
123 s_ptr = &technic_info[use_realm - MIN_TECHNIC][spell];
125 s_ptr = &mp_ptr->info[use_realm - 1][spell];
128 PERCENTAGE chance = s_ptr->sfail;
129 chance -= 3 * (player_ptr->lev - s_ptr->slevel);
130 chance -= 3 * (adj_mag_stat[player_ptr->stat_index[mp_ptr->spell_stat]] - 1);
131 if (player_ptr->riding)
132 chance += (std::max(r_info[player_ptr->current_floor_ptr->m_list[player_ptr->riding].r_idx].level - player_ptr->skill_exp[PlayerSkillKindType::RIDING] / 100 - 10, 0));
134 MANA_POINT need_mana = mod_need_mana(player_ptr, s_ptr->smana, spell, use_realm);
135 if (need_mana > player_ptr->csp) {
136 chance += 5 * (need_mana - player_ptr->csp);
139 if ((use_realm != player_ptr->realm1) && ((player_ptr->pclass == PlayerClassType::MAGE) || (player_ptr->pclass == PlayerClassType::PRIEST)))
142 PERCENTAGE minfail = adj_mag_fail[player_ptr->stat_index[mp_ptr->spell_stat]];
143 if (any_bits(mp_ptr->spell_xtra, extra_min_magic_fail_rate)) {
148 if (((player_ptr->pclass == PlayerClassType::PRIEST) || (player_ptr->pclass == PlayerClassType::SORCERER)) && player_ptr->is_icky_wield[0])
150 if (((player_ptr->pclass == PlayerClassType::PRIEST) || (player_ptr->pclass == PlayerClassType::SORCERER)) && player_ptr->is_icky_wield[1])
153 chance = mod_spell_chance_1(player_ptr, chance);
154 PERCENTAGE penalty = (mp_ptr->spell_stat == A_WIS) ? 10 : 4;
157 if ((player_ptr->alignment > 50) || (player_ptr->alignment < -50))
162 if (player_ptr->alignment < -20)
168 if (player_ptr->alignment > 20)
173 if (chance < minfail)
176 auto player_stun = player_ptr->effects()->stun();
177 chance += player_stun->get_magic_chance_penalty();
182 if ((use_realm == player_ptr->realm1) || (use_realm == player_ptr->realm2) || (player_ptr->pclass == PlayerClassType::SORCERER)
183 || (player_ptr->pclass == PlayerClassType::RED_MAGE)) {
184 auto exp = PlayerSkill(player_ptr).exp_of_spell(use_realm, spell);
185 if (exp >= PlayerSkill::spell_exp_at(PlayerSkillRank::EXPERT))
187 if (exp >= PlayerSkill::spell_exp_at(PlayerSkillRank::MASTER))
191 return mod_spell_chance_2(player_ptr, chance);
196 * Print a list of spells (for browsing or casting or viewing)
197 * @param player_ptr 術者の参照ポインタ
198 * @param target_spell 呪文ID
199 * @param spells 表示するスペルID配列の参照ポインタ
200 * @param num 表示するスペルの数(spellsの要素数)
201 * @param y 表示メッセージ左上Y座標
202 * @param x 表示メッセージ左上X座標
203 * @param use_realm 魔法領域ID
205 void print_spells(player_type *player_ptr, SPELL_IDX target_spell, SPELL_IDX *spells, int num, TERM_LEN y, TERM_LEN x, int16_t use_realm)
207 if (((use_realm <= REALM_NONE) || (use_realm > MAX_REALM)) && allow_debug_options)
208 msg_print(_("警告! print_spell が領域なしに呼ばれた", "Warning! print_spells called with null realm"));
212 if (use_realm == REALM_HISSATSU)
213 strcpy(buf, _(" Lv MP", " Lv SP"));
215 strcpy(buf, _("熟練度 Lv MP 失率 効果", "Profic Lv SP Fail Effect"));
217 put_str(_("名前", "Name"), y, x + 5);
218 put_str(buf, y, x + 29);
221 if ((player_ptr->pclass == PlayerClassType::SORCERER) || (player_ptr->pclass == PlayerClassType::RED_MAGE))
223 else if (use_realm == player_ptr->realm1)
225 else if (use_realm == player_ptr->realm2)
229 const magic_type *s_ptr;
234 for (i = 0; i < num; i++) {
235 SPELL_IDX spell = spells[i];
237 if (!is_magic(use_realm)) {
238 s_ptr = &technic_info[use_realm - MIN_TECHNIC][spell];
240 s_ptr = &mp_ptr->info[use_realm - 1][spell];
243 MANA_POINT need_mana;
244 if (use_realm == REALM_HISSATSU)
245 need_mana = s_ptr->smana;
247 auto exp = PlayerSkill(player_ptr).exp_of_spell(use_realm, spell);
248 need_mana = mod_need_mana(player_ptr, s_ptr->smana, spell, use_realm);
249 PlayerSkillRank skill_rank;
250 if ((increment == 64) || (s_ptr->slevel >= 99))
251 skill_rank = PlayerSkillRank::UNSKILLED;
253 skill_rank = PlayerSkill::spell_skill_rank(exp);
256 if (!increment && (skill_rank == PlayerSkillRank::MASTER))
258 else if ((increment == 32) && (skill_rank >= PlayerSkillRank::EXPERT))
260 else if (s_ptr->slevel >= 99)
262 else if ((player_ptr->pclass == PlayerClassType::RED_MAGE) && (skill_rank >= PlayerSkillRank::SKILLED))
265 strncpy(ryakuji, PlayerSkill::skill_rank_str(skill_rank), 4);
270 if (use_menu && target_spell) {
271 if (i == (target_spell - 1))
272 strcpy(out_val, _(" 》 ", " > "));
274 strcpy(out_val, " ");
276 sprintf(out_val, " %c) ", I2A(i));
278 if (s_ptr->slevel >= 99) {
279 strcat(out_val, format("%-30s", _("(判読不能)", "(illegible)")));
280 c_prt(TERM_L_DARK, out_val, y + i + 1, x);
284 strcpy(info, exe_spell(player_ptr, use_realm, spell, SPELL_INFO));
285 concptr comment = info;
286 byte line_attr = TERM_WHITE;
287 if ((player_ptr->pclass == PlayerClassType::SORCERER) || (player_ptr->pclass == PlayerClassType::RED_MAGE)) {
288 if (s_ptr->slevel > player_ptr->max_plv) {
289 comment = _("未知", "unknown");
290 line_attr = TERM_L_BLUE;
291 } else if (s_ptr->slevel > player_ptr->lev) {
292 comment = _("忘却", "forgotten");
293 line_attr = TERM_YELLOW;
295 } else if ((use_realm != player_ptr->realm1) && (use_realm != player_ptr->realm2)) {
296 comment = _("未知", "unknown");
297 line_attr = TERM_L_BLUE;
298 } else if ((use_realm == player_ptr->realm1) ? ((player_ptr->spell_forgotten1 & (1UL << spell))) : ((player_ptr->spell_forgotten2 & (1UL << spell)))) {
299 comment = _("忘却", "forgotten");
300 line_attr = TERM_YELLOW;
301 } else if (!((use_realm == player_ptr->realm1) ? (player_ptr->spell_learned1 & (1UL << spell)) : (player_ptr->spell_learned2 & (1UL << spell)))) {
302 comment = _("未知", "unknown");
303 line_attr = TERM_L_BLUE;
304 } else if (!((use_realm == player_ptr->realm1) ? (player_ptr->spell_worked1 & (1UL << spell)) : (player_ptr->spell_worked2 & (1UL << spell)))) {
305 comment = _("未経験", "untried");
306 line_attr = TERM_L_GREEN;
309 if (use_realm == REALM_HISSATSU) {
310 strcat(out_val, format("%-25s %2d %4d", exe_spell(player_ptr, use_realm, spell, SPELL_NAME), s_ptr->slevel, need_mana));
313 format("%-25s%c%-4s %2d %4d %3d%% %s", exe_spell(player_ptr, use_realm, spell, SPELL_NAME), (max ? '!' : ' '), ryakuji, s_ptr->slevel,
314 need_mana, spell_chance(player_ptr, spell, use_realm), comment));
317 c_prt(line_attr, out_val, y + i + 1, x);
320 prt("", y + i + 1, x);