OSDN Git Service

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