OSDN Git Service

Merge remote-tracking branch 'remotes/origin/feature/Fix-saved-floor-exceed' into...
[hengband/hengband.git] / src / cmd-io / cmd-process-screen.c
1 /*!
2  * @brief 記念撮影のセーブとロード
3  * @date 2020/04/22
4  * @Author Hourier
5  */
6
7 #include "cmd-io/cmd-process-screen.h"
8 #include "cmd-visual/cmd-draw.h"
9 #include "core/asking-player.h"
10 #include "core/player-redraw-types.h"
11 #include "core/stuff-handler.h"
12 #include "core/visuals-reseter.h"
13 #include "game-option/special-options.h"
14 #include "io/files-util.h"
15 #include "io/input-key-acceptor.h"
16 #include "term/gameterm.h"
17 #include "term/screen-processor.h"
18 #include "term/term-color-types.h"
19 #include "util/angband-files.h"
20 #include "view/display-messages.h"
21
22 // Encode the screen colors
23 static char hack[17] = "dwsorgbuDWvyRGBU";
24
25 static concptr tags[4] = { "HEADER_START:", "HEADER_END:", "FOOTER_START:", "FOOTER_END:", };
26 static concptr html_head[3] = { "<html>\n<body text=\"#ffffff\" bgcolor=\"#000000\">\n", "<pre>", 0, };
27 static concptr html_foot[3] = { "</pre>\n", "</body>\n</html>\n", 0, };
28
29 /*!
30  * todo io/ 以下に移したいところだが、このファイルの行数も大したことがないので一旦保留
31  * @brief 一時ファイルを読み込み、ファイルに書き出す
32  * @param fff ファイルへの参照ポインタ
33  * @param tempfff 一時ファイルへの参照ポインタ
34  * @param buf バッファ
35  * @param buf_size バッファサイズ
36  * @param num_tag タグ番号
37  */
38 static void read_temporary_file(FILE *fff, FILE *tmpfff, char buf[], size_t buf_size, int num_tag)
39 {
40         bool is_first_line = TRUE;
41         int next_tag = num_tag + 1;
42         while (!angband_fgets(tmpfff, buf, buf_size))
43         {
44                 if (is_first_line)
45                 {
46                         if (strncmp(buf, tags[num_tag], strlen(tags[num_tag])) == 0)
47                                 is_first_line = FALSE;
48
49                         continue;
50                 }
51
52                 if (strncmp(buf, tags[next_tag], strlen(tags[next_tag])) == 0)
53                         break;
54
55                 fprintf(fff, "%s\n", buf);
56         }
57 }
58
59
60 /*!
61  * @brief 記念撮影を1行ダンプする
62  * @param wid 幅
63  * @param y 現在の行位置
64  * @param fff 記念撮影ファイルへの参照ポインタ
65  * @return なし
66  */
67 static void screen_dump_one_line(int wid, int y, FILE *fff)
68 {
69         TERM_COLOR a = 0, old_a = 0;
70         char c = ' ';
71         for (TERM_LEN x = 0; x < wid - 1; x++)
72         {
73                 concptr cc = NULL;
74                 (void)(term_what(x, y, &a, &c));
75                 switch (c)
76                 {
77                 case '&': cc = "&amp;"; break;
78                 case '<': cc = "&lt;"; break;
79                 case '>': cc = "&gt;"; break;
80 #ifdef WINDOWS
81                 case 0x1f: c = '.'; break;
82                 case 0x7f: c = (a == 0x09) ? '%' : '#'; break;
83 #endif
84                 }
85
86                 a = a & 0x0F;
87                 if ((y == 0 && x == 0) || a != old_a)
88                 {
89                         int rv = angband_color_table[a][1];
90                         int gv = angband_color_table[a][2];
91                         int bv = angband_color_table[a][3];
92                         fprintf(fff, "%s<font color=\"#%02x%02x%02x\">",
93                                 ((y == 0 && x == 0) ? "" : "</font>"), rv, gv, bv);
94                         old_a = a;
95                 }
96
97                 if (cc)
98                         fprintf(fff, "%s", cc);
99                 else
100                         fprintf(fff, "%c", c);
101         }
102 }
103
104
105 /*!
106  * @brief 記念撮影を行方向にスイープする
107  * @param wid 幅
108  * @param hgt 高さ
109  * @param fff 記念撮影ファイルへの参照ポインタ
110  * @return なし
111  */
112 static void screen_dump_lines(int wid, int hgt, FILE *fff)
113 {
114         for (TERM_LEN y = 0; y < hgt; y++)
115         {
116                 if (y != 0)
117                         fprintf(fff, "\n");
118
119                 screen_dump_one_line(wid, y, fff);
120         }
121 }
122
123
124 /*!
125  * @brief ファイルへ書き込めない場合にエラーを表示する
126  * @param fff ダンプファイルへの参照ポインタ
127  * @param buf バッファ
128  * @return ファイルへ書き込めるならTRUE、書き込めないならFALSE
129  */
130 static bool check_screen_html_can_open(FILE *fff, char *filename, int message)
131 {
132         if (fff) return TRUE;
133         if (message == 0) return FALSE;
134
135         msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), filename);
136         msg_print(NULL);
137         return FALSE;
138 }
139
140
141 /*!
142  * @brief HTMLヘッダを書き込む
143  * @param tmpfff 一時ファイルへの参照ポインタ
144  * @param fff 記念撮影ファイルへの参照ポインタ
145  * @param buf バッファ
146  * @param buf_size バッファサイズ
147  */
148 static void write_html_header(FILE *tmpfff, FILE *fff, char buf[], size_t buf_size)
149 {
150         if (tmpfff)
151         {
152                 read_temporary_file(fff, tmpfff, buf, buf_size, 0);
153                 return;
154         }
155
156         for (int i = 0; html_head[i]; i++)
157                 fputs(html_head[i], fff);
158 }
159
160
161 /*!
162  * @brief HTMLフッタを書き込む
163  * @param tmpfff 一時ファイルへの参照ポインタ
164  * @param fff 記念撮影ファイルへの参照ポインタ
165  * @param buf バッファ
166  * @param buf_size バッファサイズ
167  */
168 static void write_html_footer(FILE *tmpfff, FILE *fff, char buf[], size_t buf_size)
169 {
170         fprintf(fff, "</font>");
171         if (!tmpfff)
172         {
173                 for (int i = 0; html_foot[i]; i++)
174                         fputs(html_foot[i], fff);
175         }
176         else
177         {
178                 rewind(tmpfff);
179                 read_temporary_file(fff, tmpfff, buf, buf_size, 2);
180                 angband_fclose(tmpfff);
181         }
182
183         fprintf(fff, "\n");
184 }
185
186
187 void do_cmd_save_screen_html_aux(char *filename, int message)
188 {
189         TERM_LEN wid, hgt;
190         term_get_size(&wid, &hgt);
191         FILE *fff;
192         fff = angband_fopen(filename, "w");
193         if (!check_screen_html_can_open(fff, filename, message)) return;
194
195         if (message) screen_save();
196
197         char buf[2048];
198         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "htmldump.prf");
199         FILE *tmpfff;
200         tmpfff = angband_fopen(buf, "r");
201         write_html_header(tmpfff, fff, buf, sizeof(buf));
202         screen_dump_lines(wid, hgt, fff);
203         write_html_footer(tmpfff, fff, buf, sizeof(buf));
204         angband_fclose(fff);
205         if (message)
206         {
207                 msg_print(_("画面(記念撮影)をファイルに書き出しました。", "Screen dump saved."));
208                 msg_print(NULL);
209         }
210
211         if (message)
212                 screen_load();
213 }
214
215
216 /*!
217  * @brief HTML方式で記念撮影する / Save a screen dump to a file
218  * @param なし
219  * @return なし
220  */
221 static void do_cmd_save_screen_html(void)
222 {
223         char buf[1024], tmp[256] = "screen.html";
224
225         if (!get_string(_("ファイル名: ", "File name: "), tmp, 80))
226                 return;
227         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
228
229         msg_print(NULL);
230
231         do_cmd_save_screen_html_aux(buf, 1);
232 }
233
234
235 /*!
236  * @brief 記念撮影の方式を問い合わせる
237  * @param html_dump HTMLダンプするか否か
238  * @return ダンプするならTRUE、キャンセルならFALSE
239  */
240 static bool ask_html_dump(bool *html_dump)
241 {
242         while (TRUE)
243         {
244                 char c = inkey();
245                 if (c == 'Y' || c == 'y')
246                 {
247                         *html_dump = FALSE;
248                         return TRUE;
249                 }
250                 
251                 if (c == 'H' || c == 'h')
252                 {
253                         *html_dump = TRUE;
254                         return TRUE;
255                 }
256
257                 prt("", 0, 0);
258                 return FALSE;
259         }
260
261         // コンパイル警告対応.
262         return FALSE;
263 }
264
265
266 /*!
267  * @brief ファイルへ書き込めない場合にエラーを表示する
268  * @param fff ダンプファイルへの参照ポインタ
269  * @param buf バッファ
270  * @return ファイルへ書き込めるならTRUE、書き込めないならFALSE
271  */
272 static bool check_screen_text_can_open(FILE *fff, char buf[])
273 {
274         if (fff) return TRUE;
275
276         msg_format(_("ファイル %s を開けませんでした。", "Failed to open file %s."), buf);
277         msg_print(NULL);
278         return FALSE;
279 }
280
281
282 /*!
283  * todo どこかバグっていて、(恐らく初期化されていない)変な文字列まで出力される
284  * @brief テキスト方式で記念撮影する
285  * @param wid 幅
286  * @param hgt 高さ
287  * @return 記念撮影に成功したらTRUE、ファイルが開けなかったらFALSE
288  */
289 static bool do_cmd_save_screen_text(int wid, int hgt)
290 {
291         TERM_COLOR a = 0;
292         SYMBOL_CODE c = ' ';
293         FILE *fff;
294         char buf[1024];
295         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "dump.txt");
296         fff = angband_fopen(buf, "w");
297         if (!check_screen_text_can_open(fff, buf)) return FALSE;
298
299         screen_save();
300         for (TERM_LEN y = 0; y < hgt; y++)
301         {
302                 TERM_LEN x;
303                 for (x = 0; x < wid - 1; x++)
304                 {
305                         (void)(term_what(x, y, &a, &c));
306                         buf[x] = c;
307                 }
308
309                 buf[x] = '\0';
310                 fprintf(fff, "%s\n", buf);
311         }
312
313         fprintf(fff, "\n");
314         for (TERM_LEN y = 0; y < hgt; y++)
315         {
316                 TERM_LEN x;
317                 for (x = 0; x < wid - 1; x++)
318                 {
319                         (void)(term_what(x, y, &a, &c));
320                         buf[x] = hack[a & 0x0F];
321                 }
322
323                 buf[x] = '\0';
324                 fprintf(fff, "%s\n", buf);
325         }
326
327         fprintf(fff, "\n");
328         angband_fclose(fff);
329         msg_print(_("画面(記念撮影)をファイルに書き出しました。", "Screen dump saved."));
330         msg_print(NULL);
331         screen_load();
332         return TRUE;
333 }
334
335
336 /*!
337  * @brief 記念撮影のためにグラフィック使用をOFFにする
338  * @param creature_ptr プレーヤーへの参照ポインタ
339  * @param handle_stuff 画面更新用の関数ポインタ
340  * @return 記念撮影直前のグラフィックオプション
341  */
342 static bool update_use_graphics(player_type *creature_ptr, void(*process_autopick_file_command)(char*))
343 {
344         if (!use_graphics) return TRUE;
345
346         use_graphics = FALSE;
347         reset_visuals(creature_ptr, process_autopick_file_command);
348         creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
349         handle_stuff(creature_ptr);
350         return FALSE;
351 }
352
353
354 /*
355  * Save a screen dump to a file
356  * @param creature_ptr プレーヤーへの参照ポインタ
357  * @param handle_stuff 画面更新用の関数ポインタ
358  * @return なし
359  */
360 void do_cmd_save_screen(player_type *creature_ptr, void(*process_autopick_file_command)(char*))
361 {
362         prt(_("記念撮影しますか? [(y)es/(h)tml/(n)o] ", "Save screen dump? [(y)es/(h)tml/(n)o] "), 0, 0);
363         bool html_dump;
364         if (!ask_html_dump(&html_dump)) return;
365
366         int wid, hgt;
367         term_get_size(&wid, &hgt);
368
369         bool old_use_graphics = update_use_graphics(creature_ptr, process_autopick_file_command);
370
371         if (html_dump)
372         {
373                 do_cmd_save_screen_html();
374                 do_cmd_redraw(creature_ptr);
375         }
376         else if (!do_cmd_save_screen_text(wid, hgt))
377         {
378                 return;
379         }
380
381         if (old_use_graphics) return;
382
383         use_graphics = TRUE;
384         reset_visuals(creature_ptr, process_autopick_file_command);
385         creature_ptr->redraw |= (PR_WIPE | PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIPPY);
386         handle_stuff(creature_ptr);
387 }
388
389
390 /*!
391  * @brief 白文字だけ画面に描画する (todo 目的は不明瞭)
392  * @param buf 描画用バッファ
393  * @param fff 記念撮影ファイルへの参照ポインタ
394  * @param wid 幅
395  * @param hgt 高さ
396  * @return ファイルが読み込めなくなったらFALSEで抜ける
397  */
398 static bool draw_white_characters(char buf[], FILE *fff, int wid, int hgt)
399 {
400         bool okay = TRUE;
401         for (TERM_LEN y = 0; okay; y++)
402         {
403                 if (!fgets(buf, 1024, fff)) okay = FALSE;
404
405                 if (buf[0] == '\n' || buf[0] == '\0') break;
406                 if (y >= hgt) continue;
407
408                 for (TERM_LEN x = 0; x < wid - 1; x++)
409                 {
410                         if (buf[x] == '\n' || buf[x] == '\0') break;
411
412                         term_draw(x, y, TERM_WHITE, buf[x]);
413                 }
414         }
415
416         return okay;
417 }
418
419
420 /*!
421  * @brief 白以外の文字を画面に描画する (todo 目的は不明瞭)
422  * @param buf 描画用バッファ
423  * @param fff 記念撮影ファイルへの参照ポインタ
424  * @param wid 幅
425  * @param hgt 高さ
426  * @param 白文字が途中で読み込めなくなっていたらTRUE
427  * @return なし
428  */
429 static void draw_colored_characters(char buf[], FILE *fff, int wid, int hgt, bool okay)
430 {
431         TERM_COLOR a = TERM_DARK;
432         SYMBOL_CODE c = ' ';
433         for (TERM_LEN y = 0; okay; y++)
434         {
435                 if (!fgets(buf, 1024, fff)) okay = FALSE;
436
437                 if (buf[0] == '\n' || buf[0] == '\0') break;
438                 if (y >= hgt) continue;
439
440                 for (TERM_LEN x = 0; x < wid - 1; x++)
441                 {
442                         if (buf[x] == '\n' || buf[x] == '\0') break;
443
444                         (void)(term_what(x, y, &a, &c));
445                         for (int i = 0; i < 16; i++)
446                         {
447                                 if (hack[i] == buf[x]) a = (byte)i;
448                         }
449
450                         term_draw(x, y, a, c);
451                 }
452         }
453 }
454
455
456 /*
457  * @brief Load a screen dump from a file
458  * @param なし
459  * @return なし
460  */
461 void do_cmd_load_screen(void)
462 {
463         FILE *fff;
464         char buf[1024];
465         TERM_LEN wid, hgt;
466         term_get_size(&wid, &hgt);
467         path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "dump.txt");
468         fff = angband_fopen(buf, "r");
469         if (!fff)
470         {
471                 msg_format(_("%s を開くことができませんでした。", "Failed to open %s."), buf);
472                 msg_print(NULL);
473                 return;
474         }
475
476         screen_save();
477         term_clear();
478         bool okay = draw_white_characters(buf, fff, wid, hgt);
479         draw_colored_characters(buf, fff, wid, hgt, okay);
480
481         angband_fclose(fff);
482         prt(_("ファイルに書き出された画面(記念撮影)をロードしました。", "Screen dump loaded."), 0, 0);
483         flush();
484         inkey();
485         screen_load();
486 }