1 /* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
2 /* NetHack may be freely redistributed.  See license for details. */
3 
4 /*
5  * This file implements the interface between the window port specific
6  * code in the mswin port and the rest of the nethack game engine.
7 */
8 
9 #include "hack.h"
10 #include "dlb.h"
11 #include "winMS.h"
12 #include "mhmap.h"
13 #include "mhstatus.h"
14 #include "mhtext.h"
15 #include "mhmsgwnd.h"
16 #include "mhmenu.h"
17 #include "mhmsg.h"
18 #include "mhcmd.h"
19 #include "mhinput.h"
20 #include "mhaskyn.h"
21 #include "mhdlg.h"
22 #include "mhrip.h"
23 #include "mhmain.h"
24 #include "mhfont.h"
25 #include "mhcolor.h"
26 
27 #define LLEN 128
28 
29 #ifdef _DEBUG
30 extern void logDebug(const char *fmt, ...);
31 #else
logDebug(const char * fmt,...)32 void logDebug(const char *fmt, ...) { }
33 #endif
34 
35 static void mswin_main_loop();
36 static BOOL initMapTiles(void);
37 static void prompt_for_player_selection(void);
38 
39 /* Interface definition, for windows.c */
40 struct window_procs mswin_procs = {
41     "MSWIN",
42     WC_COLOR|WC_HILITE_PET|WC_ALIGN_MESSAGE|WC_ALIGN_STATUS|
43 	WC_INVERSE|WC_SCROLL_MARGIN|WC_MAP_MODE|
44 	WC_FONT_MESSAGE|WC_FONT_STATUS|WC_FONT_MENU|WC_FONT_TEXT|WC_FONT_MAP|
45 	WC_FONTSIZ_MESSAGE|WC_FONTSIZ_STATUS|WC_FONTSIZ_MENU|WC_FONTSIZ_TEXT|
46 	WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE|WC_VARY_MSGCOUNT|
47 	WC_WINDOWCOLORS|WC_PLAYER_SELECTION,
48     WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT,
49     mswin_init_nhwindows,
50     mswin_player_selection,
51     mswin_askname,
52     mswin_get_nh_event,
53     mswin_exit_nhwindows,
54     mswin_suspend_nhwindows,
55     mswin_resume_nhwindows,
56     mswin_create_nhwindow,
57     mswin_clear_nhwindow,
58     mswin_display_nhwindow,
59     mswin_destroy_nhwindow,
60     mswin_curs,
61     mswin_putstr,
62     mswin_display_file,
63     mswin_start_menu,
64     mswin_add_menu,
65     mswin_end_menu,
66     mswin_select_menu,
67     genl_message_menu,		/* no need for X-specific handling */
68     mswin_update_inventory,
69     mswin_mark_synch,
70     mswin_wait_synch,
71 #ifdef CLIPPING
72     mswin_cliparound,
73 #endif
74 #ifdef POSITIONBAR
75     donull,
76 #endif
77     mswin_print_glyph,
78     mswin_raw_print,
79     mswin_raw_print_bold,
80     mswin_nhgetch,
81     mswin_nh_poskey,
82     mswin_nhbell,
83     mswin_doprev_message,
84     mswin_yn_function,
85     mswin_getlin,
86     mswin_get_ext_cmd,
87     mswin_number_pad,
88     mswin_delay_output,
89 #ifdef CHANGE_COLOR	/* only a Mac option currently */
90 	mswin,
91 	mswin_change_background,
92 #endif
93     /* other defs that really should go away (they're tty specific) */
94     mswin_start_screen,
95     mswin_end_screen,
96     mswin_outrip,
97     mswin_preference_update,
98 };
99 
100 /*
101 init_nhwindows(int* argcp, char** argv)
102                 -- Initialize the windows used by NetHack.  This can also
103                    create the standard windows listed at the top, but does
104                    not display them.
105                 -- Any commandline arguments relevant to the windowport
106                    should be interpreted, and *argcp and *argv should
107                    be changed to remove those arguments.
108                 -- When the message window is created, the variable
109                    iflags.window_inited needs to be set to TRUE.  Otherwise
110                    all plines() will be done via raw_print().
111                 ** Why not have init_nhwindows() create all of the "standard"
112                 ** windows?  Or at least all but WIN_INFO?      -dean
113 */
mswin_init_nhwindows(int * argc,char ** argv)114 void mswin_init_nhwindows(int* argc, char** argv)
115 {
116 	HWND hWnd;
117 	logDebug("mswin_init_nhwindows()\n");
118 
119 #ifdef _DEBUG
120 	{
121 		/* truncate trace file */
122 		FILE *dfp = fopen("nhtrace.log", "w");
123 		fclose(dfp);
124 	}
125 #endif
126 
127 	/* intialize input subsystem */
128     mswin_nh_input_init();
129 
130 	/* read registry settings */
131     mswin_read_reg();
132 
133 	/* set it to WIN_ERR so we can detect attempts to
134 	   use this ID before it is inialized */
135 	WIN_MAP = WIN_ERR;
136 
137     /* check default values */
138 	if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN ||
139 		iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
140 		iflags.wc_fontsiz_status = NHFONT_STATUS_DEFAULT_SIZE;
141 
142 	if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN ||
143 		iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
144 		iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
145 
146 	if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN ||
147 		iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
148 		iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
149 
150 	if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN ||
151 		iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
152 		iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
153 
154 	if( iflags.wc_align_message==0 ) iflags.wc_align_message = ALIGN_BOTTOM;
155 	if( iflags.wc_align_status==0 ) iflags.wc_align_status = ALIGN_TOP;
156 	if( iflags.wc_scroll_margin==0 ) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
157 	if( iflags.wc_tile_width==0 ) iflags.wc_tile_width = TILE_X;
158 	if( iflags.wc_tile_height==0 ) iflags.wc_tile_height = TILE_Y;
159 
160 	if( iflags.wc_vary_msgcount==0 ) iflags.wc_vary_msgcount = 3;
161 
162 	/* force tabs in menus */
163 	iflags.menu_tab_sep = 1;
164 
165 	/* force toptenwin to be true.  toptenwin is the option that decides whether to
166 	 * write output to a window or stdout.  stdout doesn't make sense on Windows
167 	 * non-console applications
168 	 */
169 	flags.toptenwin = 1;
170 	set_option_mod_status("toptenwin", SET_IN_FILE);
171 
172 	/* initialize map tiles bitmap */
173 	initMapTiles();
174 
175 	/* set tile-related options to readonly */
176 	set_wc_option_mod_status(
177 	   WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE,
178 	   DISP_IN_GAME);
179 
180 	/* init color table */
181 	mswin_init_color_table();
182 
183 	/* set font-related options to change in the game */
184 	set_wc_option_mod_status(
185 		WC_HILITE_PET |
186 		WC_ALIGN_MESSAGE |
187 		WC_ALIGN_STATUS |
188 		WC_SCROLL_MARGIN |
189 		WC_MAP_MODE |
190 		WC_FONT_MESSAGE |
191 		WC_FONT_STATUS |
192 		WC_FONT_MENU |
193 		WC_FONT_TEXT |
194 		WC_FONTSIZ_MESSAGE |
195 		WC_FONTSIZ_STATUS |
196 		WC_FONTSIZ_MENU |
197 		WC_FONTSIZ_TEXT |
198 		WC_VARY_MSGCOUNT,
199 		SET_IN_GAME
200 	);
201 
202 	/* WC2 options */
203 	set_wc2_option_mod_status(
204 		WC2_FULLSCREEN|
205 		WC2_SOFTKEYBOARD,
206 		SET_IN_FILE
207 	);
208 	GetNHApp()->bFullScreen = iflags.wc2_fullscreen;
209 	GetNHApp()->bUseSIP = iflags.wc2_softkeyboard;
210 
211 	set_wc2_option_mod_status(
212 		WC2_WRAPTEXT,
213 		SET_IN_GAME
214 	);
215 	GetNHApp()->bWrapText = iflags.wc2_wraptext;
216 
217 	/* create the main nethack window */
218 	hWnd = mswin_init_main_window();
219 	if (!hWnd) panic( "Cannot create the main window." );
220 	ShowWindow(hWnd, GetNHApp()->nCmdShow);
221 	UpdateWindow(hWnd);
222 	GetNHApp()->hMainWnd = hWnd;
223 
224 	/* set Full screen if requested */
225 	mswin_set_fullscreen(GetNHApp()->bFullScreen);
226 
227 	/* let nethack code know that the window subsystem is ready */
228 	iflags.window_inited = TRUE;
229 }
230 
231 
232 /* Do a window-port specific player type selection. If player_selection()
233    offers a Quit option, it is its responsibility to clean up and terminate
234    the process. You need to fill in pl_character[0].
235 */
mswin_player_selection(void)236 void mswin_player_selection(void)
237 {
238 	logDebug("mswin_player_selection()\n");
239 
240 #if defined(WIN_CE_SMARTPHONE)
241 	/* SmartPhone does not supprt combo-boxes therefor we cannot
242 	   use dialog for player selection */
243     prompt_for_player_selection();
244 #else
245 	if (iflags.wc_player_selection == VIA_DIALOG) {
246 		int nRole;
247 
248 	    /* pick player type randomly (use pre-selected role/race/gender/alignment) */
249 	    if( flags.randomall ) {
250 		if (flags.initrole < 0) {
251 			flags.initrole = pick_role(flags.initrace, flags.initgend,
252 							flags.initalign, PICK_RANDOM);
253 			if (flags.initrole < 0) {
254 				raw_print("Incompatible role!");
255 				flags.initrole = randrole();
256 			}
257 		}
258 
259 		if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
260 			flags.initrace = pick_race(flags.initrole, flags.initgend,
261 								flags.initalign, PICK_RANDOM);
262 			if (flags.initrace < 0) {
263 				raw_print("Incompatible race!");
264 				flags.initrace = randrace(flags.initrole);
265 			}
266 		}
267 
268 		if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
269 						flags.initgend)) {
270 			flags.initgend = pick_gend(flags.initrole, flags.initrace,
271 							flags.initalign, PICK_RANDOM);
272 			if (flags.initgend < 0) {
273 				raw_print("Incompatible gender!");
274 				flags.initgend = randgend(flags.initrole, flags.initrace);
275 			}
276 		}
277 
278 		if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
279 								flags.initalign)) {
280 			flags.initalign = pick_align(flags.initrole, flags.initrace,
281 								flags.initgend, PICK_RANDOM);
282 			if (flags.initalign < 0) {
283 				raw_print("Incompatible alignment!");
284 				flags.initalign = randalign(flags.initrole, flags.initrace);
285 			}
286 		}
287 	    } else {
288 		/* select a role */
289 		if( mswin_player_selection_window( &nRole ) == IDCANCEL ) {
290 			bail(0);
291 		}
292 	    }
293 	} else { /* iflags.wc_player_selection == VIA_PROMPTS */
294 	    prompt_for_player_selection();
295 	}
296 #endif /* defined(WIN_CE_SMARTPHONE) */
297 }
298 
prompt_for_player_selection(void)299 void prompt_for_player_selection(void)
300 {
301 	int i, k, n;
302 	char pick4u = 'n', thisch, lastch = 0;
303 	char pbuf[QBUFSZ], plbuf[QBUFSZ];
304 	winid win;
305 	anything any;
306 	menu_item *selected = 0;
307 	int box_result;
308 	TCHAR wbuf[BUFSZ];
309 
310   	logDebug("prompt_for_player_selection()\n");
311 
312 	/* prevent an unnecessary prompt */
313 	rigid_role_checks();
314 
315 	/* Should we randomly pick for the player? */
316 	if (!flags.randomall &&
317 	    (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
318 	     flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
319 	    /* int echoline; */
320 	    char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,
321 				flags.initrace, flags.initgend, flags.initalign);
322 
323 	    /* tty_putstr(BASE_WINDOW, 0, ""); */
324 	    /* echoline = wins[BASE_WINDOW]->cury; */
325         box_result = MessageBox(NULL,
326 					NH_A2W(prompt, wbuf, BUFSZ),
327 					TEXT("NetHack for Windows"),
328 #if defined(WIN_CE_SMARTPHONE)
329 					MB_YESNO | MB_DEFBUTTON1
330 #else
331 					MB_YESNOCANCEL | MB_DEFBUTTON1
332 #endif
333 					);
334 
335         pick4u = (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033';
336 	    /* tty_putstr(BASE_WINDOW, 0, prompt); */
337 	    do {
338 		/* pick4u = lowc(readchar()); */
339 		if (index(quitchars, pick4u)) pick4u = 'y';
340 	    } while(!index(ynqchars, pick4u));
341 	    if ((int)strlen(prompt) + 1 < CO) {
342 		/* Echo choice and move back down line */
343 		/* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, pick4u); */
344 		/* tty_putstr(BASE_WINDOW, 0, ""); */
345 	    } else
346 		/* Otherwise it's hard to tell where to echo, and things are
347 		 * wrapping a bit messily anyway, so (try to) make sure the next
348 		 * question shows up well and doesn't get wrapped at the
349 		 * bottom of the window.
350 		 */
351 		/* tty_clear_nhwindow(BASE_WINDOW) */ ;
352 
353 	    if (pick4u != 'y' && pick4u != 'n') {
354 give_up:	/* Quit */
355 		if (selected) free((genericptr_t) selected);
356 		bail((char *)0);
357 		/*NOTREACHED*/
358 		return;
359 	    }
360 	}
361 
362 	(void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
363 			flags.initrole, flags.initrace, flags.initgend, flags.initalign);
364 
365 	/* Select a role, if necessary */
366 	/* we'll try to be compatible with pre-selected race/gender/alignment,
367 	 * but may not succeed */
368 	if (flags.initrole < 0) {
369 	    char rolenamebuf[QBUFSZ];
370 	    /* Process the choice */
371 	    if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
372 		/* Pick a random role */
373 		flags.initrole = pick_role(flags.initrace, flags.initgend,
374 						flags.initalign, PICK_RANDOM);
375 		if (flags.initrole < 0) {
376 		    /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
377 		    flags.initrole = randrole();
378 		}
379  	    } else {
380 	    	/* tty_clear_nhwindow(BASE_WINDOW); */
381 		/* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
382 		/* Prompt for a role */
383 		win = create_nhwindow(NHW_MENU);
384 		start_menu(win);
385 		any.a_void = 0;         /* zero out all bits */
386 		for (i = 0; roles[i].name.m; i++) {
387 		    if (ok_role(i, flags.initrace, flags.initgend,
388 							flags.initalign)) {
389 			any.a_int = i+1;	/* must be non-zero */
390 			thisch = lowc(roles[i].name.m[0]);
391 			if (thisch == lastch) thisch = highc(thisch);
392 			if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) {
393 				if (flags.initgend == 1  && roles[i].name.f)
394 					Strcpy(rolenamebuf, roles[i].name.f);
395 				else
396 					Strcpy(rolenamebuf, roles[i].name.m);
397 			} else {
398 				if (roles[i].name.f) {
399 					Strcpy(rolenamebuf, roles[i].name.m);
400 					Strcat(rolenamebuf, "/");
401 					Strcat(rolenamebuf, roles[i].name.f);
402 				} else
403 					Strcpy(rolenamebuf, roles[i].name.m);
404 			}
405 			add_menu(win, NO_GLYPH, &any, thisch,
406 			    0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED);
407 			lastch = thisch;
408 		    }
409 		}
410 		any.a_int = pick_role(flags.initrace, flags.initgend,
411 				    flags.initalign, PICK_RANDOM)+1;
412 		if (any.a_int == 0)	/* must be non-zero */
413 		    any.a_int = randrole()+1;
414 		add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
415 				"Random", MENU_UNSELECTED);
416 		any.a_int = i+1;	/* must be non-zero */
417 		add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
418 				"Quit", MENU_UNSELECTED);
419 		Sprintf(pbuf, "Pick a role for your %s", plbuf);
420 		end_menu(win, pbuf);
421 		n = select_menu(win, PICK_ONE, &selected);
422 		destroy_nhwindow(win);
423 
424 		/* Process the choice */
425 		if (n != 1 || selected[0].item.a_int == any.a_int)
426 		    goto give_up;		/* Selected quit */
427 
428 		flags.initrole = selected[0].item.a_int - 1;
429 		free((genericptr_t) selected),	selected = 0;
430 	    }
431 	    (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
432 			flags.initrole, flags.initrace, flags.initgend, flags.initalign);
433 	}
434 
435 	/* Select a race, if necessary */
436 	/* force compatibility with role, try for compatibility with
437 	 * pre-selected gender/alignment */
438 	if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
439 	    /* pre-selected race not valid */
440 	    if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
441 		flags.initrace = pick_race(flags.initrole, flags.initgend,
442 							flags.initalign, PICK_RANDOM);
443 		if (flags.initrace < 0) {
444 		    /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
445 		    flags.initrace = randrace(flags.initrole);
446 		}
447 	    } else {	/* pick4u == 'n' */
448 		/* Count the number of valid races */
449 		n = 0;	/* number valid */
450 		k = 0;	/* valid race */
451 		for (i = 0; races[i].noun; i++) {
452 		    if (ok_race(flags.initrole, i, flags.initgend,
453 							flags.initalign)) {
454 			n++;
455 			k = i;
456 		    }
457 		}
458 		if (n == 0) {
459 		    for (i = 0; races[i].noun; i++) {
460 			if (validrace(flags.initrole, i)) {
461 			    n++;
462 			    k = i;
463 			}
464 		    }
465 		}
466 
467 		/* Permit the user to pick, if there is more than one */
468 		if (n > 1) {
469 		    /* tty_clear_nhwindow(BASE_WINDOW); */
470 		    /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
471 		    win = create_nhwindow(NHW_MENU);
472 		    start_menu(win);
473 		    any.a_void = 0;         /* zero out all bits */
474 		    for (i = 0; races[i].noun; i++)
475 			if (ok_race(flags.initrole, i, flags.initgend,
476 							flags.initalign)) {
477 			    any.a_int = i+1;	/* must be non-zero */
478 			    add_menu(win, NO_GLYPH, &any, races[i].noun[0],
479 				0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
480 			}
481 		    any.a_int = pick_race(flags.initrole, flags.initgend,
482 					flags.initalign, PICK_RANDOM)+1;
483 		    if (any.a_int == 0)	/* must be non-zero */
484 			any.a_int = randrace(flags.initrole)+1;
485 		    add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
486 				    "Random", MENU_UNSELECTED);
487 		    any.a_int = i+1;	/* must be non-zero */
488 		    add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
489 				    "Quit", MENU_UNSELECTED);
490 		    Sprintf(pbuf, "Pick the race of your %s", plbuf);
491 		    end_menu(win, pbuf);
492 		    n = select_menu(win, PICK_ONE, &selected);
493 		    destroy_nhwindow(win);
494 		    if (n != 1 || selected[0].item.a_int == any.a_int)
495 			goto give_up;		/* Selected quit */
496 
497 		    k = selected[0].item.a_int - 1;
498 		    free((genericptr_t) selected),	selected = 0;
499 		}
500 		flags.initrace = k;
501 	    }
502 	    (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
503 			flags.initrole, flags.initrace, flags.initgend, flags.initalign);
504 	}
505 
506 	/* Select a gender, if necessary */
507 	/* force compatibility with role/race, try for compatibility with
508 	 * pre-selected alignment */
509 	if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
510 						flags.initgend)) {
511 	    /* pre-selected gender not valid */
512 	    if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
513 		flags.initgend = pick_gend(flags.initrole, flags.initrace,
514 						flags.initalign, PICK_RANDOM);
515 		if (flags.initgend < 0) {
516 		    /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
517 		    flags.initgend = randgend(flags.initrole, flags.initrace);
518 		}
519 	    } else {	/* pick4u == 'n' */
520 		/* Count the number of valid genders */
521 		n = 0;	/* number valid */
522 		k = 0;	/* valid gender */
523 		for (i = 0; i < ROLE_GENDERS; i++) {
524 		    if (ok_gend(flags.initrole, flags.initrace, i,
525 							flags.initalign)) {
526 			n++;
527 			k = i;
528 		    }
529 		}
530 		if (n == 0) {
531 		    for (i = 0; i < ROLE_GENDERS; i++) {
532 			if (validgend(flags.initrole, flags.initrace, i)) {
533 			    n++;
534 			    k = i;
535 			}
536 		    }
537 		}
538 
539 		/* Permit the user to pick, if there is more than one */
540 		if (n > 1) {
541 		    /* tty_clear_nhwindow(BASE_WINDOW); */
542 		    /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
543 		    win = create_nhwindow(NHW_MENU);
544 		    start_menu(win);
545 		    any.a_void = 0;         /* zero out all bits */
546 		    for (i = 0; i < ROLE_GENDERS; i++)
547 			if (ok_gend(flags.initrole, flags.initrace, i,
548 							    flags.initalign)) {
549 			    any.a_int = i+1;
550 			    add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
551 				0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
552 			}
553 		    any.a_int = pick_gend(flags.initrole, flags.initrace,
554 					    flags.initalign, PICK_RANDOM)+1;
555 		    if (any.a_int == 0)	/* must be non-zero */
556 			any.a_int = randgend(flags.initrole, flags.initrace)+1;
557 		    add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
558 				    "Random", MENU_UNSELECTED);
559 		    any.a_int = i+1;	/* must be non-zero */
560 		    add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
561 				    "Quit", MENU_UNSELECTED);
562 		    Sprintf(pbuf, "Pick the gender of your %s", plbuf);
563 		    end_menu(win, pbuf);
564 		    n = select_menu(win, PICK_ONE, &selected);
565 		    destroy_nhwindow(win);
566 		    if (n != 1 || selected[0].item.a_int == any.a_int)
567 			goto give_up;		/* Selected quit */
568 
569 		    k = selected[0].item.a_int - 1;
570 		    free((genericptr_t) selected),	selected = 0;
571 		}
572 		flags.initgend = k;
573 	    }
574 	    (void)  root_plselection_prompt(plbuf, QBUFSZ - 1,
575 			flags.initrole, flags.initrace, flags.initgend, flags.initalign);
576 	}
577 
578 	/* Select an alignment, if necessary */
579 	/* force compatibility with role/race/gender */
580 	if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
581 							flags.initalign)) {
582 	    /* pre-selected alignment not valid */
583 	    if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
584 		flags.initalign = pick_align(flags.initrole, flags.initrace,
585 							flags.initgend, PICK_RANDOM);
586 		if (flags.initalign < 0) {
587 		    /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
588 		    flags.initalign = randalign(flags.initrole, flags.initrace);
589 		}
590 	    } else {	/* pick4u == 'n' */
591 		/* Count the number of valid alignments */
592 		n = 0;	/* number valid */
593 		k = 0;	/* valid alignment */
594 		for (i = 0; i < ROLE_ALIGNS; i++) {
595 		    if (ok_align(flags.initrole, flags.initrace, flags.initgend,
596 							i)) {
597 			n++;
598 			k = i;
599 		    }
600 		}
601 		if (n == 0) {
602 		    for (i = 0; i < ROLE_ALIGNS; i++) {
603 			if (validalign(flags.initrole, flags.initrace, i)) {
604 			    n++;
605 			    k = i;
606 			}
607 		    }
608 		}
609 
610 		/* Permit the user to pick, if there is more than one */
611 		if (n > 1) {
612 		    /* tty_clear_nhwindow(BASE_WINDOW); */
613 		    /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
614 		    win = create_nhwindow(NHW_MENU);
615 		    start_menu(win);
616 		    any.a_void = 0;         /* zero out all bits */
617 		    for (i = 0; i < ROLE_ALIGNS; i++)
618 			if (ok_align(flags.initrole, flags.initrace,
619 							flags.initgend, i)) {
620 			    any.a_int = i+1;
621 			    add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
622 				 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
623 			}
624 		    any.a_int = pick_align(flags.initrole, flags.initrace,
625 					    flags.initgend, PICK_RANDOM)+1;
626 		    if (any.a_int == 0)	/* must be non-zero */
627 			any.a_int = randalign(flags.initrole, flags.initrace)+1;
628 		    add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
629 				    "Random", MENU_UNSELECTED);
630 		    any.a_int = i+1;	/* must be non-zero */
631 		    add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
632 				    "Quit", MENU_UNSELECTED);
633 		    Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
634 		    end_menu(win, pbuf);
635 		    n = select_menu(win, PICK_ONE, &selected);
636 		    destroy_nhwindow(win);
637 		    if (n != 1 || selected[0].item.a_int == any.a_int)
638 			goto give_up;		/* Selected quit */
639 
640 		    k = selected[0].item.a_int - 1;
641 		    free((genericptr_t) selected),	selected = 0;
642 		}
643 		flags.initalign = k;
644 	    }
645 	}
646 	/* Success! */
647 	/* tty_display_nhwindow(BASE_WINDOW, FALSE); */
648 }
649 
650 /* Ask the user for a player name. */
mswin_askname(void)651 void mswin_askname(void)
652 {
653 	logDebug("mswin_askname()\n");
654 
655 	if( mswin_getlin_window("who are you?", plname, PL_NSIZ)==IDCANCEL ) {
656 		bail("bye-bye");
657 		/* not reached */
658 	}
659 }
660 
661 
662 /* Does window event processing (e.g. exposure events).
663    A noop for the tty and X window-ports.
664 */
mswin_get_nh_event(void)665 void mswin_get_nh_event(void)
666 {
667 	logDebug("mswin_get_nh_event()\n");
668 	return;
669 }
670 
671 /* Exits the window system.  This should dismiss all windows,
672    except the "window" used for raw_print().  str is printed if possible.
673 */
mswin_exit_nhwindows(const char * str)674 void mswin_exit_nhwindows(const char *str)
675 {
676 	logDebug("mswin_exit_nhwindows(%s)\n", str);
677 
678     /* Write Window settings to the registry */
679     mswin_write_reg();
680 
681 	// Don't do any of this (?) - exit_nhwindows does not terminate
682 	// the application
683 	// DestroyWindow(GetNHApp()->hMainWnd);
684 	// terminate(EXIT_SUCCESS);
685 }
686 
687 /* Prepare the window to be suspended. */
mswin_suspend_nhwindows(const char * str)688 void mswin_suspend_nhwindows(const char *str)
689 {
690 	logDebug("mswin_suspend_nhwindows(%s)\n", str);
691 	return;
692 }
693 
694 
695 /* Restore the windows after being suspended. */
mswin_resume_nhwindows()696 void mswin_resume_nhwindows()
697 {
698 	logDebug("mswin_resume_nhwindows()\n");
699 	return;
700 }
701 
702 /*  Create a window of type "type" which can be
703         NHW_MESSAGE     (top line)
704         NHW_STATUS      (bottom lines)
705         NHW_MAP         (main dungeon)
706         NHW_MENU        (inventory or other "corner" windows)
707         NHW_TEXT        (help/text, full screen paged window)
708 */
709 winid
mswin_create_nhwindow(int type)710 mswin_create_nhwindow(int type)
711 {
712 	winid i = 0;
713 	MSNHMsgAddWnd data;
714 
715 	logDebug("mswin_create_nhwindow(%d)\n", type);
716 
717 	/* Return the next available winid
718 	 */
719 
720 	for (i=1; i<MAXWINDOWS; i++)
721 	  if (GetNHApp()->windowlist[i].win == NULL &&
722 		  !GetNHApp()->windowlist[i].dead)
723 		  break;
724 	if (i == MAXWINDOWS)
725 	  panic ("ERROR:  No windows available...\n");
726 
727     switch (type) {
728     case NHW_MAP:
729 	{
730 		GetNHApp()->windowlist[i].win = mswin_init_map_window();
731 		GetNHApp()->windowlist[i].type = type;
732 		GetNHApp()->windowlist[i].dead = 0;
733 		break;
734 	}
735     case NHW_MESSAGE:
736 	{
737 		GetNHApp()->windowlist[i].win = mswin_init_message_window();
738 		GetNHApp()->windowlist[i].type = type;
739 		GetNHApp()->windowlist[i].dead = 0;
740 		break;
741 	}
742     case NHW_STATUS:
743 	{
744 		GetNHApp()->windowlist[i].win = mswin_init_status_window();
745 		GetNHApp()->windowlist[i].type = type;
746 		GetNHApp()->windowlist[i].dead = 0;
747 		break;
748 	}
749     case NHW_MENU:
750 	{
751 		GetNHApp()->windowlist[i].win = NULL; //will create later
752 		GetNHApp()->windowlist[i].type = type;
753 		GetNHApp()->windowlist[i].dead = 1;
754 		break;
755 	}
756     case NHW_TEXT:
757 	{
758 		GetNHApp()->windowlist[i].win = mswin_init_text_window();
759 		GetNHApp()->windowlist[i].type = type;
760 		GetNHApp()->windowlist[i].dead = 0;
761 		break;
762 	}
763 	}
764 
765 	ZeroMemory(&data, sizeof(data) );
766 	data.wid = i;
767 	SendMessage( GetNHApp()->hMainWnd,
768 		         WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDWND, (LPARAM)&data );
769 	return i;
770 }
771 
772 /* Clear the given window, when asked to. */
mswin_clear_nhwindow(winid wid)773 void mswin_clear_nhwindow(winid wid)
774 {
775 	logDebug("mswin_clear_nhwindow(%d)\n", wid);
776 
777     if ((wid >= 0) &&
778         (wid < MAXWINDOWS) &&
779         (GetNHApp()->windowlist[wid].win != NULL))
780     {
781 #ifdef REINCARNATION
782 		if( GetNHApp()->windowlist[wid].type == NHW_MAP ) {
783 			if( Is_rogue_level(&u.uz) )
784 				mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), ROGUE_LEVEL_MAP_MODE);
785 			else
786 				mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode);
787 		}
788 #endif
789 
790          SendMessage(
791 			 GetNHApp()->windowlist[wid].win,
792 			 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLEAR_WINDOW, (LPARAM)NULL );
793     }
794 }
795 
796 /* -- Display the window on the screen.  If there is data
797                    pending for output in that window, it should be sent.
798                    If blocking is TRUE, display_nhwindow() will not
799                    return until the data has been displayed on the screen,
800                    and acknowledged by the user where appropriate.
801                 -- All calls are blocking in the tty window-port.
802                 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
803                    --more--, if necessary, in the tty window-port.
804 */
mswin_display_nhwindow(winid wid,BOOLEAN_P block)805 void mswin_display_nhwindow(winid wid, BOOLEAN_P block)
806 {
807 	logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block);
808 	if (GetNHApp()->windowlist[wid].win != NULL)
809 	{
810 		if (GetNHApp()->windowlist[wid].type == NHW_MENU) {
811 			MENU_ITEM_P* p;
812 			mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, PICK_NONE, &p);
813 		} if (GetNHApp()->windowlist[wid].type == NHW_TEXT) {
814 			mswin_display_text_window(GetNHApp()->windowlist[wid].win);
815 		} if (GetNHApp()->windowlist[wid].type == NHW_RIP) {
816 			mswin_display_RIP_window(GetNHApp()->windowlist[wid].win);
817 		} else {
818 			if( !block ) {
819 				UpdateWindow(GetNHApp()->windowlist[wid].win);
820 			} else {
821 				if ( GetNHApp()->windowlist[wid].type == NHW_MAP ) {
822 					(void) mswin_nhgetch();
823 				}
824 			}
825 		}
826 		SetFocus(GetNHApp()->hMainWnd);
827 	}
828 }
829 
830 
mswin_hwnd_from_winid(winid wid)831 HWND mswin_hwnd_from_winid(winid wid)
832 {
833 	if( wid>=0 && wid<MAXWINDOWS) {
834 		return GetNHApp()->windowlist[wid].win;
835 	} else {
836 		return NULL;
837 	}
838 }
839 
mswin_winid_from_handle(HWND hWnd)840 winid mswin_winid_from_handle(HWND hWnd)
841 {
842 	winid i = 0;
843 
844 	for (i=1; i<MAXWINDOWS; i++)
845 	  if (GetNHApp()->windowlist[i].win == hWnd)
846 		  return i;
847 	return -1;
848 }
849 
mswin_winid_from_type(int type)850 winid mswin_winid_from_type(int type)
851 {
852 	winid i = 0;
853 
854 	for (i=1; i<MAXWINDOWS; i++)
855 	  if (GetNHApp()->windowlist[i].type == type)
856 		  return i;
857 	return -1;
858 }
859 
mswin_window_mark_dead(winid wid)860 void mswin_window_mark_dead(winid wid)
861 {
862 	if( wid>=0 && wid<MAXWINDOWS) {
863 		GetNHApp()->windowlist[wid].win = NULL;
864 		GetNHApp()->windowlist[wid].dead = 1;
865 	}
866 }
867 
868 /* Destroy will dismiss the window if the window has not
869  * already been dismissed.
870 */
mswin_destroy_nhwindow(winid wid)871 void mswin_destroy_nhwindow(winid wid)
872 {
873 	logDebug("mswin_destroy_nhwindow(%d)\n", wid);
874 
875     if ((GetNHApp()->windowlist[wid].type == NHW_MAP) ||
876         (GetNHApp()->windowlist[wid].type == NHW_MESSAGE) ||
877         (GetNHApp()->windowlist[wid].type == NHW_STATUS)) {
878 		/* main windows is going to take care of those */
879 		return;
880     }
881 
882     if (wid != -1) {
883 		if( !GetNHApp()->windowlist[wid].dead &&
884 			GetNHApp()->windowlist[wid].win != NULL )
885 			DestroyWindow(GetNHApp()->windowlist[wid].win);
886 		GetNHApp()->windowlist[wid].win = NULL;
887 		GetNHApp()->windowlist[wid].type = 0;
888 		GetNHApp()->windowlist[wid].dead = 0;
889 	}
890 }
891 
892 /* Next output to window will start at (x,y), also moves
893  displayable cursor to (x,y).  For backward compatibility,
894  1 <= x < cols, 0 <= y < rows, where cols and rows are
895  the size of window.
896 */
mswin_curs(winid wid,int x,int y)897 void mswin_curs(winid wid, int x, int y)
898 {
899 	logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y);
900 
901     if ((wid >= 0) &&
902         (wid < MAXWINDOWS) &&
903         (GetNHApp()->windowlist[wid].win != NULL))
904     {
905 		 MSNHMsgCursor data;
906 		 data.x = x;
907 		 data.y = y;
908 		 SendMessage(
909 			 GetNHApp()->windowlist[wid].win,
910 			 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CURSOR, (LPARAM)&data );
911     }
912 }
913 
914 /*
915 putstr(window, attr, str)
916                 -- Print str on the window with the given attribute.  Only
917                    printable ASCII characters (040-0126) must be supported.
918                    Multiple putstr()s are output on separate lines.
919 Attributes
920                    can be one of
921                         ATR_NONE (or 0)
922                         ATR_ULINE
923                         ATR_BOLD
924                         ATR_BLINK
925                         ATR_INVERSE
926                    If a window-port does not support all of these, it may map
927                    unsupported attributes to a supported one (e.g. map them
928                    all to ATR_INVERSE).  putstr() may compress spaces out of
929                    str, break str, or truncate str, if necessary for the
930                    display.  Where putstr() breaks a line, it has to clear
931                    to end-of-line.
932                 -- putstr should be implemented such that if two putstr()s
933                    are done consecutively the user will see the first and
934                    then the second.  In the tty port, pline() achieves this
935                    by calling more() or displaying both on the same line.
936 */
mswin_putstr(winid wid,int attr,const char * text)937 void mswin_putstr(winid wid, int attr, const char *text)
938 {
939 	logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text);
940 
941 	mswin_putstr_ex(wid, attr, text, 0);
942 }
943 
mswin_putstr_ex(winid wid,int attr,const char * text,boolean app)944 void mswin_putstr_ex(winid wid, int attr, const char *text, boolean app)
945 {
946 	if( (wid >= 0) &&
947         (wid < MAXWINDOWS) )
948 	{
949 		if( GetNHApp()->windowlist[wid].win==NULL &&
950 			GetNHApp()->windowlist[wid].type==NHW_MENU ) {
951 			GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_TEXT);
952 			GetNHApp()->windowlist[wid].dead = 0;
953 		}
954 
955 		if (GetNHApp()->windowlist[wid].win != NULL)
956 		{
957 			 MSNHMsgPutstr data;
958 			 ZeroMemory(&data, sizeof(data));
959 			 data.attr = attr;
960 			 data.text = text;
961 			 data.append = app;
962 			 SendMessage(
963 				 GetNHApp()->windowlist[wid].win,
964 				 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PUTSTR, (LPARAM)&data );
965 		}
966 	}
967 }
968 
969 /* Display the file named str.  Complain about missing files
970                    iff complain is TRUE.
971 */
mswin_display_file(const char * filename,BOOLEAN_P must_exist)972 void mswin_display_file(const char *filename,BOOLEAN_P must_exist)
973 {
974 	dlb *f;
975 	TCHAR wbuf[BUFSZ];
976 
977 	logDebug("mswin_display_file(%s, %d)\n", filename, must_exist);
978 
979 	f = dlb_fopen(filename, RDTMODE);
980 	if (!f) {
981 		if (must_exist) {
982 			TCHAR message[90];
983 			_stprintf(message, TEXT("Warning! Could not find file: %s\n"), NH_A2W(filename, wbuf, sizeof(wbuf)));
984 			MessageBox(GetNHApp()->hMainWnd, message, TEXT("ERROR"), MB_OK | MB_ICONERROR );
985 		}
986 	} else {
987 		winid text;
988 		char line[LLEN];
989 
990 		text = mswin_create_nhwindow(NHW_TEXT);
991 
992 		while (dlb_fgets(line, LLEN, f)) {
993 			 size_t len;
994 			 len = strlen(line);
995 			 if( line[len-1]=='\n' ) line[len-1]='\x0';
996 				mswin_putstr(text, ATR_NONE, line);
997 		}
998 		(void) dlb_fclose(f);
999 
1000 		mswin_display_nhwindow(text, 1);
1001 		mswin_destroy_nhwindow(text);
1002 	}
1003 }
1004 
1005 /* Start using window as a menu.  You must call start_menu()
1006    before add_menu().  After calling start_menu() you may not
1007    putstr() to the window.  Only windows of type NHW_MENU may
1008    be used for menus.
1009 */
mswin_start_menu(winid wid)1010 void mswin_start_menu(winid wid)
1011 {
1012 	logDebug("mswin_start_menu(%d)\n", wid);
1013 	if( (wid >= 0) &&
1014         (wid < MAXWINDOWS) ) {
1015 		if( GetNHApp()->windowlist[wid].win==NULL &&
1016 			GetNHApp()->windowlist[wid].type==NHW_MENU ) {
1017 			GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_MENU);
1018 			GetNHApp()->windowlist[wid].dead = 0;
1019 		}
1020 
1021 		if(GetNHApp()->windowlist[wid].win != NULL)	{
1022 			SendMessage(
1023 				 GetNHApp()->windowlist[wid].win,
1024 				 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_STARTMENU, (LPARAM)NULL
1025 			);
1026 		}
1027 	}
1028 }
1029 
1030 /*
1031 add_menu(windid window, int glyph, const anything identifier,
1032                                 char accelerator, char groupacc,
1033                                 int attr, char *str, boolean preselected)
1034                 -- Add a text line str to the given menu window.  If identifier
1035                    is 0, then the line cannot be selected (e.g. a title).
1036                    Otherwise, identifier is the value returned if the line is
1037                    selected.  Accelerator is a keyboard key that can be used
1038                    to select the line.  If the accelerator of a selectable
1039                    item is 0, the window system is free to select its own
1040                    accelerator.  It is up to the window-port to make the
1041                    accelerator visible to the user (e.g. put "a - " in front
1042                    of str).  The value attr is the same as in putstr().
1043                    Glyph is an optional glyph to accompany the line.  If
1044                    window port cannot or does not want to display it, this
1045                    is OK.  If there is no glyph applicable, then this
1046                    value will be NO_GLYPH.
1047                 -- All accelerators should be in the range [A-Za-z].
1048                 -- It is expected that callers do not mix accelerator
1049                    choices.  Either all selectable items have an accelerator
1050                    or let the window system pick them.  Don't do both.
1051                 -- Groupacc is a group accelerator.  It may be any character
1052                    outside of the standard accelerator (see above) or a
1053                    number.  If 0, the item is unaffected by any group
1054                    accelerator.  If this accelerator conflicts with
1055                    the menu command (or their user defined alises), it loses.
1056                    The menu commands and aliases take care not to interfere
1057                    with the default object class symbols.
1058                 -- If you want this choice to be preselected when the
1059                    menu is displayed, set preselected to TRUE.
1060 */
mswin_add_menu(winid wid,int glyph,const ANY_P * identifier,CHAR_P accelerator,CHAR_P group_accel,int attr,const char * str,BOOLEAN_P presel)1061 void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier,
1062 		CHAR_P accelerator, CHAR_P group_accel, int attr,
1063 		const char *str, BOOLEAN_P presel)
1064 {
1065 	logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n",
1066 		     wid, glyph, identifier, (char)accelerator, (char)group_accel,
1067 			 attr, str, presel);
1068 	if ((wid >= 0) &&
1069 		(wid < MAXWINDOWS) &&
1070 		(GetNHApp()->windowlist[wid].win != NULL))
1071 	{
1072 		MSNHMsgAddMenu data;
1073 		ZeroMemory(&data, sizeof(data));
1074 		data.glyph = glyph;
1075 		data.identifier = identifier;
1076 		data.accelerator = accelerator;
1077 		data.group_accel = group_accel;
1078 		data.attr = attr;
1079 		data.str = str;
1080 		data.presel = presel;
1081 
1082 		SendMessage(
1083 			 GetNHApp()->windowlist[wid].win,
1084 			 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDMENU, (LPARAM)&data
1085 		);
1086 	}
1087 }
1088 
1089 /*
1090 end_menu(window, prompt)
1091                 -- Stop adding entries to the menu and flushes the window
1092                    to the screen (brings to front?).  Prompt is a prompt
1093                    to give the user.  If prompt is NULL, no prompt will
1094                    be printed.
1095                 ** This probably shouldn't flush the window any more (if
1096                 ** it ever did).  That should be select_menu's job.  -dean
1097 */
mswin_end_menu(winid wid,const char * prompt)1098 void mswin_end_menu(winid wid, const char *prompt)
1099 {
1100 	logDebug("mswin_end_menu(%d, %s)\n", wid, prompt);
1101 	if ((wid >= 0) &&
1102 		(wid < MAXWINDOWS) &&
1103 		(GetNHApp()->windowlist[wid].win != NULL))
1104 	{
1105 		MSNHMsgEndMenu data;
1106 		ZeroMemory(&data, sizeof(data));
1107 		data.text = prompt;
1108 
1109 		SendMessage(
1110 			 GetNHApp()->windowlist[wid].win,
1111 			 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ENDMENU, (LPARAM)&data
1112 		);
1113 	}
1114 }
1115 
1116 /*
1117 int select_menu(windid window, int how, menu_item **selected)
1118                 -- Return the number of items selected; 0 if none were chosen,
1119                    -1 when explicitly cancelled.  If items were selected, then
1120                    selected is filled in with an allocated array of menu_item
1121                    structures, one for each selected line.  The caller must
1122                    free this array when done with it.  The "count" field
1123                    of selected is a user supplied count.  If the user did
1124                    not supply a count, then the count field is filled with
1125                    -1 (meaning all).  A count of zero is equivalent to not
1126                    being selected and should not be in the list.  If no items
1127                    were selected, then selected is NULL'ed out.  How is the
1128                    mode of the menu.  Three valid values are PICK_NONE,
1129                    PICK_ONE, and PICK_N, meaning: nothing is selectable,
1130                    only one thing is selectable, and any number valid items
1131                    may selected.  If how is PICK_NONE, this function should
1132                    never return anything but 0 or -1.
1133                 -- You may call select_menu() on a window multiple times --
1134                    the menu is saved until start_menu() or destroy_nhwindow()
1135                    is called on the window.
1136                 -- Note that NHW_MENU windows need not have select_menu()
1137                    called for them. There is no way of knowing whether
1138                    select_menu() will be called for the window at
1139                    create_nhwindow() time.
1140 */
mswin_select_menu(winid wid,int how,MENU_ITEM_P ** selected)1141 int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected)
1142 {
1143 	int nReturned = -1;
1144 
1145 	logDebug("mswin_select_menu(%d, %d)\n", wid, how);
1146 
1147 	if ((wid >= 0) &&
1148 		(wid < MAXWINDOWS) &&
1149 		(GetNHApp()->windowlist[wid].win != NULL))
1150 	{
1151 		nReturned = mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, how, selected);
1152 	}
1153     return nReturned;
1154 }
1155 
1156 /*
1157     -- Indicate to the window port that the inventory has been changed.
1158     -- Merely calls display_inventory() for window-ports that leave the
1159 	window up, otherwise empty.
1160 */
mswin_update_inventory()1161 void mswin_update_inventory()
1162 {
1163 	logDebug("mswin_update_inventory()\n");
1164 }
1165 
1166 /*
1167 mark_synch()    -- Don't go beyond this point in I/O on any channel until
1168                    all channels are caught up to here.  Can be an empty call
1169                    for the moment
1170 */
mswin_mark_synch()1171 void mswin_mark_synch()
1172 {
1173 	logDebug("mswin_mark_synch()\n");
1174 }
1175 
1176 /*
1177 wait_synch()    -- Wait until all pending output is complete (*flush*() for
1178                    streams goes here).
1179                 -- May also deal with exposure events etc. so that the
1180                    display is OK when return from wait_synch().
1181 */
mswin_wait_synch()1182 void mswin_wait_synch()
1183 {
1184 	logDebug("mswin_wait_synch()\n");
1185 }
1186 
1187 /*
1188 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
1189                    screen if the playing area is larger than the screen.
1190                 -- This function is only defined if CLIPPING is defined.
1191 */
mswin_cliparound(int x,int y)1192 void mswin_cliparound(int x, int y)
1193 {
1194 	winid wid = WIN_MAP;
1195 
1196 	logDebug("mswin_cliparound(%d, %d)\n", x, y);
1197 
1198     if ((wid >= 0) &&
1199         (wid < MAXWINDOWS) &&
1200         (GetNHApp()->windowlist[wid].win != NULL))
1201     {
1202 		 MSNHMsgClipAround data;
1203 		 data.x = x;
1204 		 data.y = y;
1205          SendMessage(
1206 			 GetNHApp()->windowlist[wid].win,
1207 			 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLIPAROUND, (LPARAM)&data );
1208     }
1209 }
1210 
1211 /*
1212 print_glyph(window, x, y, glyph)
1213                 -- Print the glyph at (x,y) on the given window.  Glyphs are
1214                    integers at the interface, mapped to whatever the window-
1215                    port wants (symbol, font, color, attributes, ...there's
1216                    a 1-1 map between glyphs and distinct things on the map).
1217 */
mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)1218 void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)
1219 {
1220     logDebug("mswin_print_glyph(%d, %d, %d, %d)\n", wid, x, y, glyph);
1221 
1222     if ((wid >= 0) &&
1223         (wid < MAXWINDOWS) &&
1224         (GetNHApp()->windowlist[wid].win != NULL))
1225     {
1226 		MSNHMsgPrintGlyph data;
1227 
1228 		ZeroMemory(&data, sizeof(data) );
1229 		data.x = x;
1230 		data.y = y;
1231 		data.glyph = glyph;
1232 		SendMessage( GetNHApp()->windowlist[wid].win,
1233 		         WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PRINT_GLYPH, (LPARAM)&data );
1234 	}
1235 }
1236 
1237 /*
1238 raw_print(str)  -- Print directly to a screen, or otherwise guarantee that
1239                    the user sees str.  raw_print() appends a newline to str.
1240                    It need not recognize ASCII control characters.  This is
1241                    used during startup (before windowing system initialization
1242                    -- maybe this means only error startup messages are raw),
1243                    for error messages, and maybe other "msg" uses.  E.g.
1244                    updating status for micros (i.e, "saving").
1245 */
mswin_raw_print(const char * str)1246 void mswin_raw_print(const char *str)
1247 {
1248 	TCHAR wbuf[255];
1249     logDebug("mswin_raw_print(%s)\n", str);
1250 	if( str && *str)
1251 		MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), TEXT("NetHack"), MB_OK );
1252 }
1253 
1254 /*
1255 raw_print_bold(str)
1256                 -- Like raw_print(), but prints in bold/standout (if
1257 possible).
1258 */
mswin_raw_print_bold(const char * str)1259 void mswin_raw_print_bold(const char *str)
1260 {
1261 	TCHAR wbuf[255];
1262     logDebug("mswin_raw_print_bold(%s)\n", str);
1263 	if( str && *str)
1264 		MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), TEXT("NetHack"), MB_OK );
1265 }
1266 
1267 /*
1268 int nhgetch()   -- Returns a single character input from the user.
1269                 -- In the tty window-port, nhgetch() assumes that tgetch()
1270                    will be the routine the OS provides to read a character.
1271                    Returned character _must_ be non-zero.
1272 */
mswin_nhgetch()1273 int mswin_nhgetch()
1274 {
1275 	PMSNHEvent event;
1276     int key = 0;
1277 
1278 	logDebug("mswin_nhgetch()\n");
1279 
1280 
1281 	while( (event = mswin_input_pop()) == NULL ||
1282 		   event->type != NHEVENT_CHAR )
1283 		mswin_main_loop();
1284 
1285 	key = event->kbd.ch;
1286     return (key);
1287 }
1288 
1289 /*
1290 int nh_poskey(int *x, int *y, int *mod)
1291                 -- Returns a single character input from the user or a
1292                    a positioning event (perhaps from a mouse).  If the
1293                    return value is non-zero, a character was typed, else,
1294                    a position in the MAP window is returned in x, y and mod.
1295                    mod may be one of
1296 
1297                         CLICK_1         -- mouse click type 1
1298                         CLICK_2         -- mouse click type 2
1299 
1300                    The different click types can map to whatever the
1301                    hardware supports.  If no mouse is supported, this
1302                    routine always returns a non-zero character.
1303 */
mswin_nh_poskey(int * x,int * y,int * mod)1304 int mswin_nh_poskey(int *x, int *y, int *mod)
1305 {
1306 	PMSNHEvent event;
1307   	int key;
1308 
1309 	logDebug("mswin_nh_poskey()\n");
1310 
1311 	while( (event = mswin_input_pop())==NULL ) mswin_main_loop();
1312 
1313 	if( event->type==NHEVENT_MOUSE ) {
1314 		*mod = event->ms.mod;
1315 		*x = event->ms.x;
1316 		*y = event->ms.y;
1317 		key = 0;
1318 	} else {
1319 		key = event->kbd.ch;
1320 	}
1321 	return (key);
1322 }
1323 
1324 /*
1325 nhbell()        -- Beep at user.  [This will exist at least until sounds are
1326                    redone, since sounds aren't attributable to windows anyway.]
1327 */
mswin_nhbell()1328 void mswin_nhbell()
1329 {
1330 	logDebug("mswin_nhbell()\n");
1331 }
1332 
1333 /*
1334 doprev_message()
1335                 -- Display previous messages.  Used by the ^P command.
1336                 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1337 */
mswin_doprev_message()1338 int mswin_doprev_message()
1339 {
1340     logDebug("mswin_doprev_message()\n");
1341 	SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
1342     return 0;
1343 }
1344 
1345 /*
1346 char yn_function(const char *ques, const char *choices, char default)
1347                 -- Print a prompt made up of ques, choices and default.
1348                    Read a single character response that is contained in
1349                    choices or default.  If choices is NULL, all possible
1350                    inputs are accepted and returned.  This overrides
1351                    everything else.  The choices are expected to be in
1352                    lower case.  Entering ESC always maps to 'q', or 'n',
1353                    in that order, if present in choices, otherwise it maps
1354                    to default.  Entering any other quit character (SPACE,
1355                    RETURN, NEWLINE) maps to default.
1356                 -- If the choices string contains ESC, then anything after
1357                    it is an acceptable response, but the ESC and whatever
1358                    follows is not included in the prompt.
1359                 -- If the choices string contains a '#' then accept a count.
1360                    Place this value in the global "yn_number" and return '#'.
1361                 -- This uses the top line in the tty window-port, other
1362                    ports might use a popup.
1363 */
mswin_yn_function(const char * question,const char * choices,CHAR_P def)1364 char mswin_yn_function(const char *question, const char *choices,
1365 		CHAR_P def)
1366 {
1367     int result=-1;
1368     char ch;
1369     char yn_esc_map='\033';
1370     char message[BUFSZ];
1371 	char res_ch[2];
1372 
1373 	logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def);
1374 
1375     if (choices) {
1376 		char *cb, choicebuf[QBUFSZ];
1377 		Strcpy(choicebuf, choices);
1378 		if ((cb = index(choicebuf, '\033')) != 0) {
1379 			/* anything beyond <esc> is hidden */
1380 			*cb = '\0';
1381 		}
1382 		sprintf(message, "%s [%s] ", question, choicebuf);
1383 		if (def) sprintf(eos(message), "(%c) ", def);
1384 		/* escape maps to 'q' or 'n' or default, in that order */
1385 		yn_esc_map = (index(choices, 'q') ? 'q' :
1386 			 (index(choices, 'n') ? 'n' : def));
1387 	} else {
1388 		Strcpy(message, question);
1389     }
1390 
1391 #if defined(WIN_CE_SMARTPHONE)
1392 	{
1393 	char buf[BUFSZ];
1394 	ZeroMemory(buf, sizeof(buf));
1395 	if( choices ) {
1396 		if( !index(choices, '\033') ) buf[0]='\033'; /* make sure ESC is always available */
1397 		strncat( buf, choices, sizeof(buf)-2);
1398 		NHSPhoneSetKeypadFromString( buf );
1399 	} else {
1400 		/* sometimes choices are included in the message itself, e.g. "what? [abcd]" */
1401 		char *p1, *p2;
1402 		p1 = strchr(question, '[');
1403 		p2 = strrchr(question, ']');
1404 		if( p1 && p2 && p1<p2 ) {
1405 			buf[0]='\033'; /* make sure ESC is always available */
1406 			strncat(buf, p1+1, p2-p1-1);
1407 			NHSPhoneSetKeypadFromString( buf );
1408 		} else if( strstr(question, "direction") ) {
1409 			/* asking for direction here */
1410 			NHSPhoneSetKeypadDirection( );
1411 		} else {
1412 			/* anything goes */
1413 			NHSPhoneSetKeypadFromString( "\0330-9a-zA-Z" );
1414 		}
1415 	}
1416 	}
1417 #endif /* defined(WIN_CE_SMARTPHONE) */
1418 
1419     mswin_putstr(WIN_MESSAGE, ATR_BOLD, message);
1420 
1421     /* Only here if main window is not present */
1422     while (result<0) {
1423 	ch=mswin_nhgetch();
1424 	if (ch=='\033') {
1425 	    result=yn_esc_map;
1426 	} else if (choices && !index(choices,ch)) {
1427 	    /* FYI: ch==-115 is for KP_ENTER */
1428 	    if (def && (ch==' ' || ch=='\r' || ch=='\n' || ch==-115)) {
1429 		result=def;
1430 	    } else {
1431 		mswin_nhbell();
1432 		/* and try again... */
1433 	    }
1434 	} else {
1435 	    result=ch;
1436 	}
1437     }
1438 
1439 	/* display selection in the message window */
1440 	if( isprint(ch) ) {
1441 		res_ch[0] = ch;
1442 		res_ch[1] = '\x0';
1443 		mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1);
1444 	}
1445 
1446 	/* prevent "--more--" prompt from appearing when several
1447 	   questions being asked in the same loop (like selling
1448 	   something in the shop)
1449 	   It does not really clears the window - mhmsgwnd.c */
1450 	mswin_clear_nhwindow(WIN_MESSAGE);
1451 
1452 #if defined(WIN_CE_SMARTPHONE)
1453 	NHSPhoneSetKeypadDefault();
1454 #endif
1455     return result;
1456 }
1457 
1458 /*
1459 getlin(const char *ques, char *input)
1460 	    -- Prints ques as a prompt and reads a single line of text,
1461 	       up to a newline.  The string entered is returned without the
1462 	       newline.  ESC is used to cancel, in which case the string
1463 	       "\033\000" is returned.
1464 	    -- getlin() must call flush_screen(1) before doing anything.
1465 	    -- This uses the top line in the tty window-port, other
1466 	       ports might use a popup.
1467 */
mswin_getlin(const char * question,char * input)1468 void mswin_getlin(const char *question, char *input)
1469 {
1470 	logDebug("mswin_getlin(%s, %p)\n", question, input);
1471 	if( mswin_getlin_window(question, input, BUFSZ)==IDCANCEL ) {
1472 		strcpy(input, "\033");
1473 	}
1474 }
1475 
1476 /*
1477 int get_ext_cmd(void)
1478 	    -- Get an extended command in a window-port specific way.
1479 	       An index into extcmdlist[] is returned on a successful
1480 	       selection, -1 otherwise.
1481 */
mswin_get_ext_cmd()1482 int mswin_get_ext_cmd()
1483 {
1484 	int ret;
1485 	logDebug("mswin_get_ext_cmd()\n");
1486 
1487 	if(mswin_ext_cmd_window (&ret) == IDCANCEL)
1488 		return -1;
1489 	else
1490 		return ret;
1491 }
1492 
1493 
1494 /*
1495 number_pad(state)
1496 	    -- Initialize the number pad to the given state.
1497 */
mswin_number_pad(int state)1498 void mswin_number_pad(int state)
1499 {
1500     /* Do Nothing */
1501 	logDebug("mswin_number_pad(%d)\n", state);
1502 }
1503 
1504 /*
1505 delay_output()  -- Causes a visible delay of 50ms in the output.
1506 	       Conceptually, this is similar to wait_synch() followed
1507 	       by a nap(50ms), but allows asynchronous operation.
1508 */
mswin_delay_output()1509 void mswin_delay_output()
1510 {
1511 	logDebug("mswin_delay_output()\n");
1512 	Sleep(50);
1513 }
1514 
mswin_change_color()1515 void mswin_change_color()
1516 {
1517 	logDebug("mswin_change_color()\n");
1518 }
1519 
mswin_get_color_string()1520 char *mswin_get_color_string()
1521 {
1522 	logDebug("mswin_get_color_string()\n");
1523 	return( "" );
1524 }
1525 
1526 /*
1527 start_screen()  -- Only used on Unix tty ports, but must be declared for
1528 	       completeness.  Sets up the tty to work in full-screen
1529 	       graphics mode.  Look at win/tty/termcap.c for an
1530 	       example.  If your window-port does not need this function
1531 	       just declare an empty function.
1532 */
mswin_start_screen()1533 void mswin_start_screen()
1534 {
1535     /* Do Nothing */
1536 	logDebug("mswin_start_screen()\n");
1537 }
1538 
1539 /*
1540 end_screen()    -- Only used on Unix tty ports, but must be declared for
1541 	       completeness.  The complement of start_screen().
1542 */
mswin_end_screen()1543 void mswin_end_screen()
1544 {
1545     /* Do Nothing */
1546 	logDebug("mswin_end_screen()\n");
1547 }
1548 
1549 /*
1550 outrip(winid, int)
1551 	    -- The tombstone code.  If you want the traditional code use
1552 	       genl_outrip for the value and check the #if in rip.c.
1553 */
mswin_outrip(winid wid,int how)1554 void mswin_outrip(winid wid, int how)
1555 {
1556    	logDebug("mswin_outrip(%d)\n", wid, how);
1557     if ((wid >= 0) && (wid < MAXWINDOWS) ) {
1558 		DestroyWindow(GetNHApp()->windowlist[wid].win);
1559 		GetNHApp()->windowlist[wid].win = mswin_init_RIP_window();
1560 		GetNHApp()->windowlist[wid].type = NHW_RIP;
1561 		GetNHApp()->windowlist[wid].dead = 0;
1562 	}
1563 
1564 	genl_outrip(wid, how);
1565 }
1566 
1567 /* handle options updates here */
mswin_preference_update(const char * pref)1568 void mswin_preference_update(const char *pref)
1569 {
1570 	HDC hdc;
1571 
1572 	if( _stricmp( pref, "font_menu")==0 ||
1573 		_stricmp( pref, "font_size_menu")==0 ) {
1574 		if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN ||
1575 			iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
1576 			iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
1577 
1578 		hdc = GetDC(GetNHApp()->hMainWnd);
1579 		mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE);
1580 		mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE);
1581 		mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE);
1582 		mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE);
1583 		mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE);
1584 		mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE);
1585 		ReleaseDC(GetNHApp()->hMainWnd, hdc);
1586 
1587 		mswin_layout_main_window(NULL);
1588 		return;
1589 	}
1590 
1591 	if( _stricmp( pref, "font_status")==0 ||
1592 		_stricmp( pref, "font_size_status")==0 ) {
1593 
1594 		if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN ||
1595 			iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
1596 			iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
1597 
1598 		hdc = GetDC(GetNHApp()->hMainWnd);
1599 		mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE);
1600 		mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE);
1601 		mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE);
1602 		mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE);
1603 		mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE);
1604 		mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE);
1605 		ReleaseDC(GetNHApp()->hMainWnd, hdc);
1606 
1607 		mswin_layout_main_window(NULL);
1608 		return;
1609 	}
1610 
1611 	if( _stricmp( pref, "font_message")==0 ||
1612 		_stricmp( pref, "font_size_message")==0 ) {
1613 
1614 		if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN ||
1615 			iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
1616 			iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
1617 
1618 		hdc = GetDC(GetNHApp()->hMainWnd);
1619 		mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE);
1620 		mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE);
1621 		mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE);
1622 		mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE);
1623 		mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE);
1624 		mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE);
1625 		ReleaseDC(GetNHApp()->hMainWnd, hdc);
1626 
1627 		mswin_layout_main_window(NULL);
1628 		return;
1629 	}
1630 
1631 	if( _stricmp( pref, "font_text")==0 ||
1632 		_stricmp( pref, "font_size_text")==0 ) {
1633 
1634 		if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN ||
1635 			iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
1636 			iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
1637 
1638 		hdc = GetDC(GetNHApp()->hMainWnd);
1639 		mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE);
1640 		mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE);
1641 		mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE);
1642 		mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE);
1643 		mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE);
1644 		mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE);
1645 		ReleaseDC(GetNHApp()->hMainWnd, hdc);
1646 
1647 		mswin_layout_main_window(NULL);
1648 		return;
1649 	}
1650 
1651 	if( _stricmp( pref, "scroll_margin")==0 ) {
1652 		mswin_cliparound(u.ux, u.uy);
1653 		return;
1654 	}
1655 
1656 	if( _stricmp( pref, "map_mode")==0 ) {
1657 		mswin_select_map_mode( iflags.wc_map_mode );
1658 		return;
1659 	}
1660 
1661 	if( _stricmp( pref, "hilite_pet")==0 ) {
1662 		InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE);
1663 		return;
1664 	}
1665 
1666 	if( _stricmp( pref, "align_message")==0 ||
1667 		_stricmp( pref, "align_status")==0 ) {
1668 		mswin_layout_main_window(NULL);
1669 		return;
1670 	}
1671 
1672 	if( _stricmp( pref, "vary_msgcount")==0 ) {
1673 		InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1674 		mswin_layout_main_window(NULL);
1675 		return;
1676 	}
1677 
1678 	if( _stricmp( pref, "fullscreen")==0 ) {
1679 		mswin_set_fullscreen(iflags.wc2_fullscreen);
1680 		return;
1681 	}
1682 
1683 	if( _stricmp( pref, "softkeyboard")==0 ) {
1684 		GetNHApp()->bUseSIP = iflags.wc2_softkeyboard;
1685 		return;
1686 	}
1687 
1688 	if( _stricmp( pref, "wraptext")==0 ) {
1689 		GetNHApp()->bWrapText = iflags.wc2_wraptext;
1690 		return;
1691 	}
1692 
1693 }
1694 
mswin_main_loop()1695 void mswin_main_loop()
1696 {
1697 	MSG msg;
1698 
1699 	while( !mswin_have_input() &&
1700 		   GetMessage(&msg, NULL, 0, 0)!=0 ) {
1701 		if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
1702 			TranslateMessage(&msg);
1703 			DispatchMessage(&msg);
1704 		}
1705 	}
1706 }
1707 
1708 /* clean up and quit */
bail(const char * mesg)1709 void bail(const char *mesg)
1710 {
1711     clearlocks();
1712     mswin_exit_nhwindows(mesg);
1713     terminate(EXIT_SUCCESS);
1714     /*NOTREACHED*/
1715 }
1716 
initMapTiles(void)1717 BOOL initMapTiles(void)
1718 {
1719 	HBITMAP hBmp;
1720 	BITMAP  bm;
1721 	TCHAR   wbuf[MAX_PATH];
1722 	int     tl_num;
1723 	SIZE    map_size;
1724 	extern int total_tiles_used;
1725 
1726 	/* no file - no tile */
1727 	if( !(iflags.wc_tile_file && *iflags.wc_tile_file) )
1728 		return TRUE;
1729 
1730 	/* load bitmap */
1731 	hBmp = SHLoadDIBitmap(NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH));
1732 	if( hBmp==NULL ) {
1733 		raw_print("Cannot load tiles from the file. Reverting back to default.");
1734 		return FALSE;
1735 	}
1736 
1737 	/* calculate tile dimensions */
1738 	GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bm);
1739 	if( bm.bmWidth%iflags.wc_tile_width ||
1740 		bm.bmHeight%iflags.wc_tile_height ) {
1741 		DeleteObject(hBmp);
1742 		raw_print("Tiles bitmap does not match tile_width and tile_height options. Reverting back to default.");
1743 		return FALSE;
1744 	}
1745 
1746 	tl_num = (bm.bmWidth/iflags.wc_tile_width)*
1747 		     (bm.bmHeight/iflags.wc_tile_height);
1748 	if( tl_num<total_tiles_used ) {
1749 		DeleteObject(hBmp);
1750 		raw_print("Number of tiles in the bitmap is less than required by the game. Reverting back to default.");
1751 		return FALSE;
1752 	}
1753 
1754 	/* set the tile information */
1755 	if( GetNHApp()->bmpMapTiles!=GetNHApp()->bmpTiles ) {
1756 		DeleteObject(GetNHApp()->bmpMapTiles);
1757 	}
1758 
1759 	GetNHApp()->bmpMapTiles = hBmp;
1760 	GetNHApp()->mapTile_X = iflags.wc_tile_width;
1761 	GetNHApp()->mapTile_Y = iflags.wc_tile_height;
1762 	GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width;
1763 
1764 	map_size.cx = GetNHApp()->mapTile_X * COLNO;
1765 	map_size.cy = GetNHApp()->mapTile_Y * ROWNO;
1766 	mswin_map_stretch(
1767 		mswin_hwnd_from_winid(WIN_MAP),
1768 		&map_size,
1769 		TRUE
1770 	);
1771 	return TRUE;
1772 }
1773 
mswin_popup_display(HWND hWnd,int * done_indicator)1774 void mswin_popup_display(HWND hWnd, int* done_indicator)
1775 {
1776 	MSG msg;
1777 	HWND hChild;
1778 
1779 	/* activate the menu window */
1780 	GetNHApp()->hPopupWnd = hWnd;
1781 
1782 	mswin_layout_main_window(hWnd);
1783 
1784 	/* disable game windows */
1785 	for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD);
1786 		 hChild;
1787 		 hChild = GetWindow(hChild, GW_HWNDNEXT) ) {
1788 		if( hChild!=hWnd ) EnableWindow(hChild, FALSE);
1789 	}
1790 #if defined(WIN_CE_SMARTPHONE)
1791 	ShowWindow(GetNHApp()->hMenuBar, SW_HIDE);
1792 	ShowWindow(SHFindMenuBar(hWnd), SW_SHOW);
1793 #else
1794 	EnableWindow(GetNHApp()->hMenuBar, FALSE);
1795 #endif
1796 
1797 	/* bring menu window on top */
1798 	SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1799 
1800 	/* go into message loop */
1801 	if( done_indicator ) *done_indicator = 0;
1802 	while( IsWindow(hWnd) &&
1803 		   (done_indicator==NULL || !*done_indicator) &&
1804 		   GetMessage(&msg, NULL, 0, 0)!=0 ) {
1805 		if( !IsDialogMessage(hWnd, &msg) ) {
1806 			if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
1807 				TranslateMessage(&msg);
1808 				DispatchMessage(&msg);
1809 			}
1810 		}
1811 	}
1812 }
1813 
mswin_popup_destroy(HWND hWnd)1814 void mswin_popup_destroy(HWND hWnd)
1815 {
1816 	HWND hChild;
1817 
1818 	/* enable game windows */
1819 	for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD);
1820 		 hChild;
1821 		 hChild = GetWindow(hChild, GW_HWNDNEXT) ) {
1822 		if( hChild!= hWnd) {
1823 			EnableWindow(hChild, TRUE);
1824 		}
1825 	}
1826 #if defined(WIN_CE_SMARTPHONE)
1827 	ShowWindow(SHFindMenuBar(hWnd), SW_HIDE);
1828 	ShowWindow(GetNHApp()->hMenuBar, SW_SHOW);
1829 #else
1830 	EnableWindow(GetNHApp()->hMenuBar, TRUE);
1831 #endif
1832 
1833 	SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
1834 	GetNHApp()->hPopupWnd = NULL;
1835 	mswin_window_mark_dead( mswin_winid_from_handle(hWnd) );
1836 	DestroyWindow(hWnd);
1837 
1838 	mswin_layout_main_window(hWnd);
1839 
1840 	SetFocus(GetNHApp()->hMainWnd );
1841 }
1842 
mswin_set_fullscreen(BOOL is_fullscreen)1843 void mswin_set_fullscreen(BOOL is_fullscreen)
1844 {
1845 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
1846 	SetForegroundWindow(GetNHApp()->hMainWnd);
1847 	if(	is_fullscreen ) {
1848 		SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
1849 		MoveWindow(
1850 			GetNHApp()->hMainWnd,
1851 			0,
1852 			0,
1853 			GetSystemMetrics(SM_CXSCREEN),
1854 			GetSystemMetrics(SM_CYSCREEN),
1855 			FALSE
1856 		);
1857 	} else {
1858 		RECT rc;
1859 		SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
1860 		SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
1861 		MoveWindow(
1862 			GetNHApp()->hMainWnd,
1863 			rc.left,
1864 			rc.top,
1865 			rc.right - rc.left,
1866 			rc.bottom - rc.top,
1867 			FALSE
1868 		);
1869 	}
1870 	GetNHApp()->bFullScreen = is_fullscreen;
1871 #else
1872 	GetNHApp()->bFullScreen = FALSE;
1873 #endif
1874 }
1875 
1876 #if defined(WIN_CE_SMARTPHONE)
NHSPhoneDialogSetup(HWND hDlg,BOOL is_edit,BOOL is_fullscreen)1877 void NHSPhoneDialogSetup(HWND hDlg, BOOL is_edit, BOOL is_fullscreen)
1878 {
1879     SHMENUBARINFO mbi;
1880 	HWND hOK, hCancel;
1881 	RECT rtOK, rtDlg;
1882 
1883 	// Create our MenuBar
1884     ZeroMemory(&mbi, sizeof(SHMENUBARINFO));
1885     mbi.cbSize = sizeof(mbi);
1886     mbi.hwndParent = hDlg;
1887     mbi.nToolBarId = IDC_SPHONE_DIALOGBAR;
1888     mbi.hInstRes = GetNHApp()->hApp;
1889     if(!SHCreateMenuBar(&mbi)) {
1890 		error("cannot create dialog menu");
1891 	}
1892 
1893 	if(is_fullscreen) {
1894 		SHINITDLGINFO shidi;
1895 		RECT main_wnd_rect;
1896 		shidi.dwMask = SHIDIM_FLAGS;
1897 		shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN;
1898 		shidi.hDlg = hDlg;
1899 		SHInitDialog(&shidi);
1900 
1901 		GetWindowRect(GetNHApp()->hMainWnd, &main_wnd_rect);
1902 		MoveWindow(
1903 			hDlg,
1904 			main_wnd_rect.left,
1905 			main_wnd_rect.top,
1906 			main_wnd_rect.right - main_wnd_rect.left,
1907 			main_wnd_rect.bottom - main_wnd_rect.top,
1908 			FALSE
1909 		);
1910 	}
1911 
1912 	/* hide OK and CANCEL buttons */
1913 	hOK = GetDlgItem(hDlg, IDOK);
1914 	hCancel = GetDlgItem(hDlg, IDCANCEL);
1915 
1916 	if( IsWindow(hCancel) ) ShowWindow(hCancel, SW_HIDE);
1917 	if( IsWindow(hOK) ) {
1918 		GetWindowRect(hOK, &rtOK);
1919 		GetWindowRect(hDlg, &rtDlg);
1920 
1921 		rtDlg.bottom -= rtOK.bottom-rtOK.top;
1922 		ShowWindow(hOK, SW_HIDE);
1923 		SetWindowPos( hDlg, HWND_TOP,
1924 			          0, 0,
1925 					  rtDlg.right-rtDlg.left, rtDlg.bottom-rtDlg.top,
1926 					  SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOZORDER );
1927 	}
1928 
1929 	/* override "Back" button for edit box dialogs */
1930 	if( is_edit )
1931 		SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK, MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY));
1932 }
1933 #endif /* defined(WIN_CE_SMARTPHONE) */
1934 
mswin_read_reg(void)1935 void mswin_read_reg(void)
1936 {
1937 }
1938 
mswin_destroy_reg(void)1939 void mswin_destroy_reg(void)
1940 {
1941 }
1942 
mswin_write_reg(void)1943 void mswin_write_reg(void)
1944 {
1945 }
1946 
1947 #ifdef _DEBUG
1948 #include <stdarg.h>
1949 
1950 void
logDebug(const char * fmt,...)1951 logDebug(const char *fmt, ...)
1952 {
1953   FILE *dfp = fopen("nhtrace.log", "a");
1954 
1955   if (dfp) {
1956      va_list args;
1957 
1958      va_start(args, fmt);
1959      vfprintf(dfp, fmt, args);
1960      va_end(args);
1961      fclose(dfp);
1962   }
1963 }
1964 
1965 #endif
1966 
1967