OSDN Git Service

Merge pull request #2876 from backwardsEric/blue-mage-sprintf
[hengbandforosx/hengbandosx.git] / src / knowledge / knowledge-self.cpp
1 /*!
2  * @brief 自己に関する情報を表示する
3  * @date 2020/04/24
4  * @author Hourier
5  */
6
7 #include "knowledge/knowledge-self.h"
8 #include "avatar/avatar.h"
9 #include "birth/birth-explanations-table.h"
10 #include "core/show-file.h"
11 #include "flavor/flavor-describer.h"
12 #include "floor/floor-town.h"
13 #include "info-reader/fixed-map-parser.h"
14 #include "io-dump/dump-util.h"
15 #include "player-info/alignment.h"
16 #include "player-info/class-info.h"
17 #include "player/player-personality.h"
18 #include "player/player-status-table.h"
19 #include "player/race-info-table.h"
20 #include "realm/realm-names-table.h"
21 #include "store/store-util.h"
22 #include "system/item-entity.h"
23 #include "system/player-type-definition.h"
24 #include "util/angband-files.h"
25 #include "util/buffer-shaper.h"
26 #include "util/enum-converter.h"
27 #include "util/int-char-converter.h"
28 #include "util/string-processor.h"
29 #include "world/world.h"
30 #include <string>
31
32 /*
33  * List virtues & status
34  */
35 void do_cmd_knowledge_virtues(PlayerType *player_ptr)
36 {
37     FILE *fff = nullptr;
38     GAME_TEXT file_name[FILE_NAME_SIZE];
39     if (!open_temporary_file(&fff, file_name)) {
40         return;
41     }
42
43     std::string alg = PlayerAlignment(player_ptr).get_alignment_description();
44     fprintf(fff, _("現在の属性 : %s\n\n", "Your alignment : %s\n\n"), alg.data());
45     dump_virtues(player_ptr, fff);
46     angband_fclose(fff);
47     (void)show_file(player_ptr, true, file_name, _("八つの徳", "Virtues"), 0, 0);
48     fd_kill(file_name);
49 }
50
51 /*!
52  * @brief 自分に関する情報を画面に表示する
53  * @param player_ptr プレイヤーへの参照ポインタ
54  * @param fff ファイルポインタ
55  */
56 static void dump_yourself(PlayerType *player_ptr, FILE *fff)
57 {
58     if (!fff) {
59         return;
60     }
61
62     char temp[80 * 10];
63     shape_buffer(race_explanations[enum2i(player_ptr->prace)].data(), 78, temp, sizeof(temp));
64     fprintf(fff, "\n\n");
65     fprintf(fff, _("種族: %s\n", "Race: %s\n"), race_info[enum2i(player_ptr->prace)].title);
66     concptr t = temp;
67
68     for (int i = 0; i < 10; i++) {
69         if (t[0] == 0) {
70             break;
71         }
72         fprintf(fff, "%s\n", t);
73         t += strlen(t) + 1;
74     }
75
76     auto short_pclass = enum2i(player_ptr->pclass);
77     shape_buffer(class_explanations[short_pclass].data(), 78, temp, sizeof(temp));
78     fprintf(fff, "\n");
79     fprintf(fff, _("職業: %s\n", "Class: %s\n"), class_info[short_pclass].title);
80
81     t = temp;
82     for (int i = 0; i < 10; i++) {
83         if (t[0] == 0) {
84             break;
85         }
86         fprintf(fff, "%s\n", t);
87         t += strlen(t) + 1;
88     }
89
90     shape_buffer(personality_explanations[player_ptr->ppersonality].data(), 78, temp, sizeof(temp));
91     fprintf(fff, "\n");
92     fprintf(fff, _("性格: %s\n", "Pesonality: %s\n"), personality_info[player_ptr->ppersonality].title);
93
94     t = temp;
95     for (int i = 0; i < A_MAX; i++) {
96         if (t[0] == 0) {
97             break;
98         }
99         fprintf(fff, "%s\n", t);
100         t += strlen(t) + 1;
101     }
102
103     fprintf(fff, "\n");
104     if (player_ptr->realm1) {
105         shape_buffer(realm_explanations[technic2magic(player_ptr->realm1) - 1].data(), 78, temp, sizeof(temp));
106         fprintf(fff, _("魔法: %s\n", "Realm: %s\n"), realm_names[player_ptr->realm1]);
107
108         t = temp;
109         for (int i = 0; i < A_MAX; i++) {
110             if (t[0] == 0) {
111                 break;
112             }
113
114             fprintf(fff, "%s\n", t);
115             t += strlen(t) + 1;
116         }
117     }
118
119     fprintf(fff, "\n");
120     if (player_ptr->realm2) {
121         shape_buffer(realm_explanations[technic2magic(player_ptr->realm2) - 1].data(), 78, temp, sizeof(temp));
122         fprintf(fff, _("魔法: %s\n", "Realm: %s\n"), realm_names[player_ptr->realm2]);
123
124         t = temp;
125         for (int i = 0; i < A_MAX; i++) {
126             if (t[0] == 0) {
127                 break;
128             }
129
130             fprintf(fff, "%s\n", t);
131             t += strlen(t) + 1;
132         }
133     }
134 }
135
136 /*!
137  * @brief 勝利済みの職業をダンプする
138  * @param fff ファイルストリームのポインタ
139  */
140 static void dump_winner_classes(FILE *fff)
141 {
142     int n = w_ptr->sf_winner.count();
143     concptr ss = n > 1 ? _("", "s") : "";
144     fprintf(fff, _("*勝利*済みの職業%s : %d\n", "Class of *Winner%s* : %d\n"), ss, n);
145     if (n == 0) {
146         return;
147     }
148
149     size_t max_len = 75;
150     std::string s = "";
151     std::string l = "";
152     for (int c = 0; c < PLAYER_CLASS_TYPE_MAX; c++) {
153         if (w_ptr->sf_winner.has_not(i2enum<PlayerClassType>(c))) {
154             continue;
155         }
156
157         auto &cl = class_info[c];
158         auto t = std::string(cl.title);
159
160         if (w_ptr->sf_retired.has_not(i2enum<PlayerClassType>(c))) {
161             t = "(" + t + ")";
162         }
163
164         if (l.size() + t.size() + 2 > max_len) {
165             fprintf(fff, " %s\n", str_rtrim(l).data());
166             l = "";
167         }
168         if (l.size() > 0) {
169             l += ", ";
170         }
171         l += t;
172     }
173
174     if (l.size() > 0) {
175         fprintf(fff, " %s\n", str_rtrim(l).data());
176     }
177 }
178
179 /*
180  * List virtues & status
181  *
182  */
183 void do_cmd_knowledge_stat(PlayerType *player_ptr)
184 {
185     FILE *fff = nullptr;
186     GAME_TEXT file_name[FILE_NAME_SIZE];
187     if (!open_temporary_file(&fff, file_name)) {
188         return;
189     }
190
191     update_playtime();
192     uint32_t play_time = w_ptr->play_time;
193     uint32_t all_time = w_ptr->sf_play_time + play_time;
194     fprintf(fff, _("現在のプレイ時間 : %d:%02d:%02d\n", "Current Play Time is %d:%02d:%02d\n"), play_time / (60 * 60), (play_time / 60) % 60, play_time % 60);
195     fprintf(fff, _("合計のプレイ時間 : %d:%02d:%02d\n", "  Total play Time is %d:%02d:%02d\n"), all_time / (60 * 60), (all_time / 60) % 60, all_time % 60);
196     fputs("\n", fff);
197
198     int percent = (int)(((long)player_ptr->player_hp[PY_MAX_LEVEL - 1] * 200L) / (2 * player_ptr->hitdie + ((PY_MAX_LEVEL - 1 + 3) * (player_ptr->hitdie + 1))));
199
200     if (player_ptr->knowledge & KNOW_HPRATE) {
201         fprintf(fff, _("現在の体力ランク : %d/100\n\n", "Your current Life Rating is %d/100.\n\n"), percent);
202     } else {
203         fprintf(fff, _("現在の体力ランク : ???\n\n", "Your current Life Rating is ???.\n\n"));
204     }
205
206     fprintf(fff, _("能力の最大値\n\n", "Limits of maximum stats\n\n"));
207     for (int v_nr = 0; v_nr < A_MAX; v_nr++) {
208         if ((player_ptr->knowledge & KNOW_STAT) || player_ptr->stat_max[v_nr] == player_ptr->stat_max_max[v_nr]) {
209             fprintf(fff, "%s 18/%d\n", stat_names[v_nr], player_ptr->stat_max_max[v_nr] - 18);
210         } else {
211             fprintf(fff, "%s ???\n", stat_names[v_nr]);
212         }
213     }
214
215     dump_yourself(player_ptr, fff);
216     dump_winner_classes(fff);
217     angband_fclose(fff);
218
219     (void)show_file(player_ptr, true, file_name, _("自分に関する情報", "HP-rate & Max stat"), 0, 0);
220     fd_kill(file_name);
221 }
222
223 /*
224  * List my home
225  * @param player_ptr プレイヤーへの参照ポインタ
226  */
227 void do_cmd_knowledge_home(PlayerType *player_ptr)
228 {
229     parse_fixed_map(player_ptr, WILDERNESS_DEFINITION, 0, 0, w_ptr->max_wild_y, w_ptr->max_wild_x);
230
231     FILE *fff = nullptr;
232     GAME_TEXT file_name[FILE_NAME_SIZE];
233     if (!open_temporary_file(&fff, file_name)) {
234         return;
235     }
236
237     store_type *store_ptr;
238     store_ptr = &town_info[1].store[enum2i(StoreSaleType::HOME)];
239
240     if (store_ptr->stock_num) {
241 #ifdef JP
242         TERM_LEN x = 1;
243 #endif
244         fprintf(fff, _("  [ 我が家のアイテム ]\n", "  [Home Inventory]\n"));
245         concptr paren = ")";
246         GAME_TEXT o_name[MAX_NLEN];
247         for (int i = 0; i < store_ptr->stock_num; i++) {
248 #ifdef JP
249             if ((i % 12) == 0) {
250                 fprintf(fff, "\n ( %d ページ )\n", x++);
251             }
252             describe_flavor(player_ptr, o_name, &store_ptr->stock[i], 0);
253             if (strlen(o_name) <= 80 - 3) {
254                 fprintf(fff, "%c%s %s\n", I2A(i % 12), paren, o_name);
255             } else {
256                 int n;
257                 char *t;
258                 for (n = 0, t = o_name; n < 80 - 3; n++, t++) {
259                     if (iskanji(*t)) {
260                         t++;
261                         n++;
262                     }
263                 }
264                 if (n == 81 - 3) {
265                     n = 79 - 3;
266                 } /* 最後が漢字半分 */
267
268                 fprintf(fff, "%c%s %.*s\n", I2A(i % 12), paren, n, o_name);
269                 fprintf(fff, "   %.77s\n", o_name + n);
270             }
271 #else
272             describe_flavor(player_ptr, o_name, &store_ptr->stock[i], 0);
273             fprintf(fff, "%c%s %s\n", I2A(i % 12), paren, o_name);
274 #endif
275         }
276
277         fprintf(fff, "\n\n");
278     }
279
280     angband_fclose(fff);
281     (void)show_file(player_ptr, true, file_name, _("我が家のアイテム", "Home Inventory"), 0, 0);
282     fd_kill(file_name);
283 }