OSDN Git Service

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