OSDN Git Service

[Refactor] 意味もなく引き回しているprocess_autopick_file_command引数の削除
[hengbandforosx/hengbandosx.git] / src / birth / birth-wizard.cpp
1 #include "birth/birth-wizard.h"
2 #include "birth/auto-roller.h"
3 #include "birth/birth-body-spec.h"
4 #include "birth/birth-explanations-table.h"
5 #include "birth/birth-select-class.h"
6 #include "birth/birth-select-personality.h"
7 #include "birth/birth-select-race.h"
8 #include "birth/birth-select-realm.h"
9 #include "birth/birth-stat.h"
10 #include "birth/birth-util.h"
11 #include "birth/game-play-initializer.h"
12 #include "birth/history-editor.h"
13 #include "birth/history-generator.h"
14 #include "birth/quick-start.h"
15 #include "cmd-io/cmd-gameoption.h"
16 #include "cmd-io/cmd-help.h"
17 #include "core/asking-player.h"
18 #include "core/player-update-types.h"
19 #include "game-option/birth-options.h"
20 #include "io/input-key-acceptor.h"
21 #include "main/sound-definitions-table.h"
22 #include "main/sound-of-music.h"
23 #include "player-info/avatar.h"
24 #include "player/patron.h"
25 #include "player/player-class.h"
26 #include "player/player-race.h"
27 #include "player/player-sex.h"
28 #include "player/process-name.h"
29 #include "player/player-status-table.h"
30 #include "system/game-option-types.h"
31 #include "term/screen-processor.h"
32 #include "term/term-color-types.h"
33 #include "util/buffer-shaper.h"
34 #include "util/int-char-converter.h"
35 #include "view/display-birth.h" // 暫定。後で消す予定。
36 #include "view/display-player.h" // 暫定。後で消す.
37 #include "world/world.h"
38
39 /*!
40  * オートローラーの内容を描画する間隔 /
41  * How often the autoroller will update the display and pause
42  * to check for user interuptions.
43  * Bigger values will make the autoroller faster, but slower
44  * system may have problems because the user can't stop the
45  * autoroller for this number of rolls.
46  */
47 #define AUTOROLLER_STEP 54321L
48
49 static void display_initial_birth_message(player_type *creature_ptr)
50 {
51     term_clear();
52     put_str(_("名前  :", "Name  :"), 1, 26);
53     put_str(_("性別        :", "Sex         :"), 3, 1);
54     put_str(_("種族        :", "Race        :"), 4, 1);
55     put_str(_("職業        :", "Class       :"), 5, 1);
56     c_put_str(TERM_L_BLUE, creature_ptr->name, 1, 34);
57     put_str(_("キャラクターを作成します。('S'やり直す, 'Q'終了, '?'ヘルプ)", "Make your character. ('S' Restart, 'Q' Quit, '?' Help)"), 8, 10);
58     put_str(_("注意:《性別》の違いはゲーム上ほとんど影響を及ぼしません。", "Note: Your 'sex' does not have any significant gameplay effects."), 23, 5);
59 }
60
61 /*!
62  * @prief 性別選択画面でヘルプを表示させる
63  * @param creature_ptr プレーヤーへの参照ポインタ
64  * @param c 入力したコマンド
65  * @return なし
66  * @details 他の関数名と被りそうだったので少し眺め
67  */
68 static void display_help_on_sex_select(player_type *creature_ptr, char c)
69 {
70     if (c == '?')
71         do_cmd_help(creature_ptr);
72     else if (c == '=') {
73         screen_save();
74         do_cmd_options_aux(creature_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
75         screen_load();
76     } else if (c != '4' && c != '6')
77         bell();
78 }
79
80 /*!
81  * @brief プレイヤーの性別選択を行う / Player sex
82  * @param creature_ptr プレーヤーへの参照ポインタ
83  * @buf 表示用バッファ
84  * @return やり直すならFALSE、それ以外はTRUE
85  */
86 static bool get_player_sex(player_type *creature_ptr, char *buf)
87 {
88     const char p2 = ')';
89     char cur[80];
90     sprintf(cur, _("%c%c%s", "%c%c %s"), '*', p2, _("ランダム", "Random"));
91     int k = -1;
92     int cs = 0;
93     int os = MAX_SEXES;
94     while (TRUE) {
95         if (cs != os) {
96             put_str(cur, 12 + (os / 5), 2 + 15 * (os % 5));
97             if (cs == MAX_SEXES)
98                 sprintf(cur, _("%c%c%s", "%c%c %s"), '*', p2, _("ランダム", "Random"));
99             else {
100                 sp_ptr = &sex_info[cs];
101                 concptr str = sp_ptr->title;
102                 sprintf(cur, _("%c%c%s", "%c%c %s"), I2A(cs), p2, str);
103             }
104
105             c_put_str(TERM_YELLOW, cur, 12 + (cs / 5), 2 + 15 * (cs % 5));
106             os = cs;
107         }
108
109         if (k >= 0)
110             break;
111
112         sprintf(buf, _("性別を選んで下さい (%c-%c) ('='初期オプション設定): ", "Choose a sex (%c-%c) ('=' for options): "), I2A(0), I2A(1));
113         put_str(buf, 10, 10);
114         char c = inkey();
115         if (c == 'Q')
116             birth_quit();
117
118         if (c == 'S')
119             return FALSE;
120
121         if (c == ' ' || c == '\r' || c == '\n') {
122             k = cs == MAX_SEXES ? randint0(MAX_SEXES) : cs;
123             break;
124         }
125
126         if (c == '*') {
127             k = randint0(MAX_SEXES);
128             break;
129         }
130
131         if (c == '4') {
132             if (cs > 0)
133                 cs--;
134         }
135
136         if (c == '6') {
137             if (cs < MAX_SEXES)
138                 cs++;
139         }
140
141         k = (islower(c) ? A2I(c) : -1);
142         if ((k >= 0) && (k < MAX_SEXES)) {
143             cs = k;
144             continue;
145         } else
146             k = -1;
147
148         display_help_on_sex_select(creature_ptr, c);
149     }
150
151     creature_ptr->psex = (byte)k;
152     sp_ptr = &sex_info[creature_ptr->psex];
153     c_put_str(TERM_L_BLUE, sp_ptr->title, 3, 15);
154     return TRUE;
155 }
156
157 static bool let_player_select_race(player_type *creature_ptr)
158 {
159     clear_from(10);
160     creature_ptr->prace = RACE_HUMAN;
161     while (TRUE) {
162         char temp[80 * 10];
163         if (!get_player_race(creature_ptr))
164             return FALSE;
165
166         clear_from(10);
167         shape_buffer(race_explanations[creature_ptr->prace], 74, temp, sizeof(temp));
168         concptr t = temp;
169         for (int i = 0; i < 10; i++) {
170             if (t[0] == 0)
171                 break;
172             else {
173                 prt(t, 12 + i, 3);
174                 t += strlen(t) + 1;
175             }
176         }
177         if (get_check_strict(creature_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
178             break;
179
180         clear_from(10);
181         c_put_str(TERM_WHITE, "              ", 4, 15);
182     }
183
184     return TRUE;
185 }
186
187 static bool let_player_select_class(player_type *creature_ptr)
188 {
189     clear_from(10);
190     creature_ptr->pclass = CLASS_WARRIOR;
191     while (TRUE) {
192         char temp[80 * 9];
193         if (!get_player_class(creature_ptr))
194             return FALSE;
195
196         clear_from(10);
197         shape_buffer(class_explanations[creature_ptr->pclass], 74, temp, sizeof(temp));
198         concptr t = temp;
199         for (int i = 0; i < 9; i++) {
200             if (t[0] == 0)
201                 break;
202             else {
203                 prt(t, 12 + i, 3);
204                 t += strlen(t) + 1;
205             }
206         }
207
208         if (get_check_strict(creature_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
209             break;
210
211         c_put_str(TERM_WHITE, "              ", 5, 15);
212     }
213
214     return TRUE;
215 }
216
217 static bool let_player_select_personality(player_type *creature_ptr)
218 {
219     creature_ptr->pseikaku = PERSONALITY_ORDINARY;
220     while (TRUE) {
221         char temp[80 * 8];
222         if (!get_player_personality(creature_ptr))
223             return FALSE;
224
225         clear_from(10);
226         shape_buffer(personality_explanations[creature_ptr->pseikaku], 74, temp, sizeof(temp));
227         concptr t = temp;
228         for (int i = 0; i < A_MAX; i++) {
229             if (t[0] == 0)
230                 break;
231             else {
232                 prt(t, 12 + i, 3);
233                 t += strlen(t) + 1;
234             }
235         }
236
237         if (get_check_strict(creature_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
238             break;
239
240         c_put_str(TERM_L_BLUE, creature_ptr->name, 1, 34);
241         prt("", 1, 34 + strlen(creature_ptr->name));
242     }
243
244     return TRUE;
245 }
246
247 static bool let_player_build_character(player_type *creature_ptr)
248 {
249     char buf[80];
250     if (!get_player_sex(creature_ptr, buf))
251         return FALSE;
252
253     if (!let_player_select_race(creature_ptr))
254         return FALSE;
255
256     if (!let_player_select_class(creature_ptr))
257         return FALSE;
258
259     if (!get_player_realms(creature_ptr))
260         return FALSE;
261
262     if (!let_player_select_personality(creature_ptr))
263         return FALSE;
264
265     return TRUE;
266 }
267
268 static void display_initial_options(player_type *creature_ptr)
269 {
270     u16b expfact = get_expfact(creature_ptr) - 100;
271     s16b adj[A_MAX];
272     for (int i = 0; i < A_MAX; i++) {
273         adj[i] = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
274     }
275
276     char buf[80];
277     put_str("                                   ", 3, 40);
278     put_str(_("修正の合計値", "Your total modification"), 3, 40);
279     put_str(_("腕力 知能 賢さ 器用 耐久 魅力 経験 ", "Str  Int  Wis  Dex  Con  Chr   EXP "), 4, 40);
280     sprintf(buf, "%+3d  %+3d  %+3d  %+3d  %+3d  %+3d %+4d%% ", adj[0], adj[1], adj[2], adj[3], adj[4], adj[5], expfact);
281     c_put_str(TERM_L_BLUE, buf, 5, 40);
282
283     put_str("HD ", 6, 40);
284     sprintf(buf, "%2d", rp_ptr->r_mhp + cp_ptr->c_mhp + ap_ptr->a_mhp);
285     c_put_str(TERM_L_BLUE, buf, 6, 43);
286
287     put_str(_("隠密", "Stealth"), 6, 47);
288     if (creature_ptr->pclass == CLASS_BERSERKER)
289         strcpy(buf, "xx");
290     else
291         sprintf(buf, "%+2d", rp_ptr->r_stl + cp_ptr->c_stl + ap_ptr->a_stl);
292     c_put_str(TERM_L_BLUE, buf, 6, _(52, 55));
293
294     put_str(_("赤外線視力", "Infra"), 6, _(56, 59));
295     sprintf(buf, _("%2dft", "%2dft"), 10 * rp_ptr->infra);
296     c_put_str(TERM_L_BLUE, buf, 6, _(67, 65));
297
298     clear_from(10);
299     screen_save();
300     do_cmd_options_aux(creature_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
301     screen_load();
302 }
303
304 static void display_auto_roller_success_rate(const int col)
305 {
306     if (!autoroller)
307         return;
308
309     put_str(_("最小値", " Limit"), 2, col + 13);
310     put_str(_("現在値", "  Roll"), 2, col + 24);
311
312     char buf[32];
313
314     if (autoroll_chance >= 1)
315         sprintf(buf, _("確率 :  1/%8d00", "Prob :  1/%8d00"), autoroll_chance);
316     else if (autoroll_chance == -999)
317         sprintf(buf, _("確率 :     不可能", "Prob :     Impossible"));
318     else
319         sprintf(buf, _("確率 :     1/10000以上", "Prob :     >1/10000"));
320     put_str(buf, 11, col + 10);
321
322     put_str(_(
323         "注意 : 体格等のオートローラを併用時は、上記確率より困難です。",
324         "Note : Prob may be lower when you use the 'autochara' option."
325         ), 22, 5);
326
327     for (int i = 0; i < A_MAX; i++) {
328         put_str(stat_names[i], 3 + i, col + 8);
329         int j = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
330         int m = adjust_stat(stat_limit[i], j);
331         cnv_stat(m, buf);
332         c_put_str(TERM_L_BLUE, buf, 3 + i, col + 13);
333     }
334 }
335
336 static void auto_roller_count(void)
337 {
338     if (auto_round < 1000000000L)
339         return;
340
341     auto_round = 1;
342     if (!autoroller)
343         return;
344
345     auto_upper_round++;
346 }
347
348 static bool decide_initial_stat(player_type *creature_ptr)
349 {
350     if (!autoroller)
351         return TRUE;
352
353     bool accept = TRUE;
354     for (int i = 0; i < A_MAX; i++) {
355         if (creature_ptr->stat_max[i] < stat_limit[i]) {
356             accept = FALSE;
357             break;
358         }
359     }
360
361     return accept;
362 }
363
364 static bool decide_body_spec(player_type *creature_ptr, chara_limit_type chara_limit, bool *accept)
365 {
366     if (!*accept)
367         return FALSE;
368
369     get_ahw(creature_ptr);
370     get_history(creature_ptr);
371
372     if (autochara) {
373         if ((creature_ptr->age < chara_limit.agemin) || (creature_ptr->age > chara_limit.agemax))
374             *accept = FALSE;
375         if ((creature_ptr->ht < chara_limit.htmin) || (creature_ptr->ht > chara_limit.htmax))
376             *accept = FALSE;
377         if ((creature_ptr->wt < chara_limit.wtmin) || (creature_ptr->wt > chara_limit.wtmax))
378             *accept = FALSE;
379         if ((creature_ptr->sc < chara_limit.scmin) || (creature_ptr->sc > chara_limit.scmax))
380             *accept = FALSE;
381     }
382
383     return *accept;
384 }
385
386 static bool display_auto_roller_count(player_type *creature_ptr, const int col)
387 {
388     if ((auto_round % AUTOROLLER_STEP) != 0)
389         return FALSE;
390
391     birth_put_stats(creature_ptr);
392     if (auto_upper_round)
393         put_str(format("%ld%09ld", auto_upper_round, auto_round), 10, col + 20);
394     else
395         put_str(format("%10ld", auto_round), 10, col + 20);
396     term_fresh();
397     inkey_scan = TRUE;
398     if (inkey()) {
399         get_ahw(creature_ptr);
400         get_history(creature_ptr);
401         return TRUE;
402     }
403
404     return FALSE;
405 }
406
407 static void exe_auto_roller(player_type *creature_ptr, chara_limit_type chara_limit, const int col)
408 {
409     while (autoroller || autochara) {
410         get_stats(creature_ptr);
411         auto_round++;
412         auto_roller_count();
413         bool accept = decide_initial_stat(creature_ptr);
414         if (decide_body_spec(creature_ptr, chara_limit, &accept))
415             return;
416
417         if (display_auto_roller_count(creature_ptr, col))
418             return;
419     }
420 }
421
422 static bool display_auto_roller_result(player_type *creature_ptr, bool prev, char *c)
423 {
424     BIT_FLAGS mode = 0;
425     while (TRUE) {
426         creature_ptr->update |= (PU_BONUS | PU_HP);
427         update_creature(creature_ptr);
428         creature_ptr->chp = creature_ptr->mhp;
429         creature_ptr->csp = creature_ptr->msp;
430         display_player(creature_ptr, mode);
431         term_gotoxy(2, 23);
432         const char b1 = '[';
433         term_addch(TERM_WHITE, b1);
434         term_addstr(-1, TERM_WHITE, _("'r' 次の数値", "'r'eroll"));
435         if (prev)
436             term_addstr(-1, TERM_WHITE, _(", 'p' 前の数値", "'p'previous"));
437
438         if (mode)
439             term_addstr(-1, TERM_WHITE, _(", 'h' その他の情報", ", 'h' Misc."));
440         else
441             term_addstr(-1, TERM_WHITE, _(", 'h' 生い立ちを表示", ", 'h'istory"));
442
443         term_addstr(-1, TERM_WHITE, _(", Enter この数値に決定", ", or Enter to accept"));
444         const char b2 = ']';
445         term_addch(TERM_WHITE, b2);
446         *c = inkey();
447         if (*c == 'Q')
448             birth_quit();
449
450         if (*c == 'S')
451             return FALSE;
452
453         if (*c == '\r' || *c == '\n' || *c == ESCAPE)
454             break;
455
456         if ((*c == ' ') || (*c == 'r'))
457             break;
458
459         if (prev && (*c == 'p')) {
460             load_prev_data(creature_ptr, TRUE);
461             continue;
462         }
463
464         if ((*c == 'H') || (*c == 'h')) {
465             mode = ((mode != 0) ? 0 : 1);
466             continue;
467         }
468
469         birth_help_option(creature_ptr, *c, BK_AUTO_ROLLER);
470         bell();
471     }
472
473     return TRUE;
474 }
475
476 /*
477  * @brief オートロールを回して結果を表示し、その数値に決めるかさらに回すか確認する。
478  * @param creature_ptr プレーヤーへの参照ポインタ
479  * @param chara_limit 社会的地位の要求水準
480  * @detail 2つめの結果以降は、'p'キーで1つ前のロール結果に戻せる。
481  */
482 static bool display_auto_roller(player_type *creature_ptr, chara_limit_type chara_limit)
483 {
484     bool prev = FALSE;
485
486     while (TRUE) {
487         int col = 22;
488         if (autoroller || autochara) {
489             term_clear();
490             put_str(_("回数 :", "Round:"), 10, col + 10);
491             put_str(_("(ESCで停止)", "(Hit ESC to stop)"), 13, col + 13);
492         } else {
493             get_stats(creature_ptr);
494             get_ahw(creature_ptr);
495             get_history(creature_ptr);
496         }
497
498         display_auto_roller_success_rate(col);
499         exe_auto_roller(creature_ptr, chara_limit, col);
500         if (autoroller || autochara)
501             sound(SOUND_LEVEL);
502
503         flush();
504
505         get_extra(creature_ptr, TRUE);
506         get_money(creature_ptr);
507         creature_ptr->chaos_patron = (s16b)randint0(MAX_PATRON);
508
509         char c;
510         if (!display_auto_roller_result(creature_ptr, prev, &c))
511             return FALSE;
512
513         if (c == '\r' || c == '\n' || c == ESCAPE)
514             break;
515
516         save_prev_data(creature_ptr, &previous_char);
517         previous_char.quick_ok = FALSE;
518         prev = TRUE;
519     }
520
521     return TRUE;
522 }
523
524 /*!
525  * @brief 名前と生い立ちを設定する
526  * @param creature_ptr プレーヤーへの参照ポインタ
527  * @return なし
528  * @details ついでにステータス限界もここで決めている
529  */
530 static void set_name_history(player_type *creature_ptr)
531 {
532     clear_from(23);
533     get_name(creature_ptr);
534     process_player_name(creature_ptr, current_world_ptr->creating_savefile);
535     edit_history(creature_ptr);
536     get_max_stats(creature_ptr);
537     get_virtues(creature_ptr);
538     prt(_("[ 'Q' 中断, 'S' 初めから, Enter ゲーム開始 ]", "['Q'uit, 'S'tart over, or Enter to continue]"), 23, _(14, 10));
539 }
540
541 /*!
542  * @brief プレーヤーキャラ作成ウィザード
543  * @details
544  * The delay may be reduced, but is recommended to keep players
545  * from continuously rolling up characters, which can be VERY
546  * expensive CPU wise.  And it cuts down on player stupidity.
547  * @return なし
548  */
549 bool player_birth_wizard(player_type *creature_ptr)
550 {
551     display_initial_birth_message(creature_ptr);
552     const char p2 = ')';
553     char buf[80];
554     for (int n = 0; n < MAX_SEXES; n++) {
555         sp_ptr = &sex_info[n];
556         sprintf(buf, _("%c%c%s", "%c%c %s"), I2A(n), p2, sp_ptr->title);
557         put_str(buf, 12 + (n / 5), 2 + 15 * (n % 5));
558     }
559
560     if (!let_player_build_character(creature_ptr))
561         return FALSE;
562
563     display_initial_options(creature_ptr);
564     if (autoroller || autochara) {
565         auto_round = 0L;
566         auto_upper_round = 0L;
567         autoroll_chance = 0L;
568     }
569
570     if (autoroller)
571         if (!get_stat_limits(creature_ptr))
572             return FALSE;
573
574     chara_limit_type chara_limit;
575     initialize_chara_limit(&chara_limit);
576     if (autochara)
577         if (!get_chara_limits(creature_ptr, &chara_limit))
578             return FALSE;
579
580     clear_from(10);
581     init_turn(creature_ptr);
582     if (!display_auto_roller(creature_ptr, chara_limit))
583         return FALSE;
584
585     set_name_history(creature_ptr);
586     char c = inkey();
587     if (c == 'Q')
588         birth_quit();
589
590     if (c == 'S')
591         return FALSE;
592
593     init_dungeon_quests(creature_ptr);
594     save_prev_data(creature_ptr, &previous_char);
595     previous_char.quick_ok = TRUE;
596     return TRUE;
597 }