OSDN Git Service

61963077b3a916374f668461740050112383df80
[hengbandforosx/hengbandosx.git] / src / spell / spell-info.cpp
1 #include "spell/spell-info.h"
2 #include "io/input-key-requester.h"
3 #include "monster-race/monster-race.h"
4 #include "player/player-class.h"
5 #include "player/player-skill.h"
6 #include "player/player-status-table.h"
7 #include "player/player-status.h"
8 #include "realm/realm-names-table.h"
9 #include "realm/realm-types.h"
10 #include "spell/spells-execution.h"
11 #include "system/floor-type-definition.h"
12 #include "system/monster-race-definition.h"
13 #include "system/monster-type-definition.h"
14 #include "system/player-type-definition.h"
15 #include "term/screen-processor.h"
16 #include "term/term-color-types.h"
17 #include "util/bit-flags-calculator.h"
18 #include "util/int-char-converter.h"
19 #include "view/display-messages.h"
20 #include "world/world.h"
21
22 // 5%
23 static const int extra_min_magic_fail_rate = 2;
24
25 /*!
26  * @brief 呪文の経験値を返す /
27  * Returns experience of a spell
28  * @param caster_ptr プレーヤーへの参照ポインタ
29  * @param spell 呪文ID
30  * @param use_realm 魔法領域
31  * @return 経験値
32  */
33 EXP experience_of_spell(player_type *caster_ptr, SPELL_IDX spell, REALM_IDX use_realm)
34 {
35     if (caster_ptr->pclass == CLASS_SORCERER)
36         return SPELL_EXP_MASTER;
37     else if (caster_ptr->pclass == CLASS_RED_MAGE)
38         return SPELL_EXP_SKILLED;
39     else if (use_realm == caster_ptr->realm1)
40         return caster_ptr->spell_exp[spell];
41     else if (use_realm == caster_ptr->realm2)
42         return caster_ptr->spell_exp[spell + 32];
43     else
44         return 0;
45 }
46
47 /*!
48  * @brief 呪文の消費MPを返す /
49  * Modify mana consumption rate using spell exp and dec_mana
50  * @param caster_ptr プレーヤーへの参照ポインタ
51  * @param need_mana 基本消費MP
52  * @param spell 呪文ID
53  * @param realm 魔法領域
54  * @return 消費MP
55  */
56 MANA_POINT mod_need_mana(player_type *caster_ptr, MANA_POINT need_mana, SPELL_IDX spell, REALM_IDX realm)
57 {
58 #define MANA_CONST 2400
59 #define MANA_DIV 4
60 #define DEC_MANA_DIV 3
61     if ((realm > REALM_NONE) && (realm <= MAX_REALM)) {
62         need_mana = need_mana * (MANA_CONST + SPELL_EXP_EXPERT - experience_of_spell(caster_ptr, spell, realm)) + (MANA_CONST - 1);
63         need_mana *= caster_ptr->dec_mana ? DEC_MANA_DIV : MANA_DIV;
64         need_mana /= MANA_CONST * MANA_DIV;
65         if (need_mana < 1)
66             need_mana = 1;
67     } else {
68         if (caster_ptr->dec_mana)
69             need_mana = (need_mana + 1) * DEC_MANA_DIV / MANA_DIV;
70     }
71
72 #undef DEC_MANA_DIV
73 #undef MANA_DIV
74 #undef MANA_CONST
75
76     return need_mana;
77 }
78
79 /*!
80  * @brief 呪文の失敗率修正処理1(呪い、消費魔力減少、呪文簡易化) /
81  * Modify spell fail rate
82  * Using to_m_chance, dec_mana, easy_spell and heavy_spell
83  * @param caster_ptr プレーヤーへの参照ポインタ
84  * @param chance 修正前失敗率
85  * @return 失敗率(%)
86  * @todo 統合を検討
87  */
88 PERCENTAGE mod_spell_chance_1(player_type *caster_ptr, PERCENTAGE chance)
89 {
90     chance += caster_ptr->to_m_chance;
91
92     if (caster_ptr->heavy_spell)
93         chance += 20;
94
95     if (caster_ptr->dec_mana && caster_ptr->easy_spell)
96         chance -= 4;
97     else if (caster_ptr->easy_spell)
98         chance -= 3;
99     else if (caster_ptr->dec_mana)
100         chance -= 2;
101
102     return chance;
103 }
104
105 /*!
106  * @brief 呪文の失敗率修正処理2(消費魔力減少、呪い、負値修正) /
107  * Modify spell fail rate
108  * Using to_m_chance, dec_mana, easy_spell and heavy_spell
109  * @param caster_ptr プレーヤーへの参照ポインタ
110  * @param chance 修正前失敗率
111  * @return 失敗率(%)
112  * Modify spell fail rate (as "suffix" process)
113  * Using dec_mana, easy_spell and heavy_spell
114  * Note: variable "chance" cannot be negative.
115  * @todo 統合を検討
116  */
117 PERCENTAGE mod_spell_chance_2(player_type *caster_ptr, PERCENTAGE chance)
118 {
119     if (caster_ptr->dec_mana)
120         chance--;
121     if (caster_ptr->heavy_spell)
122         chance += 5;
123     return MAX(chance, 0);
124 }
125
126 /*!
127  * @brief 呪文の失敗率計算メインルーチン /
128  * Returns spell chance of failure for spell -RAK-
129  * @param caster_ptr プレーヤーへの参照ポインタ
130  * @param spell 呪文ID
131  * @param use_realm 魔法領域ID
132  * @return 失敗率(%)
133  */
134 PERCENTAGE spell_chance(player_type *caster_ptr, SPELL_IDX spell, REALM_IDX use_realm)
135 {
136     if (!mp_ptr->spell_book)
137         return 100;
138     if (use_realm == REALM_HISSATSU)
139         return 0;
140
141     const magic_type *s_ptr;
142     if (!is_magic(use_realm)) {
143         s_ptr = &technic_info[use_realm - MIN_TECHNIC][spell];
144     } else {
145         s_ptr = &mp_ptr->info[use_realm - 1][spell];
146     }
147
148     PERCENTAGE chance = s_ptr->sfail;
149     chance -= 3 * (caster_ptr->lev - s_ptr->slevel);
150     chance -= 3 * (adj_mag_stat[caster_ptr->stat_index[mp_ptr->spell_stat]] - 1);
151     if (caster_ptr->riding)
152         chance += (MAX(r_info[caster_ptr->current_floor_ptr->m_list[caster_ptr->riding].r_idx].level - caster_ptr->skill_exp[SKILL_RIDING] / 100 - 10, 0));
153
154     MANA_POINT need_mana = mod_need_mana(caster_ptr, s_ptr->smana, spell, use_realm);
155     if (need_mana > caster_ptr->csp) {
156         chance += 5 * (need_mana - caster_ptr->csp);
157     }
158
159     if ((use_realm != caster_ptr->realm1) && ((caster_ptr->pclass == CLASS_MAGE) || (caster_ptr->pclass == CLASS_PRIEST)))
160         chance += 5;
161
162     PERCENTAGE minfail = adj_mag_fail[caster_ptr->stat_index[mp_ptr->spell_stat]];
163     if (any_bits(mp_ptr->spell_xtra, extra_min_magic_fail_rate)) {
164         if (minfail < 5)
165             minfail = 5;
166     }
167
168     if (((caster_ptr->pclass == CLASS_PRIEST) || (caster_ptr->pclass == CLASS_SORCERER)) && caster_ptr->icky_wield[0])
169         chance += 25;
170     if (((caster_ptr->pclass == CLASS_PRIEST) || (caster_ptr->pclass == CLASS_SORCERER)) && caster_ptr->icky_wield[1])
171         chance += 25;
172
173     chance = mod_spell_chance_1(caster_ptr, chance);
174     PERCENTAGE penalty = (mp_ptr->spell_stat == A_WIS) ? 10 : 4;
175     switch (use_realm) {
176     case REALM_NATURE:
177         if ((caster_ptr->alignment > 50) || (caster_ptr->alignment < -50))
178             chance += penalty;
179         break;
180     case REALM_LIFE:
181     case REALM_CRUSADE:
182         if (caster_ptr->alignment < -20)
183             chance += penalty;
184         break;
185     case REALM_DEATH:
186     case REALM_DAEMON:
187     case REALM_HEX:
188         if (caster_ptr->alignment > 20)
189             chance += penalty;
190         break;
191     }
192
193     if (chance < minfail)
194         chance = minfail;
195
196     if (caster_ptr->stun > 50)
197         chance += 25;
198     else if (caster_ptr->stun)
199         chance += 15;
200
201     if (chance > 95)
202         chance = 95;
203
204     if ((use_realm == caster_ptr->realm1) || (use_realm == caster_ptr->realm2) || (caster_ptr->pclass == CLASS_SORCERER)
205         || (caster_ptr->pclass == CLASS_RED_MAGE)) {
206         EXP exp = experience_of_spell(caster_ptr, spell, use_realm);
207         if (exp >= SPELL_EXP_EXPERT)
208             chance--;
209         if (exp >= SPELL_EXP_MASTER)
210             chance--;
211     }
212
213     return mod_spell_chance_2(caster_ptr, chance);
214 }
215
216 /*!
217  * @brief 呪文情報の表示処理 /
218  * Print a list of spells (for browsing or casting or viewing)
219  * @param caster_ptr 術者の参照ポインタ
220  * @param target_spell 呪文ID
221  * @param spells 表示するスペルID配列の参照ポインタ
222  * @param num 表示するスペルの数(spellsの要素数)
223  * @param y 表示メッセージ左上Y座標
224  * @param x 表示メッセージ左上X座標
225  * @param use_realm 魔法領域ID
226  */
227 void print_spells(player_type *caster_ptr, SPELL_IDX target_spell, SPELL_IDX *spells, int num, TERM_LEN y, TERM_LEN x, REALM_IDX use_realm)
228 {
229     if (((use_realm <= REALM_NONE) || (use_realm > MAX_REALM)) && current_world_ptr->wizard)
230         msg_print(_("警告! print_spell が領域なしに呼ばれた", "Warning! print_spells called with null realm"));
231
232     prt("", y, x);
233     char buf[256];
234     if (use_realm == REALM_HISSATSU)
235         strcpy(buf, _("  Lv   MP", "  Lv   SP"));
236     else
237         strcpy(buf, _("熟練度 Lv   MP 失率 効果", "Profic Lv   SP Fail Effect"));
238
239     put_str(_("名前", "Name"), y, x + 5);
240     put_str(buf, y, x + 29);
241
242     int increment = 64;
243     if ((caster_ptr->pclass == CLASS_SORCERER) || (caster_ptr->pclass == CLASS_RED_MAGE))
244         increment = 0;
245     else if (use_realm == caster_ptr->realm1)
246         increment = 0;
247     else if (use_realm == caster_ptr->realm2)
248         increment = 32;
249
250     int i;
251     int exp_level;
252     const magic_type *s_ptr;
253     char info[80];
254     char out_val[160];
255     char ryakuji[5];
256     bool max = false;
257     for (i = 0; i < num; i++) {
258         SPELL_IDX spell = spells[i];
259
260         if (!is_magic(use_realm)) {
261             s_ptr = &technic_info[use_realm - MIN_TECHNIC][spell];
262         } else {
263             s_ptr = &mp_ptr->info[use_realm - 1][spell];
264         }
265
266         MANA_POINT need_mana;
267         if (use_realm == REALM_HISSATSU)
268             need_mana = s_ptr->smana;
269         else {
270             EXP exp = experience_of_spell(caster_ptr, spell, use_realm);
271             need_mana = mod_need_mana(caster_ptr, s_ptr->smana, spell, use_realm);
272             if ((increment == 64) || (s_ptr->slevel >= 99))
273                 exp_level = EXP_LEVEL_UNSKILLED;
274             else
275                 exp_level = spell_exp_level(exp);
276
277             max = false;
278             if (!increment && (exp_level == EXP_LEVEL_MASTER))
279                 max = true;
280             else if ((increment == 32) && (exp_level >= EXP_LEVEL_EXPERT))
281                 max = true;
282             else if (s_ptr->slevel >= 99)
283                 max = true;
284             else if ((caster_ptr->pclass == CLASS_RED_MAGE) && (exp_level >= EXP_LEVEL_SKILLED))
285                 max = true;
286
287             strncpy(ryakuji, exp_level_str[exp_level], 4);
288             ryakuji[3] = ']';
289             ryakuji[4] = '\0';
290         }
291
292         if (use_menu && target_spell) {
293             if (i == (target_spell - 1))
294                 strcpy(out_val, _("  》 ", "  >  "));
295             else
296                 strcpy(out_val, "     ");
297         } else
298             sprintf(out_val, "  %c) ", I2A(i));
299
300         if (s_ptr->slevel >= 99) {
301             strcat(out_val, format("%-30s", _("(判読不能)", "(illegible)")));
302             c_prt(TERM_L_DARK, out_val, y + i + 1, x);
303             continue;
304         }
305
306         strcpy(info, exe_spell(caster_ptr, use_realm, spell, SPELL_INFO));
307         concptr comment = info;
308         byte line_attr = TERM_WHITE;
309         if ((caster_ptr->pclass == CLASS_SORCERER) || (caster_ptr->pclass == CLASS_RED_MAGE)) {
310             if (s_ptr->slevel > caster_ptr->max_plv) {
311                 comment = _("未知", "unknown");
312                 line_attr = TERM_L_BLUE;
313             } else if (s_ptr->slevel > caster_ptr->lev) {
314                 comment = _("忘却", "forgotten");
315                 line_attr = TERM_YELLOW;
316             }
317         } else if ((use_realm != caster_ptr->realm1) && (use_realm != caster_ptr->realm2)) {
318             comment = _("未知", "unknown");
319             line_attr = TERM_L_BLUE;
320         } else if ((use_realm == caster_ptr->realm1) ? ((caster_ptr->spell_forgotten1 & (1UL << spell))) : ((caster_ptr->spell_forgotten2 & (1UL << spell)))) {
321             comment = _("忘却", "forgotten");
322             line_attr = TERM_YELLOW;
323         } else if (!((use_realm == caster_ptr->realm1) ? (caster_ptr->spell_learned1 & (1UL << spell)) : (caster_ptr->spell_learned2 & (1UL << spell)))) {
324             comment = _("未知", "unknown");
325             line_attr = TERM_L_BLUE;
326         } else if (!((use_realm == caster_ptr->realm1) ? (caster_ptr->spell_worked1 & (1UL << spell)) : (caster_ptr->spell_worked2 & (1UL << spell)))) {
327             comment = _("未経験", "untried");
328             line_attr = TERM_L_GREEN;
329         }
330
331         if (use_realm == REALM_HISSATSU) {
332             strcat(out_val, format("%-25s %2d %4d", exe_spell(caster_ptr, use_realm, spell, SPELL_NAME), s_ptr->slevel, need_mana));
333         } else {
334             strcat(out_val,
335                 format("%-25s%c%-4s %2d %4d %3d%% %s", exe_spell(caster_ptr, use_realm, spell, SPELL_NAME), (max ? '!' : ' '), ryakuji, s_ptr->slevel,
336                     need_mana, spell_chance(caster_ptr, spell, use_realm), comment));
337         }
338
339         c_prt(line_attr, out_val, y + i + 1, x);
340     }
341
342     prt("", y + i + 1, x);
343 }