1 /* Copyright (C) 2001 by Alex Kompel <shurikk@pacbell.net> */
2 /* NetHack may be freely redistributed. See license for details. */
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.
11 #include "func_tab.h" /* for extended commands */
30 extern const char *killed_by_prefix[];
33 extern void logDebug(const char *fmt, ...);
35 void logDebug(const char *fmt, ...) { }
38 static void mswin_main_loop(void);
39 static BOOL initMapTiles(void);
40 static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr);
41 static void prompt_for_player_selection(void);
43 #define TOTAL_BRUSHES 10
44 HBRUSH brush_table[TOTAL_BRUSHES];
47 HBRUSH menu_bg_brush = NULL;
48 HBRUSH menu_fg_brush = NULL;
49 HBRUSH text_bg_brush = NULL;
50 HBRUSH text_fg_brush = NULL;
51 HBRUSH status_bg_brush = NULL;
52 HBRUSH status_fg_brush = NULL;
53 HBRUSH message_bg_brush = NULL;
54 HBRUSH message_fg_brush = NULL;
56 COLORREF menu_bg_color = RGB(0, 0, 0);
57 COLORREF menu_fg_color = RGB(0xFF, 0xFF, 0xFF);
58 COLORREF text_bg_color = RGB(0, 0, 0);
59 COLORREF text_fg_color = RGB(0xFF, 0xFF, 0xFF);
60 COLORREF status_bg_color = RGB(0, 0, 0);
61 COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF);
62 COLORREF message_bg_color = RGB(0, 0, 0);
63 COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF);
65 /* Interface definition, for windows.c */
66 struct window_procs mswin_procs = {
68 WC_COLOR|WC_HILITE_PET|WC_ALIGN_MESSAGE|WC_ALIGN_STATUS|
69 WC_INVERSE|WC_SCROLL_AMOUNT|WC_SCROLL_MARGIN|WC_MAP_MODE|
70 WC_FONT_MESSAGE|WC_FONT_STATUS|WC_FONT_MENU|WC_FONT_TEXT|WC_FONT_MAP|
71 WC_FONTSIZ_MESSAGE|WC_FONTSIZ_STATUS|WC_FONTSIZ_MENU|WC_FONTSIZ_TEXT|
72 WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE|WC_VARY_MSGCOUNT|
73 WC_WINDOWCOLORS|WC_PLAYER_SELECTION|WC_SPLASH_SCREEN|WC_POPUP_DIALOG,
76 mswin_player_selection,
80 mswin_suspend_nhwindows,
81 mswin_resume_nhwindows,
82 mswin_create_nhwindow,
84 mswin_display_nhwindow,
85 mswin_destroy_nhwindow,
93 genl_message_menu, /* no need for X-specific handling */
94 mswin_update_inventory,
105 mswin_raw_print_bold,
109 mswin_doprev_message,
115 #ifdef CHANGE_COLOR /* only a Mac option currently */
117 mswin_change_background,
119 /* other defs that really should go away (they're tty specific) */
123 mswin_preference_update,
128 init_nhwindows(int* argcp, char** argv)
129 -- Initialize the windows used by NetHack. This can also
130 create the standard windows listed at the top, but does
132 -- Any commandline arguments relevant to the windowport
133 should be interpreted, and *argcp and *argv should
134 be changed to remove those arguments.
135 -- When the message window is created, the variable
136 iflags.window_inited needs to be set to TRUE. Otherwise
137 all plines() will be done via raw_print().
138 ** Why not have init_nhwindows() create all of the "standard"
139 ** windows? Or at least all but WIN_INFO? -dean
141 void mswin_init_nhwindows(int* argc, char** argv)
143 logDebug("mswin_init_nhwindows()\n");
147 /* truncate trace file */
148 FILE *dfp = fopen("nhtrace.log", "w");
152 mswin_nh_input_init();
154 /* set it to WIN_ERR so we can detect attempts to
155 use this ID before it is inialized */
158 /* Read Windows settings from the reqistry */
159 /* First set safe defaults */
160 GetNHApp()->regMainMinX = CW_USEDEFAULT;
162 /* Create the main window */
163 GetNHApp()->hMainWnd = mswin_init_main_window();
164 if (!GetNHApp()->hMainWnd)
166 panic("Cannot create main window");
169 /* Set menu check mark for interface mode */
170 mswin_menu_check_intf_mode();
172 /* check default values */
173 if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN ||
174 iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
175 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
177 if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN ||
178 iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
179 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
181 if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN ||
182 iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
183 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
185 if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN ||
186 iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
187 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
189 if( iflags.wc_align_message==0 ) iflags.wc_align_message = ALIGN_TOP;
190 if( iflags.wc_align_status==0 ) iflags.wc_align_status = ALIGN_BOTTOM;
191 if( iflags.wc_scroll_margin==0 ) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
192 if( iflags.wc_scroll_amount==0 ) iflags.wc_scroll_amount = DEF_CLIPAROUND_AMOUNT;
193 if( iflags.wc_tile_width==0 ) iflags.wc_tile_width = TILE_X;
194 if( iflags.wc_tile_height==0 ) iflags.wc_tile_height = TILE_Y;
196 if( iflags.wc_vary_msgcount==0 ) iflags.wc_vary_msgcount = 4;
198 /* force tabs in menus */
199 iflags.menu_tab_sep = 1;
201 /* force toptenwin to be true. toptenwin is the option that decides whether to
202 * write output to a window or stdout. stdout doesn't make sense on Windows
203 * non-console applications
206 set_option_mod_status("toptenwin", SET_IN_FILE);
207 set_option_mod_status("perm_invent", SET_IN_FILE);
209 /* initialize map tiles bitmap */
212 /* set tile-related options to readonly */
213 set_wc_option_mod_status(
214 WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE,
217 /* set font-related options to change in the game */
218 set_wc_option_mod_status(
237 mswin_color_from_string(iflags.wc_foregrnd_menu, &menu_fg_brush, &menu_fg_color);
238 mswin_color_from_string(iflags.wc_foregrnd_message, &message_fg_brush, &message_fg_color);
239 mswin_color_from_string(iflags.wc_foregrnd_status, &status_fg_brush, &status_fg_color);
240 mswin_color_from_string(iflags.wc_foregrnd_text, &text_fg_brush, &text_fg_color);
241 mswin_color_from_string(iflags.wc_backgrnd_menu, &menu_bg_brush, &menu_bg_color);
242 mswin_color_from_string(iflags.wc_backgrnd_message, &message_bg_brush, &message_bg_color);
243 mswin_color_from_string(iflags.wc_backgrnd_status, &status_bg_brush, &status_bg_color);
244 mswin_color_from_string(iflags.wc_backgrnd_text, &text_bg_brush, &text_bg_color);
246 if (iflags.wc_splash_screen) mswin_display_splash_window(FALSE);
247 iflags.window_inited = TRUE;
251 /* Do a window-port specific player type selection. If player_selection()
252 offers a Quit option, it is its responsibility to clean up and terminate
253 the process. You need to fill in pl_character[0].
255 void mswin_player_selection(void)
259 logDebug("mswin_player_selection()\n");
261 if (iflags.wc_player_selection == VIA_DIALOG) {
262 /* pick player type randomly (use pre-selected role/race/gender/alignment) */
263 if( flags.randomall ) {
264 if (flags.initrole < 0) {
265 flags.initrole = pick_role(flags.initrace, flags.initgend,
266 flags.initalign, PICK_RANDOM);
267 if (flags.initrole < 0) {
268 raw_print("Incompatible role!");
269 flags.initrole = randrole();
273 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
274 flags.initrace = pick_race(flags.initrole, flags.initgend,
275 flags.initalign, PICK_RANDOM);
276 if (flags.initrace < 0) {
277 raw_print("Incompatible race!");
278 flags.initrace = randrace(flags.initrole);
282 if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
284 flags.initgend = pick_gend(flags.initrole, flags.initrace,
285 flags.initalign, PICK_RANDOM);
286 if (flags.initgend < 0) {
287 raw_print("Incompatible gender!");
288 flags.initgend = randgend(flags.initrole, flags.initrace);
292 if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
294 flags.initalign = pick_align(flags.initrole, flags.initrace,
295 flags.initgend, PICK_RANDOM);
296 if (flags.initalign < 0) {
297 raw_print("Incompatible alignment!");
298 flags.initalign = randalign(flags.initrole, flags.initrace);
303 if( mswin_player_selection_window( &nRole ) == IDCANCEL ) {
307 } else { /* iflags.wc_player_selection == VIA_PROMPTS */
308 prompt_for_player_selection();
312 void prompt_for_player_selection(void)
315 char pick4u = 'n', thisch, lastch = 0;
316 char pbuf[QBUFSZ], plbuf[QBUFSZ];
319 menu_item *selected = 0;
322 logDebug("prompt_for_player_selection()\n");
324 /* prevent an unnecessary prompt */
327 /* Should we randomly pick for the player? */
328 if (!flags.randomall &&
329 (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
330 flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
332 char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,
333 flags.initrace, flags.initgend, flags.initalign);
335 /* tty_putstr(BASE_WINDOW, 0, ""); */
336 /* echoline = wins[BASE_WINDOW]->cury; */
337 box_result = NHMessageBox(NULL, prompt,
338 MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON1);
339 pick4u = (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033';
340 /* tty_putstr(BASE_WINDOW, 0, prompt); */
342 /* pick4u = lowc(readchar()); */
343 if (index(quitchars, pick4u)) pick4u = 'y';
344 } while(!index(ynqchars, pick4u));
345 if ((int)strlen(prompt) + 1 < CO) {
346 /* Echo choice and move back down line */
347 /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, pick4u); */
348 /* tty_putstr(BASE_WINDOW, 0, ""); */
350 /* Otherwise it's hard to tell where to echo, and things are
351 * wrapping a bit messily anyway, so (try to) make sure the next
352 * question shows up well and doesn't get wrapped at the
353 * bottom of the window.
355 /* tty_clear_nhwindow(BASE_WINDOW) */ ;
357 if (pick4u != 'y' && pick4u != 'n') {
359 if (selected) free((genericptr_t) selected);
366 (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
367 flags.initrole, flags.initrace, flags.initgend, flags.initalign);
369 /* Select a role, if necessary */
370 /* we'll try to be compatible with pre-selected race/gender/alignment,
371 * but may not succeed */
372 if (flags.initrole < 0) {
373 char rolenamebuf[QBUFSZ];
374 /* Process the choice */
375 if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
376 /* Pick a random role */
377 flags.initrole = pick_role(flags.initrace, flags.initgend,
378 flags.initalign, PICK_RANDOM);
379 if (flags.initrole < 0) {
380 /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
381 flags.initrole = randrole();
384 /* tty_clear_nhwindow(BASE_WINDOW); */
385 /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
386 /* Prompt for a role */
387 win = create_nhwindow(NHW_MENU);
389 any.a_void = 0; /* zero out all bits */
390 for (i = 0; roles[i].name.m; i++) {
391 if (ok_role(i, flags.initrace, flags.initgend,
393 any.a_int = i+1; /* must be non-zero */
394 thisch = lowc(roles[i].name.m[0]);
395 if (thisch == lastch) thisch = highc(thisch);
396 if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) {
397 if (flags.initgend == 1 && roles[i].name.f)
398 Strcpy(rolenamebuf, roles[i].name.f);
400 Strcpy(rolenamebuf, roles[i].name.m);
402 if (roles[i].name.f) {
403 Strcpy(rolenamebuf, roles[i].name.m);
404 Strcat(rolenamebuf, "/");
405 Strcat(rolenamebuf, roles[i].name.f);
407 Strcpy(rolenamebuf, roles[i].name.m);
409 add_menu(win, NO_GLYPH, &any, thisch,
410 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED);
414 any.a_int = pick_role(flags.initrace, flags.initgend,
415 flags.initalign, PICK_RANDOM)+1;
416 if (any.a_int == 0) /* must be non-zero */
417 any.a_int = randrole()+1;
418 add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
419 "Random", MENU_UNSELECTED);
420 any.a_int = i+1; /* must be non-zero */
421 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
422 "Quit", MENU_UNSELECTED);
423 Sprintf(pbuf, "Pick a role for your %s", plbuf);
425 n = select_menu(win, PICK_ONE, &selected);
426 destroy_nhwindow(win);
428 /* Process the choice */
429 if (n != 1 || selected[0].item.a_int == any.a_int)
430 goto give_up; /* Selected quit */
432 flags.initrole = selected[0].item.a_int - 1;
433 free((genericptr_t) selected), selected = 0;
435 (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
436 flags.initrole, flags.initrace, flags.initgend, flags.initalign);
439 /* Select a race, if necessary */
440 /* force compatibility with role, try for compatibility with
441 * pre-selected gender/alignment */
442 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
443 /* pre-selected race not valid */
444 if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
445 flags.initrace = pick_race(flags.initrole, flags.initgend,
446 flags.initalign, PICK_RANDOM);
447 if (flags.initrace < 0) {
448 /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
449 flags.initrace = randrace(flags.initrole);
451 } else { /* pick4u == 'n' */
452 /* Count the number of valid races */
453 n = 0; /* number valid */
454 k = 0; /* valid race */
455 for (i = 0; races[i].noun; i++) {
456 if (ok_race(flags.initrole, i, flags.initgend,
463 for (i = 0; races[i].noun; i++) {
464 if (validrace(flags.initrole, i)) {
471 /* Permit the user to pick, if there is more than one */
473 /* tty_clear_nhwindow(BASE_WINDOW); */
474 /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
475 win = create_nhwindow(NHW_MENU);
477 any.a_void = 0; /* zero out all bits */
478 for (i = 0; races[i].noun; i++)
479 if (ok_race(flags.initrole, i, flags.initgend,
481 any.a_int = i+1; /* must be non-zero */
482 add_menu(win, NO_GLYPH, &any, races[i].noun[0],
483 0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
485 any.a_int = pick_race(flags.initrole, flags.initgend,
486 flags.initalign, PICK_RANDOM)+1;
487 if (any.a_int == 0) /* must be non-zero */
488 any.a_int = randrace(flags.initrole)+1;
489 add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
490 "Random", MENU_UNSELECTED);
491 any.a_int = i+1; /* must be non-zero */
492 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
493 "Quit", MENU_UNSELECTED);
494 Sprintf(pbuf, "Pick the race of your %s", plbuf);
496 n = select_menu(win, PICK_ONE, &selected);
497 destroy_nhwindow(win);
498 if (n != 1 || selected[0].item.a_int == any.a_int)
499 goto give_up; /* Selected quit */
501 k = selected[0].item.a_int - 1;
502 free((genericptr_t) selected), selected = 0;
506 (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
507 flags.initrole, flags.initrace, flags.initgend, flags.initalign);
510 /* Select a gender, if necessary */
511 /* force compatibility with role/race, try for compatibility with
512 * pre-selected alignment */
513 if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
515 /* pre-selected gender not valid */
516 if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
517 flags.initgend = pick_gend(flags.initrole, flags.initrace,
518 flags.initalign, PICK_RANDOM);
519 if (flags.initgend < 0) {
520 /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
521 flags.initgend = randgend(flags.initrole, flags.initrace);
523 } else { /* pick4u == 'n' */
524 /* Count the number of valid genders */
525 n = 0; /* number valid */
526 k = 0; /* valid gender */
527 for (i = 0; i < ROLE_GENDERS; i++) {
528 if (ok_gend(flags.initrole, flags.initrace, i,
535 for (i = 0; i < ROLE_GENDERS; i++) {
536 if (validgend(flags.initrole, flags.initrace, i)) {
543 /* Permit the user to pick, if there is more than one */
545 /* tty_clear_nhwindow(BASE_WINDOW); */
546 /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
547 win = create_nhwindow(NHW_MENU);
549 any.a_void = 0; /* zero out all bits */
550 for (i = 0; i < ROLE_GENDERS; i++)
551 if (ok_gend(flags.initrole, flags.initrace, i,
554 add_menu(win, NO_GLYPH, &any, genders[i].adj[0],
555 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
557 any.a_int = pick_gend(flags.initrole, flags.initrace,
558 flags.initalign, PICK_RANDOM)+1;
559 if (any.a_int == 0) /* must be non-zero */
560 any.a_int = randgend(flags.initrole, flags.initrace)+1;
561 add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
562 "Random", MENU_UNSELECTED);
563 any.a_int = i+1; /* must be non-zero */
564 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
565 "Quit", MENU_UNSELECTED);
566 Sprintf(pbuf, "Pick the gender of your %s", plbuf);
568 n = select_menu(win, PICK_ONE, &selected);
569 destroy_nhwindow(win);
570 if (n != 1 || selected[0].item.a_int == any.a_int)
571 goto give_up; /* Selected quit */
573 k = selected[0].item.a_int - 1;
574 free((genericptr_t) selected), selected = 0;
578 (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
579 flags.initrole, flags.initrace, flags.initgend, flags.initalign);
582 /* Select an alignment, if necessary */
583 /* force compatibility with role/race/gender */
584 if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
586 /* pre-selected alignment not valid */
587 if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
588 flags.initalign = pick_align(flags.initrole, flags.initrace,
589 flags.initgend, PICK_RANDOM);
590 if (flags.initalign < 0) {
591 /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
592 flags.initalign = randalign(flags.initrole, flags.initrace);
594 } else { /* pick4u == 'n' */
595 /* Count the number of valid alignments */
596 n = 0; /* number valid */
597 k = 0; /* valid alignment */
598 for (i = 0; i < ROLE_ALIGNS; i++) {
599 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
606 for (i = 0; i < ROLE_ALIGNS; i++) {
607 if (validalign(flags.initrole, flags.initrace, i)) {
614 /* Permit the user to pick, if there is more than one */
616 /* tty_clear_nhwindow(BASE_WINDOW); */
617 /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
618 win = create_nhwindow(NHW_MENU);
620 any.a_void = 0; /* zero out all bits */
621 for (i = 0; i < ROLE_ALIGNS; i++)
622 if (ok_align(flags.initrole, flags.initrace,
623 flags.initgend, i)) {
625 add_menu(win, NO_GLYPH, &any, aligns[i].adj[0],
626 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
628 any.a_int = pick_align(flags.initrole, flags.initrace,
629 flags.initgend, PICK_RANDOM)+1;
630 if (any.a_int == 0) /* must be non-zero */
631 any.a_int = randalign(flags.initrole, flags.initrace)+1;
632 add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE,
633 "Random", MENU_UNSELECTED);
634 any.a_int = i+1; /* must be non-zero */
635 add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE,
636 "Quit", MENU_UNSELECTED);
637 Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
639 n = select_menu(win, PICK_ONE, &selected);
640 destroy_nhwindow(win);
641 if (n != 1 || selected[0].item.a_int == any.a_int)
642 goto give_up; /* Selected quit */
644 k = selected[0].item.a_int - 1;
645 free((genericptr_t) selected), selected = 0;
651 /* tty_display_nhwindow(BASE_WINDOW, FALSE); */
654 /* Ask the user for a player name. */
655 void mswin_askname(void)
657 logDebug("mswin_askname()\n");
659 if( mswin_getlin_window("Who are you?", plname, PL_NSIZ)==IDCANCEL ) {
666 /* Does window event processing (e.g. exposure events).
667 A noop for the tty and X window-ports.
669 void mswin_get_nh_event(void)
673 logDebug("mswin_get_nh_event()\n");
674 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)!=0 ) {
675 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
676 TranslateMessage(&msg);
677 DispatchMessage(&msg);
683 /* Exits the window system. This should dismiss all windows,
684 except the "window" used for raw_print(). str is printed if possible.
686 void mswin_exit_nhwindows(const char *str)
688 logDebug("mswin_exit_nhwindows(%s)\n", str);
689 /* Write Window settings to the registry */
692 DeleteObject(brush_table[--max_brush]);
695 /* Prepare the window to be suspended. */
696 void mswin_suspend_nhwindows(const char *str)
698 logDebug("mswin_suspend_nhwindows(%s)\n", str);
703 /* Restore the windows after being suspended. */
704 void mswin_resume_nhwindows()
706 logDebug("mswin_resume_nhwindows()\n");
710 /* Create a window of type "type" which can be
711 NHW_MESSAGE (top line)
712 NHW_STATUS (bottom lines)
713 NHW_MAP (main dungeon)
714 NHW_MENU (inventory or other "corner" windows)
715 NHW_TEXT (help/text, full screen paged window)
718 mswin_create_nhwindow(int type)
723 logDebug("mswin_create_nhwindow(%d)\n", type);
725 /* Return the next available winid
728 for (i=1; i<MAXWINDOWS; i++)
729 if (GetNHApp()->windowlist[i].win == NULL &&
730 !GetNHApp()->windowlist[i].dead)
733 panic ("ERROR: No windows available...\n");
738 GetNHApp()->windowlist[i].win = mswin_init_map_window();
739 GetNHApp()->windowlist[i].type = type;
740 GetNHApp()->windowlist[i].dead = 0;
745 GetNHApp()->windowlist[i].win = mswin_init_message_window();
746 GetNHApp()->windowlist[i].type = type;
747 GetNHApp()->windowlist[i].dead = 0;
752 GetNHApp()->windowlist[i].win = mswin_init_status_window();
753 GetNHApp()->windowlist[i].type = type;
754 GetNHApp()->windowlist[i].dead = 0;
759 GetNHApp()->windowlist[i].win = NULL; //will create later
760 GetNHApp()->windowlist[i].type = type;
761 GetNHApp()->windowlist[i].dead = 1;
766 GetNHApp()->windowlist[i].win = mswin_init_text_window();
767 GetNHApp()->windowlist[i].type = type;
768 GetNHApp()->windowlist[i].dead = 0;
773 ZeroMemory(&data, sizeof(data) );
775 SendMessage( GetNHApp()->hMainWnd,
776 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDWND, (LPARAM)&data );
780 /* Clear the given window, when asked to. */
781 void mswin_clear_nhwindow(winid wid)
783 logDebug("mswin_clear_nhwindow(%d)\n", wid);
786 (wid < MAXWINDOWS) &&
787 (GetNHApp()->windowlist[wid].win != NULL))
790 if( GetNHApp()->windowlist[wid].type == NHW_MAP ) {
791 if( Is_rogue_level(&u.uz) )
792 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), ROGUE_LEVEL_MAP_MODE);
794 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode);
799 GetNHApp()->windowlist[wid].win,
800 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLEAR_WINDOW, (LPARAM)NULL );
804 /* -- Display the window on the screen. If there is data
805 pending for output in that window, it should be sent.
806 If blocking is TRUE, display_nhwindow() will not
807 return until the data has been displayed on the screen,
808 and acknowledged by the user where appropriate.
809 -- All calls are blocking in the tty window-port.
810 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
811 --more--, if necessary, in the tty window-port.
813 void mswin_display_nhwindow(winid wid, BOOLEAN_P block)
815 logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block);
816 if (GetNHApp()->windowlist[wid].win != NULL)
818 if (GetNHApp()->windowlist[wid].type == NHW_MENU) {
820 mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, PICK_NONE, &p);
821 } if (GetNHApp()->windowlist[wid].type == NHW_TEXT) {
822 mswin_display_text_window(GetNHApp()->windowlist[wid].win);
823 } if (GetNHApp()->windowlist[wid].type == NHW_RIP) {
824 mswin_display_RIP_window(GetNHApp()->windowlist[wid].win);
827 UpdateWindow(GetNHApp()->windowlist[wid].win);
829 if ( GetNHApp()->windowlist[wid].type == NHW_MAP ) {
830 (void) mswin_nhgetch();
834 SetFocus(GetNHApp()->hMainWnd);
839 HWND mswin_hwnd_from_winid(winid wid)
841 if( wid>=0 && wid<MAXWINDOWS) {
842 return GetNHApp()->windowlist[wid].win;
848 winid mswin_winid_from_handle(HWND hWnd)
852 for (i=1; i<MAXWINDOWS; i++)
853 if (GetNHApp()->windowlist[i].win == hWnd)
858 winid mswin_winid_from_type(int type)
862 for (i=1; i<MAXWINDOWS; i++)
863 if (GetNHApp()->windowlist[i].type == type)
868 void mswin_window_mark_dead(winid wid)
870 if( wid>=0 && wid<MAXWINDOWS) {
871 GetNHApp()->windowlist[wid].win = NULL;
872 GetNHApp()->windowlist[wid].dead = 1;
876 /* Destroy will dismiss the window if the window has not
877 * already been dismissed.
879 void mswin_destroy_nhwindow(winid wid)
881 logDebug("mswin_destroy_nhwindow(%d)\n", wid);
883 if ((GetNHApp()->windowlist[wid].type == NHW_MAP) ||
884 (GetNHApp()->windowlist[wid].type == NHW_MESSAGE) ||
885 (GetNHApp()->windowlist[wid].type == NHW_STATUS)) {
886 /* main windows is going to take care of those */
891 if( !GetNHApp()->windowlist[wid].dead &&
892 GetNHApp()->windowlist[wid].win != NULL )
893 DestroyWindow(GetNHApp()->windowlist[wid].win);
894 GetNHApp()->windowlist[wid].win = NULL;
895 GetNHApp()->windowlist[wid].type = 0;
896 GetNHApp()->windowlist[wid].dead = 0;
900 /* Next output to window will start at (x,y), also moves
901 displayable cursor to (x,y). For backward compatibility,
902 1 <= x < cols, 0 <= y < rows, where cols and rows are
905 void mswin_curs(winid wid, int x, int y)
907 logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y);
910 (wid < MAXWINDOWS) &&
911 (GetNHApp()->windowlist[wid].win != NULL))
917 GetNHApp()->windowlist[wid].win,
918 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CURSOR, (LPARAM)&data );
923 putstr(window, attr, str)
924 -- Print str on the window with the given attribute. Only
925 printable ASCII characters (040-0126) must be supported.
926 Multiple putstr()s are output on separate lines.
934 If a window-port does not support all of these, it may map
935 unsupported attributes to a supported one (e.g. map them
936 all to ATR_INVERSE). putstr() may compress spaces out of
937 str, break str, or truncate str, if necessary for the
938 display. Where putstr() breaks a line, it has to clear
940 -- putstr should be implemented such that if two putstr()s
941 are done consecutively the user will see the first and
942 then the second. In the tty port, pline() achieves this
943 by calling more() or displaying both on the same line.
945 void mswin_putstr(winid wid, int attr, const char *text)
947 logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text);
949 mswin_putstr_ex(wid, attr, text, 0);
952 void mswin_putstr_ex(winid wid, int attr, const char *text, int app)
957 if( GetNHApp()->windowlist[wid].win==NULL &&
958 GetNHApp()->windowlist[wid].type==NHW_MENU ) {
959 GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_TEXT);
960 GetNHApp()->windowlist[wid].dead = 0;
963 if (GetNHApp()->windowlist[wid].win != NULL)
966 ZeroMemory(&data, sizeof(data));
971 GetNHApp()->windowlist[wid].win,
972 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PUTSTR, (LPARAM)&data );
974 /* yield a bit so it gets done immediately */
975 mswin_get_nh_event();
979 // build text to display later in message box
980 GetNHApp()->saved_text = realloc(GetNHApp()->saved_text, strlen(text) +
981 strlen(GetNHApp()->saved_text) + 1);
982 strcat(GetNHApp()->saved_text, text);
986 /* Display the file named str. Complain about missing files
987 iff complain is TRUE.
989 void mswin_display_file(const char *filename,BOOLEAN_P must_exist)
994 logDebug("mswin_display_file(%s, %d)\n", filename, must_exist);
996 f = dlb_fopen(filename, RDTMODE);
1000 _stprintf(message, TEXT("Warning! Could not find file: %s\n"), NH_A2W(filename, wbuf, sizeof(wbuf)));
1001 NHMessageBox(GetNHApp()->hMainWnd, message, MB_OK | MB_ICONEXCLAMATION );
1007 text = mswin_create_nhwindow(NHW_TEXT);
1009 while (dlb_fgets(line, LLEN, f)) {
1012 if( line[len-1]=='\n' ) line[len-1]='\x0';
1013 mswin_putstr(text, ATR_NONE, line);
1015 (void) dlb_fclose(f);
1017 mswin_display_nhwindow(text, 1);
1018 mswin_destroy_nhwindow(text);
1022 /* Start using window as a menu. You must call start_menu()
1023 before add_menu(). After calling start_menu() you may not
1024 putstr() to the window. Only windows of type NHW_MENU may
1027 void mswin_start_menu(winid wid)
1029 logDebug("mswin_start_menu(%d)\n", wid);
1031 (wid < MAXWINDOWS) ) {
1032 if( GetNHApp()->windowlist[wid].win==NULL &&
1033 GetNHApp()->windowlist[wid].type==NHW_MENU ) {
1034 GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_MENU);
1035 GetNHApp()->windowlist[wid].dead = 0;
1038 if(GetNHApp()->windowlist[wid].win != NULL) {
1040 GetNHApp()->windowlist[wid].win,
1041 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_STARTMENU, (LPARAM)NULL
1048 add_menu(windid window, int glyph, const anything identifier,
1049 char accelerator, char groupacc,
1050 int attr, char *str, boolean preselected)
1051 -- Add a text line str to the given menu window. If identifier
1052 is 0, then the line cannot be selected (e.g. a title).
1053 Otherwise, identifier is the value returned if the line is
1054 selected. Accelerator is a keyboard key that can be used
1055 to select the line. If the accelerator of a selectable
1056 item is 0, the window system is free to select its own
1057 accelerator. It is up to the window-port to make the
1058 accelerator visible to the user (e.g. put "a - " in front
1059 of str). The value attr is the same as in putstr().
1060 Glyph is an optional glyph to accompany the line. If
1061 window port cannot or does not want to display it, this
1062 is OK. If there is no glyph applicable, then this
1063 value will be NO_GLYPH.
1064 -- All accelerators should be in the range [A-Za-z].
1065 -- It is expected that callers do not mix accelerator
1066 choices. Either all selectable items have an accelerator
1067 or let the window system pick them. Don't do both.
1068 -- Groupacc is a group accelerator. It may be any character
1069 outside of the standard accelerator (see above) or a
1070 number. If 0, the item is unaffected by any group
1071 accelerator. If this accelerator conflicts with
1072 the menu command (or their user defined alises), it loses.
1073 The menu commands and aliases take care not to interfere
1074 with the default object class symbols.
1075 -- If you want this choice to be preselected when the
1076 menu is displayed, set preselected to TRUE.
1078 void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier,
1079 CHAR_P accelerator, CHAR_P group_accel, int attr,
1080 const char *str, BOOLEAN_P presel)
1082 logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n",
1083 wid, glyph, identifier, (char)accelerator, (char)group_accel,
1086 (wid < MAXWINDOWS) &&
1087 (GetNHApp()->windowlist[wid].win != NULL))
1089 MSNHMsgAddMenu data;
1090 ZeroMemory(&data, sizeof(data));
1092 data.identifier = identifier;
1093 data.accelerator = accelerator;
1094 data.group_accel = group_accel;
1097 data.presel = presel;
1100 GetNHApp()->windowlist[wid].win,
1101 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDMENU, (LPARAM)&data
1107 end_menu(window, prompt)
1108 -- Stop adding entries to the menu and flushes the window
1109 to the screen (brings to front?). Prompt is a prompt
1110 to give the user. If prompt is NULL, no prompt will
1112 ** This probably shouldn't flush the window any more (if
1113 ** it ever did). That should be select_menu's job. -dean
1115 void mswin_end_menu(winid wid, const char *prompt)
1117 logDebug("mswin_end_menu(%d, %s)\n", wid, prompt);
1119 (wid < MAXWINDOWS) &&
1120 (GetNHApp()->windowlist[wid].win != NULL))
1122 MSNHMsgEndMenu data;
1123 ZeroMemory(&data, sizeof(data));
1127 GetNHApp()->windowlist[wid].win,
1128 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ENDMENU, (LPARAM)&data
1134 int select_menu(windid window, int how, menu_item **selected)
1135 -- Return the number of items selected; 0 if none were chosen,
1136 -1 when explicitly cancelled. If items were selected, then
1137 selected is filled in with an allocated array of menu_item
1138 structures, one for each selected line. The caller must
1139 free this array when done with it. The "count" field
1140 of selected is a user supplied count. If the user did
1141 not supply a count, then the count field is filled with
1142 -1 (meaning all). A count of zero is equivalent to not
1143 being selected and should not be in the list. If no items
1144 were selected, then selected is NULL'ed out. How is the
1145 mode of the menu. Three valid values are PICK_NONE,
1146 PICK_ONE, and PICK_N, meaning: nothing is selectable,
1147 only one thing is selectable, and any number valid items
1148 may selected. If how is PICK_NONE, this function should
1149 never return anything but 0 or -1.
1150 -- You may call select_menu() on a window multiple times --
1151 the menu is saved until start_menu() or destroy_nhwindow()
1152 is called on the window.
1153 -- Note that NHW_MENU windows need not have select_menu()
1154 called for them. There is no way of knowing whether
1155 select_menu() will be called for the window at
1156 create_nhwindow() time.
1158 int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected)
1162 logDebug("mswin_select_menu(%d, %d)\n", wid, how);
1165 (wid < MAXWINDOWS) &&
1166 (GetNHApp()->windowlist[wid].win != NULL))
1168 nReturned = mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, how, selected);
1174 -- Indicate to the window port that the inventory has been changed.
1175 -- Merely calls display_inventory() for window-ports that leave the
1176 window up, otherwise empty.
1178 void mswin_update_inventory()
1180 logDebug("mswin_update_inventory()\n");
1184 mark_synch() -- Don't go beyond this point in I/O on any channel until
1185 all channels are caught up to here. Can be an empty call
1188 void mswin_mark_synch()
1190 logDebug("mswin_mark_synch()\n");
1194 wait_synch() -- Wait until all pending output is complete (*flush*() for
1196 -- May also deal with exposure events etc. so that the
1197 display is OK when return from wait_synch().
1199 void mswin_wait_synch()
1201 logDebug("mswin_wait_synch()\n");
1205 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
1206 screen if the playing area is larger than the screen.
1207 -- This function is only defined if CLIPPING is defined.
1209 void mswin_cliparound(int x, int y)
1211 winid wid = WIN_MAP;
1213 logDebug("mswin_cliparound(%d, %d)\n", x, y);
1216 (wid < MAXWINDOWS) &&
1217 (GetNHApp()->windowlist[wid].win != NULL))
1219 MSNHMsgClipAround data;
1223 GetNHApp()->windowlist[wid].win,
1224 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLIPAROUND, (LPARAM)&data );
1229 print_glyph(window, x, y, glyph)
1230 -- Print the glyph at (x,y) on the given window. Glyphs are
1231 integers at the interface, mapped to whatever the window-
1232 port wants (symbol, font, color, attributes, ...there's
1233 a 1-1 map between glyphs and distinct things on the map).
1235 void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)
1237 logDebug("mswin_print_glyph(%d, %d, %d, %d)\n", wid, x, y, glyph);
1240 (wid < MAXWINDOWS) &&
1241 (GetNHApp()->windowlist[wid].win != NULL))
1243 MSNHMsgPrintGlyph data;
1245 ZeroMemory(&data, sizeof(data) );
1249 SendMessage( GetNHApp()->windowlist[wid].win,
1250 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PRINT_GLYPH, (LPARAM)&data );
1255 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
1256 the user sees str. raw_print() appends a newline to str.
1257 It need not recognize ASCII control characters. This is
1258 used during startup (before windowing system initialization
1259 -- maybe this means only error startup messages are raw),
1260 for error messages, and maybe other "msg" uses. E.g.
1261 updating status for micros (i.e, "saving").
1263 void mswin_raw_print(const char *str)
1266 logDebug("mswin_raw_print(%s)\n", str);
1268 NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)),
1269 MB_ICONINFORMATION | MB_OK );
1274 -- Like raw_print(), but prints in bold/standout (if
1277 void mswin_raw_print_bold(const char *str)
1280 logDebug("mswin_raw_print_bold(%s)\n", str);
1282 NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)),
1283 MB_ICONINFORMATION | MB_OK );
1287 int nhgetch() -- Returns a single character input from the user.
1288 -- In the tty window-port, nhgetch() assumes that tgetch()
1289 will be the routine the OS provides to read a character.
1290 Returned character _must_ be non-zero.
1297 logDebug("mswin_nhgetch()\n");
1300 while( (event = mswin_input_pop()) == NULL ||
1301 event->type != NHEVENT_CHAR )
1304 key = event->kbd.ch;
1309 int nh_poskey(int *x, int *y, int *mod)
1310 -- Returns a single character input from the user or a
1311 a positioning event (perhaps from a mouse). If the
1312 return value is non-zero, a character was typed, else,
1313 a position in the MAP window is returned in x, y and mod.
1316 CLICK_1 -- mouse click type 1
1317 CLICK_2 -- mouse click type 2
1319 The different click types can map to whatever the
1320 hardware supports. If no mouse is supported, this
1321 routine always returns a non-zero character.
1323 int mswin_nh_poskey(int *x, int *y, int *mod)
1328 logDebug("mswin_nh_poskey()\n");
1330 while( (event = mswin_input_pop())==NULL ) mswin_main_loop();
1332 if( event->type==NHEVENT_MOUSE ) {
1333 *mod = event->ms.mod;
1338 key = event->kbd.ch;
1344 nhbell() -- Beep at user. [This will exist at least until sounds are
1345 redone, since sounds aren't attributable to windows anyway.]
1349 logDebug("mswin_nhbell()\n");
1354 -- Display previous messages. Used by the ^P command.
1355 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1357 int mswin_doprev_message()
1359 logDebug("mswin_doprev_message()\n");
1360 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL);
1365 char yn_function(const char *ques, const char *choices, char default)
1366 -- Print a prompt made up of ques, choices and default.
1367 Read a single character response that is contained in
1368 choices or default. If choices is NULL, all possible
1369 inputs are accepted and returned. This overrides
1370 everything else. The choices are expected to be in
1371 lower case. Entering ESC always maps to 'q', or 'n',
1372 in that order, if present in choices, otherwise it maps
1373 to default. Entering any other quit character (SPACE,
1374 RETURN, NEWLINE) maps to default.
1375 -- If the choices string contains ESC, then anything after
1376 it is an acceptable response, but the ESC and whatever
1377 follows is not included in the prompt.
1378 -- If the choices string contains a '#' then accept a count.
1379 Place this value in the global "yn_number" and return '#'.
1380 -- This uses the top line in the tty window-port, other
1381 ports might use a popup.
1383 char mswin_yn_function(const char *question, const char *choices,
1387 char yn_esc_map='\033';
1388 char message[BUFSZ];
1391 boolean digit_ok, allow_num;
1393 logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def);
1395 if (WIN_MESSAGE == WIN_ERR && choices == ynchars) {
1396 char *text = realloc(strdup(GetNHApp()->saved_text), strlen(question)
1397 + strlen(GetNHApp()->saved_text) + 1);
1399 strcat(text, question);
1400 box_result = NHMessageBox(NULL,
1401 NH_W2A(text, message, sizeof(message)),
1402 MB_YESNOCANCEL | MB_ICONQUESTION |
1403 ((def == 'y') ? MB_DEFBUTTON1 :
1404 (def == 'n') ? MB_DEFBUTTON2 : MB_DEFBUTTON3));
1406 GetNHApp()->saved_text = strdup("");
1407 return box_result == IDYES ? 'y' : box_result == IDNO ? 'n' : '\033';
1411 char *cb, choicebuf[QBUFSZ];
1413 allow_num = (index(choices, '#') != 0);
1415 Strcpy(choicebuf, choices);
1416 if ((cb = index(choicebuf, '\033')) != 0) {
1417 /* anything beyond <esc> is hidden */
1420 sprintf(message, "%s [%s] ", question, choicebuf);
1421 if (def) sprintf(eos(message), "(%c) ", def);
1422 /* escape maps to 'q' or 'n' or default, in that order */
1423 yn_esc_map = (index(choices, 'q') ? 'q' :
1424 (index(choices, 'n') ? 'n' : def));
1426 Strcpy(message, question);
1427 Strcat(message, " ");
1431 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE),
1432 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
1434 mswin_clear_nhwindow(WIN_MESSAGE);
1435 mswin_putstr(WIN_MESSAGE, ATR_BOLD, message);
1437 /* Only here if main window is not present */
1440 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1442 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1443 if (choices) ch = lowc(ch);
1444 else break; /* If choices is NULL, all possible inputs are accepted and returned. */
1446 digit_ok = allow_num && digit(ch);
1448 if (index(choices, 'q'))
1450 else if (index(choices, 'n'))
1455 } else if (index(quitchars, ch)) {
1458 } else if (!index(choices, ch) && !digit_ok) {
1461 /* and try again... */
1462 } else if (ch == '#' || digit_ok) {
1463 char z, digit_string[2];
1466 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, ("#"), 1); n_len++;
1467 digit_string[1] = '\0';
1469 digit_string[0] = ch;
1470 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1); n_len++;
1474 do { /* loop until we get a non-digit */
1475 z = lowc(readchar());
1477 value = (10 * value) + (z - '0');
1478 if (value < 0) break; /* overflow: try again */
1479 digit_string[0] = z;
1480 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1);
1482 } else if (z == 'y' || index(quitchars, z)) {
1483 if (z == '\033') value = -1; /* abort */
1484 z = '\n'; /* break */
1485 } else if (z == '\b') {
1486 if (n_len <= 1) { value = -1; break; }
1487 else { value /= 10; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -1); n_len--; }
1489 value = -1; /* abort */
1493 } while (z != '\n');
1494 if (value > 0) yn_number = value;
1495 else if (value == 0) ch = 'n'; /* 0 => "no" */
1496 else { /* remove number from top line, then try again */
1497 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -n_len); n_len = 0;
1504 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE),
1505 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
1507 /* display selection in the message window */
1508 if( isprint(ch) && ch!='#' ) {
1511 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1);
1518 getlin(const char *ques, char *input)
1519 -- Prints ques as a prompt and reads a single line of text,
1520 up to a newline. The string entered is returned without the
1521 newline. ESC is used to cancel, in which case the string
1522 "\033\000" is returned.
1523 -- getlin() must call flush_screen(1) before doing anything.
1524 -- This uses the top line in the tty window-port, other
1525 ports might use a popup.
1527 void mswin_getlin(const char *question, char *input)
1530 logDebug("mswin_getlin(%s, %p)\n", question, input);
1532 if (!iflags.wc_popup_dialog)
1540 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE),
1541 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
1543 mswin_clear_nhwindow(WIN_MESSAGE);
1544 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, question, 0);
1545 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, " ", 1);
1548 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1552 c = mswin_nhgetch();
1556 strcpy(input, "\033");
1566 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, -len);
1575 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, 1);
1579 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1581 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE),
1582 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
1586 if( mswin_getlin_window(question, input, BUFSZ)==IDCANCEL ) {
1587 strcpy(input, "\033");
1593 int get_ext_cmd(void)
1594 -- Get an extended command in a window-port specific way.
1595 An index into extcmdlist[] is returned on a successful
1596 selection, -1 otherwise.
1598 int mswin_get_ext_cmd()
1601 logDebug("mswin_get_ext_cmd()\n");
1603 if (!iflags.wc_popup_dialog)
1611 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE),
1612 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
1616 mswin_clear_nhwindow(WIN_MESSAGE);
1617 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, "#", 0);
1619 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1622 int oindex, com_index;
1623 c = mswin_nhgetch();
1632 for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
1633 if (!strcmpi(cmd, extcmdlist[i].ef_txt)) break;
1635 if (extcmdlist[i].ef_txt == (char *)0) {
1636 pline("%s: unknown extended command.", cmd);
1642 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, -(int)strlen(cmd));
1653 /* Find a command with this prefix in extcmdlist */
1655 for (oindex = 0; extcmdlist[oindex].ef_txt != (char *)0; oindex++) {
1656 if (!strncmpi(cmd, extcmdlist[oindex].ef_txt, len)) {
1657 if (com_index == -1) /* no matches yet */
1660 com_index = -2; /* two matches, don't complete */
1663 if (com_index >= 0) {
1664 Strcpy(cmd, extcmdlist[com_index].ef_txt);
1667 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, 1);
1671 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1673 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE),
1674 WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret );
1679 if(mswin_ext_cmd_window (&ret) == IDCANCEL)
1689 -- Initialize the number pad to the given state.
1691 void mswin_number_pad(int state)
1694 logDebug("mswin_number_pad(%d)\n", state);
1698 delay_output() -- Causes a visible delay of 50ms in the output.
1699 Conceptually, this is similar to wait_synch() followed
1700 by a nap(50ms), but allows asynchronous operation.
1702 void mswin_delay_output()
1704 logDebug("mswin_delay_output()\n");
1708 void mswin_change_color()
1710 logDebug("mswin_change_color()\n");
1713 char *mswin_get_color_string()
1715 logDebug("mswin_get_color_string()\n");
1720 start_screen() -- Only used on Unix tty ports, but must be declared for
1721 completeness. Sets up the tty to work in full-screen
1722 graphics mode. Look at win/tty/termcap.c for an
1723 example. If your window-port does not need this function
1724 just declare an empty function.
1726 void mswin_start_screen()
1729 logDebug("mswin_start_screen()\n");
1733 end_screen() -- Only used on Unix tty ports, but must be declared for
1734 completeness. The complement of start_screen().
1736 void mswin_end_screen()
1739 logDebug("mswin_end_screen()\n");
1744 -- The tombstone code. If you want the traditional code use
1745 genl_outrip for the value and check the #if in rip.c.
1747 #define STONE_LINE_LEN 16
1748 void mswin_outrip(winid wid, int how)
1752 logDebug("mswin_outrip(%d)\n", wid, how);
1753 if ((wid >= 0) && (wid < MAXWINDOWS) ) {
1754 DestroyWindow(GetNHApp()->windowlist[wid].win);
1755 GetNHApp()->windowlist[wid].win = mswin_init_RIP_window();
1756 GetNHApp()->windowlist[wid].type = NHW_RIP;
1757 GetNHApp()->windowlist[wid].dead = 0;
1760 /* Put name on stone */
1761 Sprintf(buf, "%s", plname);
1762 buf[STONE_LINE_LEN] = 0;
1763 putstr(wid, 0, buf);
1765 /* Put $ on stone */
1767 Sprintf(buf, "%ld Au", u.ugold);
1769 Sprintf(buf, "%ld Au", done_money);
1771 buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
1772 putstr(wid, 0, buf);
1774 /* Put together death description */
1775 switch (killer_format) {
1776 default: impossible("bad killer format?");
1778 Strcpy(buf, killed_by_prefix[how]);
1779 Strcat(buf, an(killer));
1782 Strcpy(buf, killed_by_prefix[how]);
1783 Strcat(buf, killer);
1785 case NO_KILLER_PREFIX:
1786 Strcpy(buf, killer);
1790 /* Put death type on stone */
1791 putstr(wid, 0, buf);
1793 /* Put year on stone */
1794 Sprintf(buf, "%4d", getyear());
1795 putstr(wid, 0, buf);
1796 mswin_finish_rip_text(wid);
1799 /* handle options updates here */
1800 void mswin_preference_update(const char *pref)
1804 if( stricmp( pref, "font_menu")==0 ||
1805 stricmp( pref, "font_size_menu")==0 ) {
1806 if( iflags.wc_fontsiz_menu<NHFONT_SIZE_MIN ||
1807 iflags.wc_fontsiz_menu>NHFONT_SIZE_MAX )
1808 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
1810 hdc = GetDC(GetNHApp()->hMainWnd);
1811 mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE);
1812 mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE);
1813 mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE);
1814 mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE);
1815 mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE);
1816 mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE);
1817 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1819 mswin_layout_main_window(NULL);
1823 if( stricmp( pref, "font_status")==0 ||
1824 stricmp( pref, "font_size_status")==0 ) {
1826 if( iflags.wc_fontsiz_status<NHFONT_SIZE_MIN ||
1827 iflags.wc_fontsiz_status>NHFONT_SIZE_MAX )
1828 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
1830 hdc = GetDC(GetNHApp()->hMainWnd);
1831 mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE);
1832 mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE);
1833 mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE);
1834 mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE);
1835 mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE);
1836 mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE);
1837 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1839 InvalidateRect(mswin_hwnd_from_winid(WIN_STATUS), NULL, TRUE);
1840 mswin_layout_main_window(NULL);
1844 if( stricmp( pref, "font_message")==0 ||
1845 stricmp( pref, "font_size_message")==0 ) {
1847 if( iflags.wc_fontsiz_message<NHFONT_SIZE_MIN ||
1848 iflags.wc_fontsiz_message>NHFONT_SIZE_MAX )
1849 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
1851 hdc = GetDC(GetNHApp()->hMainWnd);
1852 mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE);
1853 mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE);
1854 mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE);
1855 mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE);
1856 mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE);
1857 mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE);
1858 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1860 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1861 mswin_layout_main_window(NULL);
1865 if( stricmp( pref, "font_text")==0 ||
1866 stricmp( pref, "font_size_text")==0 ) {
1868 if( iflags.wc_fontsiz_text<NHFONT_SIZE_MIN ||
1869 iflags.wc_fontsiz_text>NHFONT_SIZE_MAX )
1870 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
1872 hdc = GetDC(GetNHApp()->hMainWnd);
1873 mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE);
1874 mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE);
1875 mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE);
1876 mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE);
1877 mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE);
1878 mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE);
1879 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1881 mswin_layout_main_window(NULL);
1885 if( stricmp( pref, "scroll_amount")==0 ) {
1886 mswin_cliparound(u.ux, u.uy);
1890 if( stricmp( pref, "scroll_margin")==0 ) {
1891 mswin_cliparound(u.ux, u.uy);
1895 if( stricmp( pref, "map_mode")==0 ) {
1896 mswin_select_map_mode( iflags.wc_map_mode );
1900 if( stricmp( pref, "hilite_pet")==0 ) {
1901 InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE);
1905 if( stricmp( pref, "align_message")==0 ||
1906 stricmp( pref, "align_status")==0 ) {
1907 mswin_layout_main_window(NULL);
1911 if( stricmp( pref, "vary_msgcount")==0 ) {
1912 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1913 mswin_layout_main_window(NULL);
1920 void mswin_main_loop()
1924 while( !mswin_have_input() &&
1925 GetMessage(&msg, NULL, 0, 0)!=0 ) {
1926 if (GetNHApp()->regNetHackMode ||
1927 !TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg))
1929 TranslateMessage(&msg);
1930 DispatchMessage(&msg);
1935 /* clean up and quit */
1936 void bail(const char *mesg)
1939 mswin_exit_nhwindows(mesg);
1940 terminate(EXIT_SUCCESS);
1944 BOOL initMapTiles(void)
1948 TCHAR wbuf[MAX_PATH];
1951 extern int total_tiles_used;
1953 /* no file - no tile */
1954 if( !(iflags.wc_tile_file && *iflags.wc_tile_file) )
1960 NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH),
1964 LR_LOADFROMFILE | LR_DEFAULTSIZE
1967 raw_print("Cannot load tiles from the file. Reverting back to default.");
1971 /* calculate tile dimensions */
1972 GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bm);
1973 if( bm.bmWidth%iflags.wc_tile_width ||
1974 bm.bmHeight%iflags.wc_tile_height ) {
1976 raw_print("Tiles bitmap does not match tile_width and tile_height options. Reverting back to default.");
1980 tl_num = (bm.bmWidth/iflags.wc_tile_width)*
1981 (bm.bmHeight/iflags.wc_tile_height);
1982 if( tl_num<total_tiles_used ) {
1984 raw_print("Number of tiles in the bitmap is less than required by the game. Reverting back to default.");
1988 /* set the tile information */
1989 if( GetNHApp()->bmpMapTiles!=GetNHApp()->bmpTiles ) {
1990 DeleteObject(GetNHApp()->bmpMapTiles);
1993 GetNHApp()->bmpMapTiles = hBmp;
1994 GetNHApp()->mapTile_X = iflags.wc_tile_width;
1995 GetNHApp()->mapTile_Y = iflags.wc_tile_height;
1996 GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width;
1998 map_size.cx = GetNHApp()->mapTile_X * COLNO;
1999 map_size.cy = GetNHApp()->mapTile_Y * ROWNO;
2001 mswin_hwnd_from_winid(WIN_MAP),
2008 void mswin_popup_display(HWND hWnd, int* done_indicator)
2016 /* activate the menu window */
2017 GetNHApp()->hPopupWnd = hWnd;
2019 mswin_layout_main_window(hWnd);
2021 /* disable game windows */
2022 for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD);
2024 hChild = GetWindow(hChild, GW_HWNDNEXT) ) {
2025 if( hChild!= hWnd) EnableWindow(hChild, FALSE);
2029 hMenu = GetMenu( GetNHApp()->hMainWnd );
2030 mi_count = GetMenuItemCount( hMenu );
2031 for( i=0; i<mi_count; i++ ) {
2032 EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_GRAYED);
2034 DrawMenuBar( GetNHApp()->hMainWnd );
2036 /* bring menu window on top */
2037 SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2039 /* go into message loop */
2040 while( IsWindow(hWnd) &&
2041 (done_indicator==NULL || !*done_indicator) &&
2042 GetMessage(&msg, NULL, 0, 0)!=0 ) {
2043 if( !IsDialogMessage(hWnd, &msg) ) {
2044 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
2045 TranslateMessage(&msg);
2046 DispatchMessage(&msg);
2052 void mswin_popup_destroy(HWND hWnd)
2059 /* enable game windows */
2060 for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD);
2062 hChild = GetWindow(hChild, GW_HWNDNEXT) ) {
2063 if( hChild!= hWnd) {
2064 EnableWindow(hChild, TRUE);
2069 hMenu = GetMenu( GetNHApp()->hMainWnd );
2070 mi_count = GetMenuItemCount( hMenu );
2071 for( i=0; i<mi_count; i++ ) {
2072 EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_ENABLED);
2074 DrawMenuBar( GetNHApp()->hMainWnd );
2076 SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
2077 GetNHApp()->hPopupWnd = NULL;
2078 mswin_window_mark_dead( mswin_winid_from_handle(hWnd) );
2079 DestroyWindow(hWnd);
2081 mswin_layout_main_window(hWnd);
2083 SetFocus(GetNHApp()->hMainWnd );
2090 logDebug(const char *fmt, ...)
2092 FILE *dfp = fopen("nhtrace.log", "a");
2097 va_start(args, fmt);
2098 vfprintf(dfp, fmt, args);
2107 /* Reading and writing settings from the registry. */
2108 #define CATEGORYKEY "Software"
2109 #define COMPANYKEY "NetHack"
2110 #define PRODUCTKEY "NetHack 3.4.3"
2111 #define SETTINGSKEY "Settings"
2112 #define MAINSHOWSTATEKEY "MainShowState"
2113 #define MAINMINXKEY "MainMinX"
2114 #define MAINMINYKEY "MainMinY"
2115 #define MAINMAXXKEY "MainMaxX"
2116 #define MAINMAXYKEY "MainMaxY"
2117 #define MAINLEFTKEY "MainLeft"
2118 #define MAINRIGHTKEY "MainRight"
2119 #define MAINTOPKEY "MainTop"
2120 #define MAINBOTTOMKEY "MainBottom"
2122 /* #define all the subkeys here */
2123 #define INTFKEY "Interface"
2130 char keystring[MAX_PATH];
2132 sprintf(keystring, "%s\\%s\\%s\\%s",
2133 CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY);
2135 /* Set the defaults here. The very first time the app is started, nothing is
2136 read from the registry, so these defaults apply. */
2137 GetNHApp()->saveRegistrySettings = 1; /* Normally, we always save */
2138 GetNHApp()->regNetHackMode = 0;
2140 if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key)
2144 size = sizeof(DWORD);
2145 /* Read the keys here. */
2146 RegQueryValueEx(key, INTFKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regNetHackMode)), &size);
2147 /* Main window placement */
2148 RegQueryValueEx(key, MAINSHOWSTATEKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainShowState)), &size);
2149 RegQueryValueEx(key, MAINMINXKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMinX)), &size);
2150 RegQueryValueEx(key, MAINMINYKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMinY)), &size);
2151 RegQueryValueEx(key, MAINMAXXKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMaxX)), &size);
2152 RegQueryValueEx(key, MAINMAXYKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMaxY)), &size);
2153 RegQueryValueEx(key, MAINLEFTKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainLeft)), &size);
2154 RegQueryValueEx(key, MAINRIGHTKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainRight)), &size);
2155 RegQueryValueEx(key, MAINTOPKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainTop)), &size);
2156 RegQueryValueEx(key, MAINBOTTOMKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainBottom)), &size);
2167 if (GetNHApp()->saveRegistrySettings)
2169 char keystring[MAX_PATH];
2171 sprintf(keystring, "%s\\%s\\%s\\%s",
2172 CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY);
2174 if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key) != ERROR_SUCCESS)
2176 RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "",
2177 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &disposition);
2180 /* Write the keys here */
2181 RegSetValueEx(key, INTFKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regNetHackMode)), sizeof(DWORD));
2182 /* Main window placement */
2183 RegSetValueEx(key, MAINSHOWSTATEKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainShowState)), sizeof(DWORD));
2184 RegSetValueEx(key, MAINMINXKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMinX)), sizeof(DWORD));
2185 RegSetValueEx(key, MAINMINYKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMinY)), sizeof(DWORD));
2186 RegSetValueEx(key, MAINMAXXKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMaxX)), sizeof(DWORD));
2187 RegSetValueEx(key, MAINMAXYKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMaxY)), sizeof(DWORD));
2188 RegSetValueEx(key, MAINLEFTKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainLeft)), sizeof(DWORD));
2189 RegSetValueEx(key, MAINRIGHTKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainRight)), sizeof(DWORD));
2190 RegSetValueEx(key, MAINTOPKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainTop)), sizeof(DWORD));
2191 RegSetValueEx(key, MAINBOTTOMKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainBottom)), sizeof(DWORD));
2200 char keystring[MAX_PATH];
2204 /* Delete keys one by one, as NT does not delete trees */
2205 sprintf(keystring, "%s\\%s\\%s\\%s",
2206 CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY);
2207 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2208 sprintf(keystring, "%s\\%s\\%s",
2209 CATEGORYKEY, COMPANYKEY, PRODUCTKEY);
2210 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2211 /* The company key will also contain information about newer versions
2212 of nethack (e.g. a subkey called NetHack 4.0), so only delete that
2213 if it's empty now. */
2214 sprintf(keystring, "%s\\%s", CATEGORYKEY, COMPANYKEY);
2215 /* If we cannot open it, we probably cannot delete it either... Just
2216 go on and see what happens. */
2217 RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key);
2219 RegQueryInfoKey(key, NULL, NULL, NULL, &nrsubkeys, NULL, NULL, NULL,
2220 NULL, NULL, NULL, NULL);
2223 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2225 /* Prevent saving on exit */
2226 GetNHApp()->saveRegistrySettings = 0;
2231 const char *colorstring;
2232 COLORREF colorvalue;
2233 } color_table_value;
2236 * The color list here is a combination of:
2237 * NetHack colors. (See mhmap.c)
2238 * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 )
2241 static color_table_value color_table[] = {
2242 /* NetHack colors */
2243 { "black", RGB(0x55, 0x55, 0x55)},
2244 { "red", RGB(0xFF, 0x00, 0x00)},
2245 { "green", RGB(0x00, 0x80, 0x00)},
2246 { "brown", RGB(0xA5, 0x2A, 0x2A)},
2247 { "blue", RGB(0x00, 0x00, 0xFF)},
2248 { "magenta", RGB(0xFF, 0x00, 0xFF)},
2249 { "cyan", RGB(0x00, 0xFF, 0xFF)},
2250 { "orange", RGB(0xFF, 0xA5, 0x00)},
2251 { "brightgreen", RGB(0x00, 0xFF, 0x00)},
2252 { "yellow", RGB(0xFF, 0xFF, 0x00)},
2253 { "brightblue", RGB(0x00, 0xC0, 0xFF)},
2254 { "brightmagenta", RGB(0xFF, 0x80, 0xFF)},
2255 { "brightcyan", RGB(0x80, 0xFF, 0xFF)},
2256 { "white", RGB(0xFF, 0xFF, 0xFF)},
2257 /* Remaining HTML colors */
2258 { "trueblack", RGB(0x00, 0x00, 0x00)},
2259 { "gray", RGB(0x80, 0x80, 0x80)},
2260 { "grey", RGB(0x80, 0x80, 0x80)},
2261 { "purple", RGB(0x80, 0x00, 0x80)},
2262 { "silver", RGB(0xC0, 0xC0, 0xC0)},
2263 { "maroon", RGB(0x80, 0x00, 0x00)},
2264 { "fuchsia", RGB(0xFF, 0x00, 0xFF)}, /* = NetHack magenta */
2265 { "lime", RGB(0x00, 0xFF, 0x00)}, /* = NetHack bright green */
2266 { "olive", RGB(0x80, 0x80, 0x00)},
2267 { "navy", RGB(0x00, 0x00, 0x80)},
2268 { "teal", RGB(0x00, 0x80, 0x80)},
2269 { "aqua", RGB(0x00, 0xFF, 0xFF)}, /* = NetHack cyan */
2270 { "", RGB(0x00, 0x00, 0x00)},
2277 } color_table_brush_value;
2279 static color_table_brush_value color_table_brush[] = {
2280 { "activeborder", COLOR_ACTIVEBORDER },
2281 { "activecaption", COLOR_ACTIVECAPTION },
2282 { "appworkspace", COLOR_APPWORKSPACE },
2283 { "background", COLOR_BACKGROUND },
2284 { "btnface", COLOR_BTNFACE },
2285 { "btnshadow", COLOR_BTNSHADOW },
2286 { "btntext", COLOR_BTNTEXT },
2287 { "captiontext", COLOR_CAPTIONTEXT },
2288 { "graytext", COLOR_GRAYTEXT },
2289 { "greytext", COLOR_GRAYTEXT },
2290 { "highlight", COLOR_HIGHLIGHT },
2291 { "highlighttext", COLOR_HIGHLIGHTTEXT },
2292 { "inactiveborder", COLOR_INACTIVEBORDER },
2293 { "inactivecaption", COLOR_INACTIVECAPTION },
2294 { "menu", COLOR_MENU },
2295 { "menutext", COLOR_MENUTEXT },
2296 { "scrollbar", COLOR_SCROLLBAR },
2297 { "window", COLOR_WINDOW },
2298 { "windowframe", COLOR_WINDOWFRAME },
2299 { "windowtext", COLOR_WINDOWTEXT },
2303 static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr)
2305 color_table_value *ctv_ptr = color_table;
2306 color_table_brush_value *ctbv_ptr = color_table_brush;
2307 int red_value, blue_value, green_value;
2308 static char *hexadecimals = "0123456789abcdef";
2310 if (colorstring == NULL) return;
2311 if (*colorstring == '#') {
2312 if (strlen(++colorstring) != 6) return;
2314 red_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
2316 red_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
2318 green_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
2320 green_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
2322 blue_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
2324 blue_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals;
2326 *colorptr = RGB(red_value, green_value, blue_value);
2328 while (*ctv_ptr->colorstring && stricmp(ctv_ptr->colorstring, colorstring))
2330 if (*ctv_ptr->colorstring) {
2331 *colorptr = ctv_ptr->colorvalue;
2333 while (*ctbv_ptr->colorstring && stricmp(ctbv_ptr->colorstring, colorstring))
2335 if (*ctbv_ptr->colorstring) {
2336 *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue);
2337 *colorptr = GetSysColor(ctbv_ptr->syscolorvalue);
2341 if (max_brush > TOTAL_BRUSHES) panic("Too many colors!");
2342 *brushptr = CreateSolidBrush(*colorptr);
2343 brush_table[max_brush++] = *brushptr;
2346 int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type)
2348 TCHAR title[MAX_LOADSTRING];
2350 LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING);
2352 return MessageBox(hWnd, text, title, type);