1 #include "cmd-visual/cmd-visuals.h"
2 #include "cmd-visual/cmd-draw.h"
3 #include "core/asking-player.h"
4 #include "core/visuals-reseter.h"
5 #include "flavor/flavor-describer.h"
6 #include "flavor/object-flavor-types.h"
7 #include "flavor/object-flavor.h"
8 #include "game-option/special-options.h"
9 #include "grid/feature.h"
10 #include "io/files-util.h"
11 #include "io/input-key-acceptor.h"
12 #include "io/read-pref-file.h"
13 #include "knowledge/knowledge-features.h"
14 #include "knowledge/knowledge-items.h"
15 #include "knowledge/knowledge-monsters.h"
16 #include "knowledge/lighting-level-table.h"
17 #include "main/sound-of-music.h"
18 #include "monster-race/monster-race.h"
19 #include "system/baseitem-info.h"
20 #include "system/item-entity.h"
21 #include "system/monster-race-info.h"
22 #include "system/player-type-definition.h"
23 #include "system/terrain-type-definition.h"
24 #include "term/screen-processor.h"
25 #include "term/term-color-types.h"
26 #include "term/z-form.h"
27 #include "util/angband-files.h"
28 #include "util/int-char-converter.h"
29 #include "view/display-messages.h"
33 * @brief キャラクタのビジュアルIDを変更する際の対象指定関数
34 * @param i 指定対象となるキャラクタコード
35 * @param initial_visual_id 指定されたビジュアルID
36 * @param max ビジュアルIDの最大数
37 * @return 指定が実際に行われたかと、その時のビジュアルIDの組み合わせ
39 static std::optional<short> cmd_visuals_aux(int i, int initial_visual_id, short max)
41 auto visual_id = initial_visual_id;
43 if (!get_value("Input new number", 0, max - 1, &visual_id)) {
49 return static_cast<short>((visual_id + max - 1) % max);
52 return static_cast<short>((visual_id + 1) % max);
56 * @brief キャラクタの変更メニュー表示
57 * @param choice_msg 選択メッセージ
59 static void print_visuals_menu(concptr choice_msg)
61 prt(_("[ 画面表示の設定 ]", "Interact with Visuals"), 1, 0);
62 prt(_("(0) ユーザー設定ファイルのロード", "(0) Load a user pref file"), 3, 5);
63 prt(_("(1) モンスターの 色/文字 をファイルに書き出す", "(1) Dump monster attr/chars"), 4, 5);
64 prt(_("(2) アイテムの 色/文字 をファイルに書き出す", "(2) Dump object attr/chars"), 5, 5);
65 prt(_("(3) 地形の 色/文字 をファイルに書き出す", "(3) Dump feature attr/chars"), 6, 5);
66 prt(_("(4) モンスターの 色/文字 を変更する (数値操作)", "(4) Change monster attr/chars (numeric operation)"), 7, 5);
67 prt(_("(5) アイテムの 色/文字 を変更する (数値操作)", "(5) Change object attr/chars (numeric operation)"), 8, 5);
68 prt(_("(6) 地形の 色/文字 を変更する (数値操作)", "(6) Change feature attr/chars (numeric operation)"), 9, 5);
69 prt(_("(7) モンスターの 色/文字 を変更する (シンボルエディタ)", "(7) Change monster attr/chars (visual mode)"), 10, 5);
70 prt(_("(8) アイテムの 色/文字 を変更する (シンボルエディタ)", "(8) Change object attr/chars (visual mode)"), 11, 5);
71 prt(_("(9) 地形の 色/文字 を変更する (シンボルエディタ)", "(9) Change feature attr/chars (visual mode)"), 12, 5);
72 prt(_("(R) 画面表示方法の初期化", "(R) Reset visuals"), 13, 5);
73 prt(format(_("コマンド: %s", "Command: %s"), choice_msg ? choice_msg : _("", "")), 15, 0);
77 * Interact with "visuals"
79 void do_cmd_visuals(PlayerType *player_ptr)
81 FILE *auto_dump_stream;
83 bool need_redraw = false;
84 concptr empty_symbol = "<< ? >>";
86 empty_symbol = "<< ?? >>";
92 print_visuals_menu(nullptr);
100 prt(_("コマンド: ユーザー設定ファイルのロード", "Command: Load a user pref file"), 15, 0);
101 prt(_("ファイル: ", "File: "), 17, 0);
102 strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
103 if (!askfor(tmp, 70)) {
107 (void)process_pref_file(player_ptr, tmp, true);
112 prt(_("コマンド: モンスターの[色/文字]をファイルに書き出します", "Command: Dump monster attr/chars"), 15, 0);
113 prt(_("ファイル: ", "File: "), 17, 0);
114 strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
115 if (!askfor(tmp, 70)) {
119 const auto &path = path_build(ANGBAND_DIR_USER, tmp);
120 constexpr auto mark = "Monster attr/chars";
121 if (!open_auto_dump(&auto_dump_stream, path, mark)) {
125 auto_dump_printf(auto_dump_stream, _("\n# モンスターの[色/文字]の設定\n\n", "\n# Monster attr/char definitions\n\n"));
126 for (const auto &[r_idx, r_ref] : monraces_info) {
127 if (r_ref.name.empty()) {
131 auto_dump_printf(auto_dump_stream, "# %s\n", r_ref.name.data());
132 auto_dump_printf(auto_dump_stream, "R:%d:0x%02X/0x%02X\n\n", enum2i(r_ref.idx), (byte)(r_ref.x_attr), (byte)(r_ref.x_char));
135 close_auto_dump(&auto_dump_stream, mark);
136 msg_print(_("モンスターの[色/文字]をファイルに書き出しました。", "Dumped monster attr/chars."));
140 prt(_("コマンド: アイテムの[色/文字]をファイルに書き出します", "Command: Dump object attr/chars"), 15, 0);
141 prt(_("ファイル: ", "File: "), 17, 0);
142 strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
143 if (!askfor(tmp, 70)) {
147 const auto &path = path_build(ANGBAND_DIR_USER, tmp);
148 constexpr auto mark = "Object attr/chars";
149 if (!open_auto_dump(&auto_dump_stream, path, mark)) {
153 auto_dump_printf(auto_dump_stream, _("\n# アイテムの[色/文字]の設定\n\n", "\n# Object attr/char definitions\n\n"));
154 for (const auto &baseitem : baseitems_info) {
155 if (baseitem.name.empty()) {
159 std::string item_name;
160 if (baseitem.flavor == 0) {
161 item_name = strip_name(baseitem.idx);
164 dummy.prep(baseitem.idx);
165 item_name = describe_flavor(player_ptr, &dummy, OD_FORCE_FLAVOR);
168 auto_dump_printf(auto_dump_stream, "# %s\n", item_name.data());
169 auto_dump_printf(auto_dump_stream, "K:%d:0x%02X/0x%02X\n\n", (int)baseitem.idx, (byte)(baseitem.x_attr), (byte)(baseitem.x_char));
172 close_auto_dump(&auto_dump_stream, mark);
173 msg_print(_("アイテムの[色/文字]をファイルに書き出しました。", "Dumped object attr/chars."));
177 prt(_("コマンド: 地形の[色/文字]をファイルに書き出します", "Command: Dump feature attr/chars"), 15, 0);
178 prt(_("ファイル: ", "File: "), 17, 0);
179 strnfmt(tmp, sizeof(tmp), "%s.prf", player_ptr->base_name);
180 if (!askfor(tmp, 70)) {
184 const auto &path = path_build(ANGBAND_DIR_USER, tmp);
185 constexpr auto mark = "Feature attr/chars";
186 if (!open_auto_dump(&auto_dump_stream, path, mark)) {
190 auto_dump_printf(auto_dump_stream, _("\n# 地形の[色/文字]の設定\n\n", "\n# Feature attr/char definitions\n\n"));
191 for (const auto &f_ref : terrains_info) {
192 if (f_ref.name.empty()) {
195 if (f_ref.mimic != f_ref.idx) {
199 auto_dump_printf(auto_dump_stream, "# %s\n", (f_ref.name.data()));
200 auto_dump_printf(auto_dump_stream, "F:%d:0x%02X/0x%02X:0x%02X/0x%02X:0x%02X/0x%02X\n\n", f_ref.idx, (byte)(f_ref.x_attr[F_LIT_STANDARD]),
201 (byte)(f_ref.x_char[F_LIT_STANDARD]), (byte)(f_ref.x_attr[F_LIT_LITE]), (byte)(f_ref.x_char[F_LIT_LITE]),
202 (byte)(f_ref.x_attr[F_LIT_DARK]), (byte)(f_ref.x_char[F_LIT_DARK]));
205 close_auto_dump(&auto_dump_stream, mark);
206 msg_print(_("地形の[色/文字]をファイルに書き出しました。", "Dumped feature attr/chars."));
211 static auto choice_msg = _("モンスターの[色/文字]を変更します", "Change monster attr/chars");
212 static auto monrace_id = monraces_info.begin()->second.idx;
213 prt(format(_("コマンド: %s", "Command: %s"), choice_msg), 15, 0);
215 auto *r_ptr = &monraces_info[monrace_id];
217 TERM_COLOR da = r_ptr->d_attr;
218 byte dc = r_ptr->d_char;
219 TERM_COLOR ca = r_ptr->x_attr;
220 byte cc = r_ptr->x_char;
222 term_putstr(5, 17, -1, TERM_WHITE, format(_("モンスター = %d, 名前 = %-40.40s", "Monster = %d, Name = %-40.40s"), enum2i(monrace_id), r_ptr->name.data()));
223 term_putstr(10, 19, -1, TERM_WHITE, format(_("初期値 色 / 文字 = %3u / %3u", "Default attr/char = %3u / %3u"), da, dc));
224 term_putstr(40, 19, -1, TERM_WHITE, empty_symbol);
225 term_queue_bigchar(43, 19, da, dc, 0, 0);
226 term_putstr(10, 20, -1, TERM_WHITE, format(_("現在値 色 / 文字 = %3u / %3u", "Current attr/char = %3u / %3u"), ca, cc));
227 term_putstr(40, 20, -1, TERM_WHITE, empty_symbol);
228 term_queue_bigchar(43, 20, ca, cc, 0, 0);
229 term_putstr(0, 22, -1, TERM_WHITE, _("コマンド (n/N/^N/a/A/^A/c/C/^C/v/V/^V): ", "Command (n/N/^N/a/A/^A/c/C/^C/v/V/^V): "));
236 c = 'a' + i - KTRL('A');
237 } else if (isupper(i)) {
245 auto prev_r = monrace_id;
247 const auto new_monrace_id_opt = cmd_visuals_aux(i, num, static_cast<short>(monraces_info.size()));
248 if (!new_monrace_id_opt.has_value()) {
253 const auto new_monrace_id = new_monrace_id_opt.value();
254 monrace_id = i2enum<MonsterRaceId>(new_monrace_id);
255 num = new_monrace_id;
256 } while (monraces_info[monrace_id].name.empty());
261 const auto visual_id = cmd_visuals_aux(i, r_ptr->x_attr, 256);
262 if (!visual_id.has_value()) {
266 r_ptr->x_attr = static_cast<byte>(visual_id.value());
271 const auto visual_id = cmd_visuals_aux(i, r_ptr->x_char, 256);
272 if (!visual_id.has_value()) {
276 r_ptr->x_char = static_cast<byte>(visual_id.value());
281 do_cmd_knowledge_monsters(player_ptr, &need_redraw, true, monrace_id);
283 print_visuals_menu(choice_msg);
291 static auto choice_msg = _("アイテムの[色/文字]を変更します", "Change object attr/chars");
292 static short bi_id = 0;
293 prt(format(_("コマンド: %s", "Command: %s"), choice_msg), 15, 0);
295 auto &baseitem = baseitems_info[bi_id];
297 TERM_COLOR da = baseitem.d_attr;
298 auto dc = baseitem.d_char;
299 TERM_COLOR ca = baseitem.x_attr;
300 auto cc = baseitem.x_char;
302 term_putstr(5, 17, -1, TERM_WHITE,
304 _("アイテム = %d, 名前 = %-40.40s", "Object = %d, Name = %-40.40s"), bi_id, (!baseitem.flavor ? baseitem.name : baseitem.flavor_name).data()));
305 term_putstr(10, 19, -1, TERM_WHITE, format(_("初期値 色 / 文字 = %3d / %3d", "Default attr/char = %3d / %3d"), da, dc));
306 term_putstr(40, 19, -1, TERM_WHITE, empty_symbol);
307 term_queue_bigchar(43, 19, da, dc, 0, 0);
308 term_putstr(10, 20, -1, TERM_WHITE, format(_("現在値 色 / 文字 = %3d / %3d", "Current attr/char = %3d / %3d"), ca, cc));
309 term_putstr(40, 20, -1, TERM_WHITE, empty_symbol);
310 term_queue_bigchar(43, 20, ca, cc, 0, 0);
311 term_putstr(0, 22, -1, TERM_WHITE, _("コマンド (n/N/^N/a/A/^A/c/C/^C/v/V/^V): ", "Command (n/N/^N/a/A/^A/c/C/^C/v/V/^V): "));
319 c = 'a' + i - KTRL('A');
320 } else if (isupper(i)) {
328 std::optional<short> new_baseitem_id(std::nullopt);
329 const auto previous_bi_id = bi_id;
331 new_baseitem_id = cmd_visuals_aux(i, bi_id, static_cast<short>(baseitems_info.size()));
332 if (!new_baseitem_id.has_value()) {
333 bi_id = previous_bi_id;
337 bi_id = new_baseitem_id.value();
338 if (!baseitems_info[bi_id].name.empty()) {
346 const auto visual_id = cmd_visuals_aux(i, baseitem.x_attr, 256);
347 if (!visual_id.has_value()) {
351 baseitem.x_attr = static_cast<byte>(visual_id.value());
356 const auto visual_id = cmd_visuals_aux(i, baseitem.x_char, 256);
357 if (!visual_id.has_value()) {
361 baseitem.x_char = static_cast<byte>(visual_id.value());
366 do_cmd_knowledge_objects(player_ptr, &need_redraw, true, bi_id);
368 print_visuals_menu(choice_msg);
376 static auto choice_msg = _("地形の[色/文字]を変更します", "Change feature attr/chars");
377 static short terrain_id = 0;
378 static short lighting_level = F_LIT_STANDARD;
379 prt(format(_("コマンド: %s", "Command: %s"), choice_msg), 15, 0);
381 auto *f_ptr = &terrains_info[terrain_id];
383 TERM_COLOR da = f_ptr->d_attr[lighting_level];
384 byte dc = f_ptr->d_char[lighting_level];
385 TERM_COLOR ca = f_ptr->x_attr[lighting_level];
386 byte cc = f_ptr->x_char[lighting_level];
389 term_putstr(5, 17, -1, TERM_WHITE,
390 format(_("地形 = %d, 名前 = %s, 明度 = %s", "Terrain = %d, Name = %s, Lighting = %s"), terrain_id, (f_ptr->name.data()),
391 lighting_level_str[lighting_level]));
392 term_putstr(10, 19, -1, TERM_WHITE, format(_("初期値 色 / 文字 = %3d / %3d", "Default attr/char = %3d / %3d"), da, dc));
393 term_putstr(40, 19, -1, TERM_WHITE, empty_symbol);
394 term_queue_bigchar(43, 19, da, dc, 0, 0);
395 term_putstr(10, 20, -1, TERM_WHITE, format(_("現在値 色 / 文字 = %3d / %3d", "Current attr/char = %3d / %3d"), ca, cc));
396 term_putstr(40, 20, -1, TERM_WHITE, empty_symbol);
397 term_queue_bigchar(43, 20, ca, cc, 0, 0);
398 term_putstr(0, 22, -1, TERM_WHITE,
399 _("コマンド (n/N/^N/a/A/^A/c/C/^C/l/L/^L/d/D/^D/v/V/^V): ", "Command (n/N/^N/a/A/^A/c/C/^C/l/L/^L/d/D/^D/v/V/^V): "));
407 c = 'a' + i - KTRL('A');
408 } else if (isupper(i)) {
416 std::optional<short> new_terrain_id(std::nullopt);
417 const auto previous_terrain_id = terrain_id;
419 new_terrain_id = cmd_visuals_aux(i, terrain_id, static_cast<short>(terrains_info.size()));
420 if (!new_terrain_id.has_value()) {
421 terrain_id = previous_terrain_id;
425 terrain_id = new_terrain_id.value();
426 if (!terrains_info[terrain_id].name.empty() && (terrains_info[terrain_id].mimic == terrain_id)) {
434 const auto visual_id = cmd_visuals_aux(i, f_ptr->x_attr[lighting_level], 256);
435 if (!visual_id.has_value()) {
439 f_ptr->x_attr[lighting_level] = static_cast<byte>(visual_id.value());
444 const auto visual_id = cmd_visuals_aux(i, f_ptr->x_char[lighting_level], 256);
445 if (!visual_id.has_value()) {
449 f_ptr->x_char[lighting_level] = static_cast<byte>(visual_id.value());
454 const auto visual_id = cmd_visuals_aux(i, lighting_level, F_LIT_MAX);
455 if (!visual_id.has_value()) {
459 lighting_level = visual_id.value();
463 apply_default_feat_lighting(f_ptr->x_attr, f_ptr->x_char);
467 do_cmd_knowledge_features(&need_redraw, true, terrain_id, &lighting_level);
469 print_visuals_menu(choice_msg);
477 do_cmd_knowledge_monsters(player_ptr, &need_redraw, true);
480 do_cmd_knowledge_objects(player_ptr, &need_redraw, true, -1);
483 IDX lighting_level = F_LIT_STANDARD;
484 do_cmd_knowledge_features(&need_redraw, true, -1, &lighting_level);
489 reset_visuals(player_ptr);
490 msg_print(_("画面上の[色/文字]を初期値にリセットしました。", "Visual attr/char tables reset."));
503 do_cmd_redraw(player_ptr);