OSDN Git Service

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