OSDN Git Service

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