OSDN Git Service

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