OSDN Git Service

Merge pull request #900 from Hourier/feature/Adjustment-Monsters-Alpha20
[hengbandforosx/hengbandosx.git] / src / main-win.cpp
1 /*!
2  * @file main-win.cpp
3  * @brief Windows版固有実装(メインエントリポイント含む)
4  * @date 2018/03/16
5  * @author Hengband Team
6  * @todo main関数を含むファイルの割に長過ぎる。main-win-utils.cなどといった形で分割したい
7  * @details
8  *
9  * <h3>概要</h3>
10  * Windows98かその前後の頃を起点としたAPI実装。
11  * 各種のゲームエンジンは無論、
12  * DirectXといった昨今描画に標準的となったライブラリも用いていない。
13  * タイルの描画処理などについては、現在動作の詳細を検証中。
14  *
15  * <h3>フォーク元の概要</h3>
16  * <p>
17  * Copyright (c) 1997 Ben Harrison, Skirmantas Kligys, and others
18  *
19  * This software may be copied and distributed for educational, research,
20  * and not for profit purposes provided that this copyright and statement
21  * are included in all such copies.
22  * </p>
23  * <p>
24  * This file helps Angband work with Windows computers.
25  *
26  * To use this file, use an appropriate "Makefile" or "Project File",
27  * make sure that "WINDOWS" and/or "WIN32" are defined somewhere, and
28  * make sure to obtain various extra files as described below.
29  *
30  * The official compilation uses the CodeWarrior Pro compiler, which
31  * includes a special project file and precompilable header file.
32  * </p>
33  *
34  * <p>
35  * The "lib/user/pref-win.prf" file contains keymaps, macro definitions,
36  * and/or color redefinitions.
37  * </p>
38  *
39  * <p>
40  * The "lib/user/font-win.prf" contains attr/char mappings for wall.bmp.
41  * </p>
42  *
43  * <p>
44  * The "lib/user/graf-win.prf" contains attr/char mappings for use with the
45  * special "lib/xtra/graf/*.bmp" bitmap files, which are activated by a menu
46  * item.
47  * </p>
48  *
49  * <p>
50  * Compiling this file, and using the resulting executable, requires
51  * several extra files not distributed with the standard Angband code.
52  * All of these extra files can be found in the "ext-win" archive.
53  * </p>
54  *
55  * <p>
56  * The "term_xtra_win_clear()" function should probably do a low-level
57  * clear of the current window, and redraw the borders and other things,
58  * if only for efficiency.
59  * </p>
60  *
61  * <p>
62  * A simpler method is needed for selecting the "tile size" for windows.
63  * </p>
64  *
65  * <p>
66  * The various "warning" messages assume the existance of the "screen.w"
67  * window, I think, and only a few calls actually check for its existance,
68  * this may be okay since "NULL" means "on top of all windows". (?)  The
69  * user must never be allowed to "hide" the main window, or the "menubar"
70  * will disappear.
71  * </p>
72  *
73  * <p>
74  * Initial framework (and most code) by Ben Harrison (benh@phial.com).
75  *
76  * Original code by Skirmantas Kligys (kligys@scf.usc.edu).
77  *
78  * Additional code by Ross E Becker (beckerr@cis.ohio-state.edu),
79  * and Chris R. Martin (crm7479@tam2000.tamu.edu).
80  * </p>
81  */
82
83 #ifdef WINDOWS
84
85 #include "cmd-io/cmd-process-screen.h"
86 #include "cmd-io/cmd-save.h"
87 #include "core/game-play.h"
88 #include "core/player-processor.h"
89 #include "core/scores.h"
90 #include "core/special-internal-keys.h"
91 #include "core/stuff-handler.h"
92 #include "core/visuals-reseter.h"
93 #include "floor/floor-events.h"
94 #include "game-option/runtime-arguments.h"
95 #include "game-option/special-options.h"
96 #include "io/files-util.h"
97 #include "io/input-key-acceptor.h"
98 #include "io/record-play-movie.h"
99 #include "io/signal-handlers.h"
100 #include "io/write-diary.h"
101 #include "main-win/main-win-bg.h"
102 #include "main-win/main-win-file-utils.h"
103 #include "main-win/main-win-mci.h"
104 #include "main-win/main-win-menuitem.h"
105 #include "main-win/main-win-music.h"
106 #include "main-win/main-win-sound.h"
107 #include "main-win/read-graphics.h"
108 #include "main-win/string-win.h"
109 #include "main-win/tile-info.h"
110 #include "main/angband-initializer.h"
111 #include "main/sound-of-music.h"
112 #include "monster-floor/monster-lite.h"
113 #include "save/save.h"
114 #include "system/angband-version.h"
115 #include "system/angband.h"
116 #include "system/system-variables.h"
117 #include "term/gameterm.h"
118 #include "term/screen-processor.h"
119 #include "term/term-color-types.h"
120 #include "util/angband-files.h"
121 #include "util/int-char-converter.h"
122 #include "util/string-processor.h"
123 #include "view/display-messages.h"
124 #include "wizard/spoiler-util.h"
125 #include "wizard/wizard-spoiler.h"
126 #include "world/world.h"
127
128 #include <cstdlib>
129 #include <locale>
130
131 #include <commdlg.h>
132 #include <direct.h>
133
134 /*
135  * Available graphic modes
136  */
137 enum graphics_mode {
138     GRAPHICS_NONE = 0,
139     GRAPHICS_ORIGINAL = 1,
140     GRAPHICS_ADAM_BOLT = 2,
141     GRAPHICS_HENGBAND = 3,
142 };
143
144 /*!
145  * @struct term_data
146  * @brief ターム情報構造体 / Extra "term" data
147  * @details
148  * <p>
149  * pos_x / pos_y は各タームの左上点座標を指す。
150  * </p>
151  * <p>
152  * tile_wid / tile_hgt は[ウィンドウ]メニューのタイルの幅/高さを~を
153  * 1ドットずつ調整するステータスを指す。
154  * また、フォントを変更すると都度自動調整される。
155  * </p>
156  * <p>
157  * Note the use of "font_want" for the names of the font file requested by
158  * the user.
159  * </p>
160  */
161 typedef struct {
162     term_type t;
163     concptr s;
164     HWND w;
165     DWORD dwStyle;
166     DWORD dwExStyle;
167
168     uint keys;
169     TERM_LEN rows; /* int -> uint */
170     TERM_LEN cols;
171
172     uint pos_x; //!< タームの左上X座標
173     uint pos_y; //!< タームの左上Y座標
174     uint size_wid;
175     uint size_hgt;
176     uint size_ow1;
177     uint size_oh1;
178     uint size_ow2;
179     uint size_oh2;
180
181     bool size_hack;
182     bool xtra_hack;
183     bool visible;
184     concptr font_want;
185     HFONT font_id;
186     int font_wid; //!< フォント横幅
187     int font_hgt; //!< フォント縦幅
188     int tile_wid; //!< タイル横幅
189     int tile_hgt; //!< タイル縦幅
190
191     LOGFONT lf;
192
193     bool posfix;
194 } term_data;
195
196 #define MAX_TERM_DATA 8 //!< Maximum number of windows
197
198 static term_data data[MAX_TERM_DATA]; //!< An array of term_data's
199 static term_data *my_td; //!< Hack -- global "window creation" pointer
200 POINT normsize; //!< Remember normal size of main window when maxmized
201
202 /*
203  * was main window maximized on previous playing
204  */
205 bool win_maximized = FALSE;
206
207 /*
208  * game in progress
209  */
210 bool game_in_progress = FALSE;
211
212 /*
213  * note when "open"/"new" become valid
214  */
215 bool initialized = FALSE;
216
217 /*
218  * Saved instance handle
219  */
220 static HINSTANCE hInstance;
221
222 /*
223  * Yellow brush for the cursor
224  */
225 static HBRUSH hbrYellow;
226
227 /*
228  * An icon
229  */
230 static HICON hIcon;
231
232 /* bg */
233 enum class bg_mode {
234     BG_NONE = 0,
235     BG_ONE = 1,
236     BG_PRESET = 2,
237 };
238 bg_mode current_bg_mode = bg_mode::BG_NONE;
239 #define DEFAULT_BG_FILENAME "bg.bmp"
240 char wallpaper_file[MAIN_WIN_MAX_PATH] = ""; //!< 壁紙ファイル名。
241
242 /*!
243  * 現在使用中のタイルID(0ならば未使用)
244  * Flag set once "graphics" has been initialized
245  */
246 static byte current_graphics_mode = 0;
247
248 /*
249  * The global tile
250  */
251 static tile_info infGraph;
252
253 /*
254  * The global tile mask
255  */
256 static tile_info infMask;
257
258 /*
259  * Show sub-windows even when Hengband is not in focus
260  */
261 static bool keep_subwindows = TRUE;
262
263 /*
264  * Full path to ANGBAND.INI
265  */
266 static concptr ini_file = NULL;
267
268 /*
269  * Name of application
270  */
271 static concptr AppName = "ANGBAND";
272
273 /*
274  * Name of sub-window type
275  */
276 static concptr AngList = "AngList";
277
278 /*
279  * Directory names
280  */
281 static concptr ANGBAND_DIR_XTRA_GRAF;
282
283 /*
284  * The "complex" color values
285  */
286 static COLORREF win_clr[256];
287
288 /*
289  * Flag for macro trigger with dump ASCII
290  */
291 static bool term_no_press = FALSE;
292
293 /*
294  * Copy and paste
295  */
296 static bool mouse_down = FALSE;
297 static bool paint_rect = FALSE;
298 static TERM_LEN mousex = 0, mousey = 0;
299 static TERM_LEN oldx, oldy;
300
301 /*
302  * Hack -- define which keys are "special"
303  */
304 static bool special_key[256];
305 static bool ignore_key[256];
306
307 /*
308  * Hack -- initialization list for "special_key"
309  */
310 static byte special_key_list[] = {
311     VK_CLEAR, VK_PAUSE, VK_CAPITAL, VK_KANA, VK_JUNJA, VK_FINAL, VK_KANJI, VK_CONVERT, VK_NONCONVERT, VK_ACCEPT, VK_MODECHANGE, VK_PRIOR, VK_NEXT, VK_END,
312     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_SELECT, VK_PRINT, VK_EXECUTE, VK_SNAPSHOT, VK_INSERT, VK_DELETE, VK_HELP, VK_APPS, VK_NUMPAD0, VK_NUMPAD1,
313     VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, VK_DECIMAL,
314     VK_DIVIDE, VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19,
315     VK_F20, VK_F21, VK_F22, VK_F23, VK_F24, VK_NUMLOCK, VK_SCROLL, VK_ATTN, VK_CRSEL, VK_EXSEL, VK_EREOF, VK_PLAY, VK_ZOOM, VK_NONAME, VK_PA1,
316     0 /* End of List */
317 };
318
319 static byte ignore_key_list[] = {
320     VK_ESCAPE, VK_TAB, VK_SPACE, 'F', 'W', 'O', /*'H',*/ /* these are menu characters.*/
321     VK_SHIFT, VK_CONTROL, VK_MENU, VK_LWIN, VK_RWIN, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, VK_RCONTROL, VK_LMENU, VK_RMENU, 0 /* End of List */
322 };
323
324 /*
325  * Validate a file
326  */
327 static void validate_file(concptr s)
328 {
329     if (check_file(s))
330         return;
331
332     quit_fmt(_("必要なファイル[%s]が見あたりません。", "Cannot find required file:\n%s"), s);
333 }
334
335 /*
336  * Validate a directory
337  */
338 static void validate_dir(concptr s, bool vital)
339 {
340     if (check_dir(s))
341         return;
342
343     if (vital) {
344         quit_fmt(_("必要なディレクトリ[%s]が見あたりません。", "Cannot find required directory:\n%s"), s);
345     } else if (mkdir(s)) {
346         quit_fmt("Unable to create directory:\n%s", s);
347     }
348 }
349
350 /*!
351  * @brief (Windows版固有実装)Get the "size" for a window
352  */
353 static void term_getsize(term_data *td)
354 {
355     if (td->cols < 1)
356         td->cols = 1;
357     if (td->rows < 1)
358         td->rows = 1;
359
360     TERM_LEN wid = td->cols * td->tile_wid + td->size_ow1 + td->size_ow2;
361     TERM_LEN hgt = td->rows * td->tile_hgt + td->size_oh1 + td->size_oh2;
362
363     RECT rw, rc;
364     if (td->w) {
365         GetWindowRect(td->w, &rw);
366         GetClientRect(td->w, &rc);
367
368         td->size_wid = (rw.right - rw.left) - (rc.right - rc.left) + wid;
369         td->size_hgt = (rw.bottom - rw.top) - (rc.bottom - rc.top) + hgt;
370
371         td->pos_x = rw.left;
372         td->pos_y = rw.top;
373     } else {
374         /* Tempolary calculation */
375         rc.left = 0;
376         rc.right = wid;
377         rc.top = 0;
378         rc.bottom = hgt;
379         AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
380         td->size_wid = rc.right - rc.left;
381         td->size_hgt = rc.bottom - rc.top;
382     }
383 }
384
385 /*
386  * Write the "prefs" for a single term
387  */
388 static void save_prefs_aux(int i)
389 {
390     term_data *td = &data[i];
391     GAME_TEXT sec_name[128];
392     char buf[1024];
393
394     if (!td->w)
395         return;
396
397     sprintf(sec_name, "Term-%d", i);
398
399     if (i > 0) {
400         strcpy(buf, td->visible ? "1" : "0");
401         WritePrivateProfileString(sec_name, "Visible", buf, ini_file);
402     }
403
404 #ifdef JP
405     strcpy(buf, td->lf.lfFaceName[0] != '\0' ? td->lf.lfFaceName : "MS ゴシック");
406 #else
407     strcpy(buf, td->lf.lfFaceName[0] != '\0' ? td->lf.lfFaceName : "Courier");
408 #endif
409
410     WritePrivateProfileString(sec_name, "Font", buf, ini_file);
411
412     wsprintf(buf, "%d", td->lf.lfWidth);
413     WritePrivateProfileString(sec_name, "FontWid", buf, ini_file);
414     wsprintf(buf, "%d", td->lf.lfHeight);
415     WritePrivateProfileString(sec_name, "FontHgt", buf, ini_file);
416     wsprintf(buf, "%d", td->lf.lfWeight);
417     WritePrivateProfileString(sec_name, "FontWgt", buf, ini_file);
418
419     wsprintf(buf, "%d", td->tile_wid);
420     WritePrivateProfileString(sec_name, "TileWid", buf, ini_file);
421
422     wsprintf(buf, "%d", td->tile_hgt);
423     WritePrivateProfileString(sec_name, "TileHgt", buf, ini_file);
424
425     WINDOWPLACEMENT lpwndpl;
426     lpwndpl.length = sizeof(WINDOWPLACEMENT);
427     GetWindowPlacement(td->w, &lpwndpl);
428
429     RECT rc = lpwndpl.rcNormalPosition;
430     if (i == 0)
431         wsprintf(buf, "%d", normsize.x);
432     else
433         wsprintf(buf, "%d", td->cols);
434
435     WritePrivateProfileString(sec_name, "NumCols", buf, ini_file);
436
437     if (i == 0)
438         wsprintf(buf, "%d", normsize.y);
439     else
440         wsprintf(buf, "%d", td->rows);
441
442     WritePrivateProfileString(sec_name, "NumRows", buf, ini_file);
443     if (i == 0) {
444         strcpy(buf, IsZoomed(td->w) ? "1" : "0");
445         WritePrivateProfileString(sec_name, "Maximized", buf, ini_file);
446     }
447
448     GetWindowRect(td->w, &rc);
449     wsprintf(buf, "%d", rc.left);
450     WritePrivateProfileString(sec_name, "PositionX", buf, ini_file);
451
452     wsprintf(buf, "%d", rc.top);
453     WritePrivateProfileString(sec_name, "PositionY", buf, ini_file);
454     if (i > 0) {
455         strcpy(buf, td->posfix ? "1" : "0");
456         WritePrivateProfileString(sec_name, "PositionFix", buf, ini_file);
457     }
458 }
459
460 /*
461  * Write the "prefs"
462  * We assume that the windows have all been initialized
463  */
464 static void save_prefs(void)
465 {
466     char buf[128];
467     sprintf(buf, "%d", arg_graphics);
468     WritePrivateProfileString("Angband", "Graphics", buf, ini_file);
469
470     strcpy(buf, arg_bigtile ? "1" : "0");
471     WritePrivateProfileString("Angband", "Bigtile", buf, ini_file);
472
473     strcpy(buf, arg_sound ? "1" : "0");
474     WritePrivateProfileString("Angband", "Sound", buf, ini_file);
475
476     strcpy(buf, arg_music ? "1" : "0");
477     WritePrivateProfileString("Angband", "Music", buf, ini_file);
478     strcpy(buf, use_pause_music_inactive ? "1" : "0");
479     WritePrivateProfileString("Angband", "MusicPauseInactive", buf, ini_file);
480
481     sprintf(buf, "%d", current_bg_mode);
482     WritePrivateProfileString("Angband", "BackGround", buf, ini_file);
483     WritePrivateProfileString("Angband", "BackGroundBitmap", wallpaper_file[0] != '\0' ? wallpaper_file : DEFAULT_BG_FILENAME, ini_file);
484
485     int path_length = strlen(ANGBAND_DIR) - 4; /* \libの4文字分を削除 */
486     char tmp[1024] = "";
487     strncat(tmp, ANGBAND_DIR, path_length);
488
489     int n = strncmp(tmp, savefile, path_length);
490     if (n == 0) {
491         char relative_path[1024] = "";
492         snprintf(relative_path, sizeof(relative_path), ".\\%s", (savefile + path_length));
493         WritePrivateProfileString("Angband", "SaveFile", relative_path, ini_file);
494     } else {
495         WritePrivateProfileString("Angband", "SaveFile", savefile, ini_file);
496     }
497
498     strcpy(buf, keep_subwindows ? "1" : "0");
499     WritePrivateProfileString("Angband", "KeepSubwindows", buf, ini_file);
500
501     for (int i = 0; i < MAX_TERM_DATA; ++i) {
502         save_prefs_aux(i);
503     }
504 }
505
506 /*
507  * callback for EnumDisplayMonitors API
508  */
509 BOOL CALLBACK monitorenumproc([[maybe_unused]] HMONITOR hMon, [[maybe_unused]] HDC hdcMon, [[maybe_unused]] LPRECT lpMon, LPARAM dwDate)
510 {
511     bool *result = (bool *)dwDate;
512     *result = true;
513     return FALSE;
514 }
515
516 /*
517  * Load the "prefs" for a single term
518  */
519 static void load_prefs_aux(int i)
520 {
521     term_data *td = &data[i];
522     GAME_TEXT sec_name[128];
523     char tmp[1024];
524
525     sprintf(sec_name, "Term-%d", i);
526     sprintf(sec_name, "Term-%d", i);
527     if (i > 0) {
528         td->visible = (GetPrivateProfileInt(sec_name, "Visible", td->visible, ini_file) != 0);
529     }
530
531 #ifdef JP
532     GetPrivateProfileString(sec_name, "Font", "MS ゴシック", tmp, 127, ini_file);
533 #else
534     GetPrivateProfileString(sec_name, "Font", "Courier", tmp, 127, ini_file);
535 #endif
536
537     td->font_want = string_make(tmp);
538     int hgt = 15;
539     int wid = 0;
540     td->lf.lfWidth = GetPrivateProfileInt(sec_name, "FontWid", wid, ini_file);
541     td->lf.lfHeight = GetPrivateProfileInt(sec_name, "FontHgt", hgt, ini_file);
542     td->lf.lfWeight = GetPrivateProfileInt(sec_name, "FontWgt", 0, ini_file);
543
544     td->tile_wid = GetPrivateProfileInt(sec_name, "TileWid", td->lf.lfWidth, ini_file);
545     td->tile_hgt = GetPrivateProfileInt(sec_name, "TileHgt", td->lf.lfHeight, ini_file);
546
547     td->cols = GetPrivateProfileInt(sec_name, "NumCols", td->cols, ini_file);
548     td->rows = GetPrivateProfileInt(sec_name, "NumRows", td->rows, ini_file);
549     normsize.x = td->cols;
550     normsize.y = td->rows;
551
552     if (i == 0) {
553         win_maximized = (GetPrivateProfileInt(sec_name, "Maximized", win_maximized, ini_file) != 0);
554     }
555
556     int posx = GetPrivateProfileInt(sec_name, "PositionX", 0, ini_file);
557     int posy = GetPrivateProfileInt(sec_name, "PositionY", 0, ini_file);
558     // 保存座標がモニタ内の領域にあるかチェック
559     RECT rect = { posx, posy, posx + 128, posy + 128 };
560     bool in_any_monitor = false;
561     ::EnumDisplayMonitors(NULL, &rect, monitorenumproc, (LPARAM)&in_any_monitor);
562     if (in_any_monitor) {
563         // いずれかのモニタに表示可能、ウインドウ位置を復元
564         td->pos_x = posx;
565         td->pos_y = posy;
566     }
567
568     if (i > 0) {
569         td->posfix = (GetPrivateProfileInt(sec_name, "PositionFix", td->posfix, ini_file) != 0);
570     }
571 }
572
573 /*
574  * Load the "prefs"
575  */
576 static void load_prefs(void)
577 {
578     arg_graphics = (byte)GetPrivateProfileInt("Angband", "Graphics", GRAPHICS_NONE, ini_file);
579     arg_bigtile = (GetPrivateProfileInt("Angband", "Bigtile", FALSE, ini_file) != 0);
580     use_bigtile = arg_bigtile;
581     arg_sound = (GetPrivateProfileInt("Angband", "Sound", 0, ini_file) != 0);
582     arg_music = (GetPrivateProfileInt("Angband", "Music", 0, ini_file) != 0);
583     use_pause_music_inactive = (GetPrivateProfileInt("Angband", "MusicPauseInactive", 0, ini_file) != 0);
584     current_bg_mode = static_cast<bg_mode>(GetPrivateProfileInt("Angband", "BackGround", 0, ini_file));
585     GetPrivateProfileString("Angband", "BackGroundBitmap", DEFAULT_BG_FILENAME, wallpaper_file, 1023, ini_file);
586     GetPrivateProfileString("Angband", "SaveFile", "", savefile, 1023, ini_file);
587
588     int n = strncmp(".\\", savefile, 2);
589     if (n == 0) {
590         int path_length = strlen(ANGBAND_DIR) - 4; /* \libの4文字分を削除 */
591         char tmp[1024] = "";
592         strncat(tmp, ANGBAND_DIR, path_length);
593         strncat(tmp, savefile + 2, strlen(savefile) - 2 + path_length);
594         strncpy(savefile, tmp, strlen(tmp));
595     }
596
597     keep_subwindows = (GetPrivateProfileInt("Angband", "KeepSubwindows", 0, ini_file) != 0);
598     for (int i = 0; i < MAX_TERM_DATA; ++i) {
599         load_prefs_aux(i);
600     }
601 }
602
603 /*!
604  * @brief グラフィクスを初期化する / Initialize graphics
605  * @details
606  * <ul>
607  * <li>メニュー[オプション]>[グラフィクス]が「なし」以外の時に描画処理を初期化する。</li>
608  * <li>呼び出されるタイミングはロード時、及び同メニューで「なし」以外に変更される毎になる。</li>
609  * </ul>
610  */
611 static bool init_graphics(void)
612 {
613     char buf[MAIN_WIN_MAX_PATH];
614     BYTE wid, hgt, twid, thgt, ox, oy;
615     concptr name;
616     concptr name_mask = NULL;
617
618     infGraph.delete_bitmap();
619     infMask.delete_bitmap();
620
621     if (arg_graphics == GRAPHICS_ADAM_BOLT) {
622         wid = 16;
623         hgt = 16;
624         twid = 16;
625         thgt = 16;
626         ox = 0;
627         oy = 0;
628         name = "16X16.BMP";
629         name_mask = "mask.bmp";
630
631         ANGBAND_GRAF = "new";
632     } else if (arg_graphics == GRAPHICS_HENGBAND) {
633         wid = 32;
634         hgt = 32;
635         twid = 32;
636         thgt = 32;
637         ox = 0;
638         oy = 0;
639         name = "32X32.BMP";
640         name_mask = "mask32.bmp";
641
642         ANGBAND_GRAF = "ne2";
643     } else {
644         wid = 8;
645         hgt = 8;
646         twid = 8;
647         thgt = 8;
648         ox = 0;
649         oy = 0;
650         name = "8X8.BMP";
651         ANGBAND_GRAF = "old";
652     }
653
654     path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, name);
655     infGraph.hBitmap = read_graphic(buf);
656     if (!infGraph.hBitmap) {
657         plog_fmt(_("ビットマップ '%s' を読み込めません。", "Cannot read bitmap file '%s'"), name);
658         return FALSE;
659     }
660
661     infGraph.CellWidth = wid;
662     infGraph.CellHeight = hgt;
663     infGraph.TileWidth = twid;
664     infGraph.TileHeight = thgt;
665     infGraph.OffsetX = ox;
666     infGraph.OffsetY = oy;
667
668     if (name_mask) {
669         path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, name_mask);
670         infMask.hBitmap = read_graphic(buf);
671         if (!infMask.hBitmap) {
672             plog_fmt("Cannot read bitmap file '%s'", buf);
673             return FALSE;
674         }
675     }
676
677     current_graphics_mode = arg_graphics;
678     return (current_graphics_mode != GRAPHICS_NONE);
679 }
680
681 /*
682  * Initialize music
683  */
684 static void init_music(void)
685 {
686     // Flag set once "music" has been initialized
687     static bool can_use_music = FALSE;
688
689     if (!can_use_music) {
690         main_win_music::load_music_prefs();
691         can_use_music = TRUE;
692     }
693 }
694
695 /*
696  * Initialize sound
697  */
698 static void init_sound(void)
699 {
700     // Flag set once "sound" has been initialized
701     static bool can_use_sound = FALSE;
702
703     if (!can_use_sound) {
704         load_sound_prefs();
705         can_use_sound = TRUE;
706     }
707 }
708
709 /*
710  * Initialize background
711  */
712 static void init_background(void)
713 {
714     // Flag set once "background" has been initialized
715     static bool can_use_background = FALSE;
716
717     if (!can_use_background) {
718         load_bg_prefs();
719         can_use_background = TRUE;
720     }
721 }
722
723 /*!
724  * @brief Change background mode
725  * @param new_mode bg_mode
726  * @param show_error trueに設定した場合のみ、エラーダイアログを表示する
727  * @retval true success
728  * @retval false failed
729  */
730 static bool change_bg_mode(bg_mode new_mode, bool show_error = false)
731 {
732     current_bg_mode = new_mode;
733     if (current_bg_mode != bg_mode::BG_NONE) {
734         init_background();
735         if (!load_bg(wallpaper_file)) {
736             current_bg_mode = bg_mode::BG_NONE;
737             if (show_error)
738                 plog_fmt(_("壁紙用ファイル '%s' を読み込めません。", "Can't load the image file '%s'."), wallpaper_file);
739         }
740     } else {
741         delete_bg();
742     }
743
744     return (current_bg_mode == new_mode);
745 }
746
747 /*!
748  * @brief Resize a window
749  */
750 static void term_window_resize(term_data *td)
751 {
752     if (!td->w)
753         return;
754
755     SetWindowPos(td->w, 0, 0, 0, td->size_wid, td->size_hgt, SWP_NOMOVE | SWP_NOZORDER);
756     InvalidateRect(td->w, NULL, TRUE);
757 }
758
759 /*!
760  * @brief Force the use of a new font for a term_data.
761  * This function may be called before the "window" is ready.
762  * This function returns zero only if everything succeeds.
763  * @note that the "font name" must be capitalized!!!
764  */
765 static errr term_force_font(term_data *td)
766 {
767     if (td->font_id)
768         DeleteObject(td->font_id);
769
770     td->font_id = CreateFontIndirect(&(td->lf));
771     int wid = td->lf.lfWidth;
772     int hgt = td->lf.lfHeight;
773     if (!td->font_id)
774         return 1;
775
776     if (!wid || !hgt) {
777         HDC hdcDesktop;
778         HFONT hfOld;
779         TEXTMETRIC tm;
780
781         hdcDesktop = GetDC(HWND_DESKTOP);
782         hfOld = static_cast<HFONT>(SelectObject(hdcDesktop, td->font_id));
783         GetTextMetrics(hdcDesktop, &tm);
784         SelectObject(hdcDesktop, hfOld);
785         ReleaseDC(HWND_DESKTOP, hdcDesktop);
786
787         wid = tm.tmAveCharWidth;
788         hgt = tm.tmHeight;
789     }
790
791     td->font_wid = wid;
792     td->font_hgt = hgt;
793
794     return 0;
795 }
796
797 /*
798  * Allow the user to change the font for this window.
799  */
800 static void term_change_font(term_data *td)
801 {
802     CHOOSEFONT cf;
803     memset(&cf, 0, sizeof(cf));
804     cf.lStructSize = sizeof(cf);
805     cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_NOVERTFONTS | CF_INITTOLOGFONTSTRUCT;
806     cf.lpLogFont = &(td->lf);
807
808     if (!ChooseFont(&cf))
809         return;
810
811     term_force_font(td);
812     td->tile_wid = td->font_wid;
813     td->tile_hgt = td->font_hgt;
814     term_getsize(td);
815     term_window_resize(td);
816 }
817
818 /*
819  * Allow the user to lock this window.
820  */
821 static void term_window_pos(term_data *td, HWND hWnd)
822 {
823     SetWindowPos(td->w, hWnd, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
824 }
825
826 /*
827  * Hack -- redraw a term_data
828  */
829 static void term_data_redraw(term_data *td)
830 {
831     term_activate(&td->t);
832     term_redraw();
833     term_activate(term_screen);
834 }
835
836 void term_inversed_area(HWND hWnd, int x, int y, int w, int h)
837 {
838     term_data *td = (term_data *)GetWindowLong(hWnd, 0);
839     int tx = td->size_ow1 + x * td->tile_wid;
840     int ty = td->size_oh1 + y * td->tile_hgt;
841     int tw = w * td->tile_wid - 1;
842     int th = h * td->tile_hgt - 1;
843
844     HDC hdc = GetDC(hWnd);
845     HBRUSH myBrush = CreateSolidBrush(RGB(255, 255, 255));
846     HBRUSH oldBrush = static_cast<HBRUSH>(SelectObject(hdc, myBrush));
847     HPEN oldPen = static_cast<HPEN>(SelectObject(hdc, GetStockObject(NULL_PEN)));
848
849     PatBlt(hdc, tx, ty, tw, th, PATINVERT);
850
851     SelectObject(hdc, oldBrush);
852     SelectObject(hdc, oldPen);
853 }
854
855 /*!
856  * @brief //!< Windows版ユーザ設定項目実装部(実装必須) /Interact with the User
857  */
858 static errr term_user_win(int n)
859 {
860     (void)n;
861     return 0;
862 }
863
864 static void refresh_color_table()
865 {
866     for (int i = 0; i < 256; i++) {
867         byte rv = angband_color_table[i][1];
868         byte gv = angband_color_table[i][2];
869         byte bv = angband_color_table[i][3];
870         win_clr[i] = PALETTERGB(rv, gv, bv);
871     }
872 }
873
874 /*
875  * React to global changes
876  */
877 static errr term_xtra_win_react(player_type *player_ptr)
878 {
879     refresh_color_table();
880
881     use_sound = arg_sound;
882     if (use_sound) {
883         init_sound();
884     }
885
886     if (use_graphics != (arg_graphics > 0)) {
887         if (arg_graphics && !init_graphics()) {
888             plog(_("グラフィックスを初期化できません!", "Cannot initialize graphics!"));
889             arg_graphics = GRAPHICS_NONE;
890         }
891
892         use_graphics = (arg_graphics > 0);
893         reset_visuals(player_ptr);
894     }
895
896     for (int i = 0; i < MAX_TERM_DATA; i++) {
897         term_type *old = Term;
898         term_data *td = &data[i];
899         if ((td->cols != td->t.wid) || (td->rows != td->t.hgt)) {
900             term_activate(&td->t);
901             term_resize(td->cols, td->rows);
902             term_redraw();
903             term_activate(old);
904         }
905     }
906
907     return 0;
908 }
909
910 /*
911  * Process at least one event
912  */
913 static errr term_xtra_win_event(int v)
914 {
915     MSG msg;
916     if (v) {
917         if (GetMessage(&msg, NULL, 0, 0)) {
918             TranslateMessage(&msg);
919             DispatchMessage(&msg);
920         }
921     } else {
922         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
923             TranslateMessage(&msg);
924             DispatchMessage(&msg);
925         }
926     }
927
928     return 0;
929 }
930
931 /*
932  * Process all pending events
933  */
934 static errr term_xtra_win_flush(void)
935 {
936     MSG msg;
937     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
938         TranslateMessage(&msg);
939         DispatchMessage(&msg);
940     }
941
942     return 0;
943 }
944
945 /*
946  * Hack -- clear the screen
947  *
948  * Make this more efficient
949  */
950 static errr term_xtra_win_clear(void)
951 {
952     term_data *td = (term_data *)(Term->data);
953
954     RECT rc;
955     rc.left = td->size_ow1;
956     rc.right = rc.left + td->cols * td->tile_wid;
957     rc.top = td->size_oh1;
958     rc.bottom = rc.top + td->rows * td->tile_hgt;
959
960     HDC hdc = GetDC(td->w);
961     SetBkColor(hdc, RGB(0, 0, 0));
962     SelectObject(hdc, td->font_id);
963     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
964
965     if (current_bg_mode != bg_mode::BG_NONE) {
966         rc.left = 0;
967         rc.top = 0;
968         draw_bg(hdc, &rc);
969     }
970
971     ReleaseDC(td->w, hdc);
972     return 0;
973 }
974
975 /*
976  * Hack -- make a noise
977  */
978 static errr term_xtra_win_noise(void)
979 {
980     MessageBeep(MB_ICONASTERISK);
981     return 0;
982 }
983
984 /*
985  * Hack -- make a sound
986  */
987 static errr term_xtra_win_sound(int v)
988 {
989     if (!use_sound)
990         return 1;
991     return play_sound(v);
992 }
993
994 /*
995  * Hack -- play a music
996  */
997 static errr term_xtra_win_music(int n, int v)
998 {
999     if (!use_music) {
1000         return 1;
1001     }
1002
1003     return main_win_music::play_music(n, v);
1004 }
1005
1006 /*
1007  * Hack -- play a music matches a situation
1008  */
1009 static errr term_xtra_win_scene(int v)
1010 {
1011     // TODO 場面に合った壁紙変更対応
1012     if (!use_music) {
1013         return 1;
1014     }
1015
1016     return main_win_music::play_music_scene(v);
1017 }
1018
1019 /*
1020  * Delay for "x" milliseconds
1021  */
1022 static int term_xtra_win_delay(int v)
1023 {
1024     Sleep(v);
1025     return 0;
1026 }
1027
1028 /*!
1029  * @brief Do a "special thing"
1030  * @todo z-termに影響があるのでplayer_typeの追加は保留
1031  */
1032 static errr term_xtra_win(int n, int v)
1033 {
1034     switch (n) {
1035     case TERM_XTRA_NOISE: {
1036         return (term_xtra_win_noise());
1037     }
1038     case TERM_XTRA_MUSIC_BASIC:
1039     case TERM_XTRA_MUSIC_DUNGEON:
1040     case TERM_XTRA_MUSIC_QUEST:
1041     case TERM_XTRA_MUSIC_TOWN:
1042     case TERM_XTRA_MUSIC_MONSTER: {
1043         return term_xtra_win_music(n, v);
1044     }
1045     case TERM_XTRA_MUSIC_MUTE: {
1046         return main_win_music::stop_music();
1047     }
1048     case TERM_XTRA_SCENE: {
1049         return term_xtra_win_scene(v);
1050     }
1051     case TERM_XTRA_SOUND: {
1052         return (term_xtra_win_sound(v));
1053     }
1054     case TERM_XTRA_BORED: {
1055         return (term_xtra_win_event(0));
1056     }
1057     case TERM_XTRA_EVENT: {
1058         return (term_xtra_win_event(v));
1059     }
1060     case TERM_XTRA_FLUSH: {
1061         return (term_xtra_win_flush());
1062     }
1063     case TERM_XTRA_CLEAR: {
1064         return (term_xtra_win_clear());
1065     }
1066     case TERM_XTRA_REACT: {
1067         return (term_xtra_win_react(p_ptr));
1068     }
1069     case TERM_XTRA_DELAY: {
1070         return (term_xtra_win_delay(v));
1071     }
1072     }
1073
1074     return 1;
1075 }
1076
1077 /*
1078  * Low level graphics (Assumes valid input).
1079  *
1080  * Draw a "cursor" at (x,y), using a "yellow box".
1081  */
1082 static errr term_curs_win(int x, int y)
1083 {
1084     term_data *td = (term_data *)(Term->data);
1085     int tile_wid, tile_hgt;
1086     tile_wid = td->tile_wid;
1087     tile_hgt = td->tile_hgt;
1088
1089     RECT rc;
1090     rc.left = x * tile_wid + td->size_ow1;
1091     rc.right = rc.left + tile_wid;
1092     rc.top = y * tile_hgt + td->size_oh1;
1093     rc.bottom = rc.top + tile_hgt;
1094
1095     HDC hdc = GetDC(td->w);
1096     FrameRect(hdc, &rc, hbrYellow);
1097     ReleaseDC(td->w, hdc);
1098     return 0;
1099 }
1100
1101 /*
1102  * Low level graphics (Assumes valid input).
1103  *
1104  * Draw a "big cursor" at (x,y), using a "yellow box".
1105  */
1106 static errr term_bigcurs_win(int x, int y)
1107 {
1108     term_data *td = (term_data *)(Term->data);
1109     int tile_wid, tile_hgt;
1110     tile_wid = td->tile_wid;
1111     tile_hgt = td->tile_hgt;
1112
1113     RECT rc;
1114     rc.left = x * tile_wid + td->size_ow1;
1115     rc.right = rc.left + 2 * tile_wid;
1116     rc.top = y * tile_hgt + td->size_oh1;
1117     rc.bottom = rc.top + tile_hgt;
1118
1119     HDC hdc = GetDC(td->w);
1120     FrameRect(hdc, &rc, hbrYellow);
1121     ReleaseDC(td->w, hdc);
1122     return 0;
1123 }
1124
1125 /*
1126  * Low level graphics (Assumes valid input).
1127  *
1128  * Erase a "block" of "n" characters starting at (x,y).
1129  */
1130 static errr term_wipe_win(int x, int y, int n)
1131 {
1132     term_data *td = (term_data *)(Term->data);
1133     RECT rc;
1134     rc.left = x * td->tile_wid + td->size_ow1;
1135     rc.right = rc.left + n * td->tile_wid;
1136     rc.top = y * td->tile_hgt + td->size_oh1;
1137     rc.bottom = rc.top + td->tile_hgt;
1138
1139     HDC hdc = GetDC(td->w);
1140     SetBkColor(hdc, RGB(0, 0, 0));
1141     SelectObject(hdc, td->font_id);
1142     if (current_bg_mode != bg_mode::BG_NONE)
1143         draw_bg(hdc, &rc);
1144     else
1145         ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1146
1147     ReleaseDC(td->w, hdc);
1148     return 0;
1149 }
1150
1151 /*
1152  * Low level graphics.  Assumes valid input.
1153  *
1154  * Draw several ("n") chars, with an attr, at a given location.
1155  *
1156  * All "graphic" data is handled by "term_pict_win()", below.
1157  *
1158  * One would think there is a more efficient method for telling a window
1159  * what color it should be using to draw with, but perhaps simply changing
1160  * it every time is not too inefficient.
1161  */
1162 static errr term_text_win(int x, int y, int n, TERM_COLOR a, concptr s)
1163 {
1164     term_data *td = (term_data *)(Term->data);
1165     static HBITMAP WALL;
1166     static HBRUSH myBrush, oldBrush;
1167     static HPEN oldPen;
1168     static bool init_done = FALSE;
1169
1170     if (!init_done) {
1171         WALL = LoadBitmap(hInstance, AppName);
1172         myBrush = CreatePatternBrush(WALL);
1173         init_done = TRUE;
1174     }
1175
1176     RECT rc{ static_cast<LONG>(x * td->tile_wid + td->size_ow1), static_cast<LONG>(y * td->tile_hgt + td->size_oh1),
1177         static_cast<LONG>(rc.left + n * td->tile_wid), static_cast<LONG>(rc.top + td->tile_hgt) };
1178
1179     HDC hdc = GetDC(td->w);
1180     SetBkColor(hdc, RGB(0, 0, 0));
1181     SetTextColor(hdc, win_clr[a]);
1182
1183     SelectObject(hdc, td->font_id);
1184     if (current_bg_mode != bg_mode::BG_NONE)
1185         SetBkMode(hdc, TRANSPARENT);
1186
1187     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1188     if (current_bg_mode != bg_mode::BG_NONE)
1189         draw_bg(hdc, &rc);
1190
1191     rc.left += ((td->tile_wid - td->font_wid) / 2);
1192     rc.right = rc.left + td->font_wid;
1193     rc.top += ((td->tile_hgt - td->font_hgt) / 2);
1194     rc.bottom = rc.top + td->font_hgt;
1195
1196     for (int i = 0; i < n; i++) {
1197 #ifdef JP
1198         if (use_bigtile && *(s + i) == "■"[0] && *(s + i + 1) == "■"[1]) {
1199             rc.right += td->font_wid;
1200             oldBrush = static_cast<HBRUSH>(SelectObject(hdc, myBrush));
1201             oldPen = static_cast<HPEN>(SelectObject(hdc, GetStockObject(NULL_PEN)));
1202             Rectangle(hdc, rc.left, rc.top, rc.right + 1, rc.bottom + 1);
1203             SelectObject(hdc, oldBrush);
1204             SelectObject(hdc, oldPen);
1205             rc.right -= td->font_wid;
1206             i++;
1207             rc.left += 2 * td->tile_wid;
1208             rc.right += 2 * td->tile_wid;
1209         } else if (iskanji(*(s + i))) /* 2バイト文字 */
1210         {
1211             rc.right += td->font_wid;
1212             ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, s + i, 2, NULL);
1213             rc.right -= td->font_wid;
1214             i++;
1215             rc.left += 2 * td->tile_wid;
1216             rc.right += 2 * td->tile_wid;
1217         } else if (*(s + i) == 127) {
1218             oldBrush = static_cast<HBRUSH>(SelectObject(hdc, myBrush));
1219             oldPen = static_cast<HPEN>(SelectObject(hdc, GetStockObject(NULL_PEN)));
1220             Rectangle(hdc, rc.left, rc.top, rc.right + 1, rc.bottom + 1);
1221             SelectObject(hdc, oldBrush);
1222             SelectObject(hdc, oldPen);
1223             rc.left += td->tile_wid;
1224             rc.right += td->tile_wid;
1225         } else {
1226             ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, s + i, 1, NULL);
1227             rc.left += td->tile_wid;
1228             rc.right += td->tile_wid;
1229         }
1230 #else
1231         if (*(s + i) == 127) {
1232             oldBrush = static_cast<HBRUSH>(SelectObject(hdc, myBrush));
1233             oldPen = static_cast<HPEN>(SelectObject(hdc, GetStockObject(NULL_PEN)));
1234             Rectangle(hdc, rc.left, rc.top, rc.right + 1, rc.bottom + 1);
1235             SelectObject(hdc, oldBrush);
1236             SelectObject(hdc, oldPen);
1237             rc.left += td->tile_wid;
1238             rc.right += td->tile_wid;
1239         } else {
1240             ExtTextOut(hdc, rc.left, rc.top, ETO_CLIPPED, &rc, s + i, 1, NULL);
1241             rc.left += td->tile_wid;
1242             rc.right += td->tile_wid;
1243         }
1244 #endif
1245     }
1246
1247     ReleaseDC(td->w, hdc);
1248     return 0;
1249 }
1250
1251 /*
1252  * Low level graphics.  Assumes valid input.
1253  *
1254  * Draw an array of "special" attr/char pairs at the given location.
1255  *
1256  * We use the "term_pict_win()" function for "graphic" data, which are
1257  * encoded by setting the "high-bits" of both the "attr" and the "char"
1258  * data.  We use the "attr" to represent the "row" of the main bitmap,
1259  * and the "char" to represent the "col" of the main bitmap.  The use
1260  * of this function is induced by the "higher_pict" flag.
1261  *
1262  * If "graphics" is not available, we simply "wipe" the given grids.
1263  */
1264 static errr term_pict_win(TERM_LEN x, TERM_LEN y, int n, const TERM_COLOR *ap, concptr cp, const TERM_COLOR *tap, concptr tcp)
1265 {
1266     term_data *td = (term_data *)(Term->data);
1267     int i;
1268     HDC hdcMask = NULL;
1269     if (!use_graphics) {
1270         return (term_wipe_win(x, y, n));
1271     }
1272
1273     TERM_LEN w1 = infGraph.CellWidth;
1274     TERM_LEN h1 = infGraph.CellHeight;
1275     TERM_LEN tw1 = infGraph.TileWidth;
1276     TERM_LEN th1 = infGraph.TileHeight;
1277     TERM_LEN w2, h2, tw2 = 0;
1278     w2 = td->tile_wid;
1279     h2 = td->tile_hgt;
1280     tw2 = w2;
1281     if (use_bigtile)
1282         tw2 *= 2;
1283
1284     TERM_LEN x2 = x * w2 + td->size_ow1 + infGraph.OffsetX;
1285     TERM_LEN y2 = y * h2 + td->size_oh1 + infGraph.OffsetY;
1286     HDC hdc = GetDC(td->w);
1287     HDC hdcSrc = CreateCompatibleDC(hdc);
1288     HBITMAP hbmSrcOld = static_cast<HBITMAP>(SelectObject(hdcSrc, infGraph.hBitmap));
1289
1290     if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) {
1291         hdcMask = CreateCompatibleDC(hdc);
1292         SelectObject(hdcMask, infMask.hBitmap);
1293     }
1294
1295     for (i = 0; i < n; i++, x2 += w2) {
1296         TERM_COLOR a = ap[i];
1297         char c = cp[i];
1298         int row = (a & 0x7F);
1299         int col = (c & 0x7F);
1300         TERM_LEN x1 = col * w1;
1301         TERM_LEN y1 = row * h1;
1302
1303         if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) {
1304             TERM_LEN x3 = (tcp[i] & 0x7F) * w1;
1305             TERM_LEN y3 = (tap[i] & 0x7F) * h1;
1306             tw2 = tw2 * w1 / tw1;
1307             h2 = h2 * h1 / th1;
1308             if ((tw1 == tw2) && (th1 == h2)) {
1309                 BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, SRCCOPY);
1310                 BitBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, SRCAND);
1311                 BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCPAINT);
1312                 continue;
1313             }
1314
1315             SetStretchBltMode(hdc, COLORONCOLOR);
1316             StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x3, y3, w1, h1, SRCAND);
1317             StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, w1, h1, SRCPAINT);
1318             if ((x1 != x3) || (y1 != y3)) {
1319                 StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, w1, h1, SRCAND);
1320                 StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCPAINT);
1321             }
1322
1323             continue;
1324         }
1325
1326         if ((w1 == tw2) && (h1 == h2)) {
1327             BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCCOPY);
1328             continue;
1329         }
1330
1331         SetStretchBltMode(hdc, COLORONCOLOR);
1332         StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCCOPY);
1333     }
1334
1335     SelectObject(hdcSrc, hbmSrcOld);
1336     DeleteDC(hdcSrc);
1337     if (arg_graphics == GRAPHICS_ADAM_BOLT || arg_graphics == GRAPHICS_HENGBAND) {
1338         SelectObject(hdcMask, hbmSrcOld);
1339         DeleteDC(hdcMask);
1340     }
1341
1342     ReleaseDC(td->w, hdc);
1343     return 0;
1344 }
1345
1346 /*
1347  * Create and initialize a "term_data" given a title
1348  */
1349 static void term_data_link(term_data *td)
1350 {
1351     term_type *t = &td->t;
1352     term_init(t, td->cols, td->rows, FILE_READ_BUFF_SIZE);
1353     t->soft_cursor = TRUE;
1354     t->higher_pict = TRUE;
1355     t->attr_blank = TERM_WHITE;
1356     t->char_blank = ' ';
1357     t->user_hook = term_user_win;
1358     t->xtra_hook = term_xtra_win;
1359     t->curs_hook = term_curs_win;
1360     t->bigcurs_hook = term_bigcurs_win;
1361     t->wipe_hook = term_wipe_win;
1362     t->text_hook = term_text_win;
1363     t->pict_hook = term_pict_win;
1364     t->data = (vptr)(td);
1365 }
1366
1367 /*
1368  * Create the windows
1369  *
1370  * First, instantiate the "default" values, then read the "ini_file"
1371  * to over-ride selected values, then create the windows, and fonts.
1372  *
1373  * Must use SW_SHOW not SW_SHOWNA, since on 256 color display
1374  * must make active to realize the palette.
1375  */
1376 static void init_windows(void)
1377 {
1378     term_data *td;
1379     td = &data[0];
1380     WIPE(td, term_data);
1381 #ifdef JP
1382     td->s = "変愚蛮怒";
1383 #else
1384     td->s = angband_term_name[0];
1385 #endif
1386
1387     td->keys = 1024;
1388     td->rows = 24;
1389     td->cols = 80;
1390     td->visible = TRUE;
1391     td->size_ow1 = 2;
1392     td->size_ow2 = 2;
1393     td->size_oh1 = 2;
1394     td->size_oh2 = 2;
1395     td->pos_x = 7 * 30;
1396     td->pos_y = 7 * 20;
1397     td->posfix = FALSE;
1398
1399     for (int i = 1; i < MAX_TERM_DATA; i++) {
1400         td = &data[i];
1401         WIPE(td, term_data);
1402         td->s = angband_term_name[i];
1403         td->keys = 16;
1404         td->rows = 24;
1405         td->cols = 80;
1406         td->visible = FALSE;
1407         td->size_ow1 = 1;
1408         td->size_ow2 = 1;
1409         td->size_oh1 = 1;
1410         td->size_oh2 = 1;
1411         td->pos_x = (7 - i) * 30;
1412         td->pos_y = (7 - i) * 20;
1413         td->posfix = FALSE;
1414     }
1415
1416     load_prefs();
1417
1418     /* Atrributes of main window */
1419     td = &data[0];
1420     td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | WS_VISIBLE);
1421     td->dwExStyle = 0;
1422     td->visible = TRUE;
1423
1424     /* Attributes of sub windows */
1425     for (int i = 1; i < MAX_TERM_DATA; i++) {
1426         td = &data[i];
1427         td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU);
1428         td->dwExStyle = (WS_EX_TOOLWINDOW);
1429     }
1430
1431     /* Font of each window */
1432     for (int i = 0; i < MAX_TERM_DATA; i++) {
1433         td = &data[i];
1434         strncpy(td->lf.lfFaceName, td->font_want, LF_FACESIZE);
1435         td->lf.lfCharSet = DEFAULT_CHARSET;
1436         td->lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
1437         term_force_font(td);
1438         if (!td->tile_wid)
1439             td->tile_wid = td->font_wid;
1440         if (!td->tile_hgt)
1441             td->tile_hgt = td->font_hgt;
1442         term_getsize(td);
1443         term_window_resize(td);
1444     }
1445
1446     /* Create sub windows */
1447     for (int i = MAX_TERM_DATA - 1; i >= 1; --i) {
1448         td = &data[i];
1449
1450         my_td = td;
1451         td->w
1452             = CreateWindowEx(td->dwExStyle, AngList, td->s, td->dwStyle, td->pos_x, td->pos_y, td->size_wid, td->size_hgt, HWND_DESKTOP, NULL, hInstance, NULL);
1453         my_td = NULL;
1454
1455         if (!td->w)
1456             quit(_("サブウィンドウに作成に失敗しました", "Failed to create sub-window"));
1457
1458         td->size_hack = TRUE;
1459         term_getsize(td);
1460         term_window_resize(td);
1461
1462         if (td->visible) {
1463             ShowWindow(td->w, SW_SHOW);
1464         }
1465         td->size_hack = FALSE;
1466
1467         term_data_link(td);
1468         angband_term[i] = &td->t;
1469
1470         if (td->visible) {
1471             /* Activate the window */
1472             SetActiveWindow(td->w);
1473         }
1474
1475         if (td->posfix) {
1476             term_window_pos(td, HWND_TOPMOST);
1477         } else {
1478             term_window_pos(td, td->w);
1479         }
1480     }
1481
1482     /* Create main window */
1483     td = &data[0];
1484     my_td = td;
1485     td->w = CreateWindowEx(td->dwExStyle, AppName, td->s, td->dwStyle, td->pos_x, td->pos_y, td->size_wid, td->size_hgt, HWND_DESKTOP, NULL, hInstance, NULL);
1486     my_td = NULL;
1487
1488     if (!td->w)
1489         quit(_("メインウィンドウの作成に失敗しました", "Failed to create Angband window"));
1490
1491     /* Resize */
1492     td->size_hack = TRUE;
1493     term_getsize(td);
1494     term_window_resize(td);
1495     td->size_hack = FALSE;
1496
1497     term_data_link(td);
1498     angband_term[0] = &td->t;
1499     normsize.x = td->cols;
1500     normsize.y = td->rows;
1501
1502     if (win_maximized)
1503         ShowWindow(td->w, SW_SHOWMAXIMIZED);
1504     else
1505         ShowWindow(td->w, SW_SHOW);
1506
1507     SetWindowPos(td->w, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
1508     hbrYellow = CreateSolidBrush(win_clr[TERM_YELLOW]);
1509     (void)term_xtra_win_flush();
1510 }
1511
1512 /*
1513  * Prepare the menus
1514  */
1515 static void setup_menus(void)
1516 {
1517     HMENU hm = GetMenu(data[0].w);
1518
1519     if (current_world_ptr->character_generated) {
1520         EnableMenuItem(hm, IDM_FILE_NEW, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1521         EnableMenuItem(hm, IDM_FILE_OPEN, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1522         EnableMenuItem(hm, IDM_FILE_SAVE, MF_BYCOMMAND | MF_ENABLED);
1523     } else {
1524         EnableMenuItem(hm, IDM_FILE_NEW, MF_BYCOMMAND | MF_ENABLED);
1525         EnableMenuItem(hm, IDM_FILE_OPEN, MF_BYCOMMAND | MF_ENABLED);
1526         EnableMenuItem(hm, IDM_FILE_SAVE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1527     }
1528
1529     for (int i = 0; i < MAX_TERM_DATA; i++) {
1530         EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1531         CheckMenuItem(hm, IDM_WINDOW_VIS_0 + i, (data[i].visible ? MF_CHECKED : MF_UNCHECKED));
1532         EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i, MF_BYCOMMAND | MF_ENABLED);
1533     }
1534
1535     for (int i = 0; i < MAX_TERM_DATA; i++) {
1536         EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1537
1538         if (data[i].visible) {
1539             EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i, MF_BYCOMMAND | MF_ENABLED);
1540         }
1541     }
1542
1543     for (int i = 0; i < MAX_TERM_DATA; i++) {
1544         EnableMenuItem(hm, IDM_WINDOW_POS_0 + i, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1545         CheckMenuItem(hm, IDM_WINDOW_POS_0 + i, (data[i].posfix ? MF_CHECKED : MF_UNCHECKED));
1546         if (data[i].visible) {
1547             EnableMenuItem(hm, IDM_WINDOW_POS_0 + i, MF_BYCOMMAND | MF_ENABLED);
1548         }
1549     }
1550
1551     for (int i = 0; i < MAX_TERM_DATA; i++) {
1552         EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1553         if (data[i].visible) {
1554             EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i, MF_BYCOMMAND | MF_ENABLED);
1555         }
1556     }
1557
1558     for (int i = 0; i < MAX_TERM_DATA; i++) {
1559         EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1560         if (data[i].visible) {
1561             EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i, MF_BYCOMMAND | MF_ENABLED);
1562         }
1563     }
1564
1565     for (int i = 0; i < MAX_TERM_DATA; i++) {
1566         EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1567         if (data[i].visible) {
1568             EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i, MF_BYCOMMAND | MF_ENABLED);
1569         }
1570     }
1571
1572     for (int i = 0; i < MAX_TERM_DATA; i++) {
1573         EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1574
1575         if (data[i].visible) {
1576             EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i, MF_BYCOMMAND | MF_ENABLED);
1577         }
1578     }
1579     CheckMenuItem(hm, IDM_WINDOW_KEEP_SUBWINDOWS, (keep_subwindows ? MF_CHECKED : MF_UNCHECKED));
1580
1581     CheckMenuItem(hm, IDM_OPTIONS_NO_GRAPHICS, (arg_graphics == GRAPHICS_NONE ? MF_CHECKED : MF_UNCHECKED));
1582     CheckMenuItem(hm, IDM_OPTIONS_OLD_GRAPHICS, (arg_graphics == GRAPHICS_ORIGINAL ? MF_CHECKED : MF_UNCHECKED));
1583     CheckMenuItem(hm, IDM_OPTIONS_NEW_GRAPHICS, (arg_graphics == GRAPHICS_ADAM_BOLT ? MF_CHECKED : MF_UNCHECKED));
1584     CheckMenuItem(hm, IDM_OPTIONS_NEW2_GRAPHICS, (arg_graphics == GRAPHICS_HENGBAND ? MF_CHECKED : MF_UNCHECKED));
1585     CheckMenuItem(hm, IDM_OPTIONS_BIGTILE, (arg_bigtile ? MF_CHECKED : MF_UNCHECKED));
1586     CheckMenuItem(hm, IDM_OPTIONS_MUSIC, (arg_music ? MF_CHECKED : MF_UNCHECKED));
1587     CheckMenuItem(hm, IDM_OPTIONS_MUSIC_PAUSE_INACTIVE, (use_pause_music_inactive ? MF_CHECKED : MF_UNCHECKED));
1588     CheckMenuItem(hm, IDM_OPTIONS_SOUND, (arg_sound ? MF_CHECKED : MF_UNCHECKED));
1589     CheckMenuItem(hm, IDM_OPTIONS_NO_BG, ((current_bg_mode == bg_mode::BG_NONE) ? MF_CHECKED : MF_UNCHECKED));
1590     CheckMenuItem(hm, IDM_OPTIONS_BG, ((current_bg_mode == bg_mode::BG_ONE) ? MF_CHECKED : MF_UNCHECKED));
1591     CheckMenuItem(hm, IDM_OPTIONS_PRESET_BG, ((current_bg_mode == bg_mode::BG_PRESET) ? MF_CHECKED : MF_UNCHECKED));
1592     // TODO IDM_OPTIONS_PRESET_BG を有効にする
1593     EnableMenuItem(hm, IDM_OPTIONS_PRESET_BG, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1594 }
1595
1596 /*
1597  * Check for double clicked (or dragged) savefile
1598  *
1599  * Apparently, Windows copies the entire filename into the first
1600  * piece of the "command line string".  Perhaps we should extract
1601  * the "basename" of that filename and append it to the "save" dir.
1602  */
1603 static void check_for_save_file(player_type *player_ptr, LPSTR cmd_line)
1604 {
1605     char *s;
1606     s = cmd_line;
1607     if (!*s)
1608         return;
1609
1610     strcpy(savefile, s);
1611     validate_file(savefile);
1612     game_in_progress = TRUE;
1613     play_game(player_ptr, FALSE, FALSE);
1614 }
1615
1616 /*
1617  * Process a menu command
1618  */
1619 static void process_menus(player_type *player_ptr, WORD wCmd)
1620 {
1621     if (!initialized) {
1622         plog(_("まだ初期化中です...", "You cannot do that yet..."));
1623         return;
1624     }
1625
1626     term_data *td;
1627     OPENFILENAME ofn;
1628     switch (wCmd) {
1629     case IDM_FILE_NEW: {
1630         if (game_in_progress) {
1631             plog(_("プレイ中は新しいゲームを始めることができません!", "You can't start a new game while you're still playing!"));
1632         } else {
1633             game_in_progress = TRUE;
1634             term_flush();
1635             strcpy(savefile, "");
1636             play_game(player_ptr, TRUE, FALSE);
1637             quit(NULL);
1638         }
1639
1640         break;
1641     }
1642     case IDM_FILE_OPEN: {
1643         if (game_in_progress) {
1644             plog(_("プレイ中はゲームをロードすることができません!", "You can't open a new game while you're still playing!"));
1645         } else {
1646             memset(&ofn, 0, sizeof(ofn));
1647             ofn.lStructSize = sizeof(ofn);
1648             ofn.hwndOwner = data[0].w;
1649             ofn.lpstrFilter = "Save Files (*.)\0*\0";
1650             ofn.nFilterIndex = 1;
1651             ofn.lpstrFile = savefile;
1652             ofn.nMaxFile = 1024;
1653             ofn.lpstrInitialDir = ANGBAND_DIR_SAVE;
1654             ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY;
1655
1656             if (GetOpenFileName(&ofn)) {
1657                 validate_file(savefile);
1658                 game_in_progress = TRUE;
1659                 term_flush();
1660                 play_game(player_ptr, FALSE, FALSE);
1661                 quit(NULL);
1662             }
1663         }
1664
1665         break;
1666     }
1667     case IDM_FILE_SAVE: {
1668         if (game_in_progress && current_world_ptr->character_generated) {
1669             if (!can_save) {
1670                 plog(_("今はセーブすることは出来ません。", "You may not do that right now."));
1671                 break;
1672             }
1673
1674             msg_flag = FALSE;
1675             do_cmd_save_game(player_ptr, FALSE);
1676         } else {
1677             plog(_("今、セーブすることは出来ません。", "You may not do that right now."));
1678         }
1679
1680         break;
1681     }
1682     case IDM_FILE_EXIT: {
1683         if (game_in_progress && current_world_ptr->character_generated) {
1684             if (!can_save) {
1685                 plog(_("今は終了できません。", "You may not do that right now."));
1686                 break;
1687             }
1688
1689             msg_flag = FALSE;
1690             forget_lite(player_ptr->current_floor_ptr);
1691             forget_view(player_ptr->current_floor_ptr);
1692             clear_mon_lite(player_ptr->current_floor_ptr);
1693
1694             term_key_push(SPECIAL_KEY_QUIT);
1695             break;
1696         }
1697
1698         quit(NULL);
1699         break;
1700     }
1701     case IDM_FILE_SCORE: {
1702         char buf[1024];
1703         path_build(buf, sizeof(buf), ANGBAND_DIR_APEX, "scores.raw");
1704         highscore_fd = fd_open(buf, O_RDONLY);
1705         if (highscore_fd < 0) {
1706             msg_print("Score file unavailable.");
1707         } else {
1708             screen_save();
1709             term_clear();
1710             display_scores_aux(0, MAX_HISCORES, -1, NULL);
1711             (void)fd_close(highscore_fd);
1712             highscore_fd = -1;
1713             screen_load();
1714             term_fresh();
1715         }
1716
1717         break;
1718     }
1719     case IDM_FILE_MOVIE: {
1720         if (game_in_progress) {
1721             plog(_("プレイ中はムービーをロードすることができません!", "You can't open a movie while you're playing!"));
1722         } else {
1723             memset(&ofn, 0, sizeof(ofn));
1724             ofn.lStructSize = sizeof(ofn);
1725             ofn.hwndOwner = data[0].w;
1726             ofn.lpstrFilter = "Angband Movie Files (*.amv)\0*.amv\0";
1727             ofn.nFilterIndex = 1;
1728             ofn.lpstrFile = savefile;
1729             ofn.nMaxFile = 1024;
1730             ofn.lpstrInitialDir = ANGBAND_DIR_USER;
1731             ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
1732
1733             if (GetOpenFileName(&ofn)) {
1734                 prepare_browse_movie_without_path_build(savefile);
1735                 play_game(player_ptr, FALSE, TRUE);
1736                 quit(NULL);
1737                 return;
1738             }
1739         }
1740
1741         break;
1742     }
1743     case IDM_WINDOW_VIS_0: {
1744         plog(_("メインウィンドウは非表示にできません!", "You are not allowed to do that!"));
1745         break;
1746     }
1747     case IDM_WINDOW_VIS_1:
1748     case IDM_WINDOW_VIS_2:
1749     case IDM_WINDOW_VIS_3:
1750     case IDM_WINDOW_VIS_4:
1751     case IDM_WINDOW_VIS_5:
1752     case IDM_WINDOW_VIS_6:
1753     case IDM_WINDOW_VIS_7: {
1754         int i = wCmd - IDM_WINDOW_VIS_0;
1755         if ((i < 0) || (i >= MAX_TERM_DATA))
1756             break;
1757
1758         td = &data[i];
1759         if (!td->visible) {
1760             td->visible = TRUE;
1761             ShowWindow(td->w, SW_SHOW);
1762             term_data_redraw(td);
1763         } else {
1764             td->visible = FALSE;
1765             td->posfix = FALSE;
1766             ShowWindow(td->w, SW_HIDE);
1767         }
1768
1769         break;
1770     }
1771     case IDM_WINDOW_FONT_0:
1772     case IDM_WINDOW_FONT_1:
1773     case IDM_WINDOW_FONT_2:
1774     case IDM_WINDOW_FONT_3:
1775     case IDM_WINDOW_FONT_4:
1776     case IDM_WINDOW_FONT_5:
1777     case IDM_WINDOW_FONT_6:
1778     case IDM_WINDOW_FONT_7: {
1779         int i = wCmd - IDM_WINDOW_FONT_0;
1780         if ((i < 0) || (i >= MAX_TERM_DATA))
1781             break;
1782
1783         td = &data[i];
1784         term_change_font(td);
1785         break;
1786     }
1787     case IDM_WINDOW_POS_1:
1788     case IDM_WINDOW_POS_2:
1789     case IDM_WINDOW_POS_3:
1790     case IDM_WINDOW_POS_4:
1791     case IDM_WINDOW_POS_5:
1792     case IDM_WINDOW_POS_6:
1793     case IDM_WINDOW_POS_7: {
1794         int i = wCmd - IDM_WINDOW_POS_0;
1795         if ((i < 0) || (i >= MAX_TERM_DATA))
1796             break;
1797
1798         td = &data[i];
1799         if (!td->posfix && td->visible) {
1800             td->posfix = TRUE;
1801             term_window_pos(td, HWND_TOPMOST);
1802         } else {
1803             td->posfix = FALSE;
1804             term_window_pos(td, data[0].w);
1805         }
1806
1807         break;
1808     }
1809     case IDM_WINDOW_I_WID_0:
1810     case IDM_WINDOW_I_WID_1:
1811     case IDM_WINDOW_I_WID_2:
1812     case IDM_WINDOW_I_WID_3:
1813     case IDM_WINDOW_I_WID_4:
1814     case IDM_WINDOW_I_WID_5:
1815     case IDM_WINDOW_I_WID_6:
1816     case IDM_WINDOW_I_WID_7: {
1817         int i = wCmd - IDM_WINDOW_I_WID_0;
1818         if ((i < 0) || (i >= MAX_TERM_DATA))
1819             break;
1820
1821         td = &data[i];
1822         td->tile_wid += 1;
1823         term_getsize(td);
1824         term_window_resize(td);
1825         break;
1826     }
1827     case IDM_WINDOW_D_WID_0:
1828     case IDM_WINDOW_D_WID_1:
1829     case IDM_WINDOW_D_WID_2:
1830     case IDM_WINDOW_D_WID_3:
1831     case IDM_WINDOW_D_WID_4:
1832     case IDM_WINDOW_D_WID_5:
1833     case IDM_WINDOW_D_WID_6:
1834     case IDM_WINDOW_D_WID_7: {
1835         int i = wCmd - IDM_WINDOW_D_WID_0;
1836         if ((i < 0) || (i >= MAX_TERM_DATA))
1837             break;
1838
1839         td = &data[i];
1840         td->tile_wid -= 1;
1841         term_getsize(td);
1842         term_window_resize(td);
1843         break;
1844     }
1845     case IDM_WINDOW_I_HGT_0:
1846     case IDM_WINDOW_I_HGT_1:
1847     case IDM_WINDOW_I_HGT_2:
1848     case IDM_WINDOW_I_HGT_3:
1849     case IDM_WINDOW_I_HGT_4:
1850     case IDM_WINDOW_I_HGT_5:
1851     case IDM_WINDOW_I_HGT_6:
1852     case IDM_WINDOW_I_HGT_7: {
1853         int i = wCmd - IDM_WINDOW_I_HGT_0;
1854         if ((i < 0) || (i >= MAX_TERM_DATA))
1855             break;
1856
1857         td = &data[i];
1858         td->tile_hgt += 1;
1859         term_getsize(td);
1860         term_window_resize(td);
1861         break;
1862     }
1863     case IDM_WINDOW_D_HGT_0:
1864     case IDM_WINDOW_D_HGT_1:
1865     case IDM_WINDOW_D_HGT_2:
1866     case IDM_WINDOW_D_HGT_3:
1867     case IDM_WINDOW_D_HGT_4:
1868     case IDM_WINDOW_D_HGT_5:
1869     case IDM_WINDOW_D_HGT_6:
1870     case IDM_WINDOW_D_HGT_7: {
1871         int i = wCmd - IDM_WINDOW_D_HGT_0;
1872         if ((i < 0) || (i >= MAX_TERM_DATA))
1873             break;
1874
1875         td = &data[i];
1876         td->tile_hgt -= 1;
1877         term_getsize(td);
1878         term_window_resize(td);
1879         break;
1880     }
1881     case IDM_WINDOW_KEEP_SUBWINDOWS: {
1882         keep_subwindows = !keep_subwindows;
1883         break;
1884     }
1885     case IDM_OPTIONS_NO_GRAPHICS: {
1886         if (arg_graphics != GRAPHICS_NONE) {
1887             arg_graphics = GRAPHICS_NONE;
1888
1889             if (inkey_flag) {
1890                 term_xtra_win_react(player_ptr);
1891                 term_key_push(KTRL('R'));
1892             }
1893         }
1894         break;
1895     }
1896     case IDM_OPTIONS_OLD_GRAPHICS: {
1897         if (arg_graphics != GRAPHICS_ORIGINAL) {
1898             arg_graphics = GRAPHICS_ORIGINAL;
1899
1900             if (inkey_flag) {
1901                 term_xtra_win_react(player_ptr);
1902                 term_key_push(KTRL('R'));
1903             } else if (!init_graphics()) {
1904                 arg_graphics = GRAPHICS_NONE;
1905             }
1906         }
1907
1908         break;
1909     }
1910     case IDM_OPTIONS_NEW_GRAPHICS: {
1911         if (arg_graphics != GRAPHICS_ADAM_BOLT) {
1912             arg_graphics = GRAPHICS_ADAM_BOLT;
1913
1914             if (inkey_flag) {
1915                 term_xtra_win_react(player_ptr);
1916                 term_key_push(KTRL('R'));
1917             } else if (!init_graphics()) {
1918                 arg_graphics = GRAPHICS_NONE;
1919             }
1920         }
1921
1922         break;
1923     }
1924     case IDM_OPTIONS_NEW2_GRAPHICS: {
1925         if (arg_graphics != GRAPHICS_HENGBAND) {
1926             arg_graphics = GRAPHICS_HENGBAND;
1927
1928             if (inkey_flag) {
1929                 term_xtra_win_react(player_ptr);
1930                 term_key_push(KTRL('R'));
1931             } else if (!init_graphics()) {
1932                 arg_graphics = GRAPHICS_NONE;
1933             }
1934         }
1935
1936         break;
1937     }
1938     case IDM_OPTIONS_BIGTILE: {
1939         td = &data[0];
1940         arg_bigtile = !arg_bigtile;
1941         term_activate(&td->t);
1942         term_resize(td->cols, td->rows);
1943         InvalidateRect(td->w, NULL, TRUE);
1944         break;
1945     }
1946     case IDM_OPTIONS_MUSIC: {
1947         arg_music = !arg_music;
1948         use_music = arg_music;
1949         if (use_music) {
1950             init_music();
1951             if (game_in_progress)
1952                 select_floor_music(player_ptr);
1953         } else {
1954             main_win_music::stop_music();
1955         }
1956         break;
1957     }
1958     case IDM_OPTIONS_MUSIC_PAUSE_INACTIVE: {
1959         use_pause_music_inactive = !use_pause_music_inactive;
1960         break;
1961     }
1962     case IDM_OPTIONS_SOUND: {
1963         arg_sound = !arg_sound;
1964         if (inkey_flag)
1965             term_xtra_win_react(player_ptr);
1966         break;
1967     }
1968     case IDM_OPTIONS_NO_BG: {
1969         change_bg_mode(bg_mode::BG_NONE);
1970         td = &data[0];
1971         InvalidateRect(td->w, NULL, TRUE);
1972         break;
1973     }
1974     case IDM_OPTIONS_PRESET_BG: {
1975         change_bg_mode(bg_mode::BG_PRESET);
1976         td = &data[0];
1977         InvalidateRect(td->w, NULL, TRUE);
1978         break;
1979     }
1980     case IDM_OPTIONS_BG: {
1981         bool ret = change_bg_mode(bg_mode::BG_ONE);
1982         if (ret) {
1983             td = &data[0];
1984             InvalidateRect(td->w, NULL, TRUE);
1985             break;
1986         }
1987         // 壁紙の設定に失敗した(ファイルが存在しない等)場合、壁紙に使うファイルを選択させる
1988     }
1989         [[fallthrough]]; /* Fall through */
1990     case IDM_OPTIONS_OPEN_BG: {
1991         memset(&ofn, 0, sizeof(ofn));
1992         ofn.lStructSize = sizeof(ofn);
1993         ofn.hwndOwner = data[0].w;
1994         ofn.lpstrFilter = "Image Files (*.bmp;*.png;*.jpg;*.jpeg;)\0*.bmp;*.png;*.jpg;*.jpeg;\0";
1995         ofn.nFilterIndex = 1;
1996         ofn.lpstrFile = wallpaper_file;
1997         ofn.nMaxFile = 1023;
1998         ofn.lpstrInitialDir = NULL;
1999         ofn.lpstrTitle = _("壁紙を選んでね。", "Choose wall paper.");
2000         ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
2001
2002         if (GetOpenFileName(&ofn)) {
2003             change_bg_mode(bg_mode::BG_ONE, true);
2004             td = &data[0];
2005             InvalidateRect(td->w, NULL, TRUE);
2006         }
2007         break;
2008     }
2009     case IDM_DUMP_SCREEN_HTML: {
2010         OPENFILENAMEW ofnw;
2011         std::vector<WCHAR> buf(MAIN_WIN_MAX_PATH + 1);
2012         memset(&ofnw, 0, sizeof(ofnw));
2013         ofnw.lStructSize = sizeof(ofnw);
2014         ofnw.hwndOwner = data[0].w;
2015         ofnw.lpstrFilter = L"HTML Files (*.html)\0*.html\0";
2016         ofnw.nFilterIndex = 1;
2017         ofnw.lpstrFile = &buf[0];
2018         ofnw.nMaxFile = MAIN_WIN_MAX_PATH;
2019         ofnw.lpstrDefExt = L"html";
2020         ofnw.lpstrInitialDir = NULL;
2021         ofnw.lpstrTitle = _(L"HTMLでスクリーンダンプを保存", L"Save screen dump as HTML.");
2022         ofnw.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
2023
2024         if (GetSaveFileNameW(&ofnw)) {
2025             do_cmd_save_screen_html_aux(to_multibyte(&buf[0]).c_str(), 0);
2026         }
2027
2028         break;
2029     }
2030     }
2031 }
2032
2033 /*
2034  * Add a keypress to the "queue"
2035  */
2036 static errr term_keypress(int k)
2037 {
2038     /* Refuse to enqueue non-keys */
2039     if (!k)
2040         return -1;
2041
2042     /* Store the char, advance the queue */
2043     Term->key_queue[Term->key_head++] = (char)k;
2044
2045     /* Circular queue, handle wrap */
2046     if (Term->key_head == Term->key_size)
2047         Term->key_head = 0;
2048
2049     if (Term->key_head != Term->key_tail)
2050         return 0;
2051
2052     return 1;
2053 }
2054
2055 static bool process_keydown(WPARAM wParam, LPARAM lParam)
2056 {
2057     bool mc = FALSE;
2058     bool ms = FALSE;
2059     bool ma = FALSE;
2060
2061     if (GetKeyState(VK_CONTROL) & 0x8000)
2062         mc = TRUE;
2063     if (GetKeyState(VK_SHIFT) & 0x8000)
2064         ms = TRUE;
2065     if (GetKeyState(VK_MENU) & 0x8000)
2066         ma = TRUE;
2067
2068     term_no_press = (ma) ? TRUE : FALSE;
2069     if (special_key[(byte)(wParam)] || (ma && !ignore_key[(byte)(wParam)])) {
2070         bool ext_key = (lParam & 0x1000000L) ? TRUE : FALSE;
2071         bool numpad = FALSE;
2072
2073         term_keypress(31);
2074         if (mc)
2075             term_keypress('C');
2076         if (ms)
2077             term_keypress('S');
2078         if (ma)
2079             term_keypress('A');
2080
2081         int i = LOBYTE(HIWORD(lParam));
2082         term_keypress('x');
2083         switch (wParam) {
2084         case VK_DIVIDE:
2085             term_no_press = TRUE;
2086             [[fallthrough]]; /* Fall through */
2087         case VK_RETURN:
2088             numpad = ext_key;
2089             break;
2090         case VK_NUMPAD0:
2091         case VK_NUMPAD1:
2092         case VK_NUMPAD2:
2093         case VK_NUMPAD3:
2094         case VK_NUMPAD4:
2095         case VK_NUMPAD5:
2096         case VK_NUMPAD6:
2097         case VK_NUMPAD7:
2098         case VK_NUMPAD8:
2099         case VK_NUMPAD9:
2100         case VK_ADD:
2101         case VK_MULTIPLY:
2102         case VK_SUBTRACT:
2103         case VK_SEPARATOR:
2104         case VK_DECIMAL:
2105             term_no_press = TRUE;
2106             [[fallthrough]]; /* Fall through */
2107         case VK_CLEAR:
2108         case VK_HOME:
2109         case VK_END:
2110         case VK_PRIOR:
2111         case VK_NEXT:
2112         case VK_INSERT:
2113         case VK_DELETE:
2114         case VK_UP:
2115         case VK_DOWN:
2116         case VK_LEFT:
2117         case VK_RIGHT:
2118             numpad = !ext_key;
2119         }
2120
2121         if (numpad)
2122             term_keypress('K');
2123
2124         term_keypress(hexsym[i / 16]);
2125         term_keypress(hexsym[i % 16]);
2126         term_keypress(13);
2127
2128         return 1;
2129     }
2130
2131     return 0;
2132 }
2133
2134 static void handle_app_active(HWND hWnd, UINT uMsg, WPARAM wParam, [[maybe_unused]] LPARAM lParam)
2135 {
2136     switch (uMsg) {
2137     case WM_ACTIVATEAPP: {
2138         if (wParam) {
2139             if (use_pause_music_inactive)
2140                 main_win_music::resume_music();
2141         } else {
2142             if (use_pause_music_inactive)
2143                 main_win_music::pause_music();
2144         }
2145         break;
2146     }
2147     case WM_WINDOWPOSCHANGING: {
2148         if (!IsIconic(hWnd))
2149             if (use_pause_music_inactive)
2150                 main_win_music::resume_music();
2151         break;
2152     }
2153     }
2154 }
2155
2156 /*!
2157  * @todo WNDCLASSに影響があるのでplayer_type*の追加は保留
2158  */
2159 LRESULT PASCAL AngbandWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2160 {
2161     PAINTSTRUCT ps;
2162     term_data *td;
2163     td = (term_data *)GetWindowLong(hWnd, 0);
2164
2165     handle_app_active(hWnd, uMsg, wParam, lParam);
2166
2167     switch (uMsg) {
2168     case WM_NCCREATE: {
2169         SetWindowLong(hWnd, 0, (LONG)(my_td));
2170         break;
2171     }
2172     case WM_CREATE: {
2173         setup_mci(hWnd);
2174         return 0;
2175     }
2176     case WM_GETMINMAXINFO: {
2177         MINMAXINFO *lpmmi;
2178         RECT rc;
2179
2180         lpmmi = (MINMAXINFO *)lParam;
2181         if (!td)
2182             return 1;
2183
2184         rc.left = rc.top = 0;
2185         rc.right = rc.left + 80 * td->tile_wid + td->size_ow1 + td->size_ow2;
2186         rc.bottom = rc.top + 24 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1;
2187
2188         AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
2189
2190         lpmmi->ptMinTrackSize.x = rc.right - rc.left;
2191         lpmmi->ptMinTrackSize.y = rc.bottom - rc.top;
2192
2193         return 0;
2194     }
2195     case WM_PAINT: {
2196         BeginPaint(hWnd, &ps);
2197         if (td)
2198             term_data_redraw(td);
2199         EndPaint(hWnd, &ps);
2200         ValidateRect(hWnd, NULL);
2201         return 0;
2202     }
2203     case MM_MCINOTIFY: {
2204         main_win_music::on_mci_notify(wParam, lParam);
2205
2206         return 0;
2207     }
2208     case WM_SYSKEYDOWN:
2209     case WM_KEYDOWN: {
2210         if (process_keydown(wParam, lParam))
2211             return 0;
2212         break;
2213     }
2214     case WM_CHAR: {
2215         if (term_no_press)
2216             term_no_press = FALSE;
2217         else
2218             term_keypress(wParam);
2219         return 0;
2220     }
2221     case WM_LBUTTONDOWN: {
2222         mousex = MIN(LOWORD(lParam) / td->tile_wid, td->cols - 1);
2223         mousey = MIN(HIWORD(lParam) / td->tile_hgt, td->rows - 1);
2224         mouse_down = TRUE;
2225         oldx = mousex;
2226         oldy = mousey;
2227         return 0;
2228     }
2229     case WM_LBUTTONUP: {
2230         HGLOBAL hGlobal;
2231         LPSTR lpStr;
2232         TERM_LEN dx = abs(oldx - mousex) + 1;
2233         TERM_LEN dy = abs(oldy - mousey) + 1;
2234         TERM_LEN ox = (oldx > mousex) ? mousex : oldx;
2235         TERM_LEN oy = (oldy > mousey) ? mousey : oldy;
2236
2237         mouse_down = FALSE;
2238         paint_rect = FALSE;
2239
2240 #ifdef JP
2241         int sz = (dx + 3) * dy;
2242 #else
2243         int sz = (dx + 2) * dy;
2244 #endif
2245         hGlobal = GlobalAlloc(GHND, sz + 1);
2246         if (hGlobal == NULL)
2247             return 0;
2248         lpStr = (LPSTR)GlobalLock(hGlobal);
2249
2250         for (int i = 0; i < dy; i++) {
2251 #ifdef JP
2252             char *s;
2253             const auto &scr = data[0].t.scr->c;
2254
2255             C_MAKE(s, (dx + 1), char);
2256             strncpy(s, &scr[oy + i][ox], dx);
2257
2258             if (ox > 0) {
2259                 if (iskanji(scr[oy + i][ox - 1]))
2260                     s[0] = ' ';
2261             }
2262
2263             if (ox + dx < data[0].cols) {
2264                 if (iskanji(scr[oy + i][ox + dx - 1]))
2265                     s[dx - 1] = ' ';
2266             }
2267
2268             for (int j = 0; j < dx; j++) {
2269                 if (s[j] == 127)
2270                     s[j] = '#';
2271                 *lpStr++ = s[j];
2272             }
2273 #else
2274             for (int j = 0; j < dx; j++) {
2275                 *lpStr++ = data[0].t.scr->c[oy + i][ox + j];
2276             }
2277 #endif
2278             if (dy > 1) {
2279                 *lpStr++ = '\r';
2280                 *lpStr++ = '\n';
2281             }
2282         }
2283
2284         GlobalUnlock(hGlobal);
2285         if (OpenClipboard(hWnd) == 0) {
2286             GlobalFree(hGlobal);
2287             return 0;
2288         }
2289
2290         EmptyClipboard();
2291         SetClipboardData(CF_TEXT, hGlobal);
2292         CloseClipboard();
2293         term_redraw();
2294         return 0;
2295     }
2296     case WM_MOUSEMOVE: {
2297         if (!mouse_down)
2298             return 0;
2299
2300         int dx, dy;
2301         int cx = MIN(LOWORD(lParam) / td->tile_wid, td->cols - 1);
2302         int cy = MIN(HIWORD(lParam) / td->tile_hgt, td->rows - 1);
2303         int ox, oy;
2304
2305         if (paint_rect) {
2306             dx = abs(oldx - mousex) + 1;
2307             dy = abs(oldy - mousey) + 1;
2308             ox = (oldx > mousex) ? mousex : oldx;
2309             oy = (oldy > mousey) ? mousey : oldy;
2310             term_inversed_area(hWnd, ox, oy, dx, dy);
2311         } else {
2312             paint_rect = TRUE;
2313         }
2314
2315         dx = abs(cx - mousex) + 1;
2316         dy = abs(cy - mousey) + 1;
2317         ox = (cx > mousex) ? mousex : cx;
2318         oy = (cy > mousey) ? mousey : cy;
2319         term_inversed_area(hWnd, ox, oy, dx, dy);
2320
2321         oldx = cx;
2322         oldy = cy;
2323         return 0;
2324     }
2325     case WM_INITMENU: {
2326         setup_menus();
2327         return 0;
2328     }
2329     case WM_CLOSE: {
2330         if (!game_in_progress || !current_world_ptr->character_generated) {
2331             quit(NULL);
2332             return 0;
2333         }
2334
2335         if (!can_save) {
2336             plog(_("今は終了できません。", "You may not do that right now."));
2337             return 0;
2338         }
2339
2340         msg_flag = FALSE;
2341         forget_lite(p_ptr->current_floor_ptr);
2342         forget_view(p_ptr->current_floor_ptr);
2343         clear_mon_lite(p_ptr->current_floor_ptr);
2344         term_key_push(SPECIAL_KEY_QUIT);
2345         return 0;
2346     }
2347     case WM_QUERYENDSESSION: {
2348         if (!game_in_progress || !current_world_ptr->character_generated) {
2349             quit(NULL);
2350             return 0;
2351         }
2352
2353         msg_flag = FALSE;
2354         if (p_ptr->chp < 0)
2355             p_ptr->is_dead = FALSE;
2356         exe_write_diary(p_ptr, DIARY_GAMESTART, 0, _("----ゲーム中断----", "---- Save and Exit Game ----"));
2357
2358         p_ptr->panic_save = 1;
2359         signals_ignore_tstp();
2360         (void)strcpy(p_ptr->died_from, _("(緊急セーブ)", "(panic save)"));
2361         (void)save_player(p_ptr, SAVE_TYPE_CLOSE_GAME);
2362         quit(NULL);
2363         return 0;
2364     }
2365     case WM_QUIT: {
2366         quit(NULL);
2367         return 0;
2368     }
2369     case WM_COMMAND: {
2370         process_menus(p_ptr, LOWORD(wParam));
2371         return 0;
2372     }
2373     case WM_SIZE: {
2374         if (!td)
2375             return 1;
2376         if (!td->w)
2377             return 1;
2378         if (td->size_hack)
2379             return 1;
2380
2381         //!< @todo 二重のswitch文。後で分割する.
2382         switch (wParam) {
2383         case SIZE_MINIMIZED: {
2384             for (int i = 1; i < MAX_TERM_DATA; i++) {
2385                 if (data[i].visible)
2386                     ShowWindow(data[i].w, SW_HIDE);
2387             }
2388
2389             return 0;
2390         }
2391         case SIZE_MAXIMIZED:
2392         case SIZE_RESTORED: {
2393             TERM_LEN cols = (LOWORD(lParam) - td->size_ow1) / td->tile_wid;
2394             TERM_LEN rows = (HIWORD(lParam) - td->size_oh1) / td->tile_hgt;
2395             if ((td->cols != cols) || (td->rows != rows)) {
2396                 td->cols = cols;
2397                 td->rows = rows;
2398                 if (!IsZoomed(td->w) && !IsIconic(td->w)) {
2399                     normsize.x = td->cols;
2400                     normsize.y = td->rows;
2401                 }
2402
2403                 term_activate(&td->t);
2404                 term_resize(td->cols, td->rows);
2405                 InvalidateRect(td->w, NULL, TRUE);
2406             }
2407
2408             td->size_hack = TRUE;
2409             for (int i = 1; i < MAX_TERM_DATA; i++) {
2410                 if (data[i].visible)
2411                     ShowWindow(data[i].w, SW_SHOW);
2412             }
2413
2414             td->size_hack = FALSE;
2415
2416             return 0;
2417         }
2418         }
2419
2420         break;
2421     }
2422     case WM_ACTIVATE: {
2423         if (!wParam || HIWORD(lParam))
2424             break;
2425
2426         for (int i = 1; i < MAX_TERM_DATA; i++) {
2427             if (!data[i].posfix)
2428                 term_window_pos(&data[i], hWnd);
2429         }
2430
2431         SetFocus(hWnd);
2432         return 0;
2433     }
2434     case WM_ACTIVATEAPP: {
2435         if (IsIconic(td->w))
2436             break;
2437
2438         for (int i = 1; i < MAX_TERM_DATA; i++) {
2439             if (data[i].visible) {
2440                 if (wParam == TRUE) {
2441                     ShowWindow(data[i].w, SW_SHOW);
2442                 } else {
2443                     ShowWindow(data[i].w, SW_HIDE);
2444                 }
2445             }
2446         }
2447     }
2448         [[fallthrough]]; /* Fall through */
2449     case WM_ENABLE: {
2450         if (wParam == FALSE && keep_subwindows) {
2451             for (int i = 0; i < MAX_TERM_DATA; i++) {
2452                 if (data[i].visible) {
2453                     ShowWindow(data[i].w, SW_SHOW);
2454                 }
2455             }
2456         }
2457     }
2458     }
2459
2460     return DefWindowProc(hWnd, uMsg, wParam, lParam);
2461 }
2462
2463 /*!
2464  * @todo WNDCLASSに影響があるのでplayer_type*の追加は保留
2465  */
2466 LRESULT PASCAL AngbandListProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2467 {
2468     term_data *td;
2469     PAINTSTRUCT ps;
2470     td = (term_data *)GetWindowLong(hWnd, 0);
2471
2472     switch (uMsg) {
2473     case WM_NCCREATE: {
2474         SetWindowLong(hWnd, 0, (LONG)(my_td));
2475         break;
2476     }
2477     case WM_CREATE: {
2478         return 0;
2479     }
2480     case WM_GETMINMAXINFO: {
2481         MINMAXINFO *lpmmi;
2482         RECT rc;
2483
2484         lpmmi = (MINMAXINFO *)lParam;
2485         if (!td)
2486             return 1;
2487
2488         rc.left = rc.top = 0;
2489         rc.right = rc.left + 20 * td->tile_wid + td->size_ow1 + td->size_ow2;
2490         rc.bottom = rc.top + 3 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1;
2491
2492         AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
2493         lpmmi->ptMinTrackSize.x = rc.right - rc.left;
2494         lpmmi->ptMinTrackSize.y = rc.bottom - rc.top;
2495         return 0;
2496     }
2497     case WM_SIZE: {
2498         if (!td)
2499             return 1;
2500         if (!td->w)
2501             return 1;
2502         if (td->size_hack)
2503             return 1;
2504
2505         td->size_hack = TRUE;
2506
2507         TERM_LEN cols = (LOWORD(lParam) - td->size_ow1) / td->tile_wid;
2508         TERM_LEN rows = (HIWORD(lParam) - td->size_oh1) / td->tile_hgt;
2509         if ((td->cols != cols) || (td->rows != rows)) {
2510             term_type *old_term = Term;
2511             td->cols = cols;
2512             td->rows = rows;
2513             term_activate(&td->t);
2514             term_resize(td->cols, td->rows);
2515             term_activate(old_term);
2516             InvalidateRect(td->w, NULL, TRUE);
2517             p_ptr->window_flags = 0xFFFFFFFF;
2518             handle_stuff(p_ptr);
2519         }
2520
2521         td->size_hack = FALSE;
2522         return 0;
2523     }
2524     case WM_PAINT: {
2525         BeginPaint(hWnd, &ps);
2526         if (td)
2527             term_data_redraw(td);
2528         EndPaint(hWnd, &ps);
2529         return 0;
2530     }
2531     case WM_SYSKEYDOWN:
2532     case WM_KEYDOWN: {
2533         if (process_keydown(wParam, lParam))
2534             return 0;
2535
2536         break;
2537     }
2538     case WM_CHAR: {
2539         if (term_no_press)
2540             term_no_press = FALSE;
2541         else
2542             term_keypress(wParam);
2543         return 0;
2544     }
2545     case WM_NCLBUTTONDOWN: {
2546         if (wParam == HTCLOSE)
2547             wParam = HTSYSMENU;
2548
2549         if (wParam == HTSYSMENU) {
2550             if (td->visible) {
2551                 td->visible = FALSE;
2552                 ShowWindow(td->w, SW_HIDE);
2553             }
2554
2555             return 0;
2556         }
2557
2558         break;
2559     }
2560     }
2561
2562     return DefWindowProc(hWnd, uMsg, wParam, lParam);
2563 }
2564
2565 /*
2566  * Display warning message (see "z-util.c")
2567  */
2568 static void hack_plog(concptr str)
2569 {
2570     if (str) {
2571         MessageBoxW(NULL, to_wchar(str).wc_str(), _(L"警告!", L"Warning"), MB_ICONEXCLAMATION | MB_OK);
2572     }
2573 }
2574
2575 /*
2576  * Display error message and quit (see "z-util.c")
2577  */
2578 static void hack_quit(concptr str)
2579 {
2580     if (str) {
2581         MessageBoxW(NULL, to_wchar(str).wc_str(), _(L"エラー!", L"Error"), MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
2582     }
2583
2584     UnregisterClass(AppName, hInstance);
2585     if (hIcon)
2586         DestroyIcon(hIcon);
2587
2588     exit(0);
2589 }
2590
2591 /*
2592  * Display warning message (see "z-util.c")
2593  */
2594 static void hook_plog(concptr str)
2595 {
2596     if (str) {
2597         MessageBoxW(data[0].w, to_wchar(str).wc_str(), _(L"警告!", L"Warning"), MB_ICONEXCLAMATION | MB_OK);
2598     }
2599 }
2600
2601 /*
2602  * Display error message and quit (see "z-util.c")
2603  */
2604 static void hook_quit(concptr str)
2605 {
2606     if (str) {
2607         MessageBoxW(data[0].w, to_wchar(str).wc_str(), _(L"エラー!", L"Error"), MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
2608     }
2609
2610     save_prefs();
2611     for (int i = MAX_TERM_DATA - 1; i >= 0; --i) {
2612         term_force_font(&data[i]);
2613         if (data[i].font_want)
2614             string_free(data[i].font_want);
2615         if (data[i].w)
2616             DestroyWindow(data[i].w);
2617         data[i].w = 0;
2618     }
2619
2620     infGraph.delete_bitmap();
2621     infMask.delete_bitmap();
2622
2623     DeleteObject(hbrYellow);
2624     finalize_bg();
2625     finalize_graphics();
2626
2627     UnregisterClass(AppName, hInstance);
2628     if (hIcon)
2629         DestroyIcon(hIcon);
2630
2631     exit(0);
2632 }
2633
2634 /*
2635  * Init some stuff
2636  */
2637 static void init_stuff(void)
2638 {
2639     char path[1024];
2640     GetModuleFileName(hInstance, path, 512);
2641     argv0 = path;
2642     strcpy(path + strlen(path) - 4, ".INI");
2643     ini_file = string_make(path);
2644     int i = strlen(path);
2645
2646     for (; i > 0; i--) {
2647         if (path[i] == '\\') {
2648             break;
2649         }
2650     }
2651
2652     strcpy(path + i + 1, "lib\\");
2653     validate_dir(path, TRUE);
2654     init_file_paths(path, path);
2655     validate_dir(ANGBAND_DIR_APEX, FALSE);
2656     validate_dir(ANGBAND_DIR_BONE, FALSE);
2657     if (!check_dir(ANGBAND_DIR_EDIT)) {
2658         validate_dir(ANGBAND_DIR_DATA, TRUE);
2659     } else {
2660         validate_dir(ANGBAND_DIR_DATA, FALSE);
2661     }
2662
2663     validate_dir(ANGBAND_DIR_FILE, TRUE);
2664     validate_dir(ANGBAND_DIR_HELP, FALSE);
2665     validate_dir(ANGBAND_DIR_INFO, FALSE);
2666     validate_dir(ANGBAND_DIR_PREF, TRUE);
2667     validate_dir(ANGBAND_DIR_SAVE, FALSE);
2668     validate_dir(ANGBAND_DIR_DEBUG_SAVE, FALSE);
2669     validate_dir(ANGBAND_DIR_USER, TRUE);
2670     validate_dir(ANGBAND_DIR_XTRA, TRUE);
2671     path_build(path, sizeof(path), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
2672
2673     validate_file(path);
2674     path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "graf");
2675     ANGBAND_DIR_XTRA_GRAF = string_make(path);
2676     validate_dir(ANGBAND_DIR_XTRA_GRAF, TRUE);
2677
2678     path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "sound");
2679     ANGBAND_DIR_XTRA_SOUND = string_make(path);
2680     validate_dir(ANGBAND_DIR_XTRA_SOUND, FALSE);
2681
2682     path_build(path, sizeof(path), ANGBAND_DIR_XTRA, "music");
2683     ANGBAND_DIR_XTRA_MUSIC = string_make(path);
2684     validate_dir(ANGBAND_DIR_XTRA_MUSIC, FALSE);
2685 }
2686
2687 /*!
2688  * @brief コマンドラインから全スポイラー出力を行う
2689  * Create Spoiler files from Command Line
2690  * @return spoiler_output_status
2691  */
2692 static spoiler_output_status create_debug_spoiler(LPSTR cmd_line)
2693 {
2694     char *s;
2695     concptr option;
2696     s = cmd_line;
2697     if (!*s)
2698         return SPOILER_OUTPUT_CANCEL;
2699     option = "--output-spoilers";
2700
2701     if (strncmp(s, option, strlen(option)) != 0)
2702         return SPOILER_OUTPUT_CANCEL;
2703
2704     init_stuff();
2705     init_angband(p_ptr, TRUE);
2706
2707     return output_all_spoilers();
2708 }
2709
2710 /*!
2711  * @todo よく見るとhMutexはちゃんと使われていない……?
2712  * @brief (Windows固有)変愚蛮怒が起動済かどうかのチェック
2713  */
2714 static bool is_already_running(void)
2715 {
2716     HANDLE hMutex;
2717     hMutex = CreateMutex(NULL, TRUE, VERSION_NAME);
2718     if (GetLastError() == ERROR_ALREADY_EXISTS) {
2719         return TRUE;
2720     }
2721
2722     return FALSE;
2723 }
2724
2725 /*!
2726  * @brief (Windows固有)Windowsアプリケーションとしてのエントリポイント
2727  */
2728 int WINAPI WinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInst, _In_ LPSTR lpCmdLine, [[maybe_unused]] _In_ int nCmdShow)
2729 {
2730     setlocale(LC_ALL, "ja_JP");
2731     hInstance = hInst;
2732     if (is_already_running()) {
2733         MessageBoxW(
2734             NULL, _(L"変愚蛮怒はすでに起動しています。", L"Hengband is already running."), _(L"エラー!", L"Error"), MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
2735         return FALSE;
2736     }
2737
2738     switch (create_debug_spoiler(lpCmdLine)) {
2739     case SPOILER_OUTPUT_SUCCESS:
2740         fprintf(stdout, "Successfully created a spoiler file.");
2741         quit(NULL);
2742         return 0;
2743     case SPOILER_OUTPUT_FAIL_FOPEN:
2744         fprintf(stderr, "Cannot create spoiler file.");
2745         quit(NULL);
2746         return 0;
2747     case SPOILER_OUTPUT_FAIL_FCLOSE:
2748         fprintf(stderr, "Cannot close spoiler file.");
2749         quit(NULL);
2750         return 0;
2751     default:
2752         break;
2753     }
2754
2755     if (hPrevInst == NULL) {
2756         WNDCLASS wc;
2757         wc.style = CS_CLASSDC;
2758         wc.lpfnWndProc = AngbandWndProc;
2759         wc.cbClsExtra = 0;
2760         wc.cbWndExtra = 4;
2761         wc.hInstance = hInst;
2762         wc.hIcon = hIcon = LoadIcon(hInst, AppName);
2763         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
2764         wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
2765         wc.lpszMenuName = AppName;
2766         wc.lpszClassName = AppName;
2767
2768         if (!RegisterClass(&wc))
2769             exit(1);
2770
2771         wc.lpfnWndProc = AngbandListProc;
2772         wc.lpszMenuName = NULL;
2773         wc.lpszClassName = AngList;
2774
2775         if (!RegisterClass(&wc))
2776             exit(2);
2777     }
2778
2779     plog_aux = hack_plog;
2780     quit_aux = hack_quit;
2781     core_aux = hack_quit;
2782
2783     init_stuff();
2784     for (int i = 0; special_key_list[i]; ++i) {
2785         special_key[special_key_list[i]] = TRUE;
2786     }
2787
2788     for (int i = 0; ignore_key_list[i]; ++i) {
2789         ignore_key[ignore_key_list[i]] = TRUE;
2790     }
2791
2792     HDC hdc = GetDC(NULL);
2793     if (GetDeviceCaps(hdc, BITSPIXEL) <= 8) {
2794         quit(_("画面を16ビット以上のカラーモードにして下さい。", "Please switch to High Color (16-bit) or higher color mode."));
2795     }
2796     ReleaseDC(NULL, hdc);
2797
2798     refresh_color_table();
2799     init_windows();
2800     change_bg_mode(current_bg_mode, true);
2801
2802     plog_aux = hook_plog;
2803     quit_aux = hook_quit;
2804     core_aux = hook_quit;
2805
2806     ANGBAND_SYS = "win";
2807     if (7 != GetKeyboardType(0))
2808         ANGBAND_KEYBOARD = "0";
2809     else {
2810         switch (GetKeyboardType(1)) {
2811         case 0x0D01:
2812         case 0x0D02:
2813         case 0x0D03:
2814         case 0x0D04:
2815         case 0x0D05:
2816         case 0x0D06:
2817             /* NEC PC-98x1 */
2818             ANGBAND_KEYBOARD = "NEC98";
2819             break;
2820         default:
2821             /* PC/AT */
2822             ANGBAND_KEYBOARD = "JAPAN";
2823         }
2824     }
2825
2826     signals_init();
2827     term_activate(term_screen);
2828     init_angband(p_ptr, FALSE);
2829     initialized = TRUE;
2830     check_for_save_file(p_ptr, lpCmdLine);
2831     prt(_("[ファイル] メニューの [新規] または [開く] を選択してください。", "[Choose 'New' or 'Open' from the 'File' menu]"), 23, _(8, 17));
2832     term_fresh();
2833
2834     use_music = arg_music;
2835     if (use_music) {
2836         init_music();
2837     }
2838
2839     MSG msg;
2840     while (GetMessage(&msg, NULL, 0, 0)) {
2841         TranslateMessage(&msg);
2842         DispatchMessage(&msg);
2843     }
2844
2845     quit(NULL);
2846     return 0;
2847 }
2848 #endif /* WINDOWS */