1 #include "birth/birth-wizard.h"
2 #include "avatar/avatar.h"
3 #include "birth/auto-roller.h"
4 #include "birth/birth-body-spec.h"
5 #include "birth/birth-explanations-table.h"
6 #include "birth/birth-select-class.h"
7 #include "birth/birth-select-personality.h"
8 #include "birth/birth-select-race.h"
9 #include "birth/birth-select-realm.h"
10 #include "birth/birth-stat.h"
11 #include "birth/birth-util.h"
12 #include "birth/game-play-initializer.h"
13 #include "birth/history-editor.h"
14 #include "birth/history-generator.h"
15 #include "birth/quick-start.h"
16 #include "cmd-io/cmd-gameoption.h"
17 #include "cmd-io/cmd-help.h"
18 #include "core/asking-player.h"
19 #include "game-option/birth-options.h"
20 #include "io/input-key-acceptor.h"
21 #include "locale/japanese.h"
22 #include "main/sound-definitions-table.h"
23 #include "main/sound-of-music.h"
24 #include "player-base/player-class.h"
25 #include "player-info/class-info.h"
26 #include "player-info/race-info.h"
27 #include "player/patron.h"
28 #include "player/player-personality.h"
29 #include "player/player-sex.h"
30 #include "player/player-status-table.h"
31 #include "player/player-status.h"
32 #include "player/process-name.h"
33 #include "system/game-option-types.h"
34 #include "system/player-type-definition.h"
35 #include "system/redrawing-flags-updater.h"
36 #include "term/screen-processor.h"
37 #include "term/term-color-types.h"
38 #include "term/z-form.h"
39 #include "util/enum-converter.h"
40 #include "util/int-char-converter.h"
41 #include "util/string-processor.h"
42 #include "view/display-birth.h" // 暫定。後で消す予定。
43 #include "view/display-player-misc-info.h"
44 #include "view/display-player.h" // 暫定。後で消す.
45 #include "view/display-util.h"
46 #include "world/world.h"
51 * How often the autoroller will update the display and pause
52 * to check for user interuptions.
53 * Bigger values will make the autoroller faster, but slower
54 * system may have problems because the user can't stop the
55 * autoroller for this number of rolls.
57 #define AUTOROLLER_STEP 54321L
59 static void display_initial_birth_message(PlayerType *player_ptr)
62 display_player_name(player_ptr, true);
63 put_str(_("性別 :", "Sex :"), 3, 1);
64 put_str(_("種族 :", "Race :"), 4, 1);
65 put_str(_("職業 :", "Class :"), 5, 1);
66 put_str(_("キャラクターを作成します。('S'やり直す, 'Q'終了, '?'ヘルプ)", "Make your character. ('S' Restart, 'Q' Quit, '?' Help)"), 8, 10);
67 put_str(_("注意:《性別》の違いはゲーム上ほとんど影響を及ぼしません。", "Note: Your 'sex' does not have any significant gameplay effects."), 23, 5);
71 * @prief 性別選択画面でヘルプを表示させる
72 * @param player_ptr プレイヤーへの参照ポインタ
74 * @details 他の関数名と被りそうだったので少し眺め
76 static void display_help_on_sex_select(PlayerType *player_ptr, char c)
79 do_cmd_help(player_ptr);
80 } else if (c == '=') {
82 do_cmd_options_aux(player_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
84 } else if (c != '4' && c != '6') {
90 * @brief 表示されている性別のラベルを取得する
92 * @return std::string 表示するラベルを保持
94 static std::string birth_sex_label(int cs)
99 if (cs < 0 || cs >= MAX_SEXES) {
100 ss << '*' << p2 << _("ランダム", "Random");
102 ss << I2A(cs) << p2 << sex_info[cs].title;
108 * @brief プレイヤーの性別選択を行う / Player sex
109 * @param player_ptr プレイヤーへの参照ポインタ
110 * @return やり直すならFALSE、それ以外はTRUE
112 static bool get_player_sex(PlayerType *player_ptr)
117 auto cur = birth_sex_label(os);
120 put_str(cur, 12 + (os / 5), 2 + 15 * (os % 5));
121 cur = birth_sex_label(cs);
122 c_put_str(TERM_YELLOW, cur, 12 + (cs / 5), 2 + 15 * (cs % 5));
131 strnfmt(buf, sizeof(buf), _("性別を選んで下さい (%c-%c) ('='初期オプション設定): ", "Choose a sex (%c-%c) ('=' for options): "), I2A(0), I2A(1));
132 put_str(buf, 10, 10);
142 if (c == ' ' || c == '\r' || c == '\n') {
143 k = cs == MAX_SEXES ? randint0(MAX_SEXES) : cs;
148 k = randint0(MAX_SEXES);
159 if (cs < MAX_SEXES) {
164 k = (islower(c) ? A2I(c) : -1);
165 if ((k >= 0) && (k < MAX_SEXES)) {
172 display_help_on_sex_select(player_ptr, c);
175 player_ptr->psex = i2enum<player_sex>(k);
176 sp_ptr = &sex_info[player_ptr->psex];
177 c_put_str(TERM_L_BLUE, sp_ptr->title, 3, 15);
181 static bool let_player_select_race(PlayerType *player_ptr)
184 player_ptr->prace = PlayerRaceType::HUMAN;
186 if (!get_player_race(player_ptr)) {
191 display_wrap_around(race_explanations[enum2i(player_ptr->prace)], 74, 12, 3);
192 if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::DEFAULT_Y)) {
197 c_put_str(TERM_WHITE, " ", 4, 15);
203 static bool let_player_select_class(PlayerType *player_ptr)
206 player_ptr->pclass = PlayerClassType::WARRIOR;
208 if (!get_player_class(player_ptr)) {
213 display_wrap_around(class_explanations[enum2i(player_ptr->pclass)], 74, 12, 3);
215 if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::DEFAULT_Y)) {
219 c_put_str(TERM_WHITE, " ", 5, 15);
225 static bool let_player_select_personality(PlayerType *player_ptr)
227 player_ptr->ppersonality = PERSONALITY_ORDINARY;
229 if (!get_player_personality(player_ptr)) {
234 display_wrap_around(personality_explanations[player_ptr->ppersonality], 74, 12, 3);
236 if (input_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), UserCheck::DEFAULT_Y)) {
240 display_player_name(player_ptr, true);
246 static bool let_player_build_character(PlayerType *player_ptr)
248 if (!get_player_sex(player_ptr)) {
252 if (!let_player_select_race(player_ptr)) {
256 if (!let_player_select_class(player_ptr)) {
260 if (!get_player_realms(player_ptr)) {
264 if (!let_player_select_personality(player_ptr)) {
268 PlayerClass(player_ptr).init_specific_data();
273 static void display_initial_options(PlayerType *player_ptr)
275 uint16_t expfact = get_expfact(player_ptr) - 100;
277 for (int i = 0; i < A_MAX; i++) {
278 adj[i] = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
283 put_str(_("修正の合計値", "Your total modification"), 3, 40);
284 put_str(_("腕力 知能 賢さ 器用 耐久 魅力 経験 ", "Str Int Wis Dex Con Chr EXP "), 4, 40);
285 strnfmt(buf, sizeof(buf), "%+3d %+3d %+3d %+3d %+3d %+3d %+4d%% ", adj[0], adj[1], adj[2], adj[3], adj[4], adj[5], expfact);
286 c_put_str(TERM_L_BLUE, buf, 5, 40);
288 put_str("HD ", 6, 40);
289 strnfmt(buf, sizeof(buf), "%2d", rp_ptr->r_mhp + cp_ptr->c_mhp + ap_ptr->a_mhp);
290 c_put_str(TERM_L_BLUE, buf, 6, 43);
292 put_str(_("隠密", "Stealth"), 6, 47);
293 if (PlayerClass(player_ptr).equals(PlayerClassType::BERSERKER)) {
294 angband_strcpy(buf, "xx", sizeof(buf));
296 strnfmt(buf, sizeof(buf), "%+2d", rp_ptr->r_stl + cp_ptr->c_stl + ap_ptr->a_stl);
298 c_put_str(TERM_L_BLUE, buf, 6, _(52, 55));
300 put_str(_("赤外線視力", "Infra"), 6, _(56, 59));
301 strnfmt(buf, sizeof(buf), _("%2dft", "%2dft"), 10 * rp_ptr->infra);
302 c_put_str(TERM_L_BLUE, buf, 6, _(67, 65));
306 do_cmd_options_aux(player_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
310 static void display_auto_roller_success_rate(const int col)
316 put_str(_("最小値", " Limit"), 2, col + 13);
317 put_str(_("現在値", " Roll"), 2, col + 24);
321 if (autoroll_chance >= 1) {
322 strnfmt(buf, sizeof(buf), _("確率 : 1/%8d00", "Prob : 1/%8d00"), autoroll_chance);
323 } else if (autoroll_chance == -999) {
324 angband_strcpy(buf, _("確率 : 不可能", "Prob : Impossible"), sizeof(buf));
326 angband_strcpy(buf, _("確率 : 1/10000以上", "Prob : >1/10000"), sizeof(buf));
328 put_str(buf, 11, col + 10);
330 put_str(_("注意 : 体格等のオートローラを併用時は、上記確率より困難です。", "Note : Prob may be lower when you use the 'autochara' option."), 22, 5);
332 for (int i = 0; i < A_MAX; i++) {
333 put_str(stat_names[i], 3 + i, col + 8);
334 int j = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
335 int m = adjust_stat(stat_limit[i], j);
336 c_put_str(TERM_L_BLUE, cnv_stat(m), 3 + i, col + 13);
340 static void auto_roller_count(void)
342 if (auto_round < 1000000000L) {
354 static bool decide_initial_stat(PlayerType *player_ptr)
361 for (int i = 0; i < A_MAX; i++) {
362 if (player_ptr->stat_max[i] < stat_limit[i]) {
371 static bool decide_body_spec(PlayerType *player_ptr, chara_limit_type chara_limit, bool *accept)
378 get_history(player_ptr);
381 if ((player_ptr->age < chara_limit.agemin) || (player_ptr->age > chara_limit.agemax)) {
384 const auto ht = _(inch_to_cm(player_ptr->ht), player_ptr->ht);
385 if ((ht < chara_limit.htmin) || (ht > chara_limit.htmax)) {
388 const auto wt = _(lb_to_kg(player_ptr->wt), player_ptr->wt);
389 if ((wt < chara_limit.wtmin) || (wt > chara_limit.wtmax)) {
392 if ((player_ptr->sc < chara_limit.scmin) || (player_ptr->sc > chara_limit.scmax)) {
400 static bool display_auto_roller_count(PlayerType *player_ptr, const int col)
402 if ((auto_round % AUTOROLLER_STEP) != 0) {
406 birth_put_stats(player_ptr);
407 if (auto_upper_round) {
408 put_str(format("%d%09d", auto_upper_round, auto_round), 10, col + 20);
410 put_str(format("%10d", auto_round), 10, col + 20);
416 get_history(player_ptr);
423 static void exe_auto_roller(PlayerType *player_ptr, chara_limit_type chara_limit, const int col)
425 while (autoroller || autochara) {
426 get_stats(player_ptr);
429 bool accept = decide_initial_stat(player_ptr);
430 if (decide_body_spec(player_ptr, chara_limit, &accept)) {
434 if (display_auto_roller_count(player_ptr, col)) {
440 static bool display_auto_roller_result(PlayerType *player_ptr, bool prev, char *c)
443 auto &rfu = RedrawingFlagsUpdater::get_instance();
444 static constexpr auto flags = {
445 StatusRecalculatingFlag::BONUS,
446 StatusRecalculatingFlag::HP,
449 rfu.set_flags(flags);
450 update_creature(player_ptr);
451 player_ptr->chp = player_ptr->mhp;
452 player_ptr->csp = player_ptr->msp;
453 (void)display_player(player_ptr, mode);
456 term_addch(TERM_WHITE, b1);
457 term_addstr(-1, TERM_WHITE, _("'r' 次の数値", "'r'eroll"));
459 term_addstr(-1, TERM_WHITE, _(", 'p' 前の数値", ", 'p'revious"));
463 term_addstr(-1, TERM_WHITE, _(", 'h' その他の情報", ", 'h' Misc."));
465 term_addstr(-1, TERM_WHITE, _(", 'h' 生い立ちを表示", ", 'h'istory"));
468 term_addstr(-1, TERM_WHITE, _(", Enter この数値に決定", ", or Enter to accept"));
470 term_addch(TERM_WHITE, b2);
480 if (*c == '\r' || *c == '\n' || *c == ESCAPE) {
484 if ((*c == ' ') || (*c == 'r')) {
488 if (prev && (*c == 'p')) {
489 load_prev_data(player_ptr, true);
493 if ((*c == 'H') || (*c == 'h')) {
494 mode = ((mode != 0) ? 0 : 1);
498 birth_help_option(player_ptr, *c, BirthKind::AUTO_ROLLER);
506 * @brief オートロールを回して結果を表示し、その数値に決めるかさらに回すか確認する。
507 * @param player_ptr プレイヤーへの参照ポインタ
508 * @param chara_limit 社会的地位の要求水準
509 * @details 2つめの結果以降は、'p'キーで1つ前のロール結果に戻せる。
511 static bool display_auto_roller(PlayerType *player_ptr, chara_limit_type chara_limit)
517 if (autoroller || autochara) {
519 put_str(_("回数 :", "Round:"), 10, col + 10);
520 put_str(_("(ESCで停止)", "(Hit ESC to stop)"), 13, col + 13);
522 get_stats(player_ptr);
524 get_history(player_ptr);
527 display_auto_roller_success_rate(col);
528 exe_auto_roller(player_ptr, chara_limit, col);
529 if (autoroller || autochara) {
535 get_extra(player_ptr, true);
536 get_money(player_ptr);
537 player_ptr->chaos_patron = (int16_t)randint0(MAX_PATRON);
540 if (!display_auto_roller_result(player_ptr, prev, &c)) {
544 if (c == '\r' || c == '\n' || c == ESCAPE) {
548 save_prev_data(player_ptr, &previous_char);
549 previous_char.quick_ok = false;
557 * @brief 名前と生い立ちを設定する
558 * @param player_ptr プレイヤーへの参照ポインタ
559 * @details ついでにステータス限界もここで決めている
561 static void set_name_history(PlayerType *player_ptr)
564 get_name(player_ptr);
565 process_player_name(player_ptr, w_ptr->creating_savefile);
566 edit_history(player_ptr);
567 get_max_stats(player_ptr);
568 initialize_virtues(player_ptr);
569 prt(_("[ 'Q' 中断, 'S' 初めから, Enter ゲーム開始 ]", "['Q'uit, 'S'tart over, or Enter to continue]"), 23, _(14, 10));
573 * @brief プレイヤーキャラ作成ウィザード
575 * The delay may be reduced, but is recommended to keep players
576 * from continuously rolling up characters, which can be VERY
577 * expensive CPU wise. And it cuts down on player stupidity.
579 bool player_birth_wizard(PlayerType *player_ptr)
581 display_initial_birth_message(player_ptr);
582 for (int n = 0; n < MAX_SEXES; n++) {
583 put_str(birth_sex_label(n), 12 + (n / 5), 2 + 15 * (n % 5));
586 if (!let_player_build_character(player_ptr)) {
590 display_initial_options(player_ptr);
591 if (autoroller || autochara) {
593 auto_upper_round = 0L;
594 autoroll_chance = 0L;
598 if (!get_stat_limits(player_ptr)) {
603 chara_limit_type chara_limit;
604 initialize_chara_limit(&chara_limit);
606 if (!get_chara_limits(player_ptr, &chara_limit)) {
612 init_turn(player_ptr);
613 if (!display_auto_roller(player_ptr, chara_limit)) {
617 set_name_history(player_ptr);
627 init_dungeon_quests(player_ptr);
628 save_prev_data(player_ptr, &previous_char);
629 previous_char.quick_ok = true;