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 "main/sound-definitions-table.h"
22 #include "main/sound-of-music.h"
23 #include "player-base/player-class.h"
24 #include "player-info/class-info.h"
25 #include "player-info/race-info.h"
26 #include "player/patron.h"
27 #include "player/player-personality.h"
28 #include "player/player-sex.h"
29 #include "player/player-status-table.h"
30 #include "player/player-status.h"
31 #include "player/process-name.h"
32 #include "system/game-option-types.h"
33 #include "system/player-type-definition.h"
34 #include "system/redrawing-flags-updater.h"
35 #include "term/screen-processor.h"
36 #include "term/term-color-types.h"
37 #include "term/z-form.h"
38 #include "util/enum-converter.h"
39 #include "util/int-char-converter.h"
40 #include "util/string-processor.h"
41 #include "view/display-birth.h" // 暫定。後で消す予定。
42 #include "view/display-player.h" // 暫定。後で消す.
43 #include "view/display-util.h"
44 #include "world/world.h"
49 * How often the autoroller will update the display and pause
50 * to check for user interuptions.
51 * Bigger values will make the autoroller faster, but slower
52 * system may have problems because the user can't stop the
53 * autoroller for this number of rolls.
55 #define AUTOROLLER_STEP 54321L
57 static void display_initial_birth_message(PlayerType *player_ptr)
60 put_str(_("名前 :", "Name :"), 1, 26);
61 put_str(_("性別 :", "Sex :"), 3, 1);
62 put_str(_("種族 :", "Race :"), 4, 1);
63 put_str(_("職業 :", "Class :"), 5, 1);
64 c_put_str(TERM_L_BLUE, player_ptr->name, 1, 34);
65 put_str(_("キャラクターを作成します。('S'やり直す, 'Q'終了, '?'ヘルプ)", "Make your character. ('S' Restart, 'Q' Quit, '?' Help)"), 8, 10);
66 put_str(_("注意:《性別》の違いはゲーム上ほとんど影響を及ぼしません。", "Note: Your 'sex' does not have any significant gameplay effects."), 23, 5);
70 * @prief 性別選択画面でヘルプを表示させる
71 * @param player_ptr プレイヤーへの参照ポインタ
73 * @details 他の関数名と被りそうだったので少し眺め
75 static void display_help_on_sex_select(PlayerType *player_ptr, char c)
78 do_cmd_help(player_ptr);
79 } else if (c == '=') {
81 do_cmd_options_aux(player_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
83 } else if (c != '4' && c != '6') {
89 * @brief 表示されている性別のラベルを取得する
91 * @return std::string 表示するラベルを保持
93 static std::string birth_sex_label(int cs)
98 if (cs < 0 || cs >= MAX_SEXES) {
99 ss << '*' << p2 << _("ランダム", "Random");
101 ss << I2A(cs) << p2 << sex_info[cs].title;
107 * @brief プレイヤーの性別選択を行う / Player sex
108 * @param player_ptr プレイヤーへの参照ポインタ
109 * @return やり直すならFALSE、それ以外はTRUE
111 static bool get_player_sex(PlayerType *player_ptr)
116 auto cur = birth_sex_label(os);
119 put_str(cur, 12 + (os / 5), 2 + 15 * (os % 5));
120 cur = birth_sex_label(cs);
121 c_put_str(TERM_YELLOW, cur, 12 + (cs / 5), 2 + 15 * (cs % 5));
130 strnfmt(buf, sizeof(buf), _("性別を選んで下さい (%c-%c) ('='初期オプション設定): ", "Choose a sex (%c-%c) ('=' for options): "), I2A(0), I2A(1));
131 put_str(buf, 10, 10);
141 if (c == ' ' || c == '\r' || c == '\n') {
142 k = cs == MAX_SEXES ? randint0(MAX_SEXES) : cs;
147 k = randint0(MAX_SEXES);
158 if (cs < MAX_SEXES) {
163 k = (islower(c) ? A2I(c) : -1);
164 if ((k >= 0) && (k < MAX_SEXES)) {
171 display_help_on_sex_select(player_ptr, c);
174 player_ptr->psex = i2enum<player_sex>(k);
175 sp_ptr = &sex_info[player_ptr->psex];
176 c_put_str(TERM_L_BLUE, sp_ptr->title, 3, 15);
180 static bool let_player_select_race(PlayerType *player_ptr)
183 player_ptr->prace = PlayerRaceType::HUMAN;
185 if (!get_player_race(player_ptr)) {
190 display_wrap_around(race_explanations[enum2i(player_ptr->prace)], 74, 12, 3);
191 if (get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y)) {
196 c_put_str(TERM_WHITE, " ", 4, 15);
202 static bool let_player_select_class(PlayerType *player_ptr)
205 player_ptr->pclass = PlayerClassType::WARRIOR;
207 if (!get_player_class(player_ptr)) {
212 display_wrap_around(class_explanations[enum2i(player_ptr->pclass)], 74, 12, 3);
214 if (get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y)) {
218 c_put_str(TERM_WHITE, " ", 5, 15);
224 static bool let_player_select_personality(PlayerType *player_ptr)
226 player_ptr->ppersonality = PERSONALITY_ORDINARY;
228 if (!get_player_personality(player_ptr)) {
233 display_wrap_around(personality_explanations[player_ptr->ppersonality], 74, 12, 3);
235 if (get_check_strict(player_ptr, _("よろしいですか?", "Are you sure? "), CHECK_DEFAULT_Y)) {
239 c_put_str(TERM_L_BLUE, player_ptr->name, 1, 34);
240 prt("", 1, 34 + strlen(player_ptr->name));
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 if ((player_ptr->ht < chara_limit.htmin) || (player_ptr->ht > chara_limit.htmax)) {
387 if ((player_ptr->wt < chara_limit.wtmin) || (player_ptr->wt > chara_limit.wtmax)) {
390 if ((player_ptr->sc < chara_limit.scmin) || (player_ptr->sc > chara_limit.scmax)) {
398 static bool display_auto_roller_count(PlayerType *player_ptr, const int col)
400 if ((auto_round % AUTOROLLER_STEP) != 0) {
404 birth_put_stats(player_ptr);
405 if (auto_upper_round) {
406 put_str(format("%d%09d", auto_upper_round, auto_round), 10, col + 20);
408 put_str(format("%10d", auto_round), 10, col + 20);
414 get_history(player_ptr);
421 static void exe_auto_roller(PlayerType *player_ptr, chara_limit_type chara_limit, const int col)
423 while (autoroller || autochara) {
424 get_stats(player_ptr);
427 bool accept = decide_initial_stat(player_ptr);
428 if (decide_body_spec(player_ptr, chara_limit, &accept)) {
432 if (display_auto_roller_count(player_ptr, col)) {
438 static bool display_auto_roller_result(PlayerType *player_ptr, bool prev, char *c)
441 auto &rfu = RedrawingFlagsUpdater::get_instance();
442 static constexpr auto flags = {
443 StatusRecalculatingFlag::BONUS,
444 StatusRecalculatingFlag::HP,
447 rfu.set_flags(flags);
448 update_creature(player_ptr);
449 player_ptr->chp = player_ptr->mhp;
450 player_ptr->csp = player_ptr->msp;
451 (void)display_player(player_ptr, mode);
454 term_addch(TERM_WHITE, b1);
455 term_addstr(-1, TERM_WHITE, _("'r' 次の数値", "'r'eroll"));
457 term_addstr(-1, TERM_WHITE, _(", 'p' 前の数値", ", 'p'revious"));
461 term_addstr(-1, TERM_WHITE, _(", 'h' その他の情報", ", 'h' Misc."));
463 term_addstr(-1, TERM_WHITE, _(", 'h' 生い立ちを表示", ", 'h'istory"));
466 term_addstr(-1, TERM_WHITE, _(", Enter この数値に決定", ", or Enter to accept"));
468 term_addch(TERM_WHITE, b2);
478 if (*c == '\r' || *c == '\n' || *c == ESCAPE) {
482 if ((*c == ' ') || (*c == 'r')) {
486 if (prev && (*c == 'p')) {
487 load_prev_data(player_ptr, true);
491 if ((*c == 'H') || (*c == 'h')) {
492 mode = ((mode != 0) ? 0 : 1);
496 birth_help_option(player_ptr, *c, BirthKind::AUTO_ROLLER);
504 * @brief オートロールを回して結果を表示し、その数値に決めるかさらに回すか確認する。
505 * @param player_ptr プレイヤーへの参照ポインタ
506 * @param chara_limit 社会的地位の要求水準
507 * @details 2つめの結果以降は、'p'キーで1つ前のロール結果に戻せる。
509 static bool display_auto_roller(PlayerType *player_ptr, chara_limit_type chara_limit)
515 if (autoroller || autochara) {
517 put_str(_("回数 :", "Round:"), 10, col + 10);
518 put_str(_("(ESCで停止)", "(Hit ESC to stop)"), 13, col + 13);
520 get_stats(player_ptr);
522 get_history(player_ptr);
525 display_auto_roller_success_rate(col);
526 exe_auto_roller(player_ptr, chara_limit, col);
527 if (autoroller || autochara) {
533 get_extra(player_ptr, true);
534 get_money(player_ptr);
535 player_ptr->chaos_patron = (int16_t)randint0(MAX_PATRON);
538 if (!display_auto_roller_result(player_ptr, prev, &c)) {
542 if (c == '\r' || c == '\n' || c == ESCAPE) {
546 save_prev_data(player_ptr, &previous_char);
547 previous_char.quick_ok = false;
555 * @brief 名前と生い立ちを設定する
556 * @param player_ptr プレイヤーへの参照ポインタ
557 * @details ついでにステータス限界もここで決めている
559 static void set_name_history(PlayerType *player_ptr)
562 get_name(player_ptr);
563 process_player_name(player_ptr, w_ptr->creating_savefile);
564 edit_history(player_ptr);
565 get_max_stats(player_ptr);
566 initialize_virtues(player_ptr);
567 prt(_("[ 'Q' 中断, 'S' 初めから, Enter ゲーム開始 ]", "['Q'uit, 'S'tart over, or Enter to continue]"), 23, _(14, 10));
571 * @brief プレイヤーキャラ作成ウィザード
573 * The delay may be reduced, but is recommended to keep players
574 * from continuously rolling up characters, which can be VERY
575 * expensive CPU wise. And it cuts down on player stupidity.
577 bool player_birth_wizard(PlayerType *player_ptr)
579 display_initial_birth_message(player_ptr);
580 for (int n = 0; n < MAX_SEXES; n++) {
581 put_str(birth_sex_label(n), 12 + (n / 5), 2 + 15 * (n % 5));
584 if (!let_player_build_character(player_ptr)) {
588 display_initial_options(player_ptr);
589 if (autoroller || autochara) {
591 auto_upper_round = 0L;
592 autoroll_chance = 0L;
596 if (!get_stat_limits(player_ptr)) {
601 chara_limit_type chara_limit;
602 initialize_chara_limit(&chara_limit);
604 if (!get_chara_limits(player_ptr, &chara_limit)) {
610 init_turn(player_ptr);
611 if (!display_auto_roller(player_ptr, chara_limit)) {
615 set_name_history(player_ptr);
625 init_dungeon_quests(player_ptr);
626 save_prev_data(player_ptr, &previous_char);
627 previous_char.quick_ok = true;