OSDN Git Service

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