1 /* File: main-win.c */
2 
3 /*
4  * Copyright (c) 1997 Ben Harrison, Skirmantas Kligys, Robert Ruehlmann,
5  * and others
6  *
7  * This software may be copied and distributed for educational, research,
8  * and not for profit purposes provided that this copyright and statement
9  * are included in all such copies.
10  */
11 
12 
13 /*
14  * This file helps Angband work with Windows computers.
15  *
16  * To use this file, use an appropriate "Makefile" or "Project File",
17  * make sure that "WINDOWS" and/or "WIN32" are defined somewhere, and
18  * make sure to obtain various extra files as described below.
19  *
20  * The Windows version has been tested to compile with Visual C++ 5.0
21  * and 6.0, Cygwin 1.0, Borland C++ 5.5 command line tools, and lcc-win32.
22  *
23  *
24  * See also "main-dos.c" and "main-ibm.c".
25  *
26  *
27  * The "lib/pref/pref-win.prf" file contains keymaps, macro definitions,
28  * and/or color redefinitions.
29  *
30  * The "lib/pref/font-win.prf" contains attr/char mappings for use with the
31  * normal "*.fon" font files in the "lib/xtra/font/" directory.
32  *
33  * The "lib/pref/graf-win.prf" contains attr/char mappings for use with the
34  * special "*.bmp" bitmap files in the "lib/xtra/graf/" directory, which
35  * are activated by a menu item.
36  *
37  *
38  * Compiling this file, and using the resulting executable, requires
39  * several extra files not distributed with the standard Angband code.
40  * If "USE_GRAPHICS" is defined, then "readdib.h" and "readdib.c" must
41  * be placed into "src/", and the "8x8.bmp" bitmap file must be placed
42  * into "lib/xtra/graf".  In any case, some "*.fon" files (including
43  * "8X13.FON" if nothing else) must be placed into "lib/xtra/font/".
44  * If "USE_SOUND" is defined, then some special library (for example,
45  * "winmm.lib") may need to be linked in, and desired "*.WAV" sound
46  * files must be placed into "lib/xtra/sound/".  All of these extra
47  * files can be found in the "ext-win" archive.
48  *
49  *
50  * The "Term_xtra_win_clear()" function should probably do a low-level
51  * clear of the current window, and redraw the borders and other things,
52  * if only for efficiency.  XXX XXX XXX
53  *
54  * A simpler method is needed for selecting the "tile size" for windows.
55  * XXX XXX XXX
56  *
57  * Special "Windows Help Files" can be placed into "lib/xtra/help/" for
58  * use with the "winhelp.exe" program.  These files *may* be available
59  * at the ftp site somewhere, but I have not seen them.  XXX XXX XXX
60  *
61  * ToDo: The screensaver mode should implement ScreenSaverConfigureDialog,
62  * DefScreenSaverProc, and ScreenSaverProc.
63  *
64  * Initial framework (and most code) by Ben Harrison (benh@phial.com).
65  *
66  * Original code by Skirmantas Kligys (kligys@scf.usc.edu).
67  *
68  * Additional code by Ross E Becker (beckerr@cis.ohio-state.edu),
69  * and Chris R. Martin (crm7479@tam2000.tamu.edu).
70  *
71  * Additional code by Robert Ruehlmann <rr9@angband.org>.
72  */
73 
74 #include "angband.h"
75 
76 #include "maid-grf.h"
77 
78 
79 #ifdef WINDOWS
80 
81 
82 /*
83  * Use HTML-Help.
84  */
85 /* #define HTML_HELP */
86 
87 #ifdef HTML_HELP
88 # define HELP_GENERAL "angband.chm"
89 # define HELP_SPOILERS "angband.chm"
90 #else /* HTML_HELP */
91 # define HELP_GENERAL "angband.hlp"
92 # define HELP_SPOILERS "spoilers.hlp"
93 #endif /* HTML_HELP */
94 
95 
96 /*
97  * Extract the "WIN32" flag from the compiler
98  */
99 #if defined(__WIN32__) || defined(__WINNT__) || defined(__NT__)
100 # ifndef WIN32
101 #  define WIN32
102 # endif
103 #endif
104 
105 
106 #ifdef ALLOW_BORG
107 
108 /*
109  * Hack -- allow use of "screen saver" mode
110  */
111 /* #define USE_SAVER */
112 
113 #endif /* ALLOW_BORG */
114 
115 
116 /*
117  * Menu constants -- see "ANGBAND.RC"
118  */
119 
120 #define IDM_FILE_NEW			100
121 #define IDM_FILE_OPEN			101
122 #define IDM_FILE_SAVE			110
123 #define IDM_FILE_SCORE			120
124 #define IDM_FILE_EXIT			130
125 
126 #define IDM_WINDOW_VIS_0		200
127 #define IDM_WINDOW_VIS_1		201
128 #define IDM_WINDOW_VIS_2		202
129 #define IDM_WINDOW_VIS_3		203
130 #define IDM_WINDOW_VIS_4		204
131 #define IDM_WINDOW_VIS_5		205
132 #define IDM_WINDOW_VIS_6		206
133 #define IDM_WINDOW_VIS_7		207
134 
135 #define IDM_WINDOW_FONT_0		210
136 #define IDM_WINDOW_FONT_1		211
137 #define IDM_WINDOW_FONT_2		212
138 #define IDM_WINDOW_FONT_3		213
139 #define IDM_WINDOW_FONT_4		214
140 #define IDM_WINDOW_FONT_5		215
141 #define IDM_WINDOW_FONT_6		216
142 #define IDM_WINDOW_FONT_7		217
143 
144 #define IDM_WINDOW_I_WID_0		240
145 #define IDM_WINDOW_I_WID_1		241
146 #define IDM_WINDOW_I_WID_2		242
147 #define IDM_WINDOW_I_WID_3		243
148 #define IDM_WINDOW_I_WID_4		244
149 #define IDM_WINDOW_I_WID_5		245
150 #define IDM_WINDOW_I_WID_6		246
151 #define IDM_WINDOW_I_WID_7		247
152 
153 #define IDM_WINDOW_D_WID_0		250
154 #define IDM_WINDOW_D_WID_1		251
155 #define IDM_WINDOW_D_WID_2		252
156 #define IDM_WINDOW_D_WID_3		253
157 #define IDM_WINDOW_D_WID_4		254
158 #define IDM_WINDOW_D_WID_5		255
159 #define IDM_WINDOW_D_WID_6		256
160 #define IDM_WINDOW_D_WID_7		257
161 
162 #define IDM_WINDOW_I_HGT_0		260
163 #define IDM_WINDOW_I_HGT_1		261
164 #define IDM_WINDOW_I_HGT_2		262
165 #define IDM_WINDOW_I_HGT_3		263
166 #define IDM_WINDOW_I_HGT_4		264
167 #define IDM_WINDOW_I_HGT_5		265
168 #define IDM_WINDOW_I_HGT_6		266
169 #define IDM_WINDOW_I_HGT_7		267
170 
171 #define IDM_WINDOW_D_HGT_0		270
172 #define IDM_WINDOW_D_HGT_1		271
173 #define IDM_WINDOW_D_HGT_2		272
174 #define IDM_WINDOW_D_HGT_3		273
175 #define IDM_WINDOW_D_HGT_4		274
176 #define IDM_WINDOW_D_HGT_5		275
177 #define IDM_WINDOW_D_HGT_6		276
178 #define IDM_WINDOW_D_HGT_7		277
179 
180 #define IDM_OPTIONS_GRAPHICS_NONE   400
181 #define IDM_OPTIONS_GRAPHICS_OLD    401
182 #define IDM_OPTIONS_GRAPHICS_ADAM   402
183 #define IDM_OPTIONS_GRAPHICS_DAVID  403
184 #define IDM_OPTIONS_BIGTILE         409
185 #define IDM_OPTIONS_SOUND           410
186 #define IDM_OPTIONS_LOW_PRIORITY    420
187 #define IDM_OPTIONS_SAVER           430
188 #define IDM_OPTIONS_MAP             440
189 
190 #define IDM_HELP_GENERAL		901
191 #define IDM_HELP_SPOILERS		902
192 
193 
194 /*
195  * This may need to be removed for some compilers XXX XXX XXX
196  */
197 #define STRICT
198 
199 /*
200  * Exclude parts of WINDOWS.H that are not needed
201  */
202 #define NOCOMM            /* Comm driver APIs and definitions */
203 #define NOLOGERROR        /* LogError() and related definitions */
204 #define NOPROFILER        /* Profiler APIs */
205 #define NOLFILEIO         /* _l* file I/O routines */
206 #define NOOPENFILE        /* OpenFile and related definitions */
207 #define NORESOURCE        /* Resource management */
208 #define NOATOM            /* Atom management */
209 #define NOLANGUAGE        /* Character test routines */
210 #define NOLSTRING         /* lstr* string management routines */
211 #define NODBCS            /* Double-byte character set routines */
212 #define NOKEYBOARDINFO    /* Keyboard driver routines */
213 #define NOCOLOR           /* COLOR_* color values */
214 #define NODRAWTEXT        /* DrawText() and related definitions */
215 #define NOSCALABLEFONT    /* Truetype scalable font support */
216 #define NOMETAFILE        /* Metafile support */
217 #define NOSYSTEMPARAMSINFO /* SystemParametersInfo() and SPI_* definitions */
218 #define NODEFERWINDOWPOS  /* DeferWindowPos and related definitions */
219 #define NOKEYSTATES       /* MK_* message key state flags */
220 #define NOWH              /* SetWindowsHook and related WH_* definitions */
221 #define NOCLIPBOARD       /* Clipboard APIs and definitions */
222 #define NOICONS           /* IDI_* icon IDs */
223 #define NOMDI             /* MDI support */
224 #define NOHELP            /* Help support */
225 
226 /* Not defined since it breaks Borland C++ 5.5 */
227 /* #define NOCTLMGR */    /* Control management and controls */
228 
229 /*
230  * Exclude parts of WINDOWS.H that are not needed (Win32)
231  */
232 #define WIN32_LEAN_AND_MEAN
233 #define NONLS             /* All NLS defines and routines */
234 #define NOSERVICE         /* All Service Controller routines, SERVICE_ equates, etc. */
235 #define NOKANJI           /* Kanji support stuff. */
236 #define NOMCX             /* Modem Configuration Extensions */
237 
238 
239 /* Mega-hack, these include files require double and float to work */
240 #undef float
241 #undef double
242 
243 /*
244  * Include the "windows" support file
245  */
246 #include <windows.h>
247 
248 #ifdef USE_SOUND
249 
250 /*
251  * Exclude parts of MMSYSTEM.H that are not needed
252  */
253 #define MMNODRV          /* Installable driver support */
254 #define MMNOWAVE         /* Waveform support */
255 #define MMNOMIDI         /* MIDI support */
256 #define MMNOAUX          /* Auxiliary audio support */
257 #define MMNOTIMER        /* Timer support */
258 #define MMNOJOY          /* Joystick support */
259 #define MMNOMCI          /* MCI support */
260 #define MMNOMMIO         /* Multimedia file I/O support */
261 #define MMNOMMSYSTEM     /* General MMSYSTEM functions */
262 
263 #include <mmsystem.h>
264 
265 #endif /* USE_SOUND */
266 
267 #include <commdlg.h>
268 
269 /*
270  * HTML-Help requires htmlhelp.h and htmlhelp.lib from Microsoft's
271  * HTML Workshop < msdn.microsoft.com/workshop/author/htmlhelp/ >.
272  */
273 #ifdef HTML_HELP
274 #include <htmlhelp.h>
275 #endif /* HTML_HELP */
276 
277 /*
278  * Include the support for loading bitmaps
279  */
280 #ifdef USE_GRAPHICS
281 # include "readdib.h"
282 #endif /* USE_GRAPHICS */
283 
284 /*
285  * Hack -- Fake declarations from "dos.h" XXX XXX XXX
286  */
287 #ifdef WIN32
288 #define INVALID_FILE_NAME (DWORD)0xFFFFFFFF
289 #else /* WIN32 */
290 #define FA_LABEL    0x08        /* Volume label */
291 #define FA_DIREC    0x10        /* Directory */
292 unsigned _cdecl _dos_getfileattr(const char *, unsigned *);
293 #endif /* WIN32 */
294 
295 /* Mega-hack redefine them again */
296 #undef float
297 #define float floating_point_is_not_allowed
298 #undef double
299 #define double floating_point_is_not_allowed
300 
301 /*
302  * Silliness in WIN32 drawing routine
303  */
304 #ifdef WIN32
305 # define MoveTo(H,X,Y) MoveToEx(H, X, Y, NULL)
306 #endif /* WIN32 */
307 
308 /*
309  * Silliness for Windows 95
310  */
311 #ifndef WS_EX_TOOLWINDOW
312 # define WS_EX_TOOLWINDOW 0
313 #endif /* WS_EX_TOOLWINDOW */
314 
315 /*
316  * Foreground color bits (hard-coded by DOS)
317  */
318 #define VID_BLACK	0x00
319 #define VID_BLUE	0x01
320 #define VID_GREEN	0x02
321 #define VID_CYAN	0x03
322 #define VID_RED		0x04
323 #define VID_MAGENTA	0x05
324 #define VID_YELLOW	0x06
325 #define VID_WHITE	0x07
326 
327 /*
328  * Bright text (hard-coded by DOS)
329  */
330 #define VID_BRIGHT	0x08
331 
332 /*
333  * Background color bits (hard-coded by DOS)
334  */
335 #define VUD_BLACK	0x00
336 #define VUD_BLUE	0x10
337 #define VUD_GREEN	0x20
338 #define VUD_CYAN	0x30
339 #define VUD_RED		0x40
340 #define VUD_MAGENTA	0x50
341 #define VUD_YELLOW	0x60
342 #define VUD_WHITE	0x70
343 
344 /*
345  * Blinking text (hard-coded by DOS)
346  */
347 #define VUD_BRIGHT	0x80
348 
349 
350 /*
351  * Forward declare
352  */
353 typedef struct _term_data term_data;
354 
355 /*
356  * Extra "term" data
357  *
358  * Note the use of "font_want" for the names of the font file requested by
359  * the user, and the use of "font_file" for the currently active font file.
360  *
361  * The "font_file" is uppercased, and takes the form "8X13.FON", while
362  * "font_want" can be in almost any form as long as it could be construed
363  * as attempting to represent the name of a font.
364  */
365 struct _term_data
366 {
367 	term t;
368 
369 	cptr s;
370 
371 	HWND w;
372 
373 	DWORD dwStyle;
374 	DWORD dwExStyle;
375 
376 	uint keys;
377 
378 	byte rows;
379 	byte cols;
380 
381 	uint pos_x;
382 	uint pos_y;
383 	uint size_wid;
384 	uint size_hgt;
385 	uint size_ow1;
386 	uint size_oh1;
387 	uint size_ow2;
388 	uint size_oh2;
389 
390 	bool size_hack;
391 
392 	bool xtra_hack;
393 
394 	bool visible;
395 	bool maximized;
396 
397 	cptr font_want;
398 
399 	cptr font_file;
400 
401 	HFONT font_id;
402 
403 	uint font_wid;
404 	uint font_hgt;
405 
406 	uint tile_wid;
407 	uint tile_hgt;
408 
409 	uint map_tile_wid;
410 	uint map_tile_hgt;
411 
412 	bool map_active;
413 };
414 
415 
416 /*
417  * Maximum number of windows XXX XXX XXX
418  */
419 #define MAX_TERM_DATA 8
420 
421 
422 /*
423  * An array of term_data's
424  */
425 static term_data data[MAX_TERM_DATA];
426 
427 /*
428  * Hack -- global "window creation" pointer
429  */
430 static term_data *my_td;
431 
432 /*
433  * game in progress
434  */
435 bool game_in_progress = FALSE;
436 
437 /*
438  * note when "open"/"new" become valid
439  */
440 bool initialized = FALSE;
441 
442 /*
443  * screen paletted, i.e. 256 colors
444  */
445 bool paletted = FALSE;
446 
447 /*
448  * 16 colors screen, don't use RGB()
449  */
450 bool colors16 = FALSE;
451 
452 static bool low_priority = FALSE;
453 
454 /*
455  * Saved instance handle
456  */
457 static HINSTANCE hInstance;
458 
459 /*
460  * Yellow brush for the cursor
461  */
462 static HBRUSH hbrYellow;
463 
464 /*
465  * An icon
466  */
467 static HICON hIcon;
468 
469 /*
470  * A palette
471  */
472 static HPALETTE hPal;
473 
474 
475 #ifdef USE_SAVER
476 
477 /*
478  * The screen saver window
479  */
480 static HWND hwndSaver;
481 
482 static bool screensaver = FALSE;
483 static bool screensaver_active = FALSE;
484 
485 static HANDLE screensaverSemaphore;
486 
487 static char saverfilename[1024];
488 
489 static HMENU main_menu;
490 
491 #define MOUSE_SENS 10
492 
493 #endif /* USE_SAVER */
494 
495 
496 #ifdef USE_GRAPHICS
497 
498 /*
499  * Flag set once "graphics" has been initialized
500  */
501 static bool can_use_graphics = FALSE;
502 
503 /*
504  * The global bitmap
505  */
506 static DIBINIT infGraph;
507 
508 /*
509  * The global bitmap mask
510  */
511 static DIBINIT infMask;
512 
513 #endif /* USE_GRAPHICS */
514 
515 
516 #ifdef USE_SOUND
517 
518 /*
519  * Flag set once "sound" has been initialized
520  */
521 static bool can_use_sound = FALSE;
522 
523 #define SAMPLE_MAX 8
524 
525 /*
526  * An array of sound file names
527  */
528 static cptr sound_file[SOUND_MAX][SAMPLE_MAX];
529 
530 #endif /* USE_SOUND */
531 
532 
533 /*
534  * Full path to ANGBAND.INI
535  */
536 static cptr ini_file = NULL;
537 
538 /*
539  * Name of application
540  */
541 static cptr AppName = VERSION_NAME;
542 
543 /*
544  * Name of sub-window type
545  */
546 static cptr AngList = "AngList";
547 
548 /*
549  * Directory names
550  */
551 static cptr ANGBAND_DIR_XTRA_FONT;
552 static cptr ANGBAND_DIR_XTRA_GRAF;
553 static cptr ANGBAND_DIR_XTRA_SOUND;
554 static cptr ANGBAND_DIR_XTRA_HELP;
555 #if USE_MUSIC
556 static cptr ANGBAND_DIR_XTRA_MUSIC;
557 #endif /* USE_MUSIC */
558 
559 /*
560  * The "complex" color values
561  */
562 static COLORREF win_clr[256];
563 
564 
565 /*
566  * The "simple" color values
567  *
568  * See "main-ibm.c" for original table information
569  *
570  * The entries below are taken from the "color bits" defined above.
571  *
572  * Note that many of the choices below suck, but so do crappy monitors.
573  */
574 static byte win_pal[256] =
575 {
576 	VID_BLACK,					/* Dark */
577 	VID_WHITE,					/* White */
578 	VID_CYAN,					/* Slate XXX */
579 	VID_RED | VID_BRIGHT,		/* Orange XXX */
580 	VID_RED,					/* Red */
581 	VID_GREEN,					/* Green */
582 	VID_BLUE,					/* Blue */
583 	VID_YELLOW,					/* Umber XXX */
584 	VID_BLACK | VID_BRIGHT,		/* Light Dark */
585 	VID_CYAN | VID_BRIGHT,		/* Light Slate XXX */
586 	VID_MAGENTA,				/* Violet XXX */
587 	VID_YELLOW | VID_BRIGHT,	/* Yellow */
588 	VID_MAGENTA | VID_BRIGHT,	/* Light Red XXX */
589 	VID_GREEN | VID_BRIGHT,		/* Light Green */
590 	VID_BLUE | VID_BRIGHT,		/* Light Blue */
591 	VID_YELLOW					/* Light Umber XXX */
592 };
593 
594 
595 #ifdef SUPPORT_GAMMA
596 static int gamma_correction;
597 #endif /* SUPPORT_GAMMA */
598 
599 
600 /*
601  * Hack -- define which keys are "special"
602  */
603 static bool special_key[256];
604 
605 /*
606  * Hack -- initialization list for "special_key"
607  *
608  * We ignore the modifier keys (shift, control, alt, num lock, scroll lock),
609  * and the normal keys (escape, tab, return, letters, numbers, etc), but we
610  * catch the keypad keys (with and without numlock set, including keypad 5),
611  * the function keys (including the "menu" key which maps to F10), and the
612  * "pause" key (between scroll lock and numlock).  We also catch a few odd
613  * keys which I do not recognize, but which are listed among keys which we
614  * do catch, so they should be harmless to catch.
615  */
616 static const byte special_key_list[] =
617 {
618 	VK_CLEAR,		/* 0x0C (KP<5>) */
619 
620 	VK_PAUSE,		/* 0x13 (pause) */
621 
622 	VK_PRIOR,		/* 0x21 (KP<9>) */
623 	VK_NEXT,		/* 0x22 (KP<3>) */
624 	VK_END,			/* 0x23 (KP<1>) */
625 	VK_HOME,		/* 0x24 (KP<7>) */
626 	VK_LEFT,		/* 0x25 (KP<4>) */
627 	VK_UP,			/* 0x26 (KP<8>) */
628 	VK_RIGHT,		/* 0x27 (KP<6>) */
629 	VK_DOWN,		/* 0x28 (KP<2>) */
630 	VK_SELECT,		/* 0x29 (?) */
631 	VK_PRINT,		/* 0x2A (?) */
632 	VK_EXECUTE,		/* 0x2B (?) */
633 	VK_SNAPSHOT,	/* 0x2C (?) */
634 	VK_INSERT,		/* 0x2D (KP<0>) */
635 	VK_DELETE,		/* 0x2E (KP<.>) */
636 	VK_HELP,		/* 0x2F (?) */
637 
638 #if 0
639 	VK_NUMPAD0,		/* 0x60 (KP<0>) */
640 	VK_NUMPAD1,		/* 0x61 (KP<1>) */
641 	VK_NUMPAD2,		/* 0x62 (KP<2>) */
642 	VK_NUMPAD3,		/* 0x63 (KP<3>) */
643 	VK_NUMPAD4,		/* 0x64 (KP<4>) */
644 	VK_NUMPAD5,		/* 0x65 (KP<5>) */
645 	VK_NUMPAD6,		/* 0x66 (KP<6>) */
646 	VK_NUMPAD7,		/* 0x67 (KP<7>) */
647 	VK_NUMPAD8,		/* 0x68 (KP<8>) */
648 	VK_NUMPAD9,		/* 0x69 (KP<9>) */
649 	VK_MULTIPLY,	/* 0x6A (KP<*>) */
650 	VK_ADD,			/* 0x6B (KP<+>) */
651 	VK_SEPARATOR,	/* 0x6C (?????) */
652 	VK_SUBTRACT,	/* 0x6D (KP<->) */
653 	VK_DECIMAL,		/* 0x6E (KP<.>) */
654 	VK_DIVIDE,		/* 0x6F (KP</>) */
655 #endif /* 0 */
656 
657 	VK_F1,			/* 0x70 */
658 	VK_F2,			/* 0x71 */
659 	VK_F3,			/* 0x72 */
660 	VK_F4,			/* 0x73 */
661 	VK_F5,			/* 0x74 */
662 	VK_F6,			/* 0x75 */
663 	VK_F7,			/* 0x76 */
664 	VK_F8,			/* 0x77 */
665 	VK_F9,			/* 0x78 */
666 	VK_F10,			/* 0x79 */
667 	VK_F11,			/* 0x7A */
668 	VK_F12,			/* 0x7B */
669 	VK_F13,			/* 0x7C */
670 	VK_F14,			/* 0x7D */
671 	VK_F15,			/* 0x7E */
672 	VK_F16,			/* 0x7F */
673 	VK_F17,			/* 0x80 */
674 	VK_F18,			/* 0x81 */
675 	VK_F19,			/* 0x82 */
676 	VK_F20,			/* 0x83 */
677 	VK_F21,			/* 0x84 */
678 	VK_F22,			/* 0x85 */
679 	VK_F23,			/* 0x86 */
680 	VK_F24,			/* 0x87 */
681 
682 	0
683 };
684 
685 #if 0
686 /*
687  * Hack -- given a pathname, point at the filename
688  */
689 static cptr extract_file_name(cptr s)
690 {
691 	cptr p;
692 
693 	/* Start at the end */
694 	p = s + strlen(s) - 1;
695 
696 	/* Back up to divider */
697 	while ((p >= s) && (*p != ':') && (*p != '\\')) p--;
698 
699 	/* Return file name */
700 	return (p+1);
701 }
702 #endif /* 0 */
703 
704 
show_win_error(void)705 static void show_win_error(void)
706 {
707 	LPVOID lpMsgBuf;
708 
709 	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
710 	              NULL, GetLastError(),
711 	              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
712 	              (LPTSTR) &lpMsgBuf, 0, NULL);
713 
714 	MessageBox(NULL, lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION);
715 
716 	LocalFree(lpMsgBuf);
717 }
718 
719 
720 /*
721  * Hack -- given a simple filename, extract the "font size" info
722  *
723  * Return a pointer to a static buffer holding the capitalized base name.
724  */
analyze_font(char * path,int * wp,int * hp)725 static char *analyze_font(char *path, int *wp, int *hp)
726 {
727 	int wid, hgt;
728 
729 	char *s, *p;
730 
731 	/* Start at the end */
732 	p = path + strlen(path) - 1;
733 
734 	/* Back up to divider */
735 	while ((p >= path) && (*p != ':') && (*p != '\\')) --p;
736 
737 	/* Advance to file name */
738 	++p;
739 
740 	/* Capitalize */
741 	for (s = p; *s; ++s)
742 	{
743 		/* Capitalize (be paranoid) */
744 		if (islower((unsigned char)*s)) *s = toupper((unsigned char)*s);
745 	}
746 
747 	/* Find first 'X' */
748 	s = strchr(p, 'X');
749 
750 	/* Extract font width */
751 	wid = atoi(p);
752 
753 	/* Extract height */
754 	hgt = s ? atoi(s+1) : 0;
755 
756 	/* Save results */
757 	(*wp) = wid;
758 	(*hp) = hgt;
759 
760 	/* Result */
761 	return (p);
762 }
763 
764 
765 /*
766  * Check for existance of a file
767  */
check_file(cptr s)768 static bool check_file(cptr s)
769 {
770 	char path[1024];
771 
772 #ifdef WIN32
773 
774 	DWORD attrib;
775 
776 #else /* WIN32 */
777 
778 	unsigned int attrib;
779 
780 #endif /* WIN32 */
781 
782 	/* Copy it */
783 	strnfmt(path, 1024, "%s", s);
784 
785 #ifdef WIN32
786 
787 	/* Examine */
788 	attrib = GetFileAttributes(path);
789 
790 	/* Require valid filename */
791 	if (attrib == INVALID_FILE_NAME) return (FALSE);
792 
793 	/* Prohibit directory */
794 	if (attrib & FILE_ATTRIBUTE_DIRECTORY) return (FALSE);
795 
796 #else /* WIN32 */
797 
798 	/* Examine and verify */
799 	if (_dos_getfileattr(path, &attrib)) return (FALSE);
800 
801 	/* Prohibit something */
802 	if (attrib & FA_LABEL) return (FALSE);
803 
804 	/* Prohibit directory */
805 	if (attrib & FA_DIREC) return (FALSE);
806 
807 #endif /* WIN32 */
808 
809 	/* Success */
810 	return (TRUE);
811 }
812 
813 
814 /*
815  * Check for existance of a directory
816  */
check_dir(cptr s)817 static bool check_dir(cptr s)
818 {
819 	int i;
820 
821 	char path[1024];
822 
823 #ifdef WIN32
824 
825 	DWORD attrib;
826 
827 #else /* WIN32 */
828 
829 	unsigned int attrib;
830 
831 #endif /* WIN32 */
832 
833 	/* Copy it */
834 	strcpy(path, s);
835 
836 	/* Check length */
837 	i = strlen(path);
838 
839 	/* Remove trailing backslash */
840 	if (i && (path[i-1] == '\\')) path[--i] = '\0';
841 
842 #ifdef WIN32
843 
844 	/* Examine */
845 	attrib = GetFileAttributes(path);
846 
847 	/* Require valid filename */
848 	if (attrib == INVALID_FILE_NAME) return (FALSE);
849 
850 	/* Require directory */
851 	if (!(attrib & FILE_ATTRIBUTE_DIRECTORY)) return (FALSE);
852 
853 #else /* WIN32 */
854 
855 	/* Examine and verify */
856 	if (_dos_getfileattr(path, &attrib)) return (FALSE);
857 
858 	/* Prohibit something */
859 	if (attrib & FA_LABEL) return (FALSE);
860 
861 	/* Require directory */
862 	if (!(attrib & FA_DIREC)) return (FALSE);
863 
864 #endif /* WIN32 */
865 
866 	/* Success */
867 	return (TRUE);
868 }
869 
870 
871 /*
872  * Validate a file
873  */
validate_file(cptr s)874 static void validate_file(cptr s)
875 {
876 	/* Verify or fail */
877 	if (!check_file(s))
878 	{
879 		quit_fmt("Cannot find required file:\n%s", s);
880 	}
881 }
882 
883 
884 /*
885  * Validate a directory
886  */
validate_dir(cptr s)887 static void validate_dir(cptr s)
888 {
889 	/* Verify or fail */
890 	if (!check_dir(s))
891 	{
892 		quit_fmt("Cannot find required directory:\n%s", s);
893 	}
894 }
895 
896 
897 /*
898  * Get the "size" for a window
899  */
term_getsize(term_data * td)900 static void term_getsize(term_data *td)
901 {
902 	RECT rc;
903 
904 	int wid, hgt;
905 
906 	/* Paranoia */
907 	if (td->cols < 1) td->cols = 1;
908 	if (td->rows < 1) td->rows = 1;
909 
910 	/* Window sizes */
911 	wid = td->cols * td->tile_wid + td->size_ow1 + td->size_ow2;
912 	hgt = td->rows * td->tile_hgt + td->size_oh1 + td->size_oh2;
913 
914 	/* Fake window size */
915 	rc.left = 0;
916 	rc.right = rc.left + wid;
917 	rc.top = 0;
918 	rc.bottom = rc.top + hgt;
919 
920 	/* XXX XXX XXX */
921 	/* rc.right += 1; */
922 	/* rc.bottom += 1; */
923 
924 	/* Adjust */
925 	AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
926 
927 	/* Total size */
928 	td->size_wid = rc.right - rc.left;
929 	td->size_hgt = rc.bottom - rc.top;
930 
931 	/* See CreateWindowEx */
932 	if (!td->w) return;
933 
934 	/* Extract actual location */
935 	GetWindowRect(td->w, &rc);
936 
937 	/* Save the location */
938 	td->pos_x = rc.left;
939 	td->pos_y = rc.top;
940 }
941 
942 
943 /*
944  * Write the "prefs" for a single term
945  */
save_prefs_aux(term_data * td,cptr sec_name)946 static void save_prefs_aux(term_data *td, cptr sec_name)
947 {
948 	char buf[1024];
949 
950 	RECT rc;
951 
952 	WINDOWPLACEMENT lpwndpl;
953 
954 	/* Paranoia */
955 	if (!td->w) return;
956 
957 	/* Visible */
958 	strcpy(buf, td->visible ? "1" : "0");
959 	WritePrivateProfileString(sec_name, "Visible", buf, ini_file);
960 
961 	/* Font */
962 	strcpy(buf, td->font_file ? td->font_file : "8X13.FON");
963 	WritePrivateProfileString(sec_name, "Font", buf, ini_file);
964 
965 	/* Tile size (x) */
966 	wsprintf(buf, "%d", td->tile_wid);
967 	WritePrivateProfileString(sec_name, "TileWid", buf, ini_file);
968 
969 	/* Tile size (y) */
970 	wsprintf(buf, "%d", td->tile_hgt);
971 	WritePrivateProfileString(sec_name, "TileHgt", buf, ini_file);
972 
973 	/* Window size (x) */
974 	wsprintf(buf, "%d", td->cols);
975 	WritePrivateProfileString(sec_name, "NumCols", buf, ini_file);
976 
977 	/* Window size (y) */
978 	wsprintf(buf, "%d", td->rows);
979 	WritePrivateProfileString(sec_name, "NumRows", buf, ini_file);
980 
981 	/* Get window placement and dimensions */
982 	lpwndpl.length = sizeof(WINDOWPLACEMENT);
983 	GetWindowPlacement(td->w, &lpwndpl);
984 
985 	/* Acquire position in *normal* mode (not minimized) */
986 	rc = lpwndpl.rcNormalPosition;
987 
988 	/* Get information about the placement of the window */
989 	if (lpwndpl.flags & SW_SHOWMAXIMIZED)
990 		td->maximized = TRUE;
991 	else
992 		td->maximized = FALSE;
993 
994 	/* Window position (x) */
995 	wsprintf(buf, "%d", rc.left);
996 	WritePrivateProfileString(sec_name, "PositionX", buf, ini_file);
997 
998 	/* Window position (y) */
999 	wsprintf(buf, "%d", rc.top);
1000 	WritePrivateProfileString(sec_name, "PositionY", buf, ini_file);
1001 
1002 	/* Maximized */
1003 	strcpy(buf, td->maximized ? "1" : "0");
1004 	WritePrivateProfileString(sec_name, "Maximized", buf, ini_file);
1005 }
1006 
1007 
1008 /*
1009  * Write the "prefs"
1010  *
1011  * We assume that the windows have all been initialized
1012  */
save_prefs(void)1013 static void save_prefs(void)
1014 {
1015 	int i;
1016 
1017 	char buf[128];
1018 
1019 	/* Save the "arg_graphics" flag */
1020 	strnfmt(buf, 128, "%d", arg_graphics);
1021 	WritePrivateProfileString("Angband", "Graphics", buf, ini_file);
1022 
1023 	/* Save the "use_bigtile" flag */
1024 	strnfmt(buf, 128, "%d", use_bigtile ? 1 : 0);
1025 	WritePrivateProfileString("Angband", "Bigtile", buf, ini_file);
1026 
1027 	/* Save the "arg_sound" flag */
1028 	strnfmt(buf, 128, "%d", arg_sound ? 1 : 0);
1029 	WritePrivateProfileString("Angband", "Sound", buf, ini_file);
1030 
1031 	/* Save window prefs */
1032 	for (i = 0; i < MAX_TERM_DATA; i++)
1033 	{
1034 		term_data *td = &data[i];
1035 
1036 		strnfmt(buf, 128, "Term-%d", i);
1037 
1038 		save_prefs_aux(td, buf);
1039 	}
1040 }
1041 
1042 
1043 /*
1044  * Load the "prefs" for a single term
1045  */
load_prefs_aux(term_data * td,cptr sec_name)1046 static void load_prefs_aux(term_data *td, cptr sec_name)
1047 {
1048 	char tmp[1024];
1049 
1050 	int wid, hgt;
1051 
1052 	/* Visible */
1053 	td->visible = (GetPrivateProfileInt(sec_name, "Visible", td->visible, ini_file) != 0);
1054 
1055 	/* Maximized */
1056 	td->maximized = (GetPrivateProfileInt(sec_name, "Maximized", td->maximized, ini_file) != 0);
1057 
1058 	/* Desired font, with default */
1059 	GetPrivateProfileString(sec_name, "Font", "8X13.FON", tmp, 127, ini_file);
1060 
1061 	/* Analyze font, save desired font name */
1062 	td->font_want = string_make(analyze_font(tmp, &wid, &hgt));
1063 
1064 	/* Tile size */
1065 	td->tile_wid = GetPrivateProfileInt(sec_name, "TileWid", wid, ini_file);
1066 	td->tile_hgt = GetPrivateProfileInt(sec_name, "TileHgt", hgt, ini_file);
1067 
1068 	/* Window size */
1069 	td->cols = GetPrivateProfileInt(sec_name, "NumCols", td->cols, ini_file);
1070 	td->rows = GetPrivateProfileInt(sec_name, "NumRows", td->rows, ini_file);
1071 
1072 	/* Window position */
1073 	td->pos_x = GetPrivateProfileInt(sec_name, "PositionX", td->pos_x, ini_file);
1074 	td->pos_y = GetPrivateProfileInt(sec_name, "PositionY", td->pos_y, ini_file);
1075 }
1076 
1077 
1078 /*
1079  * Load the "prefs"
1080  */
load_prefs(void)1081 static void load_prefs(void)
1082 {
1083 	int i;
1084 
1085 	char buf[1024];
1086 
1087 	/* Extract the "arg_graphics" flag */
1088 	arg_graphics = GetPrivateProfileInt("Angband", "Graphics", GRAPHICS_NONE, ini_file);
1089 
1090 	/* Extract the "use_bigtile" flag */
1091 	use_bigtile = GetPrivateProfileInt("Angband", "Bigtile", FALSE, ini_file);
1092 
1093 	/* Extract the "arg_sound" flag */
1094 	arg_sound = (GetPrivateProfileInt("Angband", "Sound", 0, ini_file) != 0);
1095 
1096 	/* Extract the "arg_fiddle" flag */
1097 	arg_fiddle = (GetPrivateProfileInt("Angband", "Fiddle", 0, ini_file) != 0);
1098 
1099 	/* Extract the "arg_wizard" flag */
1100 	arg_wizard = (GetPrivateProfileInt("Angband", "Wizard", 0, ini_file) != 0);
1101 
1102 	/* Extract the "arg_roguelike" flag */
1103 	arg_force_roguelike = (GetPrivateProfileInt("Angband", "force_roguelike", 0, ini_file) != 0);
1104 
1105 	/* Extract the "arg_original" flag */
1106 	arg_force_original = (GetPrivateProfileInt("Angband", "force_original", 0, ini_file) != 0);
1107 
1108 #ifdef SUPPORT_GAMMA
1109 
1110 	/* Extract the gamma correction */
1111 	gamma_correction = GetPrivateProfileInt("Angband", "Gamma", 0, ini_file);
1112 
1113 #endif /* SUPPORT_GAMMA */
1114 
1115 	/* Load window prefs */
1116 	for (i = 0; i < MAX_TERM_DATA; i++)
1117 	{
1118 		term_data *td = &data[i];
1119 
1120 		strnfmt(buf, 1024, "Term-%d", i);
1121 
1122 		load_prefs_aux(td, buf);
1123 	}
1124 
1125 	/* Paranoia */
1126 	if (data[0].cols < 80) data[0].cols = 80;
1127 	if (data[0].rows < 24) data[0].rows = 24;
1128 }
1129 
1130 
1131 #ifdef USE_SOUND
1132 
1133 /*
1134  * XXX XXX XXX - Taken from files.c.
1135  *
1136  * Extract "tokens" from a buffer
1137  *
1138  * This function uses "whitespace" as delimiters, and treats any amount of
1139  * whitespace as a single delimiter.  We will never return any empty tokens.
1140  * When given an empty buffer, or a buffer containing only "whitespace", we
1141  * will return no tokens.  We will never extract more than "num" tokens.
1142  *
1143  * By running a token through the "text_to_ascii()" function, you can allow
1144  * that token to include (encoded) whitespace, using "\s" to encode spaces.
1145  *
1146  * We save pointers to the tokens in "tokens", and return the number found.
1147  */
tokenize_whitespace(char * buf,s16b num,char ** tokens)1148 static s16b tokenize_whitespace(char *buf, s16b num, char **tokens)
1149 {
1150 	int k = 0;
1151 
1152 	char *s = buf;
1153 
1154 
1155 	/* Process */
1156 	while (k < num)
1157 	{
1158 		char *t;
1159 
1160 		/* Skip leading whitespace */
1161 		for ( ; *s && isspace((unsigned char)*s); ++s) /* loop */;
1162 
1163 		/* All done */
1164 		if (!*s) break;
1165 
1166 		/* Find next whitespace, if any */
1167 		for (t = s; *t && !isspace((unsigned char)*t); ++t) /* loop */;
1168 
1169 		/* Nuke and advance (if necessary) */
1170 		if (*t) *t++ = '\0';
1171 
1172 		/* Save the token */
1173 		tokens[k++] = s;
1174 
1175 		/* Advance */
1176 		s = t;
1177 	}
1178 
1179 	/* Count */
1180 	return (k);
1181 }
1182 
1183 
load_sound_prefs(void)1184 static void load_sound_prefs(void)
1185 {
1186 	int i, j, num;
1187 	char tmp[1024];
1188 	char ini_path[1024];
1189 	char wav_path[1024];
1190 	char *zz[SAMPLE_MAX];
1191 
1192 	/* Access the sound.cfg */
1193 	path_make(ini_path, ANGBAND_DIR_XTRA_SOUND, "sound.cfg");
1194 
1195 	for (i = 0; i < SOUND_MAX; i++)
1196 	{
1197 		/* Ignore empty sound strings */
1198 		if (!angband_sound_name[i][0]) continue;
1199 
1200 		GetPrivateProfileString("Sound", angband_sound_name[i], "", tmp, sizeof(tmp), ini_path);
1201 
1202 		num = tokenize_whitespace(tmp, SAMPLE_MAX, zz);
1203 
1204 		for (j = 0; j < num; j++)
1205 		{
1206 			/* Access the sound */
1207 			path_make(wav_path, ANGBAND_DIR_XTRA_SOUND, zz[j]);
1208 
1209 			/* Save the sound filename, if it exists */
1210 			if (check_file(wav_path))
1211 				sound_file[i][j] = string_make(zz[j]);
1212 		}
1213 	}
1214 }
1215 
1216 #endif /* USE_SOUND */
1217 
1218 
1219 /*
1220  * Create the new global palette based on the bitmap palette
1221  * (if any), and the standard 16 entry palette derived from
1222  * "win_clr[]" which is used for the basic 16 Angband colors.
1223  *
1224  * This function is never called before all windows are ready.
1225  *
1226  * This function returns FALSE if the new palette could not be
1227  * prepared, which should normally be a fatal error.  XXX XXX
1228  *
1229  * Note that only some machines actually use a "palette".
1230  */
new_palette(void)1231 static int new_palette(void)
1232 {
1233 #ifdef USE_GRAPHICS
1234 	HPALETTE hBmPal;
1235 #endif /* USE_GRAPHICS */
1236 	HPALETTE hNewPal;
1237 	HDC hdc;
1238 	int i, nEntries;
1239 	int pLogPalSize;
1240 	LPLOGPALETTE pLogPal;
1241 	LPPALETTEENTRY lppe;
1242 
1243 	term_data *td;
1244 
1245 
1246 	/* This makes no sense */
1247 	if (!paletted) return (TRUE);
1248 
1249 	/* No bitmap */
1250 	lppe = NULL;
1251 	nEntries = 0;
1252 
1253 #ifdef USE_GRAPHICS
1254 
1255 	/* Check the bitmap palette */
1256 	hBmPal = infGraph.hPalette;
1257 
1258 	/* Use the bitmap */
1259 	if (hBmPal)
1260 	{
1261 		lppe = ralloc(256 * sizeof(PALETTEENTRY));
1262 		nEntries = GetPaletteEntries(hBmPal, 0, 255, lppe);
1263 		if ((nEntries == 0) || (nEntries > 220))
1264 		{
1265 			/* Warn the user */
1266 			plog("Please switch to high- or true-color mode.");
1267 
1268 			/* Cleanup */
1269 			free(lppe);
1270 
1271 			/* Fail */
1272 			return (FALSE);
1273 		}
1274 	}
1275 
1276 #endif /* USE_GRAPHICS */
1277 
1278 	/* Size of palette */
1279 	pLogPalSize = sizeof(LOGPALETTE) + (nEntries + 16) * sizeof(PALETTEENTRY);
1280 
1281 	/* Allocate palette */
1282 	pLogPal = (LPLOGPALETTE)ralloc(pLogPalSize);
1283 
1284 	/* Version */
1285 	pLogPal->palVersion = 0x300;
1286 
1287 	/* Make room for bitmap and normal data */
1288 	pLogPal->palNumEntries = nEntries + 16;
1289 
1290 	/* Save the bitmap data */
1291 	for (i = 0; i < nEntries; i++)
1292 	{
1293 		pLogPal->palPalEntry[i] = lppe[i];
1294 	}
1295 
1296 	/* Save the normal data */
1297 	for (i = 0; i < 16; i++)
1298 	{
1299 		LPPALETTEENTRY p;
1300 
1301 		/* Access the entry */
1302 		p = &(pLogPal->palPalEntry[i+nEntries]);
1303 
1304 		/* Save the colors */
1305 		p->peRed = GetRValue(win_clr[i]);
1306 		p->peGreen = GetGValue(win_clr[i]);
1307 		p->peBlue = GetBValue(win_clr[i]);
1308 
1309 #ifdef SUPPORT_GAMMA
1310 
1311 		if (gamma_correction > 0)
1312 		{
1313 			p->peRed = gamma_table[p->peRed];
1314 			p->peGreen = gamma_table[p->peGreen];
1315 			p->peBlue = gamma_table[p->peBlue];
1316 		}
1317 
1318 #endif /* SUPPORT_GAMMA */
1319 
1320 		/* Save the flags */
1321 		p->peFlags = PC_NOCOLLAPSE;
1322 	}
1323 
1324 	/* Free something */
1325 	if (lppe) free(lppe);
1326 
1327 	/* Create a new palette, or fail */
1328 	hNewPal = CreatePalette(pLogPal);
1329 	if (!hNewPal) quit("Cannot create palette!");
1330 
1331 	/* Free the palette */
1332 	free(pLogPal);
1333 
1334 	/* Main window */
1335 	td = &data[0];
1336 
1337 	/* Realize the palette */
1338 	hdc = GetDC(td->w);
1339 	SelectPalette(hdc, hNewPal, 0);
1340 	i = RealizePalette(hdc);
1341 	ReleaseDC(td->w, hdc);
1342 	if (i == 0) quit("Cannot realize palette!");
1343 
1344 	/* Sub-windows */
1345 	for (i = 1; i < MAX_TERM_DATA; i++)
1346 	{
1347 		td = &data[i];
1348 
1349 		hdc = GetDC(td->w);
1350 		SelectPalette(hdc, hNewPal, 0);
1351 		ReleaseDC(td->w, hdc);
1352 	}
1353 
1354 	/* Delete old palette */
1355 	if (hPal) DeleteObject(hPal);
1356 
1357 	/* Save new palette */
1358 	hPal = hNewPal;
1359 
1360 	/* Success */
1361 	return (TRUE);
1362 }
1363 
1364 
1365 #ifdef USE_GRAPHICS
1366 /*
1367  * Initialize graphics
1368  */
init_graphics(void)1369 static bool init_graphics(void)
1370 {
1371 	/* Initialize once */
1372 	/* if (can_use_graphics != arg_graphics) */
1373 	{
1374 		char buf[1024];
1375 		int wid, hgt;
1376 		cptr name;
1377 
1378 		if (arg_graphics == GRAPHICS_DAVID_GERVAIS)
1379 		{
1380 			wid = 32;
1381 			hgt = 32;
1382 
1383 			name = "32x32.bmp";
1384 
1385 			use_transparency = TRUE;
1386 		}
1387 		else if (arg_graphics == GRAPHICS_ADAM_BOLT)
1388 		{
1389 			wid = 16;
1390 			hgt = 16;
1391 
1392 			name = "16X16.BMP";
1393 
1394 			use_transparency = TRUE;
1395 		}
1396 		else
1397 		{
1398 			wid = 8;
1399 			hgt = 8;
1400 
1401 			name = "8X8.BMP";
1402 		}
1403 
1404 		/* Access the bitmap file */
1405 		path_make(buf, ANGBAND_DIR_XTRA_GRAF, name);
1406 
1407 		/* Load the bitmap or quit */
1408 		if (!ReadDIB(data[0].w, buf, &infGraph))
1409 		{
1410 			plog_fmt("Cannot read bitmap file '%s'", name);
1411 			return (FALSE);
1412 		}
1413 
1414 		/* Save the new sizes */
1415 		infGraph.CellWidth = wid;
1416 		infGraph.CellHeight = hgt;
1417 
1418 		if (arg_graphics == GRAPHICS_ADAM_BOLT)
1419 		{
1420 			/* Access the mask file */
1421 			path_make(buf, ANGBAND_DIR_XTRA_GRAF, "mask.bmp");
1422 
1423 			/* Load the bitmap or quit */
1424 			if (!ReadDIB(data[0].w, buf, &infMask))
1425 			{
1426 				plog_fmt("Cannot read bitmap file '%s'", buf);
1427 				return (FALSE);
1428 			}
1429 		}
1430 		else if (arg_graphics == GRAPHICS_DAVID_GERVAIS)
1431 		{
1432 			/* Access the mask file */
1433 			path_make(buf, ANGBAND_DIR_XTRA_GRAF, "mask32.bmp");
1434 
1435 			/* Load the bitmap or quit */
1436 			if (!ReadDIB(data[0].w, buf, &infMask))
1437 			{
1438 				plog_fmt("Cannot read bitmap file '%s'", buf);
1439 				return (FALSE);
1440 			}
1441 		}
1442 
1443 		/* Activate a palette */
1444 		if (!new_palette())
1445 		{
1446 			/* Free bitmap XXX XXX XXX */
1447 
1448 			/* Oops */
1449 			plog("Cannot activate palette!");
1450 			return (FALSE);
1451 		}
1452 
1453 		/* Graphics available */
1454 		can_use_graphics = arg_graphics;
1455 	}
1456 
1457 	/* Result */
1458 	return (can_use_graphics);
1459 }
1460 #endif /* USE_GRAPHICS */
1461 
1462 
1463 #ifdef USE_SOUND
1464 /*
1465  * Initialize sound
1466  */
init_sound(void)1467 static bool init_sound(void)
1468 {
1469 	/* Initialize once */
1470 	if (!can_use_sound)
1471 	{
1472 		/* Load the prefs */
1473 		load_sound_prefs();
1474 
1475 		/* Sound available */
1476 		can_use_sound = TRUE;
1477 	}
1478 
1479 	/* Result */
1480 	return (can_use_sound);
1481 }
1482 #endif /* USE_SOUND */
1483 
1484 
1485 /*
1486  * Resize a window
1487  */
term_window_resize(const term_data * td)1488 static void term_window_resize(const term_data *td)
1489 {
1490 	/* Require window */
1491 	if (!td->w) return;
1492 
1493 	/* Resize the window */
1494 	SetWindowPos(td->w, 0, 0, 0,
1495 	             td->size_wid, td->size_hgt,
1496 	             SWP_NOMOVE | SWP_NOZORDER);
1497 
1498 	/* Redraw later */
1499 	InvalidateRect(td->w, NULL, TRUE);
1500 }
1501 
1502 
1503 /*
1504  * Force the use of a new "font file" for a term_data
1505  *
1506  * This function may be called before the "window" is ready
1507  *
1508  * This function returns zero only if everything succeeds.
1509  *
1510  * Note that the "font name" must be capitalized!!!
1511  */
term_force_font(term_data * td,cptr path)1512 static errr term_force_font(term_data *td, cptr path)
1513 {
1514 	int i;
1515 
1516 	int wid, hgt;
1517 
1518 	char *base;
1519 
1520 	char buf[1024];
1521 
1522 
1523 	/* Forget the old font (if needed) */
1524 	if (td->font_id) DeleteObject(td->font_id);
1525 
1526 	/* Forget old font */
1527 	if (td->font_file)
1528 	{
1529 		bool used = FALSE;
1530 
1531 		/* Scan windows */
1532 		for (i = 0; i < MAX_TERM_DATA; i++)
1533 		{
1534 			/* Don't check when closing the application */
1535 			if (!path) break;
1536 
1537 			/* Check "screen" */
1538 			if ((td != &data[i]) &&
1539 			    (data[i].font_file) &&
1540 			    (streq(data[i].font_file, td->font_file)))
1541 			{
1542 				used = TRUE;
1543 			}
1544 		}
1545 
1546 		/* Remove unused font resources */
1547 		if (!used) RemoveFontResource(td->font_file);
1548 
1549 		/* Free the old name */
1550 		string_free(td->font_file);
1551 
1552 		/* Forget it */
1553 		td->font_file = NULL;
1554 	}
1555 
1556 
1557 	/* No path given */
1558 	if (!path) return (1);
1559 
1560 
1561 	/* Local copy */
1562 	strnfmt(buf, sizeof(buf), "%s", path);
1563 
1564 	/* Analyze font path */
1565 	base = analyze_font(buf, &wid, &hgt);
1566 
1567 	/* Verify suffix */
1568 	if (!suffix(base, ".FON")) return (1);
1569 
1570 	/* Verify file */
1571 	if (!check_file(buf)) return (1);
1572 
1573 	/* Load the new font */
1574 	if (!AddFontResource(buf)) return (1);
1575 
1576 	/* Save new font name */
1577 	td->font_file = string_make(base);
1578 
1579 	/* Remove the "suffix" */
1580 	base[strlen(base)-4] = '\0';
1581 
1582 	/* Create the font (using the 'base' of the font file name!) */
1583 	td->font_id = CreateFont(hgt, wid, 0, 0, FW_DONTCARE, 0, 0, 0,
1584 	                         ANSI_CHARSET, OUT_DEFAULT_PRECIS,
1585 	                         CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1586 	                         FIXED_PITCH | FF_DONTCARE, base);
1587 
1588 	/* Hack -- Unknown size */
1589 	if (!wid || !hgt)
1590 	{
1591 		HDC hdcDesktop;
1592 		HFONT hfOld;
1593 		TEXTMETRIC tm;
1594 
1595 		/* all this trouble to get the cell size */
1596 		hdcDesktop = GetDC(HWND_DESKTOP);
1597 		hfOld = SelectObject(hdcDesktop, td->font_id);
1598 		GetTextMetrics(hdcDesktop, &tm);
1599 		SelectObject(hdcDesktop, hfOld);
1600 		ReleaseDC(HWND_DESKTOP, hdcDesktop);
1601 
1602 		/* Font size info */
1603 		wid = tm.tmAveCharWidth;
1604 		hgt = tm.tmHeight;
1605 	}
1606 
1607 	/* Save the size info */
1608 	td->font_wid = wid;
1609 	td->font_hgt = hgt;
1610 
1611 	/* Success */
1612 	return (0);
1613 }
1614 
1615 
1616 
1617 /*
1618  * Allow the user to change the font for this window.
1619  */
term_change_font(term_data * td)1620 static void term_change_font(term_data *td)
1621 {
1622 	OPENFILENAME ofn;
1623 
1624 	char tmp[1024] = "";
1625 
1626 	/* Extract a default if possible */
1627 	if (td->font_file) strcpy(tmp, td->font_file);
1628 
1629 	/* Ask for a choice */
1630 	memset(&ofn, 0, sizeof(ofn));
1631 	ofn.lStructSize = sizeof(ofn);
1632 	ofn.hwndOwner = data[0].w;
1633 	ofn.lpstrFilter = "Angband Font Files (*.fon)\0*.fon\0";
1634 	ofn.nFilterIndex = 1;
1635 	ofn.lpstrFile = tmp;
1636 	ofn.nMaxFile = 128;
1637 	ofn.lpstrInitialDir = ANGBAND_DIR_XTRA_FONT;
1638 	ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
1639 	ofn.lpstrDefExt = "fon";
1640 
1641 	/* Force choice if legal */
1642 	if (GetOpenFileName(&ofn))
1643 	{
1644 		/* Force the font */
1645 		if (term_force_font(td, tmp))
1646 		{
1647 			/* Access the standard font file */
1648 			path_make(tmp, ANGBAND_DIR_XTRA_FONT, "8X13.FON");
1649 
1650 			/* Force the use of that font */
1651 			(void)term_force_font(td, tmp);
1652 		}
1653 
1654 		/* Reset the tile info */
1655 		td->tile_wid = td->font_wid;
1656 		td->tile_hgt = td->font_hgt;
1657 
1658 		/* Analyze the font */
1659 		term_getsize(td);
1660 
1661 		/* Resize the window */
1662 		term_window_resize(td);
1663 	}
1664 }
1665 
1666 
1667 static void windows_map_aux(void);
1668 
1669 
1670 /*
1671  * Hack -- redraw a term_data
1672  */
term_data_redraw(term_data * td)1673 static void term_data_redraw(term_data *td)
1674 {
1675 	if (td->map_active)
1676 	{
1677 		/* Redraw the map */
1678 		windows_map_aux();
1679 	}
1680 	else
1681 	{
1682 		/* Activate the term */
1683 		Term_activate(&td->t);
1684 
1685 		/* Redraw the contents */
1686 		Term_redraw();
1687 
1688 		/* Restore the term */
1689 		Term_activate(term_screen);
1690 	}
1691 }
1692 
1693 
1694 /*
1695  * Hack -- redraw a term_data
1696  */
term_data_redraw_section(term_data * td,int x1,int y1,int x2,int y2)1697 static void term_data_redraw_section(term_data *td, int x1, int y1, int x2, int y2)
1698 {
1699 	/* Activate the term */
1700 	Term_activate(&td->t);
1701 
1702 	/* Redraw the area */
1703 	Term_redraw_section(x1, y1, x2, y2);
1704 
1705 	/* Restore the term */
1706 	Term_activate(term_screen);
1707 }
1708 
1709 
1710 
1711 /*** Function hooks needed by "Term" ***/
1712 
1713 
1714 #if 0
1715 
1716 /*
1717  * Initialize a new Term
1718  */
1719 static void Term_init_win(term *t)
1720 {
1721 	/* XXX Unused */
1722 }
1723 
1724 
1725 /*
1726  * Nuke an old Term
1727  */
1728 static void Term_nuke_win(term *t)
1729 {
1730 	/* XXX Unused */
1731 }
1732 
1733 #endif /* 0 */
1734 
1735 
1736 /*
1737  * Interact with the User
1738  */
Term_user_win(int n)1739 static errr Term_user_win(int n)
1740 {
1741 	/* Unused parameter */
1742 	(void)n;
1743 
1744 	/* Success */
1745 	return (0);
1746 }
1747 
1748 
1749 /*
1750  * React to global changes
1751  */
Term_xtra_win_react(void)1752 static errr Term_xtra_win_react(void)
1753 {
1754 	int i;
1755 
1756 
1757 	/* Simple color */
1758 	if (colors16)
1759 	{
1760 		/* Save the default colors */
1761 		for (i = 0; i < 256; i++)
1762 		{
1763 			/* Simply accept the desired colors */
1764 			win_pal[i] = angband_color_table[i][0];
1765 		}
1766 	}
1767 
1768 	/* Complex color */
1769 	else
1770 	{
1771 		COLORREF code;
1772 
1773 		byte rv, gv, bv;
1774 
1775 		bool change = FALSE;
1776 
1777 		/* Save the default colors */
1778 		for (i = 0; i < 256; i++)
1779 		{
1780 			/* Extract desired values */
1781 			rv = angband_color_table[i][1];
1782 			gv = angband_color_table[i][2];
1783 			bv = angband_color_table[i][3];
1784 
1785 #ifdef SUPPORT_GAMMA
1786 
1787 			if (gamma_correction > 0)
1788 			{
1789 				rv = gamma_table[rv];
1790 				gv = gamma_table[gv];
1791 				bv = gamma_table[bv];
1792 			}
1793 
1794 #endif /* SUPPORT_GAMMA */
1795 
1796 			/* Extract a full color code */
1797 			code = PALETTERGB(rv, gv, bv);
1798 
1799 			/* Activate changes */
1800 			if (win_clr[i] != code)
1801 			{
1802 				/* Note the change */
1803 				change = TRUE;
1804 
1805 				/* Apply the desired color */
1806 				win_clr[i] = code;
1807 			}
1808 		}
1809 
1810 		/* Activate the palette if needed */
1811 		if (change) (void)new_palette();
1812 	}
1813 
1814 
1815 #ifdef USE_SOUND
1816 
1817 	/* Handle "arg_sound" */
1818 	if (use_sound != arg_sound)
1819 	{
1820 		/* Initialize (if needed) */
1821 		if (arg_sound && !init_sound())
1822 		{
1823 			/* Warning */
1824 			plog("Cannot initialize sound!");
1825 
1826 			/* Cannot enable */
1827 			arg_sound = FALSE;
1828 		}
1829 
1830 		/* Change setting */
1831 		use_sound = arg_sound;
1832 	}
1833 
1834 #endif /* USE_SOUND */
1835 
1836 
1837 #ifdef USE_GRAPHICS
1838 
1839 	/* Handle "arg_graphics" */
1840 	if (use_graphics != arg_graphics)
1841 	{
1842 		/* Switch off transparency */
1843 		use_transparency = FALSE;
1844 
1845 		/* Free the bitmap stuff */
1846 		FreeDIB(&infGraph);
1847 		FreeDIB(&infMask);
1848 
1849 		/* Initialize (if needed) */
1850 		if (arg_graphics && !init_graphics())
1851 		{
1852 			/* Warning */
1853 			plog("Cannot initialize graphics!");
1854 
1855 			/* Cannot enable */
1856 			arg_graphics = GRAPHICS_NONE;
1857 		}
1858 
1859 		/* Change setting */
1860 		use_graphics = arg_graphics;
1861 
1862 		/* Reset visuals */
1863 #ifdef ANGBAND_2_8_1
1864 		reset_visuals();
1865 #else /* ANGBAND_2_8_1 */
1866 		reset_visuals(TRUE);
1867 #endif /* ANGBAND_2_8_1 */
1868 	}
1869 
1870 #endif /* USE_GRAPHICS */
1871 
1872 
1873 	/* Clean up windows */
1874 	for (i = 0; i < MAX_TERM_DATA; i++)
1875 	{
1876 		term *old = Term;
1877 
1878 		term_data *td = &data[i];
1879 
1880 		/* Update resized windows */
1881 		if ((td->cols != td->t.wid) || (td->rows != td->t.hgt))
1882 		{
1883 			/* Activate */
1884 			Term_activate(&td->t);
1885 
1886 			/* Hack -- Resize the term */
1887 			Term_resize(td->cols, td->rows);
1888 
1889 			/* Redraw the contents */
1890 			Term_redraw();
1891 
1892 			/* Restore */
1893 			Term_activate(old);
1894 		}
1895 	}
1896 
1897 
1898 	/* Success */
1899 	return (0);
1900 }
1901 
1902 
1903 /*
1904  * Process at least one event
1905  */
Term_xtra_win_event(int v)1906 static errr Term_xtra_win_event(int v)
1907 {
1908 	MSG msg;
1909 
1910 	/* Wait for an event */
1911 	if (v)
1912 	{
1913 		/* Block */
1914 		if (GetMessage(&msg, NULL, 0, 0))
1915 		{
1916 			TranslateMessage(&msg);
1917 			DispatchMessage(&msg);
1918 		}
1919 	}
1920 
1921 	/* Check for an event */
1922 	else
1923 	{
1924 		/* Check */
1925 		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1926 		{
1927 			TranslateMessage(&msg);
1928 			DispatchMessage(&msg);
1929 		}
1930 	}
1931 
1932 	/* Success */
1933 	return 0;
1934 }
1935 
1936 
1937 /*
1938  * Process all pending events
1939  */
Term_xtra_win_flush(void)1940 static errr Term_xtra_win_flush(void)
1941 {
1942 	MSG msg;
1943 
1944 	/* Process all pending events */
1945 	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1946 	{
1947 		TranslateMessage(&msg);
1948 		DispatchMessage(&msg);
1949 	}
1950 
1951 	/* Success */
1952 	return (0);
1953 }
1954 
1955 
1956 /*
1957  * Hack -- clear the screen
1958  *
1959  * Make this more efficient XXX XXX XXX
1960  */
Term_xtra_win_clear(void)1961 static errr Term_xtra_win_clear(void)
1962 {
1963 	term_data *td = (term_data*)(Term->data);
1964 
1965 	HDC hdc;
1966 	RECT rc;
1967 
1968 	/* Rectangle to erase */
1969 	rc.left = td->size_ow1;
1970 	rc.right = rc.left + td->cols * td->tile_wid;
1971 	rc.top = td->size_oh1;
1972 	rc.bottom = rc.top + td->rows * td->tile_hgt;
1973 
1974 	/* Erase it */
1975 	hdc = GetDC(td->w);
1976 	SetBkColor(hdc, RGB(0, 0, 0));
1977 	SelectObject(hdc, td->font_id);
1978 	ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
1979 	ReleaseDC(td->w, hdc);
1980 
1981 	/* Success */
1982 	return 0;
1983 }
1984 
1985 
1986 /*
1987  * Hack -- make a noise
1988  */
Term_xtra_win_noise(void)1989 static errr Term_xtra_win_noise(void)
1990 {
1991 	MessageBeep(MB_ICONASTERISK);
1992 	return (0);
1993 }
1994 
1995 
1996 /*
1997  * Hack -- make a sound
1998  */
Term_xtra_win_sound(int v)1999 static errr Term_xtra_win_sound(int v)
2000 {
2001 #ifdef USE_SOUND
2002 	int i;
2003 	char buf[1024];
2004 #endif /* USE_SOUND */
2005 
2006 	/* Sound disabled */
2007 	if (!use_sound) return (1);
2008 
2009 	/* Illegal sound */
2010 	if ((v < 0) || (v >= SOUND_MAX)) return (1);
2011 
2012 #ifdef USE_SOUND
2013 
2014 	/* Count the samples */
2015 	for (i = 0; i < SAMPLE_MAX; i++)
2016 	{
2017 		if (!sound_file[v][i])
2018 			break;
2019 	}
2020 
2021 	/* No sample */
2022 	if (i == 0) return (1);
2023 
2024 	/* Build the path */
2025 	path_make(buf, ANGBAND_DIR_XTRA_SOUND, sound_file[v][Rand_simple(i)]);
2026 
2027 #ifdef WIN32
2028 
2029 	/* Play the sound, catch errors */
2030 	return (PlaySound(buf, 0, SND_FILENAME | SND_ASYNC));
2031 
2032 #else /* WIN32 */
2033 
2034 	/* Play the sound, catch errors */
2035 	return (sndPlaySound(buf, SND_ASYNC));
2036 
2037 #endif /* WIN32 */
2038 
2039 #else /* USE_SOUND */
2040 
2041 	/* Oops */
2042 	return (1);
2043 
2044 #endif /* USE_SOUND */
2045 }
2046 
2047 
2048 /*
2049  * Delay for "x" milliseconds
2050  */
Term_xtra_win_delay(int v)2051 static int Term_xtra_win_delay(int v)
2052 {
2053 
2054 #ifdef WIN32
2055 
2056 	/* Sleep */
2057 	if (v > 0) Sleep(v);
2058 
2059 #else /* WIN32 */
2060 
2061 	DWORD t;
2062 	MSG msg;
2063 
2064 	/* Final count */
2065 	t = GetTickCount() + v;
2066 
2067 	/* Wait for it */
2068 	while (GetTickCount() < t)
2069 	{
2070 		/* Handle messages */
2071 		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
2072 		{
2073 			TranslateMessage(&msg);
2074 			DispatchMessage(&msg);
2075 		}
2076 	}
2077 
2078 #endif /* WIN32 */
2079 
2080 	/* Success */
2081 	return (0);
2082 }
2083 
2084 
2085 /*
2086  * Do a "special thing"
2087  */
Term_xtra_win(int n,int v)2088 static errr Term_xtra_win(int n, int v)
2089 {
2090 	/* Handle a subset of the legal requests */
2091 	switch (n)
2092 	{
2093 		/* Make a bell sound */
2094 		case TERM_XTRA_NOISE:
2095 		{
2096 			return (Term_xtra_win_noise());
2097 		}
2098 
2099 		/* Make a special sound */
2100 		case TERM_XTRA_SOUND:
2101 		{
2102 			return (Term_xtra_win_sound(v));
2103 		}
2104 
2105 		/* Process random events */
2106 		case TERM_XTRA_BORED:
2107 		{
2108 			return (Term_xtra_win_event(0));
2109 		}
2110 
2111 		/* Process an event */
2112 		case TERM_XTRA_EVENT:
2113 		{
2114 			return (Term_xtra_win_event(v));
2115 		}
2116 
2117 		/* Flush all events */
2118 		case TERM_XTRA_FLUSH:
2119 		{
2120 			return (Term_xtra_win_flush());
2121 		}
2122 
2123 		/* React to global changes */
2124 		case TERM_XTRA_REACT:
2125 		{
2126 			return (Term_xtra_win_react());
2127 		}
2128 
2129 		/* Delay for some milliseconds */
2130 		case TERM_XTRA_DELAY:
2131 		{
2132 			return (Term_xtra_win_delay(v));
2133 		}
2134 	}
2135 
2136 	/* Oops */
2137 	return 1;
2138 }
2139 
2140 #if 0
2141 /*
2142  * Find the square a particular pixel is part of.
2143  */
2144 static void pixel_to_square(int *x, int *y, int ox, int oy)
2145 {
2146 	term_data *td = (term_data*)(Term->data);
2147 
2148 	if (td->map_active)
2149 	{
2150 		(*x) = (ox - td->size_ow1) / td->map_tile_wid;
2151 		(*y) = (oy - td->size_oh1) / td->map_tile_hgt;
2152 	}
2153 	else
2154 	{
2155 		(*x) = (ox - td->size_ow1) / td->tile_wid;
2156 		(*y) = (oy - td->size_oh1) / td->tile_hgt;
2157 
2158 		if ((use_bigtile) && ((*y) >= Term->scr->big_y1)
2159 			&& ((*y) <= Term->scr->big_y2)
2160 			&& ((*x) >= Term->scr->big_x1))
2161 		{
2162 			(*x) -= ((*x) - Term->scr->big_x1 + 1) / 2;
2163 		}
2164 	}
2165 }
2166 #endif /* 0 */
2167 
2168 /*
2169  * Find the pixel at the top-left corner of a square.
2170  */
square_to_pixel(int * x,int * y,int ox,int oy)2171 static void square_to_pixel(int *x, int *y, int ox, int oy)
2172 {
2173 	term_data *td = (term_data*)(Term->data);
2174 
2175 	if (td->map_active)
2176 	{
2177 		(*x) = ox * td->map_tile_wid + td->size_ow1;
2178 		(*y) = oy * td->map_tile_hgt + td->size_oh1;
2179 	}
2180 	else
2181 	{
2182 		(*y) = oy * td->tile_hgt + td->size_oh1;
2183 
2184 		if ((use_bigtile) && (oy >= Term->scr->big_y1)
2185 				&& (oy <= Term->scr->big_y2)
2186 				&& (ox > Term->scr->big_x1))
2187 		{
2188 			(*x) = ox * td->tile_wid * 2 + td->size_ow1 -
2189 					Term->scr->big_x1 * td->tile_wid;
2190 		}
2191 		else
2192 		{
2193 			(*x) = ox * td->tile_wid + td->size_ow1;
2194 		}
2195 	}
2196 }
2197 
2198 /*
2199  * Low level graphics (Assumes valid input).
2200  *
2201  * Draw a "cursor" at (x,y), using a "yellow box".
2202  */
Term_curs_win(int x,int y)2203 static errr Term_curs_win(int x, int y)
2204 {
2205 	term_data *td = (term_data*)(Term->data);
2206 
2207 	RECT rc;
2208 	HDC hdc;
2209 
2210 	int x1, y1;
2211 	int tile_wid, tile_hgt;
2212 
2213 	/* Top left hand corner */
2214 	square_to_pixel(&x1, &y1, x, y);
2215 
2216 	/* Frame the grid */
2217 	rc.left = x1;
2218 	rc.top = y1;
2219 
2220 	if (td->map_active)
2221 	{
2222 		tile_wid = td->map_tile_wid;
2223 		tile_hgt = td->map_tile_hgt;
2224 
2225 		rc.right = rc.left + tile_wid;
2226 	}
2227 	else
2228 	{
2229 		tile_wid = td->tile_wid;
2230 		tile_hgt = td->tile_hgt;
2231 
2232 		if (is_bigtiled(x, y))
2233 		{
2234 			rc.right = rc.left + tile_wid * 2;
2235 		}
2236 		else
2237 		{
2238 			rc.right = rc.left + tile_wid;
2239 		}
2240 	}
2241 	rc.bottom = rc.top + tile_hgt;
2242 
2243 	/* Cursor is done as a yellow "box" */
2244 	hdc = GetDC(td->w);
2245 	FrameRect(hdc, &rc, hbrYellow);
2246 	ReleaseDC(td->w, hdc);
2247 
2248 	/* Success */
2249 	return 0;
2250 }
2251 
2252 
2253 /*
2254  *
2255  * Erase a "block" of "n" characters starting at (x,y).
2256  */
Term_wipe_win(int x,int y,int n)2257 static errr Term_wipe_win(int x, int y, int n)
2258 {
2259 	term_data *td = (term_data*)(Term->data);
2260 
2261 	HDC hdc;
2262 	RECT rc;
2263 
2264 	int x1, y1, x2, y2;
2265 
2266 	/*** Find the dimensions ***/
2267 	square_to_pixel(&x1, &y1, x, y);
2268 	square_to_pixel(&x2, &y2, x + n, y);
2269 
2270 	/* Rectangle to erase in client coords */
2271 	rc.left = x1;
2272 	rc.right = x2;
2273 	rc.top = y1;
2274 	rc.bottom = y1 + td->tile_hgt;
2275 
2276 	hdc = GetDC(td->w);
2277 	SetBkColor(hdc, RGB(0, 0, 0));
2278 	SelectObject(hdc, td->font_id);
2279 	ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
2280 	ReleaseDC(td->w, hdc);
2281 
2282 	/* Success */
2283 	return 0;
2284 }
2285 
2286 
2287 /*
2288  * Low level graphics.  Assumes valid input.
2289  *
2290  * Draw several ("n") chars, with an attr, at a given location.
2291  *
2292  * All "graphic" data is handled by "Term_pict_win()", below.
2293  *
2294  * One would think there is a more efficient method for telling a window
2295  * what color it should be using to draw with, but perhaps simply changing
2296  * it every time is not too inefficient.  XXX XXX XXX
2297  */
Term_text_win(int cx,int cy,int n,byte a,cptr s)2298 static errr Term_text_win(int cx, int cy, int n, byte a, cptr s)
2299 {
2300 	term_data *td = (term_data*)(Term->data);
2301 	RECT rc;
2302 	HDC hdc;
2303 
2304 	int i;
2305 
2306 	int x, y;
2307 
2308 	/* Acquire DC */
2309 	hdc = GetDC(td->w);
2310 
2311 	/* Background color */
2312 	SetBkColor(hdc, RGB(0, 0, 0));
2313 
2314 	/* Foreground color */
2315 	if (colors16)
2316 	{
2317 		SetTextColor(hdc, PALETTEINDEX(win_pal[a]));
2318 	}
2319 	else if (paletted)
2320 	{
2321 		SetTextColor(hdc, win_clr[a&0x0F]);
2322 	}
2323 	else
2324 	{
2325 		SetTextColor(hdc, win_clr[a]);
2326 	}
2327 
2328 	/* Use the font */
2329 	SelectObject(hdc, td->font_id);
2330 
2331 	/* Erase complete rectangle */
2332 	Term_wipe_win(cx, cy, n);
2333 
2334 	/* Get top left corner */
2335 	square_to_pixel(&x, &y, cx, cy);
2336 
2337 	rc.top = y + ((td->tile_hgt - td->font_hgt) / 2);
2338 	rc.bottom = rc.top + td->font_hgt;
2339 
2340 	/* Dump each character */
2341 	for (i = 0; i < n; i++)
2342 	{
2343 		if (is_bigtiled(cx + i, cy))
2344 		{
2345 			rc.left = x + ((td->tile_wid - td->font_wid) / 2);
2346 			rc.right = rc.left + td->font_wid;
2347 
2348 			/* Dump the text */
2349 			ExtTextOut(hdc, rc.left, rc.top, 0, &rc,
2350 						s+i, 1, NULL);
2351 
2352 			/* Advance */
2353 			x += td->tile_wid * 2;
2354 		}
2355 		else
2356 		{
2357 			rc.left = x + ((td->tile_wid - td->font_wid) / 2);
2358 			rc.right = rc.left + td->font_wid;
2359 
2360 			/* Dump the text */
2361 			ExtTextOut(hdc, rc.left, rc.top, 0, &rc,
2362 						s+i, 1, NULL);
2363 
2364 			/* Advance */
2365 			x += td->tile_wid;
2366 		}
2367 	}
2368 
2369 	/* Release DC */
2370 	ReleaseDC(td->w, hdc);
2371 
2372 	/* Success */
2373 	return 0;
2374 }
2375 
2376 
2377 /*
2378  * Low level graphics.  Assumes valid input.
2379  *
2380  * Draw an array of "special" attr/char pairs at the given location.
2381  *
2382  * We use the "Term_pict_win()" function for "graphic" data, which are
2383  * encoded by setting the "high-bits" of both the "attr" and the "char"
2384  * data.  We use the "attr" to represent the "row" of the main bitmap,
2385  * and the "char" to represent the "col" of the main bitmap.  The use
2386  * of this function is induced by the "higher_pict" flag.
2387  *
2388  * If "graphics" is not available, we simply "wipe" the given grids.
2389  */
Term_pict_win(int x,int y,int n,const byte * ap,const char * cp,const byte * tap,const char * tcp)2390 static errr Term_pict_win(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp)
2391 {
2392 	term_data *td = (term_data*)(Term->data);
2393 
2394 #ifdef USE_GRAPHICS
2395 
2396 	int i;
2397 	int x1, y1, w1, h1;
2398 	int x2, y2, w2, h2, tw2;
2399 	int x3, y3;
2400 
2401 	HDC hdcMask;
2402 	HDC hdc;
2403 	HDC hdcSrc;
2404 	HBITMAP hbmSrcOld;
2405 
2406 	/* Paranoia */
2407 	if (!use_graphics)
2408 	{
2409 		/* Erase the grids */
2410 		return (Term_wipe_win(x, y, n));
2411 	}
2412 
2413 	/* Size of bitmap cell */
2414 	w1 = infGraph.CellWidth;
2415 	h1 = infGraph.CellHeight;
2416 
2417 	/* Size of window cell */
2418 	if (td->map_active)
2419 	{
2420 		w2 = td->map_tile_wid;
2421 		h2 = td->map_tile_hgt;
2422 		tw2 = w2;
2423 	}
2424 	else
2425 	{
2426 		w2 = td->tile_wid;
2427 		h2 = td->tile_hgt;
2428 
2429 		/* big tile mode */
2430 		if (use_bigtile)
2431 			tw2 = 2 * w2;
2432 		else
2433 			tw2 = w2;
2434 	}
2435 
2436 	/* Starting point */
2437 	square_to_pixel(&x2, &y2, x, y);
2438 
2439 	/* Info */
2440 	hdc = GetDC(td->w);
2441 
2442 	/* More info */
2443 	hdcSrc = CreateCompatibleDC(hdc);
2444 	hbmSrcOld = SelectObject(hdcSrc, infGraph.hBitmap);
2445 
2446 	if ((arg_graphics == GRAPHICS_ADAM_BOLT) ||
2447 			(arg_graphics == GRAPHICS_DAVID_GERVAIS))
2448 	{
2449 		hdcMask = CreateCompatibleDC(hdc);
2450 		SelectObject(hdcMask, infMask.hBitmap);
2451 	}
2452 	else
2453 	{
2454 		hdcMask = NULL;
2455 	}
2456 
2457 	/* Draw attr/char pairs */
2458 	for (i = 0; i < n; i++, x2 += w2)
2459 	{
2460 		byte a = ap[i];
2461 		char c = cp[i];
2462 
2463 		/* Extract picture */
2464 		int row = (a & 0x7F);
2465 		int col = (c & 0x7F);
2466 
2467 		/* Location of bitmap cell */
2468 		x1 = col * w1;
2469 		y1 = row * h1;
2470 
2471 		if ((arg_graphics == GRAPHICS_ADAM_BOLT) ||
2472 			(arg_graphics == GRAPHICS_DAVID_GERVAIS))
2473 		{
2474 			x3 = (tcp[i] & 0x7F) * w1;
2475 			y3 = (tap[i] & 0x7F) * h1;
2476 
2477 			/* Perfect size */
2478 			if ((w1 == tw2) && (h1 == h2))
2479 			{
2480  				/* Copy the terrain picture from the bitmap to the window */
2481 				BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, SRCCOPY);
2482 
2483  				/* Mask out the tile */
2484 				BitBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, SRCAND);
2485 
2486  				/* Draw the tile */
2487 				BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCPAINT);
2488 			}
2489 
2490 			/* Need to stretch */
2491 			else
2492 			{
2493 				/* Set the correct mode for stretching the tiles */
2494 				SetStretchBltMode(hdc, COLORONCOLOR);
2495 
2496 				/* Copy the terrain picture from the bitmap to the window */
2497 				StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x3, y3, w1, h1, SRCCOPY);
2498 
2499 				/* Only draw if terrain and overlay are different */
2500 				if ((x1 != x3) || (y1 != y3))
2501 				{
2502 					/* Mask out the tile */
2503 					StretchBlt(hdc, x2, y2, tw2, h2, hdcMask, x1, y1, w1, h1, SRCAND);
2504 
2505 					/* Draw the tile */
2506 					StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCPAINT);
2507 				}
2508 			}
2509 		}
2510 		else
2511 		{
2512 			/* Perfect size */
2513 			if ((w1 == tw2) && (h1 == h2))
2514 			{
2515 				/* Copy the picture from the bitmap to the window */
2516 				BitBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, SRCCOPY);
2517 			}
2518 
2519 			/* Need to stretch */
2520 			else
2521 			{
2522 				/* Set the correct mode for stretching the tiles */
2523 				SetStretchBltMode(hdc, COLORONCOLOR);
2524 
2525 				/* Copy the picture from the bitmap to the window */
2526 				StretchBlt(hdc, x2, y2, tw2, h2, hdcSrc, x1, y1, w1, h1, SRCCOPY);
2527 			}
2528 		}
2529 	}
2530 
2531 	/* Release */
2532 	SelectObject(hdcSrc, hbmSrcOld);
2533 	DeleteDC(hdcSrc);
2534 
2535 	if ((arg_graphics == GRAPHICS_ADAM_BOLT) ||
2536 		(arg_graphics == GRAPHICS_DAVID_GERVAIS))
2537 	{
2538 		/* Release */
2539 		SelectObject(hdcMask, hbmSrcOld);
2540 		DeleteDC(hdcMask);
2541 	}
2542 
2543 	/* Release */
2544 	ReleaseDC(td->w, hdc);
2545 
2546 #else /* USE_GRAPHICS */
2547 
2548 	/* Just erase this grid */
2549 	return (Term_wipe_win(x, y, n));
2550 
2551 #endif /* USE_GRAPHICS */
2552 
2553 	/* Success */
2554 	return 0;
2555 }
2556 
2557 
2558 static int player_x;
2559 static int player_y;
2560 
2561 /*
2562  * Notice that the player has moved
2563  */
win_player_move(int x,int y,vptr dummy)2564 static void win_player_move(int x, int y, vptr dummy)
2565 {
2566 	/* Hack - ignore parameter */
2567 	(void) dummy;
2568 
2569 	/* Save for later */
2570 	player_x = x;
2571 	player_y = y;
2572 }
2573 
2574 
2575 /*
2576  * Save the information so we can access it later
2577  */
win_map_info(map_block * mb_ptr,const term_map * map,vptr dummy)2578 static void win_map_info(map_block *mb_ptr, const term_map *map, vptr dummy)
2579 {
2580 	/* Hack -- ignore parameter */
2581 	(void) dummy;
2582 
2583 	/* Store feature code for later */
2584 	if (map->terrain)
2585 	{
2586 		mb_ptr->a = f_info[map->terrain].x_attr;
2587 		mb_ptr->c = f_info[map->terrain].x_char;
2588 	}
2589 	else
2590 	{
2591 		mb_ptr->a = 0;
2592 		mb_ptr->c = 0;
2593 	}
2594 }
2595 
windows_map_aux(void)2596 static void windows_map_aux(void)
2597 {
2598 	term_data *td = &data[0];
2599 	map_block *mb_ptr;
2600 	byte a;
2601 	char c;
2602 	int x, y;
2603 
2604 	int min_x, min_y, max_x, max_y;
2605 
2606 	/* Get size */
2607 	td->map_tile_wid = (td->tile_wid * td->cols) / MAX_WID;
2608 	td->map_tile_hgt = (td->tile_hgt * td->rows) / MAX_HGT;
2609 
2610 	/* Get bounds */
2611 	min_x = player_x - MAX_WID / 2;
2612 	max_x = min_x + MAX_WID;
2613 
2614 	min_y = player_y - MAX_HGT / 2;
2615 	max_y = player_y + MAX_HGT;
2616 
2617 	/* Draw the map */
2618 	for (x = min_x; x < max_x; x++)
2619 	{
2620 		for (y = min_y; y < max_y; y++)
2621 		{
2622 			if (map_in_bounds(x, y))
2623 			{
2624 				mb_ptr = map_loc(x, y);
2625 
2626 				/* Attr / char */
2627 				a = mb_ptr->a;
2628 				c = mb_ptr->c;
2629 
2630 				/* Ignore non-graphics */
2631 				if ((a & 0x80) && (c & 0x80))
2632 				{
2633 					Term_pict_win(x - min_x, y - min_y, 1, &a, &c, &a, &c);
2634 				}
2635 			}
2636 		}
2637 	}
2638 
2639 	/* Hilite the player */
2640 	Term_curs_win(player_x - min_x, player_y - min_y);
2641 }
2642 
2643 
2644 /*
2645  * MEGA_HACK - Display a graphical map of the dungeon.
2646  */
windows_map(void)2647 static void windows_map(void)
2648 {
2649 	term_data *td = &data[0];
2650 	char ch;
2651 
2652 	/* Only in graphics mode since the fonts can't be scaled */
2653 	if (!use_graphics) return;
2654 
2655 	/* Prevent various menu-actions from working */
2656 	initialized = FALSE;
2657 
2658 	/* Clear screen */
2659 	Term_xtra_win_clear();
2660 
2661 	td->map_active = TRUE;
2662 
2663 	/* Draw the map */
2664 	windows_map_aux();
2665 
2666 	/* Wait for a keypress, flush key buffer */
2667 	Term_inkey(&ch, TRUE, TRUE);
2668 	Term_flush();
2669 
2670 	/* Switch off the map display */
2671 	td->map_active = FALSE;
2672 
2673 	/* Restore screen */
2674 	Term_xtra_win_clear();
2675 	Term_redraw();
2676 
2677 	/* We are ready again */
2678 	initialized = TRUE;
2679 }
2680 
2681 
2682 /*** Other routines ***/
2683 
2684 
2685 /*
2686  * Create and initialize a "term_data" given a title
2687  */
term_data_link(term_data * td)2688 static void term_data_link(term_data *td)
2689 {
2690 	term *t = &td->t;
2691 
2692 	/* Initialize the term */
2693 	term_init(t, td->cols, td->rows, td->keys);
2694 
2695 	/* Use a "software" cursor */
2696 	t->soft_cursor = TRUE;
2697 
2698 	/* Use "Term_pict" for "graphic" data */
2699 	t->higher_pict = TRUE;
2700 
2701 	/* Erase with "black space" */
2702 	t->attr_blank = TERM_DARK;
2703 	t->char_blank = ' ';
2704 
2705 #if 0
2706 	/* Prepare the init/nuke hooks */
2707 	t->init_hook = Term_init_win;
2708 	t->nuke_hook = Term_nuke_win;
2709 #endif /* 0 */
2710 
2711 	/* Prepare the template hooks */
2712 	t->user_hook = Term_user_win;
2713 	t->xtra_hook = Term_xtra_win;
2714 	t->curs_hook = Term_curs_win;
2715 	t->wipe_hook = Term_wipe_win;
2716 	t->text_hook = Term_text_win;
2717 	t->pict_hook = Term_pict_win;
2718 
2719 	/* Remember where we came from */
2720 	t->data = (vptr)(td);
2721 }
2722 
2723 
2724 /*
2725  * Create the windows
2726  *
2727  * First, instantiate the "default" values, then read the "ini_file"
2728  * to over-ride selected values, then create the windows, and fonts.
2729  *
2730  * Must use SW_SHOW not SW_SHOWNA, since on 256 color display
2731  * must make active to realize the palette.  XXX XXX XXX
2732  */
init_windows(void)2733 static void init_windows(void)
2734 {
2735 	int i;
2736 
2737 	term_data *td;
2738 
2739 	char buf[1024];
2740 
2741 
2742 	/* Main window */
2743 	td = &data[0];
2744 	WIPE(td, term_data);
2745 	td->s = angband_term_name[0];
2746 	td->keys = 1024;
2747 	td->rows = 24;
2748 	td->cols = 80;
2749 	td->visible = TRUE;
2750 	td->size_ow1 = 2;
2751 	td->size_ow2 = 2;
2752 	td->size_oh1 = 2;
2753 	td->size_oh2 = 2;
2754 	td->pos_x = 30;
2755 	td->pos_y = 20;
2756 
2757 	/* Sub windows */
2758 	for (i = 1; i < MAX_TERM_DATA; i++)
2759 	{
2760 		td = &data[i];
2761 		WIPE(td, term_data);
2762 		td->s = angband_term_name[i];
2763 		td->keys = 16;
2764 		td->rows = 24;
2765 		td->cols = 80;
2766 		td->visible = FALSE;
2767 		td->size_ow1 = 1;
2768 		td->size_ow2 = 1;
2769 		td->size_oh1 = 1;
2770 		td->size_oh2 = 1;
2771 		td->pos_x = (7 - i) * 30;
2772 		td->pos_y = (7 - i) * 20;
2773 	}
2774 
2775 
2776 	/* Load prefs */
2777 	load_prefs();
2778 
2779 
2780 	/* Main window (need these before term_getsize gets called) */
2781 	td = &data[0];
2782 	td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU |
2783 	               WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION |
2784 	               WS_VISIBLE);
2785 	if (td->maximized) td->dwStyle |= WS_MAXIMIZE;
2786 	td->dwExStyle = 0;
2787 	td->visible = TRUE;
2788 
2789 	/* Sub windows (need these before term_getsize gets called) */
2790 	for (i = 1; i < MAX_TERM_DATA; i++)
2791 	{
2792 		td = &data[i];
2793 		td->dwStyle = (WS_OVERLAPPED | WS_THICKFRAME | WS_SYSMENU | WS_CAPTION);
2794 		td->dwExStyle = (WS_EX_TOOLWINDOW);
2795 	}
2796 
2797 
2798 	/* All windows */
2799 	for (i = 0; i < MAX_TERM_DATA; i++)
2800 	{
2801 		td = &data[i];
2802 
2803 		/* Access the standard font file */
2804 		path_make(buf, ANGBAND_DIR_XTRA_FONT, td->font_want);
2805 
2806 		/* Activate the chosen font */
2807 		if (term_force_font(td, buf))
2808 		{
2809 			/* Access the standard font file */
2810 			path_make(buf, ANGBAND_DIR_XTRA_FONT, "8X13.FON");
2811 
2812 			/* Force the use of that font */
2813 			(void)term_force_font(td, buf);
2814 
2815 			/* Oops */
2816 			td->tile_wid = 8;
2817 			td->tile_hgt = 13;
2818 		}
2819 
2820 		/* Analyze the font */
2821 		term_getsize(td);
2822 
2823 		/* Resize the window */
2824 		term_window_resize(td);
2825 	}
2826 
2827 
2828 	/* Sub windows (reverse order) */
2829 	for (i = MAX_TERM_DATA - 1; i >= 1; --i)
2830 	{
2831 		td = &data[i];
2832 
2833 		my_td = td;
2834 		td->w = CreateWindowEx(td->dwExStyle, AngList,
2835 		                       td->s, td->dwStyle,
2836 		                       td->pos_x, td->pos_y,
2837 		                       td->size_wid, td->size_hgt,
2838 		                       HWND_DESKTOP, NULL, hInstance, NULL);
2839 		my_td = NULL;
2840 		if (!td->w) quit("Failed to create sub-window");
2841 
2842 		if (td->visible)
2843 		{
2844 			td->size_hack = TRUE;
2845 			ShowWindow(td->w, SW_SHOW);
2846 			td->size_hack = FALSE;
2847 		}
2848 
2849 		term_data_link(td);
2850 		angband_term[i] = &td->t;
2851 
2852 		if (td->visible)
2853 		{
2854 			/* Activate the window */
2855 			SetActiveWindow(td->w);
2856 
2857 			/* Bring window to top */
2858 			SetWindowPos(td->w, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2859 		}
2860 	}
2861 
2862 
2863 	/* Main window */
2864 	td = &data[0];
2865 
2866 	/* Main window */
2867 	my_td = td;
2868 	td->w = CreateWindowEx(td->dwExStyle, AppName,
2869 	                       td->s, td->dwStyle,
2870 	                       td->pos_x, td->pos_y,
2871 	                       td->size_wid, td->size_hgt,
2872 	                       HWND_DESKTOP, NULL, hInstance, NULL);
2873 	my_td = NULL;
2874 	if (!td->w) quit_fmt("Failed to create %s window", VERSION_NAME);
2875 
2876 	term_data_link(td);
2877 	term_screen = &td->t;
2878 
2879 	/* Activate the main window */
2880 	SetActiveWindow(td->w);
2881 
2882 	/* Bring main window back to top */
2883 	SetWindowPos(td->w, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
2884 
2885 #ifdef SUPPORT_GAMMA
2886 
2887 	if (gamma_correction > 0)
2888 		build_gamma_table(gamma_correction);
2889 
2890 #endif /* SUPPORT_GAMMA */
2891 
2892 	/* New palette XXX XXX XXX */
2893 	(void)new_palette();
2894 
2895 
2896 	/* Create a "brush" for drawing the "cursor" */
2897 	hbrYellow = CreateSolidBrush(win_clr[TERM_YELLOW]);
2898 
2899 
2900 	/* Process pending messages */
2901 	(void)Term_xtra_win_flush();
2902 }
2903 
2904 
2905 #ifdef USE_SAVER
2906 
2907 /*
2908  * Stop the screensaver
2909  */
stop_screensaver(void)2910 static void stop_screensaver(void)
2911 {
2912 	if (screensaver)
2913 		SendMessage(data[0].w, WM_CLOSE, 0, 0);
2914 	else
2915 		SendMessage(data[0].w, WM_COMMAND, IDM_OPTIONS_SAVER, 0);
2916 }
2917 
2918 #endif /* USE_SAVER */
2919 
2920 
2921 /*
2922  * Prepare the menus
2923  */
setup_menus(void)2924 static void setup_menus(void)
2925 {
2926 	int i;
2927 
2928 	HMENU hm = GetMenu(data[0].w);
2929 
2930 #ifdef USE_SAVER
2931 	main_menu = hm;
2932 #endif /* USE_SAVER */
2933 
2934 	/* Menu "File", Disable all */
2935 	EnableMenuItem(hm, IDM_FILE_NEW,
2936 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
2937 	EnableMenuItem(hm, IDM_FILE_OPEN,
2938 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
2939 	EnableMenuItem(hm, IDM_FILE_SAVE,
2940 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
2941 	EnableMenuItem(hm, IDM_FILE_EXIT,
2942 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
2943 	EnableMenuItem(hm, IDM_FILE_SCORE,
2944 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
2945 
2946 
2947 	/* No character available */
2948 	if (!character_generated)
2949 	{
2950 		/* Menu "File", Item "New" */
2951 		EnableMenuItem(hm, IDM_FILE_NEW, MF_BYCOMMAND | MF_ENABLED);
2952 
2953 		/* Menu "File", Item "Open" */
2954 		EnableMenuItem(hm, IDM_FILE_OPEN, MF_BYCOMMAND | MF_ENABLED);
2955 	}
2956 
2957 	/* A character available */
2958 	if (game_in_progress && character_generated && p_ptr->cmd.inkey_flag)
2959 	{
2960 		/* Menu "File", Item "Save" */
2961 		EnableMenuItem(hm, IDM_FILE_SAVE, MF_BYCOMMAND | MF_ENABLED);
2962 	}
2963 
2964 	if (!game_in_progress || !character_generated ||
2965 	    (p_ptr->cmd.inkey_flag))
2966 	{
2967 		/* Menu "File", Item "Exit" */
2968 		EnableMenuItem(hm, IDM_FILE_EXIT, MF_BYCOMMAND | MF_ENABLED);
2969 	}
2970 
2971 	if (initialized)
2972 	{
2973 		/* Menu "File", Item "Show Scores" */
2974 		EnableMenuItem(hm, IDM_FILE_SCORE, MF_BYCOMMAND | MF_ENABLED);
2975 	}
2976 
2977 
2978 	/* Menu "Window::Visibility" */
2979 	for (i = 0; i < MAX_TERM_DATA; i++)
2980 	{
2981 		EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i,
2982 		               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
2983 
2984 		CheckMenuItem(hm, IDM_WINDOW_VIS_0 + i,
2985 		              (data[i].visible ? MF_CHECKED : MF_UNCHECKED));
2986 
2987 		EnableMenuItem(hm, IDM_WINDOW_VIS_0 + i,
2988 		               MF_BYCOMMAND | MF_ENABLED);
2989 	}
2990 
2991 	/* Menu "Window::Font" */
2992 	for (i = 0; i < MAX_TERM_DATA; i++)
2993 	{
2994 		EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i,
2995 		               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
2996 
2997 		if (data[i].visible)
2998 		{
2999 			EnableMenuItem(hm, IDM_WINDOW_FONT_0 + i,
3000 			               MF_BYCOMMAND | MF_ENABLED);
3001 		}
3002 	}
3003 
3004 	/* Menu "Window::Increase Tile Width" */
3005 	for (i = 0; i < MAX_TERM_DATA; i++)
3006 	{
3007 		EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i,
3008 		               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3009 
3010 		if (data[i].visible)
3011 		{
3012 			EnableMenuItem(hm, IDM_WINDOW_I_WID_0 + i,
3013 	    		           MF_BYCOMMAND | MF_ENABLED);
3014 
3015 		}
3016 	}
3017 
3018 	/* Menu "Window::Decrease Tile Width" */
3019 	for (i = 0; i < MAX_TERM_DATA; i++)
3020 	{
3021 		EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i,
3022 		               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3023 
3024 		if (data[i].visible)
3025 		{
3026 			EnableMenuItem(hm, IDM_WINDOW_D_WID_0 + i,
3027 	    		           MF_BYCOMMAND | MF_ENABLED);
3028 
3029 		}
3030 	}
3031 
3032 	/* Menu "Window::Increase Tile Height" */
3033 	for (i = 0; i < MAX_TERM_DATA; i++)
3034 	{
3035 		EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i,
3036 		               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3037 
3038 		if (data[i].visible)
3039 		{
3040 			EnableMenuItem(hm, IDM_WINDOW_I_HGT_0 + i,
3041 	    		           MF_BYCOMMAND | MF_ENABLED);
3042 
3043 		}
3044 	}
3045 
3046 	/* Menu "Window::Decrease Tile Height" */
3047 	for (i = 0; i < MAX_TERM_DATA; i++)
3048 	{
3049 		EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i,
3050 		               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3051 
3052 		if (data[i].visible)
3053 		{
3054 			EnableMenuItem(hm, IDM_WINDOW_D_HGT_0 + i,
3055 	    		           MF_BYCOMMAND | MF_ENABLED);
3056 
3057 		}
3058 	}
3059 
3060 	/* Menu "Options", disable all */
3061 	EnableMenuItem(hm, IDM_OPTIONS_GRAPHICS_NONE,
3062 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3063 	EnableMenuItem(hm, IDM_OPTIONS_GRAPHICS_OLD,
3064 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3065 	EnableMenuItem(hm, IDM_OPTIONS_GRAPHICS_ADAM,
3066 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3067 	EnableMenuItem(hm, IDM_OPTIONS_GRAPHICS_DAVID,
3068 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3069 	EnableMenuItem(hm, IDM_OPTIONS_BIGTILE,
3070 				   MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3071 	EnableMenuItem(hm, IDM_OPTIONS_SOUND,
3072 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3073 	EnableMenuItem(hm, IDM_OPTIONS_SAVER,
3074 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3075 	EnableMenuItem(hm, IDM_OPTIONS_LOW_PRIORITY,
3076 	               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3077 
3078 	/* Menu "Options", Item "Map" */
3079 	if (p_ptr->cmd.inkey_flag && initialized && (use_graphics != GRAPHICS_NONE))
3080 		EnableMenuItem(GetMenu(data[0].w), IDM_OPTIONS_MAP, MF_BYCOMMAND | MF_ENABLED);
3081 	else
3082 		EnableMenuItem(GetMenu(data[0].w), IDM_OPTIONS_MAP,
3083 		               MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
3084 
3085 
3086 	/* Menu "Options", update all */
3087 	CheckMenuItem(hm, IDM_OPTIONS_GRAPHICS_NONE,
3088 	              (arg_graphics == GRAPHICS_NONE ? MF_CHECKED : MF_UNCHECKED));
3089 	CheckMenuItem(hm, IDM_OPTIONS_GRAPHICS_OLD,
3090 	              (arg_graphics == GRAPHICS_ORIGINAL ? MF_CHECKED : MF_UNCHECKED));
3091 	CheckMenuItem(hm, IDM_OPTIONS_GRAPHICS_ADAM,
3092 	              (arg_graphics == GRAPHICS_ADAM_BOLT ? MF_CHECKED : MF_UNCHECKED));
3093 	CheckMenuItem(hm, IDM_OPTIONS_GRAPHICS_DAVID,
3094 	              (arg_graphics == GRAPHICS_DAVID_GERVAIS ? MF_CHECKED : MF_UNCHECKED));
3095 
3096 	CheckMenuItem(hm, IDM_OPTIONS_BIGTILE,
3097 	              (use_bigtile ? MF_CHECKED : MF_UNCHECKED));
3098 	CheckMenuItem(hm, IDM_OPTIONS_SOUND,
3099 	              (arg_sound ? MF_CHECKED : MF_UNCHECKED));
3100 #ifdef USE_SAVER
3101 	CheckMenuItem(hm, IDM_OPTIONS_SAVER,
3102 	              (hwndSaver ? MF_CHECKED : MF_UNCHECKED));
3103 #endif /* USE_SAVER */
3104 
3105 	CheckMenuItem(hm, IDM_OPTIONS_LOW_PRIORITY,
3106 	              (low_priority ? MF_CHECKED : MF_UNCHECKED));
3107 
3108 #ifdef USE_GRAPHICS
3109 	if (initialized && p_ptr->cmd.inkey_flag)
3110 	{
3111 		EnableMenuItem(hm, IDM_OPTIONS_GRAPHICS_NONE, MF_ENABLED);
3112 		EnableMenuItem(hm, IDM_OPTIONS_GRAPHICS_OLD, MF_ENABLED);
3113 		EnableMenuItem(hm, IDM_OPTIONS_GRAPHICS_ADAM, MF_ENABLED);
3114 		EnableMenuItem(hm, IDM_OPTIONS_GRAPHICS_DAVID, MF_ENABLED);
3115 		EnableMenuItem(hm, IDM_OPTIONS_BIGTILE, MF_ENABLED);
3116 	}
3117 #endif /* USE_GRAPHICS */
3118 
3119 #ifdef USE_SOUND
3120 	if (initialized && p_ptr->cmd.inkey_flag)
3121 	{
3122 		/* Menu "Options", Item "Sound" */
3123 		EnableMenuItem(hm, IDM_OPTIONS_SOUND, MF_ENABLED);
3124 	}
3125 #endif /* USE_SOUND */
3126 
3127 #ifdef USE_SAVER
3128 	/* Menu "Options", Item "ScreenSaver" */
3129 	EnableMenuItem(hm, IDM_OPTIONS_SAVER,
3130 	               MF_BYCOMMAND | MF_ENABLED);
3131 #endif /* USE_SAVER */
3132 
3133 	EnableMenuItem(hm, IDM_OPTIONS_LOW_PRIORITY,
3134 	               MF_BYCOMMAND | MF_ENABLED);
3135 }
3136 
3137 
3138 /*
3139  * Check for double clicked (or dragged) savefile
3140  *
3141  * Apparently, Windows copies the entire filename into the first
3142  * piece of the "command line string".  Perhaps we should extract
3143  * the "basename" of that filename and append it to the "save" dir.
3144  */
check_for_save_file(LPSTR cmd_line)3145 static void check_for_save_file(LPSTR cmd_line)
3146 {
3147 	char *s, *p;
3148 
3149 	/* First arg */
3150 	s = cmd_line;
3151 
3152 	/* No args */
3153 	if (!s || !*s) return;
3154 
3155 	/* Next arg */
3156 	p = strchr(s, ' ');
3157 
3158 	/* Tokenize */
3159 	if (p) *p = '\0';
3160 
3161 	/* Extract filename */
3162 	*savefile = '\0';
3163 	strncat(savefile, s, sizeof(savefile) - 1);
3164 
3165 	/* Validate the file */
3166 	validate_file(savefile);
3167 
3168 	/* Game in progress */
3169 	game_in_progress = TRUE;
3170 
3171 	Term_fresh();
3172 
3173 	/* Play game */
3174 	play_game(FALSE);
3175 
3176 	/* Quit */
3177 	quit(NULL);
3178 }
3179 
3180 
3181 #ifdef USE_SAVER
3182 
3183 #ifdef ALLOW_BORG
3184 
3185 /*
3186  * Hook into the inkey() function so that flushing keypresses
3187  * doesn't affect us.
3188  *
3189  * ToDo: Try to implement recording and playing back of games
3190  * by saving/reading the keypresses to/from a file. Note that
3191  * interrupting certain actions (resting, running, and other
3192  * repeated actions) would mess that up, so this would have to
3193  * be switched off when recording.
3194  */
3195 
3196 extern char (*inkey_hack)(int flush_first);
3197 
3198 static char screensaver_inkey_hack_buffer[1024];
3199 
screensaver_inkey_hack(int flush_first)3200 static char screensaver_inkey_hack(int flush_first)
3201 {
3202 	static int screensaver_inkey_hack_index = 0;
3203 
3204 	if (screensaver_inkey_hack_index < sizeof(screensaver_inkey_hack_buffer))
3205 		return (screensaver_inkey_hack_buffer[screensaver_inkey_hack_index++]);
3206 	else
3207 		return ESCAPE;
3208 }
3209 
3210 #endif /* ALLOW_BORG */
3211 
3212 
3213 /*
3214  * Start the screensaver
3215  */
start_screensaver(void)3216 static void start_screensaver(void)
3217 {
3218 	bool file_exists;
3219 
3220 #ifdef ALLOW_BORG
3221 	int i, j;
3222 #endif /* ALLOW_BORG */
3223 
3224 	/* Set the name for process_player_name() */
3225 	strnfmt(op_ptr->full_name, sizeof(op_ptr->full_name), "%s", saverfilename);
3226 
3227 	/* Set 'savefile' to a valid name */
3228 	process_player_name(TRUE);
3229 
3230 	/* Does the savefile already exist? */
3231 	file_exists = check_file(savefile);
3232 
3233 	/* Don't try to load a non-existant savefile */
3234 	if (!file_exists) savefile[0] = '\0';
3235 
3236 	/* Game in progress */
3237 	game_in_progress = TRUE;
3238 
3239 	Term_fresh();
3240 
3241 	/* Screensaver mode on */
3242 	SendMessage(data[0].w, WM_COMMAND, IDM_OPTIONS_SAVER, 0);
3243 
3244 	/* Low priority */
3245 	SendMessage(data[0].w, WM_COMMAND, IDM_OPTIONS_LOW_PRIORITY, 0);
3246 
3247 #ifdef ALLOW_BORG
3248 
3249 	/*
3250 	 * MegaHack - Try to start the Borg.
3251 	 *
3252 	 * The simulated keypresses will be processed when play_game()
3253 	 * is called.
3254 	 */
3255 
3256 	inkey_hack = screensaver_inkey_hack;
3257 	j = 0;
3258 
3259 	/*
3260 	 * If no savefile is present or then go through the steps necessary
3261 	 * to create a random character.  If a savefile already is present
3262 	 * then the simulated keypresses will either clean away any [-more-]
3263 	 * prompts (if the character is alive), or create a new random
3264 	 * character.
3265 	 *
3266 	 * Luckily it's possible to send the same keypresses no matter if
3267 	 * the character is alive, dead, or not even yet created.
3268 	 */
3269 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Gender */
3270 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Race */
3271 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Class */
3272 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Modify options */
3273 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Reroll */
3274 
3275 	if (!file_exists)
3276 	{
3277 		/* Savefile name */
3278 		int n = strlen(saverfilename);
3279 		for (i = 0; i < n; i++)
3280 			screensaver_inkey_hack_buffer[j++] = saverfilename[i];
3281 	}
3282 
3283 	screensaver_inkey_hack_buffer[j++] = '\r'; /* Return */
3284 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Character info */
3285 
3286 	/*
3287 	 * Make sure the "verify_special" options is off, so that we can
3288 	 * get into Borg mode without confirmation.
3289 	 */
3290 
3291 	screensaver_inkey_hack_buffer[j++] = '='; /* Enter options screen */
3292 	screensaver_inkey_hack_buffer[j++] = '2'; /* Disturbance options */
3293 
3294 	/* Cursor down to "verify_special" */
3295 	for (i = 0; i < 10; i++)
3296 		screensaver_inkey_hack_buffer[j++] = '2';
3297 
3298 	screensaver_inkey_hack_buffer[j++] = 'n'; /* Switch off "verify_special" */
3299 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Leave disturbance options */
3300 
3301 	/*
3302 	 * Make sure the "cheat_live" option is set, so that the Borg can
3303 	 * automatically restart.
3304 	 */
3305 
3306 	screensaver_inkey_hack_buffer[j++] = '6'; /* Cheat options */
3307 
3308 	/* Cursor down to "cheat live" */
3309 	for (i = 0; i < OPT_cheat_live - OPT_CHEAT; i++)
3310 		screensaver_inkey_hack_buffer[j++] = '2';
3311 
3312 	screensaver_inkey_hack_buffer[j++] = 'y'; /* Switch on "cheat_live" */
3313 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Leave cheat options */
3314 	screensaver_inkey_hack_buffer[j++] = ESCAPE; /* Leave options */
3315 
3316 	/*
3317 	 * Now start the Borg!
3318 	 */
3319 
3320 	screensaver_inkey_hack_buffer[j++] = KTRL('Z'); /* Enter borgmode */
3321 	screensaver_inkey_hack_buffer[j++] = 'z'; /* Run Borg */
3322 #endif /* ALLOW_BORG */
3323 
3324 	/* Play game */
3325 	play_game((bool)!file_exists);
3326 }
3327 
3328 #endif /* USE_SAVER */
3329 
3330 
3331 /*
3332  * Display a help file
3333  */
display_help(cptr filename)3334 static void display_help(cptr filename)
3335 {
3336 	char tmp[1024];
3337 
3338 	path_make(tmp, ANGBAND_DIR_XTRA_HELP, filename);
3339 
3340 	if (check_file(tmp))
3341 	{
3342 #ifdef HTML_HELP
3343 
3344 		HtmlHelp(data[0].w, tmp, HH_DISPLAY_TOPIC, 0);
3345 
3346 #else /* HTML_HELP */
3347 
3348 		char buf[1024];
3349 
3350 		strnfmt(buf, 1024, "winhelp.exe %s", tmp);
3351 		WinExec(buf, SW_NORMAL);
3352 
3353 #endif /* HTML_HELP */
3354 
3355 	}
3356 	else
3357 	{
3358 		plog_fmt("Cannot find help file: %s", tmp);
3359 		plog("Use the online help files instead.");
3360 	}
3361 }
3362 
3363 
3364 /*
3365  * Process a menu command
3366  */
process_menus(WORD wCmd)3367 static void process_menus(WORD wCmd)
3368 {
3369 	int i;
3370 
3371 	term_data *td;
3372 
3373 	OPENFILENAME ofn;
3374 
3375 	/* Analyze */
3376 	switch (wCmd)
3377 	{
3378 		/* New game */
3379 		case IDM_FILE_NEW:
3380 		{
3381 			if (!initialized)
3382 			{
3383 				plog("You cannot do that yet...");
3384 			}
3385 			else if (game_in_progress)
3386 			{
3387 				plog("You can't start a new game while you're still playing!");
3388 			}
3389 			else
3390 			{
3391 				game_in_progress = TRUE;
3392 				Term_flush();
3393 				play_game(TRUE);
3394 				quit(NULL);
3395 			}
3396 			break;
3397 		}
3398 
3399 		/* Open game */
3400 		case IDM_FILE_OPEN:
3401 		{
3402 			if (!initialized)
3403 			{
3404 				plog("You cannot do that yet...");
3405 			}
3406 			else if (game_in_progress)
3407 			{
3408 				plog("You can't open a new game while you're still playing!");
3409 			}
3410 			else
3411 			{
3412 				memset(&ofn, 0, sizeof(ofn));
3413 				ofn.lStructSize = sizeof(ofn);
3414 				ofn.hwndOwner = data[0].w;
3415 				ofn.lpstrFilter = "Save Files (*.)\0*\0";
3416 				ofn.nFilterIndex = 1;
3417 				ofn.lpstrFile = savefile;
3418 				ofn.nMaxFile = 1024;
3419 				ofn.lpstrInitialDir = ANGBAND_DIR_SAVE;
3420 				ofn.Flags = OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
3421 
3422 				if (GetOpenFileName(&ofn))
3423 				{
3424 					/* Load 'savefile' */
3425 					validate_file(savefile);
3426 					game_in_progress = TRUE;
3427 					Term_flush();
3428 					play_game(FALSE);
3429 					quit(NULL);
3430 				}
3431 			}
3432 			break;
3433 		}
3434 
3435 		/* Save game */
3436 		case IDM_FILE_SAVE:
3437 		{
3438 			if (game_in_progress && character_generated &&
3439 			    p_ptr->cmd.inkey_flag)
3440 			{
3441 				/* Hack -- Forget messages */
3442 				msg_flag = FALSE;
3443 
3444 				/* Save the game */
3445 #ifdef ZANGBAND
3446 				do_cmd_save_game(FALSE);
3447 #else /* ZANGBAND */
3448 				do_cmd_save_game();
3449 #endif /* ZANGBAND */
3450 			}
3451 			else
3452 			{
3453 				/* Paranoia */
3454 				plog("You may not do that right now.");
3455 			}
3456 			break;
3457 		}
3458 
3459 		/* Show scores */
3460 		case IDM_FILE_SCORE:
3461 		{
3462 			if (!initialized)
3463 			{
3464 				plog("You may not do that right now.");
3465 				break;
3466 			}
3467 
3468 			/* Show score */
3469 			ingame_score(&initialized, game_in_progress);
3470 
3471 			break;
3472 		}
3473 
3474 		/* Exit */
3475 		case IDM_FILE_EXIT:
3476 		{
3477 			if (game_in_progress && character_generated)
3478 			{
3479 				/* Paranoia */
3480 				if (!p_ptr->cmd.inkey_flag)
3481 				{
3482 					plog("You may not do that right now.");
3483 					break;
3484 				}
3485 
3486 				/* Hack -- Forget messages */
3487 				msg_flag = FALSE;
3488 
3489 				/* Save the game */
3490 #ifdef ZANGBAND
3491 				do_cmd_save_game(FALSE);
3492 #else /* ZANGBAND */
3493 				do_cmd_save_game();
3494 #endif /* ZANGBAND */
3495 			}
3496 			quit(NULL);
3497 			break;
3498 		}
3499 
3500 		case IDM_WINDOW_VIS_0:
3501 		{
3502 			plog("You are not allowed to do that!");
3503 
3504 			break;
3505 		}
3506 
3507 		/* Window visibility */
3508 		case IDM_WINDOW_VIS_1:
3509 		case IDM_WINDOW_VIS_2:
3510 		case IDM_WINDOW_VIS_3:
3511 		case IDM_WINDOW_VIS_4:
3512 		case IDM_WINDOW_VIS_5:
3513 		case IDM_WINDOW_VIS_6:
3514 		case IDM_WINDOW_VIS_7:
3515 		{
3516 			i = wCmd - IDM_WINDOW_VIS_0;
3517 
3518 			if ((i < 0) || (i >= MAX_TERM_DATA)) break;
3519 
3520 			td = &data[i];
3521 
3522 			if (!td->visible)
3523 			{
3524 				td->visible = TRUE;
3525 				ShowWindow(td->w, SW_SHOW);
3526 				term_data_redraw(td);
3527 			}
3528 			else
3529 			{
3530 				td->visible = FALSE;
3531 				ShowWindow(td->w, SW_HIDE);
3532 			}
3533 
3534 			break;
3535 		}
3536 
3537 		/* Window fonts */
3538 		case IDM_WINDOW_FONT_0:
3539 		case IDM_WINDOW_FONT_1:
3540 		case IDM_WINDOW_FONT_2:
3541 		case IDM_WINDOW_FONT_3:
3542 		case IDM_WINDOW_FONT_4:
3543 		case IDM_WINDOW_FONT_5:
3544 		case IDM_WINDOW_FONT_6:
3545 		case IDM_WINDOW_FONT_7:
3546 		{
3547 			i = wCmd - IDM_WINDOW_FONT_0;
3548 
3549 			if ((i < 0) || (i >= MAX_TERM_DATA)) break;
3550 
3551 			td = &data[i];
3552 
3553 			term_change_font(td);
3554 
3555 			break;
3556 		}
3557 
3558 		/* Increase Tile Width */
3559 		case IDM_WINDOW_I_WID_0:
3560 		case IDM_WINDOW_I_WID_1:
3561 		case IDM_WINDOW_I_WID_2:
3562 		case IDM_WINDOW_I_WID_3:
3563 		case IDM_WINDOW_I_WID_4:
3564 		case IDM_WINDOW_I_WID_5:
3565 		case IDM_WINDOW_I_WID_6:
3566 		case IDM_WINDOW_I_WID_7:
3567 		{
3568 			i = wCmd - IDM_WINDOW_I_WID_0;
3569 
3570 			if ((i < 0) || (i >= MAX_TERM_DATA)) break;
3571 
3572 			td = &data[i];
3573 
3574 			td->tile_wid += 1;
3575 
3576 			term_getsize(td);
3577 
3578 			term_window_resize(td);
3579 
3580 			break;
3581 		}
3582 
3583 		/* Decrease Tile Height */
3584 		case IDM_WINDOW_D_WID_0:
3585 		case IDM_WINDOW_D_WID_1:
3586 		case IDM_WINDOW_D_WID_2:
3587 		case IDM_WINDOW_D_WID_3:
3588 		case IDM_WINDOW_D_WID_4:
3589 		case IDM_WINDOW_D_WID_5:
3590 		case IDM_WINDOW_D_WID_6:
3591 		case IDM_WINDOW_D_WID_7:
3592 		{
3593 			i = wCmd - IDM_WINDOW_D_WID_0;
3594 
3595 			if ((i < 0) || (i >= MAX_TERM_DATA)) break;
3596 
3597 			td = &data[i];
3598 
3599 			td->tile_wid -= 1;
3600 
3601 			term_getsize(td);
3602 
3603 			term_window_resize(td);
3604 
3605 			break;
3606 		}
3607 
3608 		/* Increase Tile Height */
3609 		case IDM_WINDOW_I_HGT_0:
3610 		case IDM_WINDOW_I_HGT_1:
3611 		case IDM_WINDOW_I_HGT_2:
3612 		case IDM_WINDOW_I_HGT_3:
3613 		case IDM_WINDOW_I_HGT_4:
3614 		case IDM_WINDOW_I_HGT_5:
3615 		case IDM_WINDOW_I_HGT_6:
3616 		case IDM_WINDOW_I_HGT_7:
3617 		{
3618 			i = wCmd - IDM_WINDOW_I_HGT_0;
3619 
3620 			if ((i < 0) || (i >= MAX_TERM_DATA)) break;
3621 
3622 			td = &data[i];
3623 
3624 			td->tile_hgt += 1;
3625 
3626 			term_getsize(td);
3627 
3628 			term_window_resize(td);
3629 
3630 			break;
3631 		}
3632 
3633 		/* Decrease Tile Height */
3634 		case IDM_WINDOW_D_HGT_0:
3635 		case IDM_WINDOW_D_HGT_1:
3636 		case IDM_WINDOW_D_HGT_2:
3637 		case IDM_WINDOW_D_HGT_3:
3638 		case IDM_WINDOW_D_HGT_4:
3639 		case IDM_WINDOW_D_HGT_5:
3640 		case IDM_WINDOW_D_HGT_6:
3641 		case IDM_WINDOW_D_HGT_7:
3642 		{
3643 			i = wCmd - IDM_WINDOW_D_HGT_0;
3644 
3645 			if ((i < 0) || (i >= MAX_TERM_DATA)) break;
3646 
3647 			td = &data[i];
3648 
3649 			td->tile_hgt -= 1;
3650 
3651 			term_getsize(td);
3652 
3653 			term_window_resize(td);
3654 
3655 			break;
3656 		}
3657 
3658 		case IDM_OPTIONS_GRAPHICS_NONE:
3659 		{
3660 			/* Paranoia */
3661 			if (!p_ptr->cmd.inkey_flag || !initialized)
3662 			{
3663 				plog("You may not do that right now.");
3664 				break;
3665 			}
3666 
3667 			/* Toggle "arg_graphics" */
3668 			if (arg_graphics != GRAPHICS_NONE)
3669 			{
3670 				arg_graphics = GRAPHICS_NONE;
3671 
3672 				/* React to changes */
3673 				Term_xtra_win_react();
3674 
3675 				/* Hack -- Force redraw */
3676 				Term_key_push(KTRL('R'));
3677 			}
3678 
3679 			break;
3680 		}
3681 
3682 		case IDM_OPTIONS_GRAPHICS_OLD:
3683 		{
3684 			/* Paranoia */
3685 			if (!p_ptr->cmd.inkey_flag || !initialized)
3686 			{
3687 				plog("You may not do that right now.");
3688 				break;
3689 			}
3690 
3691 			/* Toggle "arg_graphics" */
3692 			if (arg_graphics != GRAPHICS_ORIGINAL)
3693 			{
3694 				arg_graphics = GRAPHICS_ORIGINAL;
3695 
3696 				/* React to changes */
3697 				Term_xtra_win_react();
3698 
3699 				/* Hack -- Force redraw */
3700 				Term_key_push(KTRL('R'));
3701 			}
3702 
3703 			break;
3704 		}
3705 
3706 		case IDM_OPTIONS_GRAPHICS_ADAM:
3707 		{
3708 			/* Paranoia */
3709 			if (!p_ptr->cmd.inkey_flag || !initialized)
3710 			{
3711 				plog("You may not do that right now.");
3712 				break;
3713 			}
3714 
3715 			/* Toggle "arg_graphics" */
3716 			if (arg_graphics != GRAPHICS_ADAM_BOLT)
3717 			{
3718 				arg_graphics = GRAPHICS_ADAM_BOLT;
3719 
3720 				/* React to changes */
3721 				Term_xtra_win_react();
3722 
3723 				/* Hack -- Force redraw */
3724 				Term_key_push(KTRL('R'));
3725 			}
3726 
3727 			break;
3728 		}
3729 
3730 		case IDM_OPTIONS_GRAPHICS_DAVID:
3731 		{
3732 			/* Paranoia */
3733 			if (!p_ptr->cmd.inkey_flag || !initialized)
3734 			{
3735 				plog("You may not do that right now.");
3736 				break;
3737 			}
3738 
3739 			/* Toggle "arg_graphics" */
3740 			if (arg_graphics != GRAPHICS_DAVID_GERVAIS)
3741 			{
3742 				arg_graphics = GRAPHICS_DAVID_GERVAIS;
3743 
3744 				/* React to changes */
3745 				Term_xtra_win_react();
3746 
3747 				/* Hack -- Force redraw */
3748 				Term_key_push(KTRL('R'));
3749 			}
3750 
3751 			break;
3752 		}
3753 
3754 		case IDM_OPTIONS_BIGTILE:
3755 		{
3756 			/* Paranoia */
3757 			if (!p_ptr->cmd.inkey_flag || !initialized)
3758 			{
3759 				plog("You may not do that right now.");
3760 				break;
3761 			}
3762 
3763 			/* Toggle "use_bigtile" */
3764 			toggle_bigtile();
3765 
3766 			break;
3767 		}
3768 
3769 
3770 		case IDM_OPTIONS_SOUND:
3771 		{
3772 			/* Paranoia */
3773 			if (!p_ptr->cmd.inkey_flag || !initialized)
3774 			{
3775 				plog("You may not do that right now.");
3776 				break;
3777 			}
3778 
3779 			/* Toggle "arg_sound" */
3780 			arg_sound = !arg_sound;
3781 
3782 			/* React to changes */
3783 			Term_xtra_win_react();
3784 
3785 			/* Hack -- Force redraw */
3786 			Term_key_push(KTRL('R'));
3787 
3788 			break;
3789 		}
3790 
3791 #ifdef USE_SAVER
3792 
3793 		case IDM_OPTIONS_SAVER:
3794 		{
3795 			if (hwndSaver)
3796 			{
3797 				DestroyWindow(hwndSaver);
3798 				hwndSaver = NULL;
3799 				screensaver_active = FALSE;
3800 
3801 				/* Switch main menu back on */
3802 				SetMenu(data[0].w, main_menu);
3803 
3804 				for (i = MAX_TERM_DATA - 1; i >= 0; --i)
3805 				{
3806 					td = &data[i];
3807 
3808 					if (td->visible)
3809 					{
3810 						/* Turn the Windows back to normal */
3811 						SetWindowLong(td->w, GWL_STYLE, td->dwStyle);
3812 
3813 						/* Push the window to the top */
3814 						SetWindowPos(td->w, HWND_NOTOPMOST, 0, 0, 0, 0,
3815 							   SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
3816 					}
3817 				}
3818 
3819 				ShowCursor(TRUE);
3820 			}
3821 			else
3822 			{
3823 				/* Create a screen saver window */
3824 				hwndSaver = CreateWindowEx(WS_EX_TOPMOST, "WindowsScreenSaverClass",
3825 				                           "Angband Screensaver",
3826 				                           WS_POPUP | WS_MAXIMIZE | WS_VISIBLE,
3827 				                           0, 0, GetSystemMetrics(SM_CXSCREEN),
3828 				                           GetSystemMetrics(SM_CYSCREEN),
3829 				                           NULL, NULL, hInstance, NULL);
3830 
3831 				if (hwndSaver)
3832 				{
3833 					for (i = MAX_TERM_DATA - 1; i >= 0; --i)
3834 					{
3835 						td = &data[i];
3836 
3837 						if (td->visible)
3838 						{
3839 							/* Switch off border and titlebar */
3840 							SetWindowLong(td->w, GWL_STYLE, WS_VISIBLE);
3841 
3842 							/* Switch off menu */
3843 							SetMenu(td->w, NULL);
3844 
3845 							/* Push the window to the top */
3846 							SetWindowPos(td->w, HWND_TOPMOST, 0, 0, 0, 0,
3847 								   SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
3848 						}
3849 					}
3850 
3851 					ShowCursor(FALSE);
3852 
3853 					screensaver_active = TRUE;
3854 				}
3855 				else
3856 				{
3857 					plog("Failed to create saver window");
3858 				}
3859 			}
3860 
3861 			break;
3862 		}
3863 
3864 #endif /* USE_SAVER */
3865 
3866 		case IDM_OPTIONS_LOW_PRIORITY:
3867 		{
3868 			/* Lower or reset the priority of the current process */
3869 			if (low_priority)
3870 				SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
3871 			else
3872 				SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
3873 
3874 			/* Toggle priority */
3875 			low_priority = !low_priority;
3876 
3877 			break;
3878 		}
3879 
3880 		case IDM_OPTIONS_MAP:
3881 		{
3882 			/* Paranoia */
3883 			if (!p_ptr->cmd.inkey_flag || !initialized)
3884 			{
3885 				plog("You may not do that right now.");
3886 				break;
3887 			}
3888 
3889 			windows_map();
3890 			break;
3891 		}
3892 
3893 		case IDM_HELP_GENERAL:
3894 		{
3895 			display_help(HELP_GENERAL);
3896 			break;
3897 		}
3898 
3899 		case IDM_HELP_SPOILERS:
3900 		{
3901 			display_help(HELP_SPOILERS);
3902 			break;
3903 		}
3904 	}
3905 }
3906 
3907 
3908 /*
3909  * Redraw a section of a window
3910  */
handle_wm_paint(HWND hWnd)3911 static void handle_wm_paint(HWND hWnd)
3912 {
3913 	int x1, y1, x2, y2;
3914 	PAINTSTRUCT ps;
3915 	term_data *td;
3916 
3917 	/* Acquire proper "term_data" info */
3918 	td = (term_data *)GetWindowLong(hWnd, 0);
3919 
3920 	BeginPaint(hWnd, &ps);
3921 
3922 	if (td->map_active)
3923 	{
3924 		/* Redraw the map */
3925 		/* ToDo: Only redraw the necessary parts */
3926 		windows_map_aux();
3927 	}
3928 	else
3929 	{
3930 		/* Get the area that should be updated (rounding up/down) */
3931 		/* ToDo: Take the window borders into account */
3932 		x1 = (ps.rcPaint.left / td->tile_wid) - 1;
3933 		x2 = (ps.rcPaint.right / td->tile_wid) + 1;
3934 		y1 = (ps.rcPaint.top / td->tile_hgt) - 1;
3935 		y2 = (ps.rcPaint.bottom / td->tile_hgt) + 1;
3936 
3937 		/* Redraw */
3938 		if (td) term_data_redraw_section(td, x1, y1, x2, y2);
3939 	}
3940 
3941 	EndPaint(hWnd, &ps);
3942 }
3943 
3944 
AngbandWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)3945 static LRESULT FAR PASCAL AngbandWndProc(HWND hWnd, UINT uMsg,
3946                                           WPARAM wParam, LPARAM lParam)
3947 {
3948 	HDC hdc;
3949 	term_data *td;
3950 	int i;
3951 
3952 #ifdef USE_SAVER
3953 	static int iMouse = 0;
3954 	static WORD xMouse = 0;
3955 	static WORD yMouse = 0;
3956 
3957 	int dx, dy;
3958 #endif /* USE_SAVER */
3959 
3960 	/* Acquire proper "term_data" info */
3961 	td = (term_data *)GetWindowLong(hWnd, 0);
3962 
3963 	/* Handle message */
3964 	switch (uMsg)
3965 	{
3966 		/* XXX XXX XXX */
3967 		case WM_NCCREATE:
3968 		{
3969 			SetWindowLong(hWnd, 0, (LONG)(my_td));
3970 			break;
3971 		}
3972 
3973 		/* XXX XXX XXX */
3974 		case WM_CREATE:
3975 		{
3976 			return 0;
3977 		}
3978 
3979 		case WM_GETMINMAXINFO:
3980 		{
3981 			MINMAXINFO FAR *lpmmi;
3982 			RECT rc;
3983 
3984 			lpmmi = (MINMAXINFO FAR *)lParam;
3985 
3986 			/* this message was sent before WM_NCCREATE */
3987 			if (!td) return 1;
3988 
3989 			/* Minimum window size is 80x24 */
3990 			rc.left = rc.top = 0;
3991 			rc.right = rc.left + 80 * td->tile_wid + td->size_ow1 + td->size_ow2;
3992 			rc.bottom = rc.top + 24 * td->tile_hgt + td->size_oh1 + td->size_oh2 + 1;
3993 
3994 			/* Adjust */
3995 			AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
3996 
3997 			/* Save minimum size */
3998 			lpmmi->ptMinTrackSize.x = rc.right - rc.left;
3999 			lpmmi->ptMinTrackSize.y = rc.bottom - rc.top;
4000 
4001 			return 0;
4002 		}
4003 
4004 		case WM_PAINT:
4005 		{
4006 			handle_wm_paint(hWnd);
4007 
4008 			return 0;
4009 		}
4010 
4011 		case WM_SYSKEYDOWN:
4012 		case WM_KEYDOWN:
4013 		{
4014 			bool mc = FALSE;
4015 			bool ms = FALSE;
4016 			bool ma = FALSE;
4017 
4018 #ifdef USE_SAVER
4019 			if (screensaver_active)
4020 			{
4021 				stop_screensaver();
4022 				return 0;
4023 			}
4024 #endif /* USE_SAVER */
4025 
4026 			/* Extract the modifiers */
4027 			if (GetKeyState(VK_CONTROL) & 0x8000) mc = TRUE;
4028 			if (GetKeyState(VK_SHIFT)   & 0x8000) ms = TRUE;
4029 			if (GetKeyState(VK_MENU)    & 0x8000) ma = TRUE;
4030 
4031 			/* Handle "special" keys */
4032 			if (special_key[(byte)(wParam)])
4033 			{
4034 				/* Begin the macro trigger */
4035 				Term_keypress(31);
4036 
4037 				/* Send the modifiers */
4038 				if (mc) Term_keypress('C');
4039 				if (ms) Term_keypress('S');
4040 				if (ma) Term_keypress('A');
4041 
4042 				/* Extract "scan code" */
4043 				i = LOBYTE(HIWORD(lParam));
4044 
4045 				/* Introduce the scan code */
4046 				Term_keypress('x');
4047 
4048 				/* Encode the hexidecimal scan code */
4049 				Term_keypress(hexsym[i/16]);
4050 				Term_keypress(hexsym[i%16]);
4051 
4052 				/* End the macro trigger */
4053 				Term_keypress(13);
4054 
4055 				return 0;
4056 			}
4057 
4058 			break;
4059 		}
4060 
4061 		case WM_CHAR:
4062 		{
4063 			Term_keypress(wParam);
4064 			return 0;
4065 		}
4066 
4067 #ifdef USE_SAVER
4068 
4069 		case WM_MBUTTONDOWN:
4070 		case WM_RBUTTONDOWN:
4071 		case WM_LBUTTONDOWN:
4072 		{
4073 			if (screensaver_active)
4074 			{
4075 				stop_screensaver();
4076 				return 0;
4077 			}
4078 
4079 			break;
4080 		}
4081 
4082 		case WM_MOUSEMOVE:
4083 		{
4084 			if (!screensaver_active) break;
4085 
4086 			if (iMouse)
4087 			{
4088 				dx = LOWORD(lParam) - xMouse;
4089 				dy = HIWORD(lParam) - yMouse;
4090 
4091 				if (dx < 0) dx = -dx;
4092 				if (dy < 0) dy = -dy;
4093 
4094 				if ((dx > MOUSE_SENS) || (dy > MOUSE_SENS))
4095 				{
4096 					stop_screensaver();
4097 				}
4098 			}
4099 
4100 			/* Save last location */
4101 			iMouse = 1;
4102 			xMouse = LOWORD(lParam);
4103 			yMouse = HIWORD(lParam);
4104 
4105 			return 0;
4106 		}
4107 #endif /* USE_SAVER */
4108 
4109 		case WM_INITMENU:
4110 		{
4111 			setup_menus();
4112 			return 0;
4113 		}
4114 
4115 		case WM_CLOSE:
4116 		{
4117 			if (game_in_progress && character_generated)
4118 			{
4119 				if (!p_ptr->cmd.inkey_flag)
4120 				{
4121 					plog("You may not do that right now.");
4122 					return 0;
4123 				}
4124 
4125 				/* Hack -- Forget messages */
4126 				msg_flag = FALSE;
4127 
4128 				/* Save the game */
4129 #ifdef ZANGBAND
4130 				do_cmd_save_game(FALSE);
4131 #else /* ZANGBAND */
4132 				do_cmd_save_game();
4133 #endif /* ZANGBAND */
4134 			}
4135 			quit(NULL);
4136 			return 0;
4137 		}
4138 
4139 		case WM_QUIT:
4140 		{
4141 			quit(NULL);
4142 			return 0;
4143 		}
4144 
4145 		case WM_COMMAND:
4146 		{
4147 			process_menus(LOWORD(wParam));
4148 			return 0;
4149 		}
4150 
4151 		case WM_SIZE:
4152 		{
4153 			/* this message was sent before WM_NCCREATE */
4154 			if (!td) return 1;
4155 
4156 			/* it was sent from inside CreateWindowEx */
4157 			if (!td->w) return 1;
4158 
4159 			/* was sent from WM_SIZE */
4160 			if (td->size_hack) return 1;
4161 
4162 			switch (wParam)
4163 			{
4164 				case SIZE_MINIMIZED:
4165 				{
4166 					/* Hide sub-windows */
4167 					for (i = 1; i < MAX_TERM_DATA; i++)
4168 					{
4169 						if (data[i].visible) ShowWindow(data[i].w, SW_HIDE);
4170 					}
4171 					return 0;
4172 				}
4173 
4174 				case SIZE_MAXIMIZED:
4175 				{
4176 					/* fall through XXX XXX XXX */
4177 				}
4178 
4179 				case SIZE_RESTORED:
4180 				{
4181 					int cols = (LOWORD(lParam) - td->size_ow1) / td->tile_wid;
4182 					int rows = (HIWORD(lParam) - td->size_oh1) / td->tile_hgt;
4183 
4184 					/* New size */
4185 					if ((td->cols != cols) || (td->rows != rows))
4186 					{
4187 						/* Save the new size */
4188 						td->cols = cols;
4189 						td->rows = rows;
4190 
4191 						/* Activate */
4192 						Term_activate(&td->t);
4193 
4194 						/* Resize the term */
4195 						Term_resize(td->cols, td->rows);
4196 
4197 						/* Redraw later */
4198 						InvalidateRect(td->w, NULL, TRUE);
4199 					}
4200 
4201 					td->size_hack = TRUE;
4202 
4203 					/* Show sub-windows */
4204 					for (i = 1; i < MAX_TERM_DATA; i++)
4205 					{
4206 						if (data[i].visible) ShowWindow(data[i].w, SW_SHOW);
4207 					}
4208 
4209 					td->size_hack = FALSE;
4210 
4211 					return 0;
4212 				}
4213 			}
4214 			break;
4215 		}
4216 
4217 		case WM_PALETTECHANGED:
4218 		{
4219 			/* Ignore if palette change caused by itself */
4220 			if ((HWND)wParam == hWnd) return 0;
4221 
4222 			/* Fall through... */
4223 		}
4224 
4225 		case WM_QUERYNEWPALETTE:
4226 		{
4227 			if (!paletted) return 0;
4228 
4229 			hdc = GetDC(hWnd);
4230 
4231 			SelectPalette(hdc, hPal, FALSE);
4232 
4233 			i = RealizePalette(hdc);
4234 
4235 			/* if any palette entries changed, repaint the window. */
4236 			if (i) InvalidateRect(hWnd, NULL, TRUE);
4237 
4238 			ReleaseDC(hWnd, hdc);
4239 
4240 			return 0;
4241 		}
4242 
4243 		case WM_ACTIVATE:
4244 		{
4245 			if (wParam && !HIWORD(lParam))
4246 			{
4247 				/* Do something to sub-windows */
4248 				for (i = 1; i < MAX_TERM_DATA; i++)
4249 				{
4250 					SetWindowPos(data[i].w, hWnd, 0, 0, 0, 0,
4251 					             SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
4252 				}
4253 
4254 				/* Focus on main window */
4255 				SetFocus(hWnd);
4256 
4257 				return 0;
4258 			}
4259 
4260 			break;
4261 		}
4262 	}
4263 
4264 	return DefWindowProc(hWnd, uMsg, wParam, lParam);
4265 }
4266 
4267 
AngbandListProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)4268 static LRESULT FAR PASCAL AngbandListProc(HWND hWnd, UINT uMsg,
4269                                            WPARAM wParam, LPARAM lParam)
4270 {
4271 	term_data *td;
4272 	HDC hdc;
4273 	int i;
4274 
4275 #ifdef USE_SAVER
4276 	static int iMouse = 0;
4277 	static WORD xMouse = 0;
4278 	static WORD yMouse = 0;
4279 
4280 	int dx, dy;
4281 #endif /* USE_SAVER */
4282 
4283 
4284 	/* Acquire proper "term_data" info */
4285 	td = (term_data *)GetWindowLong(hWnd, 0);
4286 
4287 	/* Process message */
4288 	switch (uMsg)
4289 	{
4290 		/* XXX XXX XXX */
4291 		case WM_NCCREATE:
4292 		{
4293 			SetWindowLong(hWnd, 0, (LONG)(my_td));
4294 			break;
4295 		}
4296 
4297 		/* XXX XXX XXX */
4298 		case WM_CREATE:
4299 		{
4300 			return 0;
4301 		}
4302 
4303 		case WM_GETMINMAXINFO:
4304 		{
4305 #if 0
4306 			MINMAXINFO FAR *lpmmi;
4307 			RECT rc;
4308 
4309 			/* this message was sent before WM_NCCREATE */
4310 			if (!td) return 1;
4311 
4312 			lpmmi = (MINMAXINFO FAR *)lParam;
4313 
4314 			/* Minimum size */
4315 			rc.left = rc.top = 0;
4316 			rc.right = rc.left + 8 * td->tile_wid + td->size_ow1 + td->size_ow2;
4317 			rc.bottom = rc.top + 2 * td->tile_hgt + td->size_oh1 + td->size_oh2;
4318 
4319 			/* Adjust */
4320 			AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
4321 
4322 			/* Save the minimum size */
4323 			lpmmi->ptMinTrackSize.x = rc.right - rc.left;
4324 			lpmmi->ptMinTrackSize.y = rc.bottom - rc.top;
4325 
4326 			/* Maximum window size */
4327 			rc.left = rc.top = 0;
4328 			rc.right = rc.left + 80 * td->tile_wid + td->size_ow1 + td->size_ow2;
4329 			rc.bottom = rc.top + 24 * td->tile_hgt + td->size_oh1 + td->size_oh2;
4330 
4331 			/* Paranoia */
4332 			rc.right += (td->tile_wid - 1);
4333 			rc.bottom += (td->tile_hgt - 1);
4334 
4335 			/* Adjust */
4336 			AdjustWindowRectEx(&rc, td->dwStyle, TRUE, td->dwExStyle);
4337 
4338 			/* Save maximum size */
4339 			lpmmi->ptMaxSize.x = rc.right - rc.left;
4340 			lpmmi->ptMaxSize.y = rc.bottom - rc.top;
4341 
4342 			/* Save the maximum size */
4343 			lpmmi->ptMaxTrackSize.x = rc.right - rc.left;
4344 			lpmmi->ptMaxTrackSize.y = rc.bottom - rc.top;
4345 #endif /* 0 */
4346 			return 0;
4347 		}
4348 
4349 		case WM_SIZE:
4350 		{
4351 			int cols;
4352 			int rows;
4353 
4354 			/* this message was sent before WM_NCCREATE */
4355 			if (!td) return 1;
4356 
4357 			/* it was sent from inside CreateWindowEx */
4358 			if (!td->w) return 1;
4359 
4360 			/* was sent from inside WM_SIZE */
4361 			if (td->size_hack) return 1;
4362 
4363 			td->size_hack = TRUE;
4364 
4365 			cols = (LOWORD(lParam) - td->size_ow1) / td->tile_wid;
4366 			rows = (HIWORD(lParam) - td->size_oh1) / td->tile_hgt;
4367 
4368 			/* New size */
4369 			if ((td->cols != cols) || (td->rows != rows))
4370 			{
4371 				/* Save old term */
4372 				term *old_term = Term;
4373 
4374 				/* Save the new size */
4375 				td->cols = cols;
4376 				td->rows = rows;
4377 
4378 				/* Activate */
4379 				Term_activate(&td->t);
4380 
4381 				/* Resize the term */
4382 				Term_resize(td->cols, td->rows);
4383 
4384 				/* Activate */
4385 				Term_activate(old_term);
4386 
4387 				/* Redraw later */
4388 				InvalidateRect(td->w, NULL, TRUE);
4389 
4390 				/* HACK - Redraw all windows */
4391 				p_ptr->window = 0xFFFFFFFF;
4392 				window_stuff();
4393 			}
4394 
4395 			td->size_hack = FALSE;
4396 
4397 			return 0;
4398 		}
4399 
4400 		case WM_PAINT:
4401 		{
4402 			handle_wm_paint(hWnd);
4403 
4404 			return 0;
4405 		}
4406 
4407 		case WM_SYSKEYDOWN:
4408 		case WM_KEYDOWN:
4409 		{
4410 			bool mc = FALSE;
4411 			bool ms = FALSE;
4412 			bool ma = FALSE;
4413 
4414 #ifdef USE_SAVER
4415 			if (screensaver_active)
4416 			{
4417 				stop_screensaver();
4418 				return 0;
4419 			}
4420 #endif /* USE_SAVER */
4421 
4422 			/* Extract the modifiers */
4423 			if (GetKeyState(VK_CONTROL) & 0x8000) mc = TRUE;
4424 			if (GetKeyState(VK_SHIFT)   & 0x8000) ms = TRUE;
4425 			if (GetKeyState(VK_MENU)    & 0x8000) ma = TRUE;
4426 
4427 			/* Handle "special" keys */
4428 			if (special_key[(byte)(wParam)])
4429 			{
4430 				/* Begin the macro trigger */
4431 				Term_keypress(31);
4432 
4433 				/* Send the modifiers */
4434 				if (mc) Term_keypress('C');
4435 				if (ms) Term_keypress('S');
4436 				if (ma) Term_keypress('A');
4437 
4438 				/* Extract "scan code" */
4439 				i = LOBYTE(HIWORD(lParam));
4440 
4441 				/* Introduce the scan code */
4442 				Term_keypress('x');
4443 
4444 				/* Encode the hexidecimal scan code */
4445 				Term_keypress(hexsym[i/16]);
4446 				Term_keypress(hexsym[i%16]);
4447 
4448 				/* End the macro trigger */
4449 				Term_keypress(13);
4450 
4451 				return 0;
4452 			}
4453 
4454 			break;
4455 		}
4456 
4457 		case WM_CHAR:
4458 		{
4459 			Term_keypress(wParam);
4460 			return 0;
4461 		}
4462 
4463 #ifdef USE_SAVER
4464 
4465 		case WM_MBUTTONDOWN:
4466 		case WM_RBUTTONDOWN:
4467 		case WM_LBUTTONDOWN:
4468 		{
4469 			if (screensaver_active)
4470 			{
4471 				stop_screensaver();
4472 				return 0;
4473 			}
4474 
4475 			break;
4476 		}
4477 
4478 		case WM_MOUSEMOVE:
4479 		{
4480 			if (!screensaver_active) break;
4481 
4482 			if (iMouse)
4483 			{
4484 				dx = LOWORD(lParam) - xMouse;
4485 				dy = HIWORD(lParam) - yMouse;
4486 
4487 				if (dx < 0) dx = -dx;
4488 				if (dy < 0) dy = -dy;
4489 
4490 				if ((dx > MOUSE_SENS) || (dy > MOUSE_SENS))
4491 				{
4492 					stop_screensaver();
4493 				}
4494 			}
4495 
4496 			/* Save last location */
4497 			iMouse = 1;
4498 			xMouse = LOWORD(lParam);
4499 			yMouse = HIWORD(lParam);
4500 
4501 			return 0;
4502 		}
4503 #endif /* USE_SAVER */
4504 
4505 		case WM_PALETTECHANGED:
4506 		{
4507 			/* ignore if palette change caused by itself */
4508 			if ((HWND)wParam == hWnd) return FALSE;
4509 			/* otherwise, fall through!!! */
4510 		}
4511 
4512 		case WM_QUERYNEWPALETTE:
4513 		{
4514 			if (!paletted) return 0;
4515 			hdc = GetDC(hWnd);
4516 			SelectPalette(hdc, hPal, FALSE);
4517 			i = RealizePalette(hdc);
4518 			/* if any palette entries changed, repaint the window. */
4519 			if (i) InvalidateRect(hWnd, NULL, TRUE);
4520 			ReleaseDC(hWnd, hdc);
4521 			return 0;
4522 		}
4523 
4524 		case WM_NCLBUTTONDOWN:
4525 		{
4526 
4527 #ifdef HTCLOSE
4528 			if (wParam == HTCLOSE) wParam = HTSYSMENU;
4529 #endif /* HTCLOSE */
4530 
4531 			if (wParam == HTSYSMENU)
4532 			{
4533 				if (td->visible)
4534 				{
4535 					td->visible = FALSE;
4536 					ShowWindow(td->w, SW_HIDE);
4537 				}
4538 
4539 				return 0;
4540 			}
4541 
4542 			break;
4543 		}
4544 	}
4545 
4546 	return DefWindowProc(hWnd, uMsg, wParam, lParam);
4547 }
4548 
4549 
4550 #ifdef USE_SAVER
4551 
AngbandSaverProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)4552 LRESULT FAR PASCAL AngbandSaverProc(HWND hWnd, UINT uMsg,
4553                                             WPARAM wParam, LPARAM lParam)
4554 {
4555 	static int iMouse = 0;
4556 	static WORD xMouse = 0;
4557 	static WORD yMouse = 0;
4558 
4559 	int dx, dy;
4560 
4561 
4562 	/* Process */
4563 	switch (uMsg)
4564 	{
4565 		/* XXX XXX XXX */
4566 		case WM_NCCREATE:
4567 		{
4568 			break;
4569 		}
4570 
4571 		case WM_SETCURSOR:
4572 		{
4573 			SetCursor(NULL);
4574 			return 0;
4575 		}
4576 
4577 #if 0
4578 		case WM_ACTIVATE:
4579 		{
4580 			if (LOWORD(wParam) == WA_INACTIVE) break;
4581 
4582 			/* else fall through */
4583 		}
4584 #endif /* 0 */
4585 
4586 		case WM_LBUTTONDOWN:
4587 		case WM_MBUTTONDOWN:
4588 		case WM_RBUTTONDOWN:
4589 		case WM_KEYDOWN:
4590 		{
4591 			stop_screensaver();
4592 			return 0;
4593 		}
4594 
4595 		case WM_MOUSEMOVE:
4596 		{
4597 			if (iMouse)
4598 			{
4599 				dx = LOWORD(lParam) - xMouse;
4600 				dy = HIWORD(lParam) - yMouse;
4601 
4602 				if (dx < 0) dx = -dx;
4603 				if (dy < 0) dy = -dy;
4604 
4605 				if ((dx > MOUSE_SENS) || (dy > MOUSE_SENS))
4606 				{
4607 					stop_screensaver();
4608 				}
4609 			}
4610 
4611 			/* Save last location */
4612 			iMouse = 1;
4613 			xMouse = LOWORD(lParam);
4614 			yMouse = HIWORD(lParam);
4615 
4616 			return 0;
4617 		}
4618 
4619 		case WM_CLOSE:
4620 		{
4621 			DestroyWindow(hwndSaver);
4622 			if (screensaver)
4623 				SendMessage(data[0].w, WM_CLOSE, 0, 0);
4624 			hwndSaver = NULL;
4625 			return 0;
4626 		}
4627 	}
4628 
4629 	/* Oops */
4630 	return DefWindowProc(hWnd, uMsg, wParam, lParam);
4631 }
4632 
4633 #endif /* USE_SAVER */
4634 
4635 
4636 
4637 
4638 
4639 /*** Temporary Hooks ***/
4640 
4641 
4642 /*
4643  * Display warning message (see "z-util.c")
4644  */
hack_plog(cptr str)4645 static void hack_plog(cptr str)
4646 {
4647 	/* Give a warning */
4648 	if (str)
4649 	{
4650 		MessageBox(NULL, str, "Warning",
4651 		           MB_ICONEXCLAMATION | MB_OK);
4652 	}
4653 }
4654 
4655 
4656 /*
4657  * Display error message and quit (see "z-util.c")
4658  */
hack_quit(cptr str)4659 static void hack_quit(cptr str)
4660 {
4661 	/* Give a warning */
4662 	if (str)
4663 	{
4664 		MessageBox(NULL, str, "Error",
4665 		           MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
4666 	}
4667 
4668 	/* Unregister the classes */
4669 	UnregisterClass(AppName, hInstance);
4670 
4671 	/* Destroy the icon */
4672 	if (hIcon) DestroyIcon(hIcon);
4673 
4674 #ifdef USE_SAVER
4675 	if (screensaverSemaphore) CloseHandle(screensaverSemaphore);
4676 #endif /* USE_SAVER */
4677 
4678 	/* Exit */
4679 	exit(0);
4680 }
4681 
4682 
4683 
4684 /*** Various hooks ***/
4685 
4686 
4687 /*
4688  * Display warning message (see "z-util.c")
4689  */
hook_plog(cptr str)4690 static void hook_plog(cptr str)
4691 {
4692 #ifdef USE_SAVER
4693 	if (screensaver_active) return;
4694 #endif /* USE_SAVER */
4695 
4696 	/* Warning */
4697 	if (str)
4698 	{
4699 		MessageBox(data[0].w, str, "Warning",
4700 		           MB_ICONEXCLAMATION | MB_OK);
4701 	}
4702 }
4703 
4704 
4705 /*
4706  * Display error message and quit (see "z-util.c")
4707  */
hook_quit(cptr str)4708 static void hook_quit(cptr str)
4709 {
4710 	int i;
4711 
4712 #ifdef USE_SOUND
4713 	int j;
4714 #endif /* USE_SOUND */
4715 
4716 
4717 
4718 #ifdef USE_SAVER
4719 	if (!screensaver_active)
4720 #endif /* USE_SAVER */
4721 	{
4722 		/* Give a warning */
4723 		if (str)
4724 		{
4725 			MessageBox(data[0].w, str, "Error",
4726 			           MB_ICONEXCLAMATION | MB_OK | MB_ICONSTOP);
4727 		}
4728 
4729 		/* Save the preferences */
4730 		save_prefs();
4731 	}
4732 
4733 	/*** Could use 'Term_nuke_win()' XXX XXX XXX */
4734 
4735 	/* Destroy all windows */
4736 	for (i = MAX_TERM_DATA - 1; i >= 0; --i)
4737 	{
4738 		term_force_font(&data[i], NULL);
4739 		if (data[i].font_want) string_free(data[i].font_want);
4740 		if (data[i].w) DestroyWindow(data[i].w);
4741 		data[i].w = 0;
4742 
4743 		term_nuke(&data[i].t);
4744 	}
4745 
4746 #ifdef USE_GRAPHICS
4747 	/* Free the bitmap stuff */
4748 	FreeDIB(&infGraph);
4749 	FreeDIB(&infMask);
4750 #endif /* USE_GRAPHICS */
4751 
4752 #ifdef USE_SOUND
4753 	/* Free the sound names */
4754 	for (i = 0; i < SOUND_MAX; i++)
4755 	{
4756 		for (j = 0; j < SAMPLE_MAX; j++)
4757 		{
4758 			if (!sound_file[i][j]) break;
4759 
4760 			string_free(sound_file[i][j]);
4761 		}
4762 	}
4763 #endif /* USE_SOUND */
4764 
4765 	/*** Free some other stuff ***/
4766 
4767 	DeleteObject(hbrYellow);
4768 
4769 	if (hPal) DeleteObject(hPal);
4770 
4771 	UnregisterClass(AppName, hInstance);
4772 
4773 	if (hIcon) DestroyIcon(hIcon);
4774 
4775 	/* Free strings */
4776 	string_free(ini_file);
4777 	string_free(argv0);
4778 	string_free(ANGBAND_DIR_XTRA_FONT);
4779 	string_free(ANGBAND_DIR_XTRA_GRAF);
4780 	string_free(ANGBAND_DIR_XTRA_SOUND);
4781 	string_free(ANGBAND_DIR_XTRA_HELP);
4782 
4783 #ifdef USE_MUSIC
4784 	string_free(ANGBAND_DIR_XTRA_MUSIC);
4785 #endif /* USE_MUSIC */
4786 
4787 #ifdef HAS_CLEANUP
4788 	cleanup_angband();
4789 #endif /* HAS_CLEANUP */
4790 
4791 	exit(0);
4792 }
4793 
4794 
4795 
4796 /*** Initialize ***/
4797 
4798 
4799 /*
4800  * Init some stuff
4801  */
init_stuff(void)4802 static void init_stuff(void)
4803 {
4804 	int i;
4805 
4806 	char path[1024];
4807 #ifdef USE_SAVER
4808 	char tmp[1024];
4809 #endif /* USE_SAVER */
4810 
4811 	/* Get program name with full path */
4812 	if (GetModuleFileName(hInstance, path, sizeof(path)) == 0)
4813 		show_win_error();
4814 
4815 	/* Paranoia */
4816 	path[sizeof(path) - 1] = '\0';
4817 
4818 	/* Save the "program name" */
4819 	argv0 = string_make(path);
4820 
4821 	/* Get the name of the "*.ini" file */
4822 	strcpy(path + strlen(path) - 4, ".INI");
4823 
4824 #ifdef USE_SAVER
4825 
4826 	/* Try to get the path to the Angband folder */
4827 	if (screensaver)
4828 	{
4829 		/* Extract the filename of the savefile for the screensaver */
4830 		GetPrivateProfileString("Angband", "SaverFile", "", saverfilename, sizeof(saverfilename), path);
4831 
4832 		GetPrivateProfileString("Angband", "AngbandPath", "", tmp, sizeof(tmp), path);
4833 
4834 		strnmt(path, sizeof(path), "%szangband.ini", tmp);
4835 	}
4836 
4837 #endif /* USE_SAVER */
4838 
4839 	/* Save the the name of the ini-file */
4840 	ini_file = string_make(path);
4841 
4842 	/* Analyze the path */
4843 	i = strlen(path);
4844 
4845 	/* Get the path */
4846 	for (; i > 0; i--)
4847 	{
4848 		if (path[i] == '\\')
4849 		{
4850 			/* End of path */
4851 			break;
4852 		}
4853 	}
4854 
4855 	/* Add "lib" to the path */
4856 	strcpy(path + i + 1, "lib\\");
4857 
4858 	/* Validate the path */
4859 	validate_dir(path);
4860 
4861 	/* Init the file paths */
4862 	init_file_paths(path);
4863 
4864 	/* Hack -- Validate the paths */
4865 	validate_dir(ANGBAND_DIR_APEX);
4866 	validate_dir(ANGBAND_DIR_BONE);
4867 	validate_dir(ANGBAND_DIR_DATA);
4868 	validate_dir(ANGBAND_DIR_EDIT);
4869 
4870 	validate_dir(ANGBAND_DIR_SCRIPT);
4871 
4872 	validate_dir(ANGBAND_DIR_FILE);
4873 	validate_dir(ANGBAND_DIR_HELP);
4874 	validate_dir(ANGBAND_DIR_INFO);
4875 	validate_dir(ANGBAND_DIR_PREF);
4876 	validate_dir(ANGBAND_DIR_SAVE);
4877 	validate_dir(ANGBAND_DIR_USER);
4878 	validate_dir(ANGBAND_DIR_XTRA);
4879 
4880 	/* Build the filename */
4881 	path_make(path, ANGBAND_DIR_FILE, "news.txt");
4882 
4883 	/* Hack -- Validate the "news.txt" file */
4884 	validate_file(path);
4885 
4886 
4887 	/* Build the "font" path */
4888 	path_make(path, ANGBAND_DIR_XTRA, "font");
4889 
4890 	/* Allocate the path */
4891 	ANGBAND_DIR_XTRA_FONT = string_make(path);
4892 
4893 	/* Validate the "font" directory */
4894 	validate_dir(ANGBAND_DIR_XTRA_FONT);
4895 
4896 	/* Build the filename */
4897 	path_make(path, ANGBAND_DIR_XTRA_FONT, "8X13.FON");
4898 
4899 	/* Hack -- Validate the basic font */
4900 	validate_file(path);
4901 
4902 
4903 #ifdef USE_GRAPHICS
4904 
4905 	/* Build the "graf" path */
4906 	path_make(path, ANGBAND_DIR_XTRA, "graf");
4907 
4908 	/* Allocate the path */
4909 	ANGBAND_DIR_XTRA_GRAF = string_make(path);
4910 
4911 	/* Validate the "graf" directory */
4912 	validate_dir(ANGBAND_DIR_XTRA_GRAF);
4913 
4914 #endif /* USE_GRAPHICS */
4915 
4916 
4917 #ifdef USE_SOUND
4918 
4919 	/* Build the "sound" path */
4920 	path_make(path, ANGBAND_DIR_XTRA, "sound");
4921 
4922 	/* Allocate the path */
4923 	ANGBAND_DIR_XTRA_SOUND = string_make(path);
4924 
4925 	/* Validate the "sound" directory */
4926 	validate_dir(ANGBAND_DIR_XTRA_SOUND);
4927 
4928 #endif /* USE_SOUND */
4929 
4930 #ifdef USE_MUSIC
4931 
4932 	/* Build the "music" path */
4933 	path_make(path, ANGBAND_DIR_XTRA, "music");
4934 
4935 	/* Allocate the path */
4936 	ANGBAND_DIR_XTRA_MUSIC = string_make(path);
4937 
4938 	/* Validate the "music" directory */
4939 	validate_dir(ANGBAND_DIR_XTRA_MUSIC);
4940 
4941 #endif /* USE_MUSIC */
4942 
4943 	/* Build the "help" path */
4944 	path_make(path, ANGBAND_DIR_XTRA, "help");
4945 
4946 	/* Allocate the path */
4947 	ANGBAND_DIR_XTRA_HELP = string_make(path);
4948 
4949 #if 0
4950 	/* Validate the "help" directory */
4951 	validate_dir(ANGBAND_DIR_XTRA_HELP);
4952 #endif /* 0 */
4953 }
4954 
4955 
4956 /*
4957  * Test to see if we need to work-around bugs in
4958  * the windows ascii-drawing routines.
4959  */
broken_ascii(void)4960 bool broken_ascii(void)
4961 {
4962 	OSVERSIONINFO Dozeversion;
4963  	Dozeversion.dwOSVersionInfoSize = sizeof(Dozeversion);
4964 
4965 	if (GetVersionEx(&Dozeversion))
4966 	{
4967 		/* Win XP is b0rken */
4968 		if ((Dozeversion.dwPlatformId >= VER_PLATFORM_WIN32_NT) &&
4969 			(Dozeversion.dwMajorVersion >= 5))
4970 		{
4971 			return (TRUE);
4972 		}
4973 	}
4974 
4975 	return (FALSE);
4976 }
4977 
4978 
4979 
WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nCmdShow)4980 int FAR PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
4981                        LPSTR lpCmdLine, int nCmdShow)
4982 {
4983 	int i;
4984 
4985 	WNDCLASS wc;
4986 	HDC hdc;
4987 	MSG msg;
4988 
4989 	/* Unused parameter */
4990 	(void)nCmdShow;
4991 
4992 #ifdef USE_SAVER
4993 	if (lpCmdLine && ((*lpCmdLine == '-') || (*lpCmdLine == '/')))
4994 	{
4995 		lpCmdLine++;
4996 
4997 		switch (*lpCmdLine)
4998 		{
4999 			case 's':
5000 			case 'S':
5001 			{
5002 				screensaver = TRUE;
5003 
5004 				/* Only run one screensaver at the time */
5005 				screensaverSemaphore = CreateSemaphore(NULL, 0, 1, "AngbandSaverSemaphore");
5006 
5007 				if (!screensaverSemaphore) exit(0);
5008 
5009 				if (GetLastError() == ERROR_ALREADY_EXISTS)
5010 				{
5011 					CloseHandle(screensaverSemaphore);
5012 					exit(0);
5013 				}
5014 
5015 				break;
5016 			}
5017 
5018 			case 'P':
5019 			case 'p':
5020 			case 'C':
5021 			case 'c':
5022 			case 'A':
5023 			case 'a':
5024 			{
5025 				/*
5026 				 * ToDo: implement preview, configuration, and changing
5027 				 * the password (as well as checking it).
5028 				 */
5029 				exit(0);
5030 			}
5031 		}
5032 	}
5033 
5034 #endif /* USE_SAVER */
5035 
5036 	/* Initialize */
5037 	if (hPrevInst == NULL)
5038 	{
5039 		wc.style         = CS_CLASSDC;
5040 		wc.lpfnWndProc   = AngbandWndProc;
5041 		wc.cbClsExtra    = 0;
5042 		wc.cbWndExtra    = 4; /* one long pointer to term_data */
5043 		wc.hInstance     = hInst;
5044 		wc.hIcon         = hIcon = LoadIcon(hInst, "ANGBAND");
5045 		wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
5046 		wc.hbrBackground = GetStockObject(BLACK_BRUSH);
5047 		wc.lpszMenuName  = "ANGBAND";
5048 		wc.lpszClassName = AppName;
5049 
5050 		if (!RegisterClass(&wc)) exit(1);
5051 
5052 		wc.lpfnWndProc   = AngbandListProc;
5053 		wc.lpszMenuName  = NULL;
5054 		wc.lpszClassName = AngList;
5055 
5056 		if (!RegisterClass(&wc)) exit(2);
5057 
5058 #ifdef USE_SAVER
5059 
5060 		wc.style          = CS_VREDRAW | CS_HREDRAW | CS_SAVEBITS | CS_DBLCLKS;
5061 		wc.lpfnWndProc    = AngbandSaverProc;
5062 		wc.hCursor        = NULL;
5063 		wc.lpszMenuName   = NULL;
5064 		wc.lpszClassName  = "WindowsScreenSaverClass";
5065 
5066 		if (!RegisterClass(&wc)) exit(3);
5067 
5068 #endif /* USE_SAVER */
5069 
5070 	}
5071 
5072 	/* Save globally */
5073 	hInstance = hInst;
5074 
5075 	/* Temporary hooks */
5076 	plog_aux = hack_plog;
5077 	quit_aux = hack_quit;
5078 	core_aux = hack_quit;
5079 
5080 	/* Prepare the filepaths */
5081 	init_stuff();
5082 
5083 	/* Initialize the keypress analyzer */
5084 	for (i = 0; special_key_list[i]; i++)
5085 	{
5086 		special_key[special_key_list[i]] = TRUE;
5087 	}
5088 
5089 	/* Determine if display is 16/256/true color */
5090 	hdc = GetDC(NULL);
5091 	colors16 = (GetDeviceCaps(hdc, BITSPIXEL) == 4);
5092 	paletted = ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) ? TRUE : FALSE);
5093 	ReleaseDC(NULL, hdc);
5094 
5095 	/* Initialize the colors */
5096 	for (i = 0; i < 256; i++)
5097 	{
5098 		byte rv, gv, bv;
5099 
5100 		/* Extract desired values */
5101 		rv = angband_color_table[i][1];
5102 		gv = angband_color_table[i][2];
5103 		bv = angband_color_table[i][3];
5104 
5105 		/* Extract the "complex" code */
5106 		win_clr[i] = PALETTERGB(rv, gv, bv);
5107 
5108 		/* Save the "simple" code */
5109 		angband_color_table[i][0] = win_pal[i];
5110 	}
5111 
5112 	/* Prepare the windows */
5113 	init_windows();
5114 
5115 	/* Activate hooks */
5116 	plog_aux = hook_plog;
5117 	quit_aux = hook_quit;
5118 	core_aux = hook_quit;
5119 
5120 	/* Set the system suffix */
5121 	ANGBAND_SYS = "win";
5122 
5123 	if (broken_ascii())
5124 	{
5125 		ANGBAND_SYS = "w2k";
5126 	}
5127 
5128 	/* Initialize */
5129 	init_angband();
5130 
5131 	/* We are now initialized */
5132 	initialized = TRUE;
5133 
5134 #ifdef USE_SAVER
5135 	if (screensaver)
5136 	{
5137 		/* Start the screensaver */
5138 		start_screensaver();
5139 
5140 		/* Paranoia */
5141 		quit(NULL);
5142 	}
5143 #endif /* USE_SAVER */
5144 
5145 	/* Did the user double click on a save file? */
5146 	check_for_save_file(lpCmdLine);
5147 
5148 	/* Save the hooks into the overhead map */
5149 	set_callback((callback_type) win_map_info, CALL_MAP_INFO, NULL);
5150 
5151 	/* Save player movement hook */
5152 	set_callback((callback_type) win_player_move, CALL_PLAYER_MOVE, NULL);
5153 
5154 	/* Prompt the user */
5155 	prtf(17, 23, "[Choose 'New' or 'Open' from the 'File' menu]");
5156 	Term_fresh();
5157 
5158 	/* Process messages forever */
5159 	while (GetMessage(&msg, NULL, 0, 0))
5160 	{
5161 		TranslateMessage(&msg);
5162 		DispatchMessage(&msg);
5163 	}
5164 
5165 	/* Paranoia */
5166 	quit(NULL);
5167 
5168 	/* Paranoia */
5169 	return (0);
5170 }
5171 
5172 #endif /* WINDOWS */
5173