OSDN Git Service

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