OSDN Git Service

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