OSDN Git Service

Merge pull request #1927 from dis-/feature/fix-special-disturb
[hengbandforosx/hengbandosx.git] / src / birth / birth-select-class.cpp
1 #include "birth/birth-select-class.h"
2 #include "birth/birth-util.h"
3 #include "io/input-key-acceptor.h"
4 #include "player-info/class-info.h"
5 #include "player-info/race-info.h"
6 #include "system/player-type-definition.h"
7 #include "term/screen-processor.h"
8 #include "term/term-color-types.h"
9 #include "util/int-char-converter.h"
10 #include "world/world.h"
11
12 static const char p2 = ')';
13
14 static TERM_COLOR birth_class_color(PlayerClassType cs)
15 {
16     if (cs < PlayerClassType::MAX) {
17         if (is_retired_class(cs))
18             return TERM_L_DARK;
19         if (is_winner_class(cs))
20             return TERM_SLATE;
21     }
22     return TERM_WHITE;
23 }
24
25 static void enumerate_class_list(char *sym)
26 {
27     for (auto n = 0; n < PLAYER_CLASS_TYPE_MAX; n++) {
28         cp_ptr = &class_info[n];
29         mp_ptr = &m_info[n];
30         concptr str = cp_ptr->title;
31         if (n < 26)
32             sym[n] = I2A(n);
33         else
34             sym[n] = ('A' + n - 26);
35
36         char buf[80];
37         if (!(rp_ptr->choice & (1UL << n)))
38             sprintf(buf, "%c%c(%s)", sym[n], p2, str);
39         else
40             sprintf(buf, "%c%c%s", sym[n], p2, str);
41
42         auto cs = i2enum<PlayerClassType>(n);
43         c_put_str(birth_class_color(cs), buf, 13 + (n / 4), 2 + 19 * (n % 4));
44     }
45 }
46
47 static void display_class_stat(int cs, int *os, char *cur, char *sym)
48 {
49     if (cs == *os)
50         return;
51
52     auto pclass = i2enum<PlayerClassType>(*os);
53     c_put_str(birth_class_color(pclass), cur, 13 + (*os / 4), 2 + 19 * (*os % 4));
54     put_str("                                   ", 3, 40);
55     if (cs == PLAYER_CLASS_TYPE_MAX) {
56         sprintf(cur, "%c%c%s", '*', p2, _("ランダム", "Random"));
57         put_str("                                   ", 4, 40);
58         put_str("                                   ", 5, 40);
59         put_str("                                   ", 6, 40);
60     } else {
61         cp_ptr = &class_info[cs];
62         mp_ptr = &m_info[cs];
63         concptr str = cp_ptr->title;
64         if (!(rp_ptr->choice & (1UL << cs)))
65             sprintf(cur, "%c%c(%s)", sym[cs], p2, str);
66         else
67             sprintf(cur, "%c%c%s", sym[cs], p2, str);
68
69         c_put_str(TERM_L_BLUE, cp_ptr->title, 3, 40);
70         put_str(_("の職業修正", ": Class modification"), 3, 40 + strlen(cp_ptr->title));
71         put_str(_("腕力 知能 賢さ 器用 耐久 魅力 経験 ", "Str  Int  Wis  Dex  Con  Chr   EXP "), 4, 40);
72         char buf[80];
73         sprintf(buf, "%+3d  %+3d  %+3d  %+3d  %+3d  %+3d %+4d%% ", cp_ptr->c_adj[0], cp_ptr->c_adj[1], cp_ptr->c_adj[2], cp_ptr->c_adj[3], cp_ptr->c_adj[4],
74             cp_ptr->c_adj[5], cp_ptr->c_exp);
75         c_put_str(TERM_L_BLUE, buf, 5, 40);
76
77         put_str("HD", 6, 40);
78         sprintf(buf, "%+3d", cp_ptr->c_mhp);
79         c_put_str(TERM_L_BLUE, buf, 6, 42);
80
81         put_str(_("隠密", "Stealth"), 6, 47);
82         if (i2enum<PlayerClassType>(cs) == PlayerClassType::BERSERKER)
83             strcpy(buf, " xx");
84         else
85             sprintf(buf, " %+2d", cp_ptr->c_stl);
86         c_put_str(TERM_L_BLUE, buf, 6, _(51, 54));
87     }
88
89     c_put_str(TERM_YELLOW, cur, 13 + (cs / 4), 2 + 19 * (cs % 4));
90     *os = cs;
91 }
92
93 static void interpret_class_select_key_move(char c, int *cs)
94 {
95     if (c == '8') {
96         if (*cs >= 4)
97             *cs -= 4;
98     }
99
100     if (c == '4') {
101         if (*cs > 0)
102             (*cs)--;
103     }
104
105     if (c == '6') {
106         if (*cs < PLAYER_CLASS_TYPE_MAX)
107             (*cs)++;
108     }
109
110     if (c == '2') {
111         if (*cs + 4 <= PLAYER_CLASS_TYPE_MAX)
112             *cs += 4;
113     }
114 }
115
116 static bool select_class(PlayerType *player_ptr, char *cur, char *sym, int *k)
117 {
118     auto cs = player_ptr->pclass;
119     auto os = PlayerClassType::MAX;
120     int int_os = enum2i(os);
121     int int_cs = enum2i(cs);
122     while (true) {
123         display_class_stat(int_cs, &int_os, cur, sym);
124         if (*k >= 0)
125             break;
126
127         char buf[80];
128         sprintf(buf, _("職業を選んで下さい (%c-%c) ('='初期オプション設定, 灰色:勝利済): ", "Choose a class (%c-%c) ('=' for options, Gray is winner): "),
129             sym[0], sym[PLAYER_CLASS_TYPE_MAX - 1]);
130
131         put_str(buf, 10, 6);
132         char c = inkey();
133         if (c == 'Q')
134             birth_quit();
135
136         if (c == 'S')
137             return false;
138
139         if (c == ' ' || c == '\r' || c == '\n') {
140             if (int_cs == enum2i(PlayerClassType::MAX)) {
141                 *k = randint0(PLAYER_CLASS_TYPE_MAX);
142                 cs = i2enum<PlayerClassType>(*k);
143                 continue;
144             } else {
145                 *k = int_cs;
146                 break;
147             }
148         }
149
150         interpret_class_select_key_move(c, &int_cs);
151         if (c == '*') {
152             *k = randint0(PLAYER_CLASS_TYPE_MAX);
153             cs = i2enum<PlayerClassType>(*k);
154             continue;
155         }
156
157         *k = (islower(c) ? A2I(c) : -1);
158         if ((*k >= 0) && (*k < PLAYER_CLASS_TYPE_MAX)) {
159             cs = i2enum<PlayerClassType>(*k);
160             continue;
161         }
162
163         *k = (isupper(c) ? (26 + c - 'A') : -1);
164         if ((*k >= 26) && (*k < PLAYER_CLASS_TYPE_MAX)) {
165             cs = i2enum<PlayerClassType>(*k);
166             continue;
167         } else
168             *k = -1;
169
170         birth_help_option(player_ptr, c, BK_CLASS);
171     }
172
173     return true;
174 }
175
176 /*!
177  * @brief プレイヤーの職業選択を行う / Player class
178  */
179 bool get_player_class(PlayerType *player_ptr)
180 {
181     clear_from(10);
182     put_str(
183         _("注意:《職業》によってキャラクターの先天的な能力やボーナスが変化します。", "Note: Your 'class' determines various intrinsic abilities and bonuses."),
184         23, 5);
185     put_str(_("()で囲まれた選択肢はこの種族には似合わない職業です。", "Any entries in parentheses should only be used by advanced players."), 11, 5);
186     put_str("                                   ", 6, 40);
187
188     char sym[PLAYER_CLASS_TYPE_MAX];
189     enumerate_class_list(sym);
190
191     char cur[80];
192     sprintf(cur, "%c%c%s", '*', p2, _("ランダム", "Random"));
193     int k = -1;
194     if (!select_class(player_ptr, cur, sym, &k))
195         return false;
196
197     player_ptr->pclass = i2enum<PlayerClassType>(k);
198     cp_ptr = &class_info[enum2i(player_ptr->pclass)];
199     mp_ptr = &m_info[enum2i(player_ptr->pclass)];
200     c_put_str(TERM_L_BLUE, cp_ptr->title, 5, 15);
201     return true;
202 }