OSDN Git Service

[Refactor] #40392 Moved birth_help_option() from birth-select-realm.c to birth-util.c
[hengband/hengband.git] / src / birth / birth-wizard.c
1 #include "system/angband.h"
2 #include "birth/birth-wizard.h"
3 #include "term/gameterm.h"
4 #include "player/player-sex.h"
5 #include "birth/birth-explanations-table.h"
6 #include "birth/auto-roller.h"
7 #include "main/sound-definitions-table.h"
8 #include "player/patron.h"
9 #include "world/world.h"
10 #include "birth/quick-start.h"
11 #include "birth/birth-util.h"
12 #include "cmd/cmd-help.h"
13 #include "birth/birth-select-race.h"
14 #include "birth/birth-select-class.h"
15 #include "birth/birth-select-personality.h"
16 #include "birth/birth-select-realm.h"
17 #include "birth/game-play-initializer.h"
18 #include "birth/birth-stat.h"
19 #include "birth/birth-body-spec.h"
20 #include "birth/history-generator.h"
21 #include "birth/history-editor.h"
22 #include "player/process-name.h"
23 #include "player/avatar.h"
24 #include "view/display-main-window.h" // 暫定。後で消す.
25 #include "view/display-birth.h" // 暫定。後で消す予定。
26 #include "view/display-player.h" // 暫定。後で消す.
27
28 /*!
29  * オートローラーの内容を描画する間隔 /
30  * How often the autoroller will update the display and pause
31  * to check for user interuptions.
32  * Bigger values will make the autoroller faster, but slower
33  * system may have problems because the user can't stop the
34  * autoroller for this number of rolls.
35  */
36 #define AUTOROLLER_STEP 5431L
37
38 static void display_initial_birth_message(player_type *creature_ptr)
39 {
40     Term_clear();
41     put_str(_("名前  :", "Name  :"), 1, 26);
42     put_str(_("性別        :", "Sex         :"), 3, 1);
43     put_str(_("種族        :", "Race        :"), 4, 1);
44     put_str(_("職業        :", "Class       :"), 5, 1);
45     c_put_str(TERM_L_BLUE, creature_ptr->name, 1, 34);
46     put_str(_("キャラクターを作成します。('S'やり直す, 'Q'終了, '?'ヘルプ)",
47                 "Make your charactor. ('S' Restart, 'Q' Quit, '?' Help)"), 8, 10);
48     put_str(_("注意:《性別》の違いはゲーム上ほとんど影響を及ぼしません。",
49                 "Note: Your 'sex' does not have any significant gameplay effects."), 23, 5);
50 }
51
52 /*!
53  * @brief プレイヤーの性別選択を行う / Player sex
54  * @param creature_ptr プレーヤーへの参照ポインタ
55  * @buf 表示用バッファ
56  * @return やり直すならFALSE、それ以外はTRUE
57  */
58 static bool get_player_sex(player_type *creature_ptr, char *buf)
59 {
60     const char p2 = ')';
61     char cur[80];
62     sprintf(cur, _("%c%c%s", "%c%c %s"), '*', p2, _("ランダム", "Random"));
63     int k = -1;
64     int cs = 0;
65     int os = MAX_SEXES;
66     while (TRUE) {
67         if (cs != os) {
68             put_str(cur, 12 + (os / 5), 2 + 15 * (os % 5));
69             if (cs == MAX_SEXES)
70                 sprintf(cur, _("%c%c%s", "%c%c %s"), '*', p2, _("ランダム", "Random"));
71             else {
72                 sp_ptr = &sex_info[cs];
73                 concptr str = sp_ptr->title;
74                 sprintf(cur, _("%c%c%s", "%c%c %s"), I2A(cs), p2, str);
75             }
76
77             c_put_str(TERM_YELLOW, cur, 12 + (cs / 5), 2 + 15 * (cs % 5));
78             os = cs;
79         }
80
81         if (k >= 0)
82             break;
83
84         sprintf(buf, _("性別を選んで下さい (%c-%c) ('='初期オプション設定): ", "Choose a sex (%c-%c) ('=' for options): "), I2A(0), I2A(1));
85         put_str(buf, 10, 10);
86         char c = inkey();
87         if (c == 'Q')
88             birth_quit();
89         if (c == 'S')
90             return FALSE;
91         if (c == ' ' || c == '\r' || c == '\n') {
92             k = cs == MAX_SEXES ? randint0(MAX_SEXES) : cs;
93             break;
94         }
95
96         if (c == '*') {
97             k = randint0(MAX_SEXES);
98             break;
99         }
100
101         if (c == '4') {
102             if (cs > 0)
103                 cs--;
104         }
105
106         if (c == '6') {
107             if (cs < MAX_SEXES)
108                 cs++;
109         }
110
111         k = (islower(c) ? A2I(c) : -1);
112         if ((k >= 0) && (k < MAX_SEXES)) {
113             cs = k;
114             continue;
115         } else
116             k = -1;
117
118         if (c == '?')
119             do_cmd_help(creature_ptr);
120         else if (c == '=') {
121             screen_save();
122             do_cmd_options_aux(OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Option((*)s effect score)"));
123             screen_load();
124         } else if (c != '4' && c != '6')
125             bell();
126     }
127
128     creature_ptr->psex = (byte)k;
129     sp_ptr = &sex_info[creature_ptr->psex];
130     c_put_str(TERM_L_BLUE, sp_ptr->title, 3, 15);
131     return TRUE;
132 }
133
134 static void display_auto_roller_success_rate(const int col)
135 {
136     if (!autoroller)
137         return;
138
139     put_str(_("最小値", " Limit"), 2, col + 5);
140     put_str(_("成功率", "  Freq"), 2, col + 13);
141     put_str(_("現在値", "  Roll"), 2, col + 24);
142     for (int i = 0; i < A_MAX; i++) {
143         put_str(stat_names[i], 3 + i, col);
144         int j = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
145         int m = adjust_stat(stat_limit[i], j);
146         char buf[32];
147         cnv_stat(m, buf);
148         c_put_str(TERM_L_BLUE, buf, 3 + i, col + 5);
149     }
150 }
151
152 static void auto_roller_count(void)
153 {
154     if (auto_round < 1000000000L)
155         return;
156
157     auto_round = 1;
158     if (!autoroller)
159         return;
160
161     for (int i = 0; i < A_MAX; i++) {
162         stat_match[i] = 0;
163     }
164 }
165
166 static bool decide_initial_stat(player_type *creature_ptr)
167 {
168     if (!autoroller)
169         return TRUE;
170
171     bool accept = TRUE;
172     for (int i = 0; i < A_MAX; i++) {
173         if (creature_ptr->stat_max[i] >= stat_limit[i])
174             stat_match[i]++;
175         else
176             accept = FALSE;
177     }
178
179     return accept;
180 }
181
182 static bool decide_body_spec(player_type *creature_ptr, chara_limit_type chara_limit, bool *accept)
183 {
184     if (!*accept)
185         return FALSE;
186
187     get_ahw(creature_ptr);
188     get_history(creature_ptr);
189
190     if (autochara) {
191         if ((creature_ptr->age < chara_limit.agemin) || (creature_ptr->age > chara_limit.agemax))
192             *accept = FALSE;
193         if ((creature_ptr->ht < chara_limit.htmin) || (creature_ptr->ht > chara_limit.htmax))
194             *accept = FALSE;
195         if ((creature_ptr->wt < chara_limit.wtmin) || (creature_ptr->wt > chara_limit.wtmax))
196             *accept = FALSE;
197         if ((creature_ptr->sc < chara_limit.scmin) || (creature_ptr->sc > chara_limit.scmax))
198             *accept = FALSE;
199     }
200
201     return *accept;
202 }
203
204 static bool display_auto_roller_count(player_type *creature_ptr, const int col)
205 {
206     if ((auto_round % AUTOROLLER_STEP) != 0)
207         return FALSE;
208
209     birth_put_stats(creature_ptr);
210     put_str(format("%10ld", auto_round), 10, col + 20);
211     Term_fresh();
212     inkey_scan = TRUE;
213     if (inkey()) {
214         get_ahw(creature_ptr);
215         get_history(creature_ptr);
216         return TRUE;
217     }
218
219     return FALSE;
220 }
221
222 static void exe_auto_roller(player_type *creature_ptr, chara_limit_type chara_limit, const int col)
223 {
224     while (autoroller || autochara) {
225         get_stats(creature_ptr);
226         auto_round++;
227         auto_roller_count();
228         bool accept = decide_initial_stat(creature_ptr);
229         if (decide_body_spec(creature_ptr, chara_limit, &accept))
230             return;
231
232         if (display_auto_roller_count(creature_ptr, col))
233             return;
234     }
235 }
236
237 static bool display_auto_roller_result(player_type *creature_ptr, bool prev, char *c)
238 {
239     BIT_FLAGS mode = 0;
240     while (TRUE) {
241         creature_ptr->update |= (PU_BONUS | PU_HP);
242         update_creature(creature_ptr);
243         creature_ptr->chp = creature_ptr->mhp;
244         creature_ptr->csp = creature_ptr->msp;
245         display_player(creature_ptr, mode, map_name);
246         Term_gotoxy(2, 23);
247         const char b1 = '[';
248         Term_addch(TERM_WHITE, b1);
249         Term_addstr(-1, TERM_WHITE, _("'r' 次の数値", "'r'eroll"));
250         if (prev)
251             Term_addstr(-1, TERM_WHITE, _(", 'p' 前の数値", "'p'previous"));
252
253         if (mode)
254             Term_addstr(-1, TERM_WHITE, _(", 'h' その他の情報", ", 'h' Misc."));
255         else
256             Term_addstr(-1, TERM_WHITE, _(", 'h' 生い立ちを表示", ", 'h'istory"));
257
258         Term_addstr(-1, TERM_WHITE, _(", Enter この数値に決定", ", or Enter to accept"));
259         const char b2 = ']';
260         Term_addch(TERM_WHITE, b2);
261         *c = inkey();
262         if (*c == 'Q')
263             birth_quit();
264
265         if (*c == 'S')
266             return FALSE;
267
268         if (*c == '\r' || *c == '\n' || *c == ESCAPE)
269             break;
270         if ((*c == ' ') || (*c == 'r'))
271             break;
272
273         if (prev && (*c == 'p')) {
274             load_prev_data(creature_ptr, TRUE);
275             continue;
276         }
277
278         if ((*c == 'H') || (*c == 'h')) {
279             mode = ((mode != 0) ? 0 : 1);
280             continue;
281         }
282
283         birth_help_option(creature_ptr, *c, BK_AUTO_ROLLER);
284         bell();
285     }
286
287     return TRUE;
288 }
289
290 static bool display_auto_roller(player_type *creature_ptr, chara_limit_type chara_limit)
291 {
292     while (TRUE) {
293         int col = 42;
294         if (autoroller || autochara) {
295             Term_clear();
296             put_str(_("回数 :", "Round:"), 10, col + 13);
297             put_str(_("(ESCで停止)", "(Hit ESC to stop)"), 12, col + 13);
298         } else {
299             get_stats(creature_ptr);
300             get_ahw(creature_ptr);
301             get_history(creature_ptr);
302         }
303
304         display_auto_roller_success_rate(col);
305         exe_auto_roller(creature_ptr, chara_limit, col);
306         if (autoroller || autochara)
307             sound(SOUND_LEVEL);
308
309         flush();
310
311         get_extra(creature_ptr, TRUE);
312         get_money(creature_ptr);
313         creature_ptr->chaos_patron = (s16b)randint0(MAX_PATRON);
314         bool prev = FALSE;
315         char c;
316         if (!display_auto_roller_result(creature_ptr, prev, &c))
317             return FALSE;
318
319         if (c == '\r' || c == '\n' || c == ESCAPE)
320             break;
321
322         save_prev_data(creature_ptr, &previous_char);
323         previous_char.quick_ok = FALSE;
324         prev = TRUE;
325     }
326
327     return TRUE;
328 }
329
330 /*!
331  * @brief プレーヤーキャラ作成ウィザード
332  * @details
333  * The delay may be reduced, but is recommended to keep players
334  * from continuously rolling up characters, which can be VERY
335  * expensive CPU wise.  And it cuts down on player stupidity.
336  * @return なし
337  */
338 bool player_birth_wizard(player_type *creature_ptr, void (*process_autopick_file_command)(char *))
339 {
340     display_initial_birth_message(creature_ptr);
341     const char p2 = ')';
342     char buf[80];
343     for (int n = 0; n < MAX_SEXES; n++) {
344         sp_ptr = &sex_info[n];
345         sprintf(buf, _("%c%c%s", "%c%c %s"), I2A(n), p2, sp_ptr->title);
346         put_str(buf, 12 + (n / 5), 2 + 15 * (n % 5));
347     }
348
349     if(!get_player_sex(creature_ptr, buf))
350         return FALSE;
351
352     clear_from(10);
353     creature_ptr->prace = 0;
354     while (TRUE) {
355         char temp[80 * 10];
356         if (!get_player_race(creature_ptr))
357             return FALSE;
358
359         clear_from(10);
360         roff_to_buf(race_explanations[creature_ptr->prace], 74, temp, sizeof(temp));
361         concptr t = temp;
362         for (int i = 0; i < 10; i++) {
363             if (t[0] == 0)
364                 break;
365             else {
366                 prt(t, 12 + i, 3);
367                 t += strlen(t) + 1;
368             }
369         }
370         if (get_check_strict(_("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
371             break;
372
373         clear_from(10);
374         c_put_str(TERM_WHITE, "              ", 4, 15);
375     }
376
377     clear_from(10);
378     creature_ptr->pclass = 0;
379     while (TRUE) {
380         char temp[80 * 9];
381         if (!get_player_class(creature_ptr))
382             return FALSE;
383
384         clear_from(10);
385         roff_to_buf(class_explanations[creature_ptr->pclass], 74, temp, sizeof(temp));
386         concptr t = temp;
387         for (int i = 0; i < 9; i++) {
388             if (t[0] == 0)
389                 break;
390             else {
391                 prt(t, 12 + i, 3);
392                 t += strlen(t) + 1;
393             }
394         }
395
396         if (get_check_strict(_("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
397             break;
398
399         c_put_str(TERM_WHITE, "              ", 5, 15);
400     }
401
402     if (!get_player_realms(creature_ptr))
403         return FALSE;
404
405     creature_ptr->pseikaku = 0;
406     while (TRUE) {
407         char temp[80 * 8];
408         if (!get_player_personality(creature_ptr))
409             return FALSE;
410
411         clear_from(10);
412         roff_to_buf(personality_explanations[creature_ptr->pseikaku], 74, temp, sizeof(temp));
413         concptr t = temp;
414         for (int i = 0; i < A_MAX; i++) {
415             if (t[0] == 0)
416                 break;
417             else {
418                 prt(t, 12 + i, 3);
419                 t += strlen(t) + 1;
420             }
421         }
422
423         if (get_check_strict(_("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y))
424             break;
425
426         c_put_str(TERM_L_BLUE, creature_ptr->name, 1, 34);
427         prt("", 1, 34 + strlen(creature_ptr->name));
428     }
429
430     clear_from(10);
431     put_str("                                   ", 3, 40);
432     put_str("                                   ", 4, 40);
433     put_str("                                   ", 5, 40);
434
435     screen_save();
436     do_cmd_options_aux(OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Option((*)s effect score)"));
437     screen_load();
438     if (autoroller || autochara)
439         auto_round = 0L;
440
441     if (autoroller)
442         if (!get_stat_limits(creature_ptr))
443             return FALSE;
444
445     chara_limit_type chara_limit;
446     initialize_chara_limit(&chara_limit);
447     if (autochara)
448         if (!get_chara_limits(creature_ptr, &chara_limit))
449             return FALSE;
450
451     clear_from(10);
452     init_turn(creature_ptr);
453     if (!display_auto_roller(creature_ptr, chara_limit))
454         return FALSE;
455
456     clear_from(23);
457     get_name(creature_ptr);
458     process_player_name(creature_ptr, current_world_ptr->creating_savefile);
459     edit_history(creature_ptr, process_autopick_file_command);
460     get_max_stats(creature_ptr);
461     get_virtues(creature_ptr);
462     prt(_("[ 'Q' 中断, 'S' 初めから, Enter ゲーム開始 ]", "['Q'uit, 'S'tart over, or Enter to continue]"), 23, _(14, 10));
463
464     char c = inkey();
465     if (c == 'Q')
466         birth_quit();
467
468     if (c == 'S')
469         return FALSE;
470
471     init_dungeon_quests(creature_ptr);
472     save_prev_data(creature_ptr, &previous_char);
473     previous_char.quick_ok = TRUE;
474     return TRUE;
475 }