OSDN Git Service

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