2 * @brief プレイヤーのインターフェイスに関するコマンドの実装 / Interface commands
4 * @author Mogami & Hourier
7 #include "io/read-pref-file.h"
8 #include "autopick/autopick-pref-processor.h"
9 #include "autopick/autopick-reader-writer.h"
10 #include "core/asking-player.h"
11 #include "io-dump/dump-remover.h"
12 #include "io/files-util.h"
13 #include "io/interpret-pref-file.h"
14 #include "io/pref-file-expressor.h"
15 #include "player-info/class-info.h"
16 #include "player-info/race-info.h"
17 #include "realm/realm-names-table.h"
18 #include "system/player-type-definition.h"
19 #include "term/z-form.h"
20 #include "util/angband-files.h"
21 #include "util/buffer-shaper.h"
22 #include "util/string-processor.h"
23 #include "view/display-messages.h"
24 #include "world/world.h"
29 //!< @todo コールバック関数に変更するので、いずれ消す.
30 #define PREF_TYPE_NORMAL 0
31 #define PREF_TYPE_AUTOPICK 1
32 #define PREF_TYPE_HISTPREF 2
34 char auto_dump_header[] = "# vvvvvvv== %s ==vvvvvvv";
35 char auto_dump_footer[] = "# ^^^^^^^== %s ==^^^^^^^";
37 // Mark strings for auto dump
39 // Variables for auto dump
40 static int auto_dump_line_num;
43 * @brief process_pref_fileのサブルーチン /
44 * Open the "user pref file" and parse it.
45 * @param player_ptr プレイヤーへの参照ポインタ
46 * @param name 読み込むファイル名
47 * @param preftype prefファイルのタイプ
51 static errr process_pref_file_aux(PlayerType *player_ptr, const std::filesystem::path &name, int preftype)
53 auto *fp = angband_fopen(name, FileOpenMode::READ);
61 std::vector<char> file_read__buf(FILE_READ_BUFF_SIZE);
62 std::string error_line;
63 while (angband_fgets(fp, file_read__buf.data(), file_read__buf.size()) == 0) {
65 if (!file_read__buf[0]) {
70 if (!iskanji(file_read__buf[0]))
72 if (iswspace(file_read__buf[0])) {
76 if (file_read__buf[0] == '#') {
79 error_line = file_read__buf.data();
81 /* Process "?:<expr>" */
82 if ((file_read__buf[0] == '?') && (file_read__buf[1] == ':')) {
85 s = file_read__buf.data() + 2;
86 concptr v = process_pref_file_expr(player_ptr, &s, &f);
87 bypass = streq(v, "0");
95 /* Process "%:<file>" */
96 if (file_read__buf[0] == '%') {
97 static int depth_count = 0;
98 if (depth_count > 20) {
104 case PREF_TYPE_AUTOPICK:
105 (void)process_autopick_file(player_ptr, file_read__buf.data() + 2);
107 case PREF_TYPE_HISTPREF:
108 (void)process_histpref_file(player_ptr, file_read__buf.data() + 2);
111 (void)process_pref_file(player_ptr, file_read__buf.data() + 2);
119 err = interpret_pref_file(player_ptr, file_read__buf.data());
121 if (preftype != PREF_TYPE_AUTOPICK) {
125 process_autopick_file_command(file_read__buf.data());
131 /* Print error message */
132 /* ToDo: Add better error messages */
133 const auto &name_str = name.string();
134 msg_format(_("ファイル'%s'の%d行でエラー番号%dのエラー。", "Error %d in line %d of file '%s'."), _(name_str.data(), err), line, _(err, name_str.data()));
135 msg_format(_("('%s'を解析中)", "Parsing '%s'"), error_line.data());
144 * @brief pref設定ファイルを読み込み設定を反映させる /
145 * Process the "user pref file" with the given name
146 * @param player_ptr プレイヤーへの参照ポインタ
147 * @param name 読み込むファイル名
148 * @param only_user_dir trueを指定するとANGBAND_DIR_USERからの読み込みのみ行う
152 * See the functions above for a list of legal "commands".
153 * We also accept the special "?" and "%" directives, which
154 * allow conditional evaluation and filename inclusion.
157 errr process_pref_file(PlayerType *player_ptr, std::string_view name, bool only_user_dir)
160 if (!only_user_dir) {
161 const auto &path = path_build(ANGBAND_DIR_PREF, name);
162 err1 = process_pref_file_aux(player_ptr, path, PREF_TYPE_NORMAL);
168 const auto &path = path_build(ANGBAND_DIR_USER, name);
169 errr err2 = process_pref_file_aux(player_ptr, path, PREF_TYPE_NORMAL);
170 if (err2 < 0 && !err1) {
178 * @brief 自動拾いファイルを読み込む /
179 * @param player_ptr プレイヤーへの参照ポインタ
183 errr process_autopick_file(PlayerType *player_ptr, std::string_view name)
185 const auto &path = path_build(ANGBAND_DIR_USER, name);
186 return process_pref_file_aux(player_ptr, path, PREF_TYPE_AUTOPICK);
190 * @brief プレイヤーの生い立ちファイルを読み込む /
191 * Process file for player's history editor.
192 * @param player_ptr プレイヤーへの参照ポインタ
197 errr process_histpref_file(PlayerType *player_ptr, std::string_view name)
199 bool old_character_xtra = w_ptr->character_xtra;
200 const auto &path = path_build(ANGBAND_DIR_USER, name);
201 w_ptr->character_xtra = true;
202 errr err = process_pref_file_aux(player_ptr, path, PREF_TYPE_HISTPREF);
203 w_ptr->character_xtra = old_character_xtra;
208 * @brief prfファイルのフォーマットに従った内容を出力する /
209 * Dump a formatted line, using "vstrnfmt()".
212 void auto_dump_printf(FILE *auto_dump_stream, const char *fmt, ...)
217 (void)vstrnfmt(buf, sizeof(buf), fmt, vp);
219 for (auto p = buf; *p; p++) {
221 auto_dump_line_num++;
225 fprintf(auto_dump_stream, "%s", buf);
229 * @brief prfファイルをファイルオープンする /
230 * Open file to append auto dump.
232 * @param mark 出力するヘッダマーク
233 * @return ファイルポインタを取得できたらTRUEを返す
235 bool open_auto_dump(FILE **fpp, const std::filesystem::path &path, std::string_view mark)
237 char header_mark_str[80];
238 strnfmt(header_mark_str, sizeof(header_mark_str), auto_dump_header, mark.data());
239 remove_auto_dump(path, mark);
240 *fpp = angband_fopen(path, FileOpenMode::APPEND);
242 const auto &path_str = path.string();
243 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), path_str.data());
248 fprintf(*fpp, "%s\n", header_mark_str);
249 auto_dump_line_num = 0;
250 auto_dump_printf(*fpp, _("# *警告!!* 以降の行は自動生成されたものです。\n", "# *Warning!* The lines below are an automatic dump.\n"));
252 *fpp, _("# *警告!!* 後で自動的に削除されるので編集しないでください。\n", "# Don't edit them; changes will be deleted and replaced automatically.\n"));
257 * @brief prfファイルをファイルクローズする /
258 * Append foot part and close auto dump.
259 * @param auto_dump_mark 出力するヘッダマーク
261 void close_auto_dump(FILE **fpp, std::string_view mark)
263 char footer_mark_str[80];
264 strnfmt(footer_mark_str, sizeof(footer_mark_str), auto_dump_footer, mark.data());
265 auto_dump_printf(*fpp, _("# *警告!!* 以降の行は自動生成されたものです。\n", "# *Warning!* The lines below are an automatic dump.\n"));
267 *fpp, _("# *警告!!* 後で自動的に削除されるので編集しないでください。\n", "# Don't edit them; changes will be deleted and replaced automatically.\n"));
268 fprintf(*fpp, "%s (%d)\n", footer_mark_str, auto_dump_line_num);
269 angband_fclose(*fpp);
273 * @brief 全ユーザプロファイルをロードする / Load some "user pref files"
274 * @paaram player_ptr プレイヤーへの参照ポインタ
276 * Modified by Arcum Dagsson to support
277 * separate macro files for different realms.
279 void load_all_pref_files(PlayerType *player_ptr)
281 process_pref_file(player_ptr, "user.prf");
282 process_pref_file(player_ptr, std::string("user-").append(ANGBAND_SYS).append(".prf"));
283 process_pref_file(player_ptr, std::string(rp_ptr->title).append(".prf"));
284 process_pref_file(player_ptr, std::string(cp_ptr->title).append(".prf"));
285 process_pref_file(player_ptr, std::string(player_ptr->base_name).append(".prf"));
286 if (player_ptr->realm1 != REALM_NONE) {
287 process_pref_file(player_ptr, std::string(realm_names[player_ptr->realm1]).append(".prf"));
290 if (player_ptr->realm2 != REALM_NONE) {
291 process_pref_file(player_ptr, std::string(realm_names[player_ptr->realm2]).append(".prf"));
294 autopick_load_pref(player_ptr, false);
298 * @brief 生い立ちメッセージをファイルからロードする。
300 bool read_histpref(PlayerType *player_ptr)
305 char histbuf[HISTPREF_LIMIT];
307 if (!get_check(_("生い立ち設定ファイルをロードしますか? ", "Load background history preference file? "))) {
312 histpref_buf = histbuf;
314 err = process_histpref_file(player_ptr, std::string(_("histedit-", "histpref-")).append(player_ptr->base_name).append(".prf").data());
317 err = process_histpref_file(player_ptr, _("histedit.prf", "histpref.prf"));
321 msg_print(_("生い立ち設定ファイルの読み込みに失敗しました。", "Failed to load background history preference."));
323 histpref_buf = nullptr;
325 } else if (!histpref_buf[0]) {
326 msg_print(_("有効な生い立ち設定はこのファイルにありません。", "There does not exist valid background history preference."));
328 histpref_buf = nullptr;
332 for (i = 0; i < 4; i++) {
333 player_ptr->history[i][0] = '\0';
337 for (s = histpref_buf; *s == ' '; s++) {
342 while ((n > 0) && (s[n - 1] == ' ')) {
346 constexpr auto max_line_len = sizeof(player_ptr->history[0]);
347 const auto history_lines = shape_buffer(s, max_line_len);
348 const auto max_lines = std::min<int>(4, history_lines.size());
349 for (auto l = 0; l < max_lines; ++l) {
350 angband_strcpy(player_ptr->history[l], history_lines[l], max_line_len);
353 for (i = 0; i < 4; i++) {
355 for (j = 0; player_ptr->history[i][j]; j++) {
359 for (; j < 59; j++) {
360 player_ptr->history[i][j] = ' ';
362 player_ptr->history[i][59] = '\0';
365 histpref_buf = nullptr;