OSDN Git Service

[fix] #41503 超能力者でゲームを開始しようとするとクラッシュ
[hengband/hengband.git] / src / blue-magic / learnt-power-getter.c
1 #include "blue-magic/learnt-power-getter.h"
2 #include "blue-magic/blue-magic-checker.h"
3 #include "blue-magic/learnt-info.h"
4 #include "core/asking-player.h"
5 #include "core/stuff-handler.h"
6 #include "core/window-redrawer.h"
7 #include "game-option/text-display-options.h"
8 #include "io/command-repeater.h"
9 #include "io/input-key-acceptor.h"
10 #include "io/input-key-requester.h"
11 #include "main/sound-of-music.h"
12 #include "mind/mind-blue-mage.h"
13 #include "mspell/monster-power-table.h"
14 #include "realm/realm-types.h"
15 #include "spell/spell-info.h"
16 #include "term/screen-processor.h"
17 #include "util/int-char-converter.h"
18 #include "view/display-messages.h"
19 #include "player/player-status-table.h"
20
21 typedef struct learnt_magic_type {
22     int blue_magic_num;
23     int count;
24     TERM_LEN y;
25     TERM_LEN x;
26     PLAYER_LEVEL plev;
27     PERCENTAGE chance;
28     int ask;
29     int mode;
30     int blue_magics[MAX_MONSPELLS];
31     char choice;
32     char out_val[160];
33     char comment[80];
34     BIT_FLAGS f4;
35     BIT_FLAGS f5;
36     BIT_FLAGS f6;
37     monster_power spell;
38     int menu_line;
39     bool flag;
40     bool redraw;
41     int need_mana;
42     char psi_desc[80];
43 } learnt_magic_type;
44
45 static learnt_magic_type *initialize_lenat_magic_type(player_type *caster_ptr, learnt_magic_type *lm_ptr)
46 {
47     lm_ptr->blue_magic_num = 0;
48     lm_ptr->count = 0;
49     lm_ptr->y = 1;
50     lm_ptr->x = 18;
51     lm_ptr->plev = caster_ptr->lev;
52     lm_ptr->chance = 0;
53     lm_ptr->ask = TRUE;
54     lm_ptr->mode = 0;
55     lm_ptr->f4 = 0L;
56     lm_ptr->f5 = 0L;
57     lm_ptr->f6 = 0L;
58     lm_ptr->menu_line = use_menu ? 1 : 0;
59     lm_ptr->flag = FALSE;
60     lm_ptr->redraw = FALSE;
61     return lm_ptr;
62 }
63
64 /*!
65  * @brief コマンド反復チェック
66  * @param sn 選択したモンスター攻撃ID
67  * @return 発動可能な魔法を選択した場合TRUE、処理続行の場合FALSE
68  */
69 static bool check_blue_magic_cancel(SPELL_IDX *sn)
70 {
71     *sn = -1;
72     COMMAND_CODE code;
73     if (!repeat_pull(&code))
74         return FALSE;
75
76     *sn = (SPELL_IDX)code;
77     return TRUE;
78 }
79
80 static bool select_blue_magic_kind_menu(learnt_magic_type *lm_ptr)
81 {
82     while (lm_ptr->mode == 0) {
83         prt(format(_(" %s ボルト", " %s bolt"), (lm_ptr->menu_line == 1) ? _("》", "> ") : "  "), 2, 14);
84         prt(format(_(" %s ボール", " %s ball"), (lm_ptr->menu_line == 2) ? _("》", "> ") : "  "), 3, 14);
85         prt(format(_(" %s ブレス", " %s breath"), (lm_ptr->menu_line == 3) ? _("》", "> ") : "  "), 4, 14);
86         prt(format(_(" %s 召喚", " %s sommoning"), (lm_ptr->menu_line == 4) ? _("》", "> ") : "  "), 5, 14);
87         prt(format(_(" %s その他", " %s others"), (lm_ptr->menu_line == 5) ? _("》", "> ") : "  "), 6, 14);
88         prt(_("どの種類の魔法を使いますか?", "use which type of magic? "), 0, 0);
89
90         lm_ptr->choice = inkey();
91         switch (lm_ptr->choice) {
92         case ESCAPE:
93         case 'z':
94         case 'Z':
95             screen_load();
96             return FALSE;
97         case '2':
98         case 'j':
99         case 'J':
100             lm_ptr->menu_line++;
101             break;
102         case '8':
103         case 'k':
104         case 'K':
105             lm_ptr->menu_line += 4;
106             break;
107         case '\r':
108         case 'x':
109         case 'X':
110             lm_ptr->mode = lm_ptr->menu_line;
111             break;
112         }
113
114         if (lm_ptr->menu_line > 5)
115             lm_ptr->menu_line -= 5;
116     }
117
118     return TRUE;
119 }
120
121 static bool select_blue_magic_kind_command(learnt_magic_type *lm_ptr)
122 {
123     sprintf(lm_ptr->comment, _("[A]ボルト, [B]ボール, [C]ブレス, [D]召喚, [E]その他:", "[A] bolt, [B] ball, [C] breath, [D] summoning, [E] others:"));
124     while (TRUE) {
125         char ch;
126         if (!get_com(lm_ptr->comment, &ch, TRUE))
127             return FALSE;
128
129         if (ch == 'A' || ch == 'a') {
130             lm_ptr->mode = 1;
131             break;
132         }
133
134         if (ch == 'B' || ch == 'b') {
135             lm_ptr->mode = 2;
136             break;
137         }
138
139         if (ch == 'C' || ch == 'c') {
140             lm_ptr->mode = 3;
141             break;
142         }
143
144         if (ch == 'D' || ch == 'd') {
145             lm_ptr->mode = 4;
146             break;
147         }
148
149         if (ch == 'E' || ch == 'e') {
150             lm_ptr->mode = 5;
151             break;
152         }
153     }
154
155     return TRUE;
156 }
157
158 static bool check_blue_magic_kind(learnt_magic_type *lm_ptr)
159 {
160     if (!use_menu)
161         return select_blue_magic_kind_command(lm_ptr);
162
163     screen_save();
164     if (!select_blue_magic_kind_menu(lm_ptr))
165         return FALSE;
166
167     screen_load();
168     return TRUE;
169 }
170
171 static bool sweep_learnt_spells(player_type *caster_ptr, learnt_magic_type *lm_ptr)
172 {
173     set_rf_masks(&lm_ptr->f4, &lm_ptr->f5, &lm_ptr->f6, lm_ptr->mode);
174     for (lm_ptr->blue_magic_num = 0, lm_ptr->count = 0; lm_ptr->blue_magic_num < 32; lm_ptr->blue_magic_num++)
175         if ((0x00000001 << lm_ptr->blue_magic_num) & lm_ptr->f4)
176             lm_ptr->blue_magics[lm_ptr->count++] = lm_ptr->blue_magic_num;
177
178     for (; lm_ptr->blue_magic_num < 64; lm_ptr->blue_magic_num++)
179         if ((0x00000001 << (lm_ptr->blue_magic_num - 32)) & lm_ptr->f5)
180             lm_ptr->blue_magics[lm_ptr->count++] = lm_ptr->blue_magic_num;
181
182     for (; lm_ptr->blue_magic_num < 96; lm_ptr->blue_magic_num++)
183         if ((0x00000001 << (lm_ptr->blue_magic_num - 64)) & lm_ptr->f6)
184             lm_ptr->blue_magics[lm_ptr->count++] = lm_ptr->blue_magic_num;
185
186     for (lm_ptr->blue_magic_num = 0; lm_ptr->blue_magic_num < lm_ptr->count; lm_ptr->blue_magic_num++) {
187         if (caster_ptr->magic_num2[lm_ptr->blue_magics[lm_ptr->blue_magic_num]] == 0)
188             continue;
189
190         if (use_menu)
191             lm_ptr->menu_line = lm_ptr->blue_magic_num + 1;
192
193         break;
194     }
195
196     if (lm_ptr->blue_magic_num == lm_ptr->count) {
197         msg_print(_("その種類の魔法は覚えていない!", "You don't know any spell of this type."));
198         return FALSE;
199     }
200
201     (void)strnfmt(lm_ptr->out_val, 78, _("(%c-%c, '*'で一覧, ESC) どの%sを唱えますか?", "(%c-%c, *=List, ESC=exit) Use which %s? "), I2A(0),
202         I2A(lm_ptr->count - 1), _("魔法", "magic"));
203     return TRUE;
204 }
205
206 static bool switch_blue_magic_choice(player_type *caster_ptr, learnt_magic_type *lm_ptr)
207 {
208     switch (lm_ptr->choice) {
209     case '0':
210         screen_load();
211         return FALSE;
212     case '8':
213     case 'k':
214     case 'K':
215         do {
216             lm_ptr->menu_line += (lm_ptr->count - 1);
217             if (lm_ptr->menu_line > lm_ptr->count)
218                 lm_ptr->menu_line -= lm_ptr->count;
219         } while (!caster_ptr->magic_num2[lm_ptr->blue_magics[lm_ptr->menu_line - 1]]);
220         return TRUE;
221     case '2':
222     case 'j':
223     case 'J':
224         do {
225             lm_ptr->menu_line++;
226             if (lm_ptr->menu_line > lm_ptr->count)
227                 lm_ptr->menu_line -= lm_ptr->count;
228         } while (!caster_ptr->magic_num2[lm_ptr->blue_magics[lm_ptr->menu_line - 1]]);
229         return TRUE;
230     case '6':
231     case 'l':
232     case 'L':
233         lm_ptr->menu_line = lm_ptr->count;
234         while (!caster_ptr->magic_num2[lm_ptr->blue_magics[lm_ptr->menu_line - 1]])
235             lm_ptr->menu_line--;
236
237         return TRUE;
238     case '4':
239     case 'h':
240     case 'H':
241         lm_ptr->menu_line = 1;
242         while (!caster_ptr->magic_num2[lm_ptr->blue_magics[lm_ptr->menu_line - 1]])
243             lm_ptr->menu_line++;
244
245         return TRUE;
246     case 'x':
247     case 'X':
248     case '\r':
249         lm_ptr->blue_magic_num = lm_ptr->menu_line - 1;
250         lm_ptr->ask = FALSE;
251         return TRUE;
252     default:
253         return TRUE;
254     }
255 }
256
257 static void calculate_blue_magic_success_probability(player_type *caster_ptr, learnt_magic_type *lm_ptr)
258 {
259     lm_ptr->chance = lm_ptr->spell.fail;
260     if (lm_ptr->plev > lm_ptr->spell.level)
261         lm_ptr->chance -= 3 * (lm_ptr->plev - lm_ptr->spell.level);
262     else
263         lm_ptr->chance += (lm_ptr->spell.level - lm_ptr->plev);
264
265     lm_ptr->chance -= 3 * (adj_mag_stat[caster_ptr->stat_ind[A_INT]] - 1);
266     lm_ptr->chance = mod_spell_chance_1(caster_ptr, lm_ptr->chance);
267     lm_ptr->need_mana = mod_need_mana(caster_ptr, monster_powers[lm_ptr->blue_magics[lm_ptr->blue_magic_num]].smana, 0, REALM_NONE);
268     if (lm_ptr->need_mana > caster_ptr->csp)
269         lm_ptr->chance += 5 * (lm_ptr->need_mana - caster_ptr->csp);
270
271     PERCENTAGE minfail = adj_mag_fail[caster_ptr->stat_ind[A_INT]];
272     if (lm_ptr->chance < minfail)
273         lm_ptr->chance = minfail;
274
275     if (caster_ptr->stun > 50)
276         lm_ptr->chance += 25;
277     else if (caster_ptr->stun)
278         lm_ptr->chance += 15;
279
280     if (lm_ptr->chance > 95)
281         lm_ptr->chance = 95;
282
283     lm_ptr->chance = mod_spell_chance_2(caster_ptr, lm_ptr->chance);
284 }
285
286 static void close_blue_magic_name(learnt_magic_type *lm_ptr)
287 {
288     if (!use_menu) {
289         sprintf(lm_ptr->psi_desc, "  %c)", I2A(lm_ptr->blue_magic_num));
290         return;
291     }
292
293     if (lm_ptr->blue_magic_num == (lm_ptr->menu_line - 1))
294         strcpy(lm_ptr->psi_desc, _("  》", "  > "));
295     else
296         strcpy(lm_ptr->psi_desc, "    ");
297 }
298
299 static void describe_blue_magic_name(player_type *caster_ptr, learnt_magic_type *lm_ptr)
300 {
301     prt("", lm_ptr->y, lm_ptr->x);
302     put_str(_("名前", "Name"), lm_ptr->y, lm_ptr->x + 5);
303     put_str(_("MP 失率 効果", "SP Fail Info"), lm_ptr->y, lm_ptr->x + 33);
304     for (lm_ptr->blue_magic_num = 0; lm_ptr->blue_magic_num < lm_ptr->count; lm_ptr->blue_magic_num++) {
305         prt("", lm_ptr->y + lm_ptr->blue_magic_num + 1, lm_ptr->x);
306         if (!caster_ptr->magic_num2[lm_ptr->blue_magics[lm_ptr->blue_magic_num]])
307             continue;
308
309         lm_ptr->spell = monster_powers[lm_ptr->blue_magics[lm_ptr->blue_magic_num]];
310         calculate_blue_magic_success_probability(caster_ptr, lm_ptr);
311         learnt_info(caster_ptr, lm_ptr->comment, lm_ptr->blue_magics[lm_ptr->blue_magic_num]);
312         close_blue_magic_name(lm_ptr);
313         strcat(lm_ptr->psi_desc, format(" %-26s %3d %3d%%%s", lm_ptr->spell.name, lm_ptr->need_mana, lm_ptr->chance, lm_ptr->comment));
314         prt(lm_ptr->psi_desc, lm_ptr->y + lm_ptr->blue_magic_num + 1, lm_ptr->x);
315     }
316 }
317
318 static bool blue_magic_key_input(player_type *caster_ptr, learnt_magic_type *lm_ptr)
319 {
320     if ((lm_ptr->choice != ' ') && (lm_ptr->choice != '*') && (lm_ptr->choice != '?') && (!use_menu || (lm_ptr->ask == 0)))
321         return FALSE;
322
323     if (lm_ptr->redraw && !use_menu) {
324         lm_ptr->redraw = FALSE;
325         screen_load();
326         return TRUE;
327     }
328
329     lm_ptr->redraw = TRUE;
330     if (!use_menu)
331         screen_save();
332
333     describe_blue_magic_name(caster_ptr, lm_ptr);
334     if (lm_ptr->y < 22)
335         prt("", lm_ptr->y + lm_ptr->blue_magic_num + 1, lm_ptr->x);
336
337     return TRUE;
338 }
339
340 static void convert_lower_blue_magic_selection(learnt_magic_type *lm_ptr)
341 {
342     if (use_menu)
343         return;
344
345     lm_ptr->ask = isupper(lm_ptr->choice);
346     if (lm_ptr->ask)
347         lm_ptr->choice = (char)tolower(lm_ptr->choice);
348
349     lm_ptr->blue_magic_num = islower(lm_ptr->choice) ? A2I(lm_ptr->choice) : -1;
350 }
351
352 static bool ask_cast_blue_magic(learnt_magic_type *lm_ptr)
353 {
354     if (lm_ptr->ask == 0)
355         return TRUE;
356
357     char tmp_val[160];
358     (void)strnfmt(tmp_val, 78, _("%sの魔法を唱えますか?", "Use %s? "), monster_powers[lm_ptr->blue_magics[lm_ptr->blue_magic_num]].name);
359     return get_check(tmp_val);
360 }
361
362 static bool select_learnt_spells(player_type *caster_ptr, learnt_magic_type *lm_ptr)
363 {
364     while (!lm_ptr->flag) {
365         if (lm_ptr->choice == ESCAPE)
366             lm_ptr->choice = ' ';
367         else if (!get_com(lm_ptr->out_val, &lm_ptr->choice, TRUE))
368             break;
369
370         if (use_menu && (lm_ptr->choice != ' ') && !switch_blue_magic_choice(caster_ptr, lm_ptr))
371             return FALSE;
372
373         if (blue_magic_key_input(caster_ptr, lm_ptr))
374             continue;
375
376         convert_lower_blue_magic_selection(lm_ptr);
377         if ((lm_ptr->blue_magic_num < 0) || (lm_ptr->blue_magic_num >= lm_ptr->count) || !caster_ptr->magic_num2[lm_ptr->blue_magics[lm_ptr->blue_magic_num]]) {
378             bell();
379             continue;
380         }
381
382         lm_ptr->spell = monster_powers[lm_ptr->blue_magics[lm_ptr->blue_magic_num]];
383         if (!ask_cast_blue_magic(lm_ptr))
384             continue;
385
386         lm_ptr->flag = TRUE;
387     }
388
389     return TRUE;
390 }
391
392 /*!
393  * @brief 使用可能な青魔法を選択する /
394  * Allow user to choose a imitation.
395  * @param caster_ptr プレーヤーへの参照ポインタ
396  * @param sn 選択したモンスター攻撃ID、キャンセルの場合-1、不正な選択の場合-2を返す
397  * @return 発動可能な魔法を選択した場合TRUE、キャンセル処理か不正な選択が行われた場合FALSEを返す。
398  * @details
399  * If a valid spell is chosen, saves it in '*sn' and returns TRUE\n
400  * If the user hits escape, returns FALSE, and set '*sn' to -1\n
401  * If there are no legal choices, returns FALSE, and sets '*sn' to -2\n
402  *\n
403  * The "prompt" should be "cast", "recite", or "study"\n
404  * The "known" should be TRUE for cast/pray, FALSE for study\n
405  *\n
406  * nb: This function has a (trivial) display bug which will be obvious\n
407  * when you run it. It's probably easy to fix but I haven't tried,\n
408  * sorry.\n
409  */
410 bool get_learned_power(player_type *caster_ptr, SPELL_IDX *sn)
411 {
412     learnt_magic_type tmp_magic;
413     learnt_magic_type *lm_ptr = initialize_lenat_magic_type(caster_ptr, &tmp_magic);
414     if (check_blue_magic_cancel(sn))
415         return TRUE;
416
417     if (!check_blue_magic_kind(lm_ptr) || !sweep_learnt_spells(caster_ptr, lm_ptr))
418         return FALSE;
419
420     if (use_menu)
421         screen_save();
422
423     lm_ptr->choice = (always_show_list || use_menu) ? ESCAPE : 1;
424     if (!select_learnt_spells(caster_ptr, lm_ptr))
425         return FALSE;
426
427     if (lm_ptr->redraw)
428         screen_load();
429
430     caster_ptr->window |= PW_SPELL;
431     handle_stuff(caster_ptr);
432
433     if (!lm_ptr->flag)
434         return FALSE;
435
436     *sn = lm_ptr->blue_magics[lm_ptr->blue_magic_num];
437     repeat_push((COMMAND_CODE)lm_ptr->blue_magics[lm_ptr->blue_magic_num]);
438     return TRUE;
439 }