7 #include "cmd-io/cmd-process-screen.h"
8 #include "cmd-visual/cmd-draw.h"
9 #include "core/asking-player.h"
10 #include "core/stuff-handler.h"
11 #include "core/visuals-reseter.h"
12 #include "game-option/special-options.h"
13 #include "io/files-util.h"
14 #include "io/input-key-acceptor.h"
15 #include "system/angband-exceptions.h"
16 #include "system/player-type-definition.h"
17 #include "system/redrawing-flags-updater.h"
18 #include "term/gameterm.h"
19 #include "term/screen-processor.h"
20 #include "term/term-color-types.h"
21 #include "util/angband-files.h"
22 #include "view/display-messages.h"
25 #include <string_view>
27 // Encode the screen colors
28 static char hack[17] = "dwsorgbuDWvyRGBU";
30 static concptr tags[4] = {
36 static concptr html_head[3] = {
37 "<html>\n<body text=\"#ffffff\" bgcolor=\"#000000\">\n",
41 static concptr html_foot[3] = {
48 * @brief 一時ファイルを読み込み、ファイルに書き出す
49 * @param fff ファイルへの参照ポインタ
50 * @param tempfff 一時ファイルへの参照ポインタ
52 * @todo io/ 以下に移したいところだが、このファイルの行数も大したことがないので一旦保留
54 static void read_temporary_file(FILE *fff, FILE *tmpfff, int num_tag)
56 bool is_first_line = true;
57 int next_tag = num_tag + 1;
59 while (!angband_fgets(tmpfff, buf, sizeof(buf))) {
61 if (strncmp(buf, tags[num_tag], strlen(tags[num_tag])) == 0) {
62 is_first_line = false;
68 if (strncmp(buf, tags[next_tag], strlen(tags[next_tag])) == 0) {
72 fprintf(fff, "%s\n", buf);
80 * @param fff 記念撮影ファイルへの参照ポインタ
82 static void screen_dump_one_line(int wid, int y, FILE *fff)
84 TERM_COLOR a = 0, old_a = 0;
86 for (TERM_LEN x = 0; x < wid - 1; x++) {
88 (void)(term_what(x, y, &a, &c));
104 c = (a == 0x09) ? '%' : '#';
110 if ((y == 0 && x == 0) || a != old_a) {
111 int rv = angband_color_table[a][1];
112 int gv = angband_color_table[a][2];
113 int bv = angband_color_table[a][3];
114 fprintf(fff, "%s<font color=\"#%02x%02x%02x\">",
115 ((y == 0 && x == 0) ? "" : "</font>"), rv, gv, bv);
120 fprintf(fff, "%s", cc);
122 fprintf(fff, "%c", c);
128 * @brief 記念撮影を行方向にスイープする
131 * @param fff 記念撮影ファイルへの参照ポインタ
133 static void screen_dump_lines(int wid, int hgt, FILE *fff)
135 for (TERM_LEN y = 0; y < hgt; y++) {
140 screen_dump_one_line(wid, y, fff);
145 * @brief ファイルへ書き込めない場合にエラーを表示する
146 * @param fff ダンプファイルへの参照ポインタ
147 * @param path 保存先HTMLファイルのパス
148 * @param need_message メッセージ表示の必要性
149 * @return メッセージを表示して後続処理を実行するか否か
151 static bool check_screen_html_can_open(FILE *fff, const std::filesystem::path &path, bool need_message)
161 const auto &path_str = path.string();
162 const auto mes = format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), path_str.data());
163 THROW_EXCEPTION(std::runtime_error, mes);
167 * @brief HTMLヘッダを書き込む
168 * @param tmpfff 一時ファイルへの参照ポインタ
169 * @param fff 記念撮影ファイルへの参照ポインタ
171 static void write_html_header(FILE *tmpfff, FILE *fff)
174 read_temporary_file(fff, tmpfff, 0);
178 for (int i = 0; html_head[i]; i++) {
179 fputs(html_head[i], fff);
184 * @brief HTMLフッタを書き込む
185 * @param tmpfff 一時ファイルへの参照ポインタ
186 * @param fff 記念撮影ファイルへの参照ポインタ
188 static void write_html_footer(FILE *tmpfff, FILE *fff)
190 fprintf(fff, "</font>");
192 for (int i = 0; html_foot[i]; i++) {
193 fputs(html_foot[i], fff);
197 read_temporary_file(fff, tmpfff, 2);
198 angband_fclose(tmpfff);
204 void exe_cmd_save_screen_html(const std::filesystem::path &path, bool need_message)
206 const auto &[wid, hgt] = term_get_size();
207 auto *fff = angband_fopen(path, FileOpenMode::WRITE, false, FileOpenType::HTML);
208 if (!check_screen_html_can_open(fff, path, need_message)) {
216 const auto &path_prf = path_build(ANGBAND_DIR_USER, "htmldump.prf");
217 auto *tmpfff = angband_fopen(path_prf, FileOpenMode::READ);
218 write_html_header(tmpfff, fff);
219 screen_dump_lines(wid, hgt, fff);
220 write_html_footer(tmpfff, fff);
226 msg_print(_("画面(記念撮影)をファイルに書き出しました。", "Screen dump saved."));
232 * @brief HTML方式で記念撮影する / Save a screen dump to a file
235 static void exe_cmd_save_screen_html_with_naming()
237 const auto filename = input_string(_("ファイル名: ", "File name: "), 80, "screen.html");
242 auto path = path_build(ANGBAND_DIR_USER, *filename);
244 exe_cmd_save_screen_html(path, true);
248 * @brief 記念撮影の方式を問い合わせる
249 * @param html_dump HTMLダンプするか否か
250 * @return ダンプするならTRUE、キャンセルならFALSE
252 static bool ask_html_dump(bool *html_dump)
256 if (c == 'Y' || c == 'y') {
261 if (c == 'H' || c == 'h') {
275 * @brief ファイルへ書き込めない場合にエラーを表示する
276 * @param fff ダンプファイルへの参照ポインタ
277 * @return ファイルへ書き込めるならTRUE、書き込めないならFALSE
279 static bool check_screen_text_can_open(FILE *fff, const std::string_view filename)
285 msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), filename.data());
291 * @brief テキスト方式で記念撮影する
294 * @return 記念撮影に成功したらTRUE、ファイルが開けなかったらFALSE
295 * @todo どこかバグっていて、(恐らく初期化されていない)変な文字列まで出力される
297 static bool do_cmd_save_screen_text(int wid, int hgt)
301 const auto &path = path_build(ANGBAND_DIR_USER, "dump.txt");
302 auto *fff = angband_fopen(path, FileOpenMode::WRITE);
303 if (!check_screen_text_can_open(fff, path.string())) {
308 for (TERM_LEN y = 0; y < hgt; y++) {
311 for (x = 0; x < wid - 1; x++) {
312 (void)(term_what(x, y, &a, &c));
317 fprintf(fff, "%s\n", buf);
321 for (TERM_LEN y = 0; y < hgt; y++) {
324 for (x = 0; x < wid - 1; x++) {
325 (void)(term_what(x, y, &a, &c));
326 buf[x] = hack[a & 0x0F];
330 fprintf(fff, "%s\n", buf);
335 msg_print(_("画面(記念撮影)をファイルに書き出しました。", "Screen dump saved."));
342 * @brief 記念撮影のためにグラフィック使用をOFFにする
343 * @param player_ptr プレイヤーへの参照ポインタ
344 * @return 記念撮影直前のグラフィックオプション
346 static bool update_use_graphics(PlayerType *player_ptr)
352 use_graphics = false;
353 reset_visuals(player_ptr);
354 static constexpr auto flags = {
355 MainWindowRedrawingFlag::WIPE,
356 MainWindowRedrawingFlag::BASIC,
357 MainWindowRedrawingFlag::EXTRA,
358 MainWindowRedrawingFlag::MAP,
359 MainWindowRedrawingFlag::EQUIPPY,
361 RedrawingFlagsUpdater::get_instance().set_flags(flags);
362 handle_stuff(player_ptr);
367 * Save a screen dump to a file
368 * @param player_ptr プレイヤーへの参照ポインタ
370 void do_cmd_save_screen(PlayerType *player_ptr)
372 prt(_("記念撮影しますか? [(y)es/(h)tml/(n)o] ", "Save screen dump? [(y)es/(h)tml/(n)o] "), 0, 0);
374 if (!ask_html_dump(&html_dump)) {
378 const auto &[wid, hgt] = term_get_size();
379 const auto old_use_graphics = update_use_graphics(player_ptr);
382 exe_cmd_save_screen_html_with_naming();
383 do_cmd_redraw(player_ptr);
384 } else if (!do_cmd_save_screen_text(wid, hgt)) {
388 if (old_use_graphics) {
393 reset_visuals(player_ptr);
394 static constexpr auto flags = {
395 MainWindowRedrawingFlag::WIPE,
396 MainWindowRedrawingFlag::BASIC,
397 MainWindowRedrawingFlag::EXTRA,
398 MainWindowRedrawingFlag::MAP,
399 MainWindowRedrawingFlag::EQUIPPY,
401 RedrawingFlagsUpdater::get_instance().set_flags(flags);
402 handle_stuff(player_ptr);
406 * @brief 白文字だけ画面に描画する
408 * @param fff 記念撮影ファイルへの参照ポインタ
412 * @return ファイルが読み込めなくなったらFALSEで抜ける
414 static bool draw_white_characters(FILE *fff, int wid, int hgt)
417 for (TERM_LEN y = 0; okay; y++) {
419 if (!fgets(buf, sizeof(buf), fff)) {
423 if (buf[0] == '\n' || buf[0] == '\0') {
430 for (TERM_LEN x = 0; x < wid - 1; x++) {
431 if (buf[x] == '\n' || buf[x] == '\0') {
435 term_draw(x, y, TERM_WHITE, buf[x]);
443 * @brief 白以外の文字を画面に描画する
444 * @param fff 記念撮影ファイルへの参照ポインタ
447 * @param 白文字が途中で読み込めなくなっていたらTRUE
450 static void draw_colored_characters(FILE *fff, int wid, int hgt, bool okay)
452 TERM_COLOR a = TERM_DARK;
454 for (TERM_LEN y = 0; okay; y++) {
456 if (!fgets(buf, sizeof(buf), fff)) {
460 if (buf[0] == '\n' || buf[0] == '\0') {
467 for (TERM_LEN x = 0; x < wid - 1; x++) {
468 if (buf[x] == '\n' || buf[x] == '\0') {
472 (void)(term_what(x, y, &a, &c));
473 for (int i = 0; i < 16; i++) {
474 if (hack[i] == buf[x]) {
479 term_draw(x, y, a, c);
485 * @brief Load a screen dump from a file
488 void do_cmd_load_screen(void)
490 const auto &[wid, hgt] = term_get_size();
491 const auto path = path_build(ANGBAND_DIR_USER, "dump.txt");
492 auto *fff = angband_fopen(path, FileOpenMode::READ);
494 const auto filename = path.string();
495 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), filename.data());
502 bool okay = draw_white_characters(fff, wid, hgt);
503 draw_colored_characters(fff, wid, hgt, okay);
506 prt(_("ファイルに書き出された画面(記念撮影)をロードしました。", "Screen dump loaded."), 0, 0);