OSDN Git Service

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