1 /* NetHack 3.6 mswproc.c $NHDT-Date: 1449116670 2015/12/03 04:24:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.94 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* NetHack may be freely redistributed. See license for details. */
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.
12 #include "func_tab.h" /* for extended commands */
32 #define NHTRACE_LOG "nhtrace.log"
36 static FILE* _s_debugfp = NULL;
37 extern void logDebug(const char *fmt, ...);
41 logDebug(const char *fmt, ...)
46 static void mswin_main_loop(void);
47 static BOOL initMapTiles(void);
48 static void mswin_color_from_string(char *colorstring, HBRUSH *brushptr,
50 static void prompt_for_player_selection(void);
52 #define TOTAL_BRUSHES 10
53 HBRUSH brush_table[TOTAL_BRUSHES];
56 HBRUSH menu_bg_brush = NULL;
57 HBRUSH menu_fg_brush = NULL;
58 HBRUSH text_bg_brush = NULL;
59 HBRUSH text_fg_brush = NULL;
60 HBRUSH status_bg_brush = NULL;
61 HBRUSH status_fg_brush = NULL;
62 HBRUSH message_bg_brush = NULL;
63 HBRUSH message_fg_brush = NULL;
65 COLORREF menu_bg_color = RGB(0, 0, 0);
66 COLORREF menu_fg_color = RGB(0xFF, 0xFF, 0xFF);
67 COLORREF text_bg_color = RGB(0, 0, 0);
68 COLORREF text_fg_color = RGB(0xFF, 0xFF, 0xFF);
69 COLORREF status_bg_color = RGB(0, 0, 0);
70 COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF);
71 COLORREF message_bg_color = RGB(0, 0, 0);
72 COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF);
74 /* Interface definition, for windows.c */
75 struct window_procs mswin_procs = {
77 WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE
78 | WC_SCROLL_AMOUNT | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE
79 | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONT_MAP
80 | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU
81 | WC_FONTSIZ_TEXT | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE
82 | WC_VARY_MSGCOUNT | WC_WINDOWCOLORS | WC_PLAYER_SELECTION
83 | WC_SPLASH_SCREEN | WC_POPUP_DIALOG,
84 0L, mswin_init_nhwindows, mswin_player_selection, mswin_askname,
85 mswin_get_nh_event, mswin_exit_nhwindows, mswin_suspend_nhwindows,
86 mswin_resume_nhwindows, mswin_create_nhwindow, mswin_clear_nhwindow,
87 mswin_display_nhwindow, mswin_destroy_nhwindow, mswin_curs, mswin_putstr,
88 genl_putmixed, mswin_display_file, mswin_start_menu, mswin_add_menu,
89 mswin_end_menu, mswin_select_menu,
90 genl_message_menu, /* no need for X-specific handling */
91 mswin_update_inventory, mswin_mark_synch, mswin_wait_synch,
98 mswin_print_glyph, mswin_raw_print, mswin_raw_print_bold, mswin_nhgetch,
99 mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function,
100 mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output,
101 #ifdef CHANGE_COLOR /* only a Mac option currently */
102 mswin, mswin_change_background,
104 /* other defs that really should go away (they're tty specific) */
105 mswin_start_screen, mswin_end_screen, mswin_outrip,
106 mswin_preference_update, mswin_getmsghistory, mswin_putmsghistory,
107 #ifdef STATUS_VIA_WINDOWPORT
108 mswin_status_init, mswin_status_finish, mswin_status_enablefield,
110 #ifdef STATUS_HILITES
111 mswin_status_threshold,
114 genl_can_suspend_yes,
118 init_nhwindows(int* argcp, char** argv)
119 -- Initialize the windows used by NetHack. This can also
120 create the standard windows listed at the top, but does
122 -- Any commandline arguments relevant to the windowport
123 should be interpreted, and *argcp and *argv should
124 be changed to remove those arguments.
125 -- When the message window is created, the variable
126 iflags.window_inited needs to be set to TRUE. Otherwise
127 all plines() will be done via raw_print().
128 ** Why not have init_nhwindows() create all of the "standard"
129 ** windows? Or at least all but WIN_INFO? -dean
132 mswin_init_nhwindows(int *argc, char **argv)
134 UNREFERENCED_PARAMETER(argc);
135 UNREFERENCED_PARAMETER(argv);
139 if (showdebug(NHTRACE_LOG) && !_s_debugfp) {
140 /* truncate trace file */
141 _s_debugfp = fopen(NHTRACE_LOG, "w");
145 logDebug("mswin_init_nhwindows()\n");
147 mswin_nh_input_init();
149 /* set it to WIN_ERR so we can detect attempts to
150 use this ID before it is inialized */
153 /* Read Windows settings from the reqistry */
154 /* First set safe defaults */
155 GetNHApp()->regMainMinX = CW_USEDEFAULT;
157 /* Create the main window */
158 GetNHApp()->hMainWnd = mswin_init_main_window();
159 if (!GetNHApp()->hMainWnd) {
160 panic("Cannot create main window");
163 /* Set menu check mark for interface mode */
164 mswin_menu_check_intf_mode();
166 /* check default values */
167 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
168 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
169 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
171 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
172 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
173 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
175 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
176 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
177 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
179 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
180 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
181 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
183 if (iflags.wc_align_message == 0)
184 iflags.wc_align_message = ALIGN_TOP;
185 if (iflags.wc_align_status == 0)
186 iflags.wc_align_status = ALIGN_BOTTOM;
187 if (iflags.wc_scroll_margin == 0)
188 iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
189 if (iflags.wc_scroll_amount == 0)
190 iflags.wc_scroll_amount = DEF_CLIPAROUND_AMOUNT;
191 if (iflags.wc_tile_width == 0)
192 iflags.wc_tile_width = TILE_X;
193 if (iflags.wc_tile_height == 0)
194 iflags.wc_tile_height = TILE_Y;
196 if (iflags.wc_vary_msgcount == 0)
197 iflags.wc_vary_msgcount = 4;
199 /* force tabs in menus */
200 iflags.menu_tab_sep = 1;
202 /* force toptenwin to be true. toptenwin is the option that decides
204 * write output to a window or stdout. stdout doesn't make sense on
206 * non-console applications
208 iflags.toptenwin = 1;
209 set_option_mod_status("toptenwin", SET_IN_FILE);
210 set_option_mod_status("perm_invent", SET_IN_FILE);
212 /* initialize map tiles bitmap */
215 /* set tile-related options to readonly */
216 set_wc_option_mod_status(WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE,
219 /* set font-related options to change in the game */
220 set_wc_option_mod_status(
221 WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_SCROLL_AMOUNT
222 | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE
223 | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT
224 | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU
225 | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT,
228 mswin_color_from_string(iflags.wc_foregrnd_menu, &menu_fg_brush,
230 mswin_color_from_string(iflags.wc_foregrnd_message, &message_fg_brush,
232 mswin_color_from_string(iflags.wc_foregrnd_status, &status_fg_brush,
234 mswin_color_from_string(iflags.wc_foregrnd_text, &text_fg_brush,
236 mswin_color_from_string(iflags.wc_backgrnd_menu, &menu_bg_brush,
238 mswin_color_from_string(iflags.wc_backgrnd_message, &message_bg_brush,
240 mswin_color_from_string(iflags.wc_backgrnd_status, &status_bg_brush,
242 mswin_color_from_string(iflags.wc_backgrnd_text, &text_bg_brush,
245 if (iflags.wc_splash_screen)
246 mswin_display_splash_window(FALSE);
248 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].
256 mswin_player_selection(void)
260 logDebug("mswin_player_selection()\n");
262 if (iflags.wc_player_selection == VIA_DIALOG) {
263 /* pick player type randomly (use pre-selected
264 * role/race/gender/alignment) */
265 if (flags.randomall) {
266 if (flags.initrole < 0) {
267 flags.initrole = pick_role(flags.initrace, flags.initgend,
268 flags.initalign, PICK_RANDOM);
269 if (flags.initrole < 0) {
270 raw_print("Incompatible role!");
271 flags.initrole = randrole();
275 if (flags.initrace < 0
276 || !validrace(flags.initrole, flags.initrace)) {
277 flags.initrace = pick_race(flags.initrole, flags.initgend,
278 flags.initalign, PICK_RANDOM);
279 if (flags.initrace < 0) {
280 raw_print("Incompatible race!");
281 flags.initrace = randrace(flags.initrole);
285 if (flags.initgend < 0
286 || !validgend(flags.initrole, flags.initrace,
288 flags.initgend = pick_gend(flags.initrole, flags.initrace,
289 flags.initalign, PICK_RANDOM);
290 if (flags.initgend < 0) {
291 raw_print("Incompatible gender!");
292 flags.initgend = randgend(flags.initrole, flags.initrace);
296 if (flags.initalign < 0
297 || !validalign(flags.initrole, flags.initrace,
299 flags.initalign = pick_align(flags.initrole, flags.initrace,
300 flags.initgend, PICK_RANDOM);
301 if (flags.initalign < 0) {
302 raw_print("Incompatible alignment!");
304 randalign(flags.initrole, flags.initrace);
309 if (mswin_player_selection_window(&nRole) == IDCANCEL) {
313 } else { /* iflags.wc_player_selection == VIA_PROMPTS */
314 prompt_for_player_selection();
319 prompt_for_player_selection(void)
322 char pick4u = 'n', thisch, lastch = 0;
323 char pbuf[QBUFSZ], plbuf[QBUFSZ];
326 menu_item *selected = 0;
329 logDebug("prompt_for_player_selection()\n");
331 /* prevent an unnecessary prompt */
334 /* Should we randomly pick for the player? */
336 && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE
337 || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
339 char *prompt = build_plselection_prompt(
340 pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend,
343 /* tty_putstr(BASE_WINDOW, 0, ""); */
344 /* echoline = wins[BASE_WINDOW]->cury; */
345 box_result = NHMessageBox(NULL, prompt, MB_YESNOCANCEL | MB_DEFBUTTON1
348 (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033';
349 /* tty_putstr(BASE_WINDOW, 0, prompt); */
351 /* pick4u = lowc(readchar()); */
352 if (index(quitchars, pick4u))
354 } while (!index(ynqchars, pick4u));
355 if ((int) strlen(prompt) + 1 < CO) {
356 /* Echo choice and move back down line */
357 /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline,
359 /* tty_putstr(BASE_WINDOW, 0, ""); */
361 /* Otherwise it's hard to tell where to echo, and things are
362 * wrapping a bit messily anyway, so (try to) make sure the next
363 * question shows up well and doesn't get wrapped at the
364 * bottom of the window.
366 /* tty_clear_nhwindow(BASE_WINDOW) */;
368 if (pick4u != 'y' && pick4u != 'n') {
371 free((genericptr_t) selected);
378 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
379 flags.initrace, flags.initgend,
382 /* Select a role, if necessary */
383 /* we'll try to be compatible with pre-selected race/gender/alignment,
384 * but may not succeed */
385 if (flags.initrole < 0) {
386 char rolenamebuf[QBUFSZ];
387 /* Process the choice */
388 if (pick4u == 'y' || flags.initrole == ROLE_RANDOM
389 || flags.randomall) {
390 /* Pick a random role */
391 flags.initrole = pick_role(flags.initrace, flags.initgend,
392 flags.initalign, PICK_RANDOM);
393 if (flags.initrole < 0) {
394 /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
395 flags.initrole = randrole();
398 /* tty_clear_nhwindow(BASE_WINDOW); */
399 /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
400 /* Prompt for a role */
401 win = create_nhwindow(NHW_MENU);
403 any = zeroany; /* zero out all bits */
404 for (i = 0; roles[i].name.m; i++) {
405 if (ok_role(i, flags.initrace, flags.initgend,
407 any.a_int = i + 1; /* must be non-zero */
408 thisch = lowc(roles[i].name.m[0]);
409 if (thisch == lastch)
410 thisch = highc(thisch);
411 if (flags.initgend != ROLE_NONE
412 && flags.initgend != ROLE_RANDOM) {
413 if (flags.initgend == 1 && roles[i].name.f)
414 Strcpy(rolenamebuf, roles[i].name.f);
416 Strcpy(rolenamebuf, roles[i].name.m);
418 if (roles[i].name.f) {
419 Strcpy(rolenamebuf, roles[i].name.m);
420 Strcat(rolenamebuf, "/");
421 Strcat(rolenamebuf, roles[i].name.f);
423 Strcpy(rolenamebuf, roles[i].name.m);
425 add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE,
426 an(rolenamebuf), MENU_UNSELECTED);
430 any.a_int = pick_role(flags.initrace, flags.initgend,
431 flags.initalign, PICK_RANDOM) + 1;
432 if (any.a_int == 0) /* must be non-zero */
433 any.a_int = randrole() + 1;
434 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
436 any.a_int = i + 1; /* must be non-zero */
437 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
439 Sprintf(pbuf, "Pick a role for your %s", plbuf);
441 n = select_menu(win, PICK_ONE, &selected);
442 destroy_nhwindow(win);
444 /* Process the choice */
445 if (n != 1 || selected[0].item.a_int == any.a_int)
446 goto give_up; /* Selected quit */
448 flags.initrole = selected[0].item.a_int - 1;
449 free((genericptr_t) selected), selected = 0;
451 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
452 flags.initrace, flags.initgend,
456 /* Select a race, if necessary */
457 /* force compatibility with role, try for compatibility with
458 * pre-selected gender/alignment */
459 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
460 /* pre-selected race not valid */
461 if (pick4u == 'y' || flags.initrace == ROLE_RANDOM
462 || flags.randomall) {
463 flags.initrace = pick_race(flags.initrole, flags.initgend,
464 flags.initalign, PICK_RANDOM);
465 if (flags.initrace < 0) {
466 /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
467 flags.initrace = randrace(flags.initrole);
469 } else { /* pick4u == 'n' */
470 /* Count the number of valid races */
471 n = 0; /* number valid */
472 k = 0; /* valid race */
473 for (i = 0; races[i].noun; i++) {
474 if (ok_race(flags.initrole, i, flags.initgend,
481 for (i = 0; races[i].noun; i++) {
482 if (validrace(flags.initrole, i)) {
489 /* Permit the user to pick, if there is more than one */
491 /* tty_clear_nhwindow(BASE_WINDOW); */
492 /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
493 win = create_nhwindow(NHW_MENU);
495 any = zeroany; /* zero out all bits */
496 for (i = 0; races[i].noun; i++)
497 if (ok_race(flags.initrole, i, flags.initgend,
499 any.a_int = i + 1; /* must be non-zero */
500 add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0,
501 ATR_NONE, races[i].noun, MENU_UNSELECTED);
503 any.a_int = pick_race(flags.initrole, flags.initgend,
504 flags.initalign, PICK_RANDOM) + 1;
505 if (any.a_int == 0) /* must be non-zero */
506 any.a_int = randrace(flags.initrole) + 1;
507 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
509 any.a_int = i + 1; /* must be non-zero */
510 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
512 Sprintf(pbuf, "Pick the race of your %s", plbuf);
514 n = select_menu(win, PICK_ONE, &selected);
515 destroy_nhwindow(win);
516 if (n != 1 || selected[0].item.a_int == any.a_int)
517 goto give_up; /* Selected quit */
519 k = selected[0].item.a_int - 1;
520 free((genericptr_t) selected), selected = 0;
524 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
525 flags.initrace, flags.initgend,
529 /* Select a gender, if necessary */
530 /* force compatibility with role/race, try for compatibility with
531 * pre-selected alignment */
532 if (flags.initgend < 0
533 || !validgend(flags.initrole, flags.initrace, flags.initgend)) {
534 /* pre-selected gender not valid */
535 if (pick4u == 'y' || flags.initgend == ROLE_RANDOM
536 || flags.randomall) {
537 flags.initgend = pick_gend(flags.initrole, flags.initrace,
538 flags.initalign, PICK_RANDOM);
539 if (flags.initgend < 0) {
540 /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
541 flags.initgend = randgend(flags.initrole, flags.initrace);
543 } else { /* pick4u == 'n' */
544 /* Count the number of valid genders */
545 n = 0; /* number valid */
546 k = 0; /* valid gender */
547 for (i = 0; i < ROLE_GENDERS; i++) {
548 if (ok_gend(flags.initrole, flags.initrace, i,
555 for (i = 0; i < ROLE_GENDERS; i++) {
556 if (validgend(flags.initrole, flags.initrace, i)) {
563 /* Permit the user to pick, if there is more than one */
565 /* tty_clear_nhwindow(BASE_WINDOW); */
566 /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
567 win = create_nhwindow(NHW_MENU);
569 any = zeroany; /* zero out all bits */
570 for (i = 0; i < ROLE_GENDERS; i++)
571 if (ok_gend(flags.initrole, flags.initrace, i,
574 add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0,
575 ATR_NONE, genders[i].adj, MENU_UNSELECTED);
577 any.a_int = pick_gend(flags.initrole, flags.initrace,
578 flags.initalign, PICK_RANDOM) + 1;
579 if (any.a_int == 0) /* must be non-zero */
580 any.a_int = randgend(flags.initrole, flags.initrace) + 1;
581 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
583 any.a_int = i + 1; /* must be non-zero */
584 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
586 Sprintf(pbuf, "Pick the gender of your %s", plbuf);
588 n = select_menu(win, PICK_ONE, &selected);
589 destroy_nhwindow(win);
590 if (n != 1 || selected[0].item.a_int == any.a_int)
591 goto give_up; /* Selected quit */
593 k = selected[0].item.a_int - 1;
594 free((genericptr_t) selected), selected = 0;
598 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
599 flags.initrace, flags.initgend,
603 /* Select an alignment, if necessary */
604 /* force compatibility with role/race/gender */
605 if (flags.initalign < 0
606 || !validalign(flags.initrole, flags.initrace, flags.initalign)) {
607 /* pre-selected alignment not valid */
608 if (pick4u == 'y' || flags.initalign == ROLE_RANDOM
609 || flags.randomall) {
610 flags.initalign = pick_align(flags.initrole, flags.initrace,
611 flags.initgend, PICK_RANDOM);
612 if (flags.initalign < 0) {
613 /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
614 flags.initalign = randalign(flags.initrole, flags.initrace);
616 } else { /* pick4u == 'n' */
617 /* Count the number of valid alignments */
618 n = 0; /* number valid */
619 k = 0; /* valid alignment */
620 for (i = 0; i < ROLE_ALIGNS; i++) {
621 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
628 for (i = 0; i < ROLE_ALIGNS; i++) {
629 if (validalign(flags.initrole, flags.initrace, i)) {
636 /* Permit the user to pick, if there is more than one */
638 /* tty_clear_nhwindow(BASE_WINDOW); */
639 /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
640 win = create_nhwindow(NHW_MENU);
642 any = zeroany; /* zero out all bits */
643 for (i = 0; i < ROLE_ALIGNS; i++)
644 if (ok_align(flags.initrole, flags.initrace,
645 flags.initgend, i)) {
647 add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0,
648 ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
650 any.a_int = pick_align(flags.initrole, flags.initrace,
651 flags.initgend, PICK_RANDOM) + 1;
652 if (any.a_int == 0) /* must be non-zero */
653 any.a_int = randalign(flags.initrole, flags.initrace) + 1;
654 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
656 any.a_int = i + 1; /* must be non-zero */
657 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
659 Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
661 n = select_menu(win, PICK_ONE, &selected);
662 destroy_nhwindow(win);
663 if (n != 1 || selected[0].item.a_int == any.a_int)
664 goto give_up; /* Selected quit */
666 k = selected[0].item.a_int - 1;
667 free((genericptr_t) selected), selected = 0;
673 /* tty_display_nhwindow(BASE_WINDOW, FALSE); */
676 /* Ask the user for a player name. */
680 logDebug("mswin_askname()\n");
682 if (mswin_getlin_window("Who are you?", plname, PL_NSIZ) == IDCANCEL) {
688 /* Does window event processing (e.g. exposure events).
689 A noop for the tty and X window-ports.
692 mswin_get_nh_event(void)
696 logDebug("mswin_get_nh_event()\n");
698 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
699 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
700 TranslateMessage(&msg);
701 DispatchMessage(&msg);
707 /* Exits the window system. This should dismiss all windows,
708 except the "window" used for raw_print(). str is printed if possible.
711 mswin_exit_nhwindows(const char *str)
713 logDebug("mswin_exit_nhwindows(%s)\n", str);
715 /* Write Window settings to the registry */
718 DeleteObject(brush_table[--max_brush]);
721 /* Prepare the window to be suspended. */
723 mswin_suspend_nhwindows(const char *str)
725 logDebug("mswin_suspend_nhwindows(%s)\n", str);
730 /* Restore the windows after being suspended. */
732 mswin_resume_nhwindows()
734 logDebug("mswin_resume_nhwindows()\n");
739 /* Create a window of type "type" which can be
740 NHW_MESSAGE (top line)
741 NHW_STATUS (bottom lines)
742 NHW_MAP (main dungeon)
743 NHW_MENU (inventory or other "corner" windows)
744 NHW_TEXT (help/text, full screen paged window)
747 mswin_create_nhwindow(int type)
752 logDebug("mswin_create_nhwindow(%d)\n", type);
754 /* Return the next available winid
757 for (i = 1; i < MAXWINDOWS; i++)
758 if (GetNHApp()->windowlist[i].win == NULL
759 && !GetNHApp()->windowlist[i].dead)
762 panic("ERROR: No windows available...\n");
766 GetNHApp()->windowlist[i].win = mswin_init_map_window();
767 GetNHApp()->windowlist[i].type = type;
768 GetNHApp()->windowlist[i].dead = 0;
772 GetNHApp()->windowlist[i].win = mswin_init_message_window();
773 GetNHApp()->windowlist[i].type = type;
774 GetNHApp()->windowlist[i].dead = 0;
778 GetNHApp()->windowlist[i].win = mswin_init_status_window();
779 GetNHApp()->windowlist[i].type = type;
780 GetNHApp()->windowlist[i].dead = 0;
784 GetNHApp()->windowlist[i].win = NULL; // will create later
785 GetNHApp()->windowlist[i].type = type;
786 GetNHApp()->windowlist[i].dead = 1;
790 GetNHApp()->windowlist[i].win = mswin_init_text_window();
791 GetNHApp()->windowlist[i].type = type;
792 GetNHApp()->windowlist[i].dead = 0;
797 ZeroMemory(&data, sizeof(data));
799 SendMessage(GetNHApp()->hMainWnd, WM_MSNH_COMMAND,
800 (WPARAM) MSNH_MSG_ADDWND, (LPARAM) &data);
804 /* Clear the given window, when asked to. */
806 mswin_clear_nhwindow(winid wid)
808 logDebug("mswin_clear_nhwindow(%d)\n", wid);
810 if ((wid >= 0) && (wid < MAXWINDOWS)
811 && (GetNHApp()->windowlist[wid].win != NULL)) {
812 if (GetNHApp()->windowlist[wid].type == NHW_MAP) {
813 if (Is_rogue_level(&u.uz))
814 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP),
815 ROGUE_LEVEL_MAP_MODE);
817 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP),
821 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
822 (WPARAM) MSNH_MSG_CLEAR_WINDOW, (LPARAM) NULL);
826 /* -- Display the window on the screen. If there is data
827 pending for output in that window, it should be sent.
828 If blocking is TRUE, display_nhwindow() will not
829 return until the data has been displayed on the screen,
830 and acknowledged by the user where appropriate.
831 -- All calls are blocking in the tty window-port.
832 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
833 --more--, if necessary, in the tty window-port.
836 mswin_display_nhwindow(winid wid, BOOLEAN_P block)
838 logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block);
839 if (GetNHApp()->windowlist[wid].win != NULL) {
840 ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW);
841 mswin_layout_main_window(GetNHApp()->windowlist[wid].win);
842 if (GetNHApp()->windowlist[wid].type == NHW_MENU) {
844 mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win,
845 PICK_NONE, &p, TRUE);
847 if (GetNHApp()->windowlist[wid].type == NHW_TEXT) {
848 mswin_display_text_window(GetNHApp()->windowlist[wid].win);
850 if (GetNHApp()->windowlist[wid].type == NHW_RIP) {
851 mswin_display_RIP_window(GetNHApp()->windowlist[wid].win);
854 UpdateWindow(GetNHApp()->windowlist[wid].win);
856 if (GetNHApp()->windowlist[wid].type == NHW_MAP) {
857 (void) mswin_nhgetch();
861 SetFocus(GetNHApp()->hMainWnd);
866 mswin_hwnd_from_winid(winid wid)
868 if (wid >= 0 && wid < MAXWINDOWS) {
869 return GetNHApp()->windowlist[wid].win;
876 mswin_winid_from_handle(HWND hWnd)
880 for (i = 1; i < MAXWINDOWS; i++)
881 if (GetNHApp()->windowlist[i].win == hWnd)
887 mswin_winid_from_type(int type)
891 for (i = 1; i < MAXWINDOWS; i++)
892 if (GetNHApp()->windowlist[i].type == type)
898 mswin_window_mark_dead(winid wid)
900 if (wid >= 0 && wid < MAXWINDOWS) {
901 GetNHApp()->windowlist[wid].win = NULL;
902 GetNHApp()->windowlist[wid].dead = 1;
906 /* Destroy will dismiss the window if the window has not
907 * already been dismissed.
910 mswin_destroy_nhwindow(winid wid)
912 logDebug("mswin_destroy_nhwindow(%d)\n", wid);
914 if ((GetNHApp()->windowlist[wid].type == NHW_MAP)
915 || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE)
916 || (GetNHApp()->windowlist[wid].type == NHW_STATUS)) {
917 /* main windows is going to take care of those */
922 if (!GetNHApp()->windowlist[wid].dead
923 && GetNHApp()->windowlist[wid].win != NULL)
924 DestroyWindow(GetNHApp()->windowlist[wid].win);
925 GetNHApp()->windowlist[wid].win = NULL;
926 GetNHApp()->windowlist[wid].type = 0;
927 GetNHApp()->windowlist[wid].dead = 0;
931 /* Next output to window will start at (x,y), also moves
932 displayable cursor to (x,y). For backward compatibility,
933 1 <= x < cols, 0 <= y < rows, where cols and rows are
937 mswin_curs(winid wid, int x, int y)
939 logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y);
941 if ((wid >= 0) && (wid < MAXWINDOWS)
942 && (GetNHApp()->windowlist[wid].win != NULL)) {
946 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
947 (WPARAM) MSNH_MSG_CURSOR, (LPARAM) &data);
952 putstr(window, attr, str)
953 -- Print str on the window with the given attribute. Only
954 printable ASCII characters (040-0126) must be supported.
955 Multiple putstr()s are output on separate lines.
963 If a window-port does not support all of these, it may map
964 unsupported attributes to a supported one (e.g. map them
965 all to ATR_INVERSE). putstr() may compress spaces out of
966 str, break str, or truncate str, if necessary for the
967 display. Where putstr() breaks a line, it has to clear
969 -- putstr should be implemented such that if two putstr()s
970 are done consecutively the user will see the first and
971 then the second. In the tty port, pline() achieves this
972 by calling more() or displaying both on the same line.
975 mswin_putstr(winid wid, int attr, const char *text)
977 logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text);
979 mswin_putstr_ex(wid, attr, text, 0);
983 mswin_putstr_ex(winid wid, int attr, const char *text, int app)
985 if ((wid >= 0) && (wid < MAXWINDOWS)) {
986 if (GetNHApp()->windowlist[wid].win == NULL
987 && GetNHApp()->windowlist[wid].type == NHW_MENU) {
988 GetNHApp()->windowlist[wid].win =
989 mswin_init_menu_window(MENU_TYPE_TEXT);
990 GetNHApp()->windowlist[wid].dead = 0;
993 if (GetNHApp()->windowlist[wid].win != NULL) {
995 ZeroMemory(&data, sizeof(data));
999 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1000 (WPARAM) MSNH_MSG_PUTSTR, (LPARAM) &data);
1002 /* yield a bit so it gets done immediately */
1003 mswin_get_nh_event();
1005 // build text to display later in message box
1006 GetNHApp()->saved_text =
1007 realloc(GetNHApp()->saved_text,
1008 strlen(text) + strlen(GetNHApp()->saved_text) + 1);
1009 strcat(GetNHApp()->saved_text, text);
1013 /* Display the file named str. Complain about missing files
1014 iff complain is TRUE.
1017 mswin_display_file(const char *filename, BOOLEAN_P must_exist)
1022 logDebug("mswin_display_file(%s, %d)\n", filename, must_exist);
1024 f = dlb_fopen(filename, RDTMODE);
1028 _stprintf(message, TEXT("Warning! Could not find file: %s\n"),
1029 NH_A2W(filename, wbuf, sizeof(wbuf)));
1030 NHMessageBox(GetNHApp()->hMainWnd, message,
1031 MB_OK | MB_ICONEXCLAMATION);
1037 text = mswin_create_nhwindow(NHW_TEXT);
1039 while (dlb_fgets(line, LLEN, f)) {
1042 if (line[len - 1] == '\n')
1043 line[len - 1] = '\x0';
1044 mswin_putstr(text, ATR_NONE, line);
1046 (void) dlb_fclose(f);
1048 mswin_display_nhwindow(text, 1);
1049 mswin_destroy_nhwindow(text);
1053 /* Start using window as a menu. You must call start_menu()
1054 before add_menu(). After calling start_menu() you may not
1055 putstr() to the window. Only windows of type NHW_MENU may
1059 mswin_start_menu(winid wid)
1061 logDebug("mswin_start_menu(%d)\n", wid);
1062 if ((wid >= 0) && (wid < MAXWINDOWS)) {
1063 if (GetNHApp()->windowlist[wid].win == NULL
1064 && GetNHApp()->windowlist[wid].type == NHW_MENU) {
1065 GetNHApp()->windowlist[wid].win =
1066 mswin_init_menu_window(MENU_TYPE_MENU);
1067 GetNHApp()->windowlist[wid].dead = 0;
1070 if (GetNHApp()->windowlist[wid].win != NULL) {
1071 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1072 (WPARAM) MSNH_MSG_STARTMENU, (LPARAM) NULL);
1078 add_menu(windid window, int glyph, const anything identifier,
1079 char accelerator, char groupacc,
1080 int attr, char *str, boolean preselected)
1081 -- Add a text line str to the given menu window. If
1083 is 0, then the line cannot be selected (e.g. a title).
1084 Otherwise, identifier is the value returned if the line is
1085 selected. Accelerator is a keyboard key that can be used
1086 to select the line. If the accelerator of a selectable
1087 item is 0, the window system is free to select its own
1088 accelerator. It is up to the window-port to make the
1089 accelerator visible to the user (e.g. put "a - " in front
1090 of str). The value attr is the same as in putstr().
1091 Glyph is an optional glyph to accompany the line. If
1092 window port cannot or does not want to display it, this
1093 is OK. If there is no glyph applicable, then this
1094 value will be NO_GLYPH.
1095 -- All accelerators should be in the range [A-Za-z].
1096 -- It is expected that callers do not mix accelerator
1097 choices. Either all selectable items have an accelerator
1098 or let the window system pick them. Don't do both.
1099 -- Groupacc is a group accelerator. It may be any character
1100 outside of the standard accelerator (see above) or a
1101 number. If 0, the item is unaffected by any group
1102 accelerator. If this accelerator conflicts with
1103 the menu command (or their user defined alises), it loses.
1104 The menu commands and aliases take care not to interfere
1105 with the default object class symbols.
1106 -- If you want this choice to be preselected when the
1107 menu is displayed, set preselected to TRUE.
1110 mswin_add_menu(winid wid, int glyph, const ANY_P *identifier,
1111 CHAR_P accelerator, CHAR_P group_accel, int attr,
1112 const char *str, BOOLEAN_P presel)
1114 logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph,
1115 identifier, (char) accelerator, (char) group_accel, attr, str,
1117 if ((wid >= 0) && (wid < MAXWINDOWS)
1118 && (GetNHApp()->windowlist[wid].win != NULL)) {
1119 MSNHMsgAddMenu data;
1120 ZeroMemory(&data, sizeof(data));
1122 data.identifier = identifier;
1123 data.accelerator = accelerator;
1124 data.group_accel = group_accel;
1127 data.presel = presel;
1129 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1130 (WPARAM) MSNH_MSG_ADDMENU, (LPARAM) &data);
1135 end_menu(window, prompt)
1136 -- Stop adding entries to the menu and flushes the window
1137 to the screen (brings to front?). Prompt is a prompt
1138 to give the user. If prompt is NULL, no prompt will
1140 ** This probably shouldn't flush the window any more (if
1141 ** it ever did). That should be select_menu's job. -dean
1144 mswin_end_menu(winid wid, const char *prompt)
1146 logDebug("mswin_end_menu(%d, %s)\n", wid, prompt);
1147 if ((wid >= 0) && (wid < MAXWINDOWS)
1148 && (GetNHApp()->windowlist[wid].win != NULL)) {
1149 MSNHMsgEndMenu data;
1150 ZeroMemory(&data, sizeof(data));
1153 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1154 (WPARAM) MSNH_MSG_ENDMENU, (LPARAM) &data);
1159 int select_menu(windid window, int how, menu_item **selected)
1160 -- Return the number of items selected; 0 if none were chosen,
1161 -1 when explicitly cancelled. If items were selected, then
1162 selected is filled in with an allocated array of menu_item
1163 structures, one for each selected line. The caller must
1164 free this array when done with it. The "count" field
1165 of selected is a user supplied count. If the user did
1166 not supply a count, then the count field is filled with
1167 -1 (meaning all). A count of zero is equivalent to not
1168 being selected and should not be in the list. If no items
1169 were selected, then selected is NULL'ed out. How is the
1170 mode of the menu. Three valid values are PICK_NONE,
1171 PICK_ONE, and PICK_N, meaning: nothing is selectable,
1172 only one thing is selectable, and any number valid items
1173 may selected. If how is PICK_NONE, this function should
1174 never return anything but 0 or -1.
1175 -- You may call select_menu() on a window multiple times --
1176 the menu is saved until start_menu() or destroy_nhwindow()
1177 is called on the window.
1178 -- Note that NHW_MENU windows need not have select_menu()
1179 called for them. There is no way of knowing whether
1180 select_menu() will be called for the window at
1181 create_nhwindow() time.
1184 mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected)
1188 logDebug("mswin_select_menu(%d, %d)\n", wid, how);
1190 if ((wid >= 0) && (wid < MAXWINDOWS)
1191 && (GetNHApp()->windowlist[wid].win != NULL)) {
1192 ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW);
1193 nReturned = mswin_menu_window_select_menu(
1194 GetNHApp()->windowlist[wid].win, how, selected,
1195 !(flags.perm_invent && wid == WIN_INVEN
1196 && how == PICK_NONE) /* don't activate inventory window if
1197 perm_invent is on */
1204 -- Indicate to the window port that the inventory has been changed.
1205 -- Merely calls display_inventory() for window-ports that leave the
1206 window up, otherwise empty.
1209 mswin_update_inventory()
1211 logDebug("mswin_update_inventory()\n");
1212 if (flags.perm_invent && program_state.something_worth_saving
1213 && iflags.window_inited && WIN_INVEN != WIN_ERR)
1214 display_inventory(NULL, FALSE);
1218 mark_synch() -- Don't go beyond this point in I/O on any channel until
1219 all channels are caught up to here. Can be an empty call
1225 logDebug("mswin_mark_synch()\n");
1229 wait_synch() -- Wait until all pending output is complete (*flush*() for
1231 -- May also deal with exposure events etc. so that the
1232 display is OK when return from wait_synch().
1237 logDebug("mswin_wait_synch()\n");
1241 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
1242 screen if the playing area is larger than the screen.
1243 -- This function is only defined if CLIPPING is defined.
1246 mswin_cliparound(int x, int y)
1248 winid wid = WIN_MAP;
1250 logDebug("mswin_cliparound(%d, %d)\n", x, y);
1252 if ((wid >= 0) && (wid < MAXWINDOWS)
1253 && (GetNHApp()->windowlist[wid].win != NULL)) {
1254 MSNHMsgClipAround data;
1257 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1258 (WPARAM) MSNH_MSG_CLIPAROUND, (LPARAM) &data);
1263 print_glyph(window, x, y, glyph, bkglyph)
1264 -- Print the glyph at (x,y) on the given window. Glyphs are
1265 integers at the interface, mapped to whatever the window-
1266 port wants (symbol, font, color, attributes, ...there's
1267 a 1-1 map between glyphs and distinct things on the map).
1268 -- bkglyph is a background glyph for potential use by some
1269 graphical or tiled environments to allow the depiction
1270 to fall against a background consistent with the grid
1275 mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph)
1277 logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid, x, y, glyph, bkglyph);
1279 if ((wid >= 0) && (wid < MAXWINDOWS)
1280 && (GetNHApp()->windowlist[wid].win != NULL)) {
1281 MSNHMsgPrintGlyph data;
1283 ZeroMemory(&data, sizeof(data));
1287 data.bkglyph = bkglyph;
1288 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1289 (WPARAM) MSNH_MSG_PRINT_GLYPH, (LPARAM) &data);
1294 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
1295 the user sees str. raw_print() appends a newline to str.
1296 It need not recognize ASCII control characters. This is
1297 used during startup (before windowing system initialization
1298 -- maybe this means only error startup messages are raw),
1299 for error messages, and maybe other "msg" uses. E.g.
1300 updating status for micros (i.e, "saving").
1303 mswin_raw_print(const char *str)
1306 logDebug("mswin_raw_print(%s)\n", str);
1308 extern int redirect_stdout;
1309 if (!redirect_stdout)
1310 NHMessageBox(GetNHApp()->hMainWnd,
1311 NH_A2W(str, wbuf, sizeof(wbuf)),
1312 MB_ICONINFORMATION | MB_OK);
1314 fprintf(stdout, "%s", str);
1320 -- Like raw_print(), but prints in bold/standout (if
1324 mswin_raw_print_bold(const char *str)
1327 logDebug("mswin_raw_print_bold(%s)\n", str);
1329 NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)),
1330 MB_ICONINFORMATION | MB_OK);
1334 int nhgetch() -- Returns a single character input from the user.
1335 -- In the tty window-port, nhgetch() assumes that tgetch()
1336 will be the routine the OS provides to read a character.
1337 Returned character _must_ be non-zero.
1345 logDebug("mswin_nhgetch()\n");
1347 while ((event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR)
1350 key = event->kbd.ch;
1355 int nh_poskey(int *x, int *y, int *mod)
1356 -- Returns a single character input from the user or a
1357 a positioning event (perhaps from a mouse). If the
1358 return value is non-zero, a character was typed, else,
1359 a position in the MAP window is returned in x, y and mod.
1362 CLICK_1 -- mouse click type 1
1363 CLICK_2 -- mouse click type 2
1365 The different click types can map to whatever the
1366 hardware supports. If no mouse is supported, this
1367 routine always returns a non-zero character.
1370 mswin_nh_poskey(int *x, int *y, int *mod)
1375 logDebug("mswin_nh_poskey()\n");
1377 while ((event = mswin_input_pop()) == NULL)
1380 if (event->type == NHEVENT_MOUSE) {
1381 *mod = event->ms.mod;
1386 key = event->kbd.ch;
1392 nhbell() -- Beep at user. [This will exist at least until sounds are
1393 redone, since sounds aren't attributable to windows
1399 logDebug("mswin_nhbell()\n");
1404 -- Display previous messages. Used by the ^P command.
1405 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1408 mswin_doprev_message()
1410 logDebug("mswin_doprev_message()\n");
1411 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL,
1412 MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
1417 char yn_function(const char *ques, const char *choices, char default)
1418 -- Print a prompt made up of ques, choices and default.
1419 Read a single character response that is contained in
1420 choices or default. If choices is NULL, all possible
1421 inputs are accepted and returned. This overrides
1422 everything else. The choices are expected to be in
1423 lower case. Entering ESC always maps to 'q', or 'n',
1424 in that order, if present in choices, otherwise it maps
1425 to default. Entering any other quit character (SPACE,
1426 RETURN, NEWLINE) maps to default.
1427 -- If the choices string contains ESC, then anything after
1428 it is an acceptable response, but the ESC and whatever
1429 follows is not included in the prompt.
1430 -- If the choices string contains a '#' then accept a count.
1431 Place this value in the global "yn_number" and return '#'.
1432 -- This uses the top line in the tty window-port, other
1433 ports might use a popup.
1436 mswin_yn_function(const char *question, const char *choices, CHAR_P def)
1439 char yn_esc_map = '\033';
1440 char message[BUFSZ];
1443 boolean digit_ok, allow_num;
1445 logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def);
1447 if (WIN_MESSAGE == WIN_ERR && choices == ynchars) {
1449 realloc(strdup(GetNHApp()->saved_text),
1450 strlen(question) + strlen(GetNHApp()->saved_text) + 1);
1452 strcat(text, question);
1454 NHMessageBox(NULL, NH_W2A(text, message, sizeof(message)),
1455 MB_ICONQUESTION | MB_YESNOCANCEL
1456 | ((def == 'y') ? MB_DEFBUTTON1
1457 : (def == 'n') ? MB_DEFBUTTON2
1460 GetNHApp()->saved_text = strdup("");
1461 return box_result == IDYES ? 'y' : box_result == IDNO ? 'n' : '\033';
1465 char *cb, choicebuf[QBUFSZ];
1467 allow_num = (index(choices, '#') != 0);
1469 Strcpy(choicebuf, choices);
1470 if ((cb = index(choicebuf, '\033')) != 0) {
1471 /* anything beyond <esc> is hidden */
1474 (void) strncpy(message, question, QBUFSZ - 1);
1475 message[QBUFSZ - 1] = '\0';
1476 sprintf(eos(message), " [%s]", choicebuf);
1478 sprintf(eos(message), " (%c)", def);
1479 Strcat(message, " ");
1480 /* escape maps to 'q' or 'n' or default, in that order */
1482 (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def));
1484 Strcpy(message, question);
1485 Strcat(message, " ");
1489 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1490 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1492 mswin_clear_nhwindow(WIN_MESSAGE);
1493 mswin_putstr(WIN_MESSAGE, ATR_BOLD, message);
1495 /* Only here if main window is not present */
1498 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1499 ch = mswin_nhgetch();
1500 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1504 break; /* If choices is NULL, all possible inputs are accepted and
1507 digit_ok = allow_num && digit(ch);
1509 if (index(choices, 'q'))
1511 else if (index(choices, 'n'))
1516 } else if (index(quitchars, ch)) {
1519 } else if (!index(choices, ch) && !digit_ok) {
1522 /* and try again... */
1523 } else if (ch == '#' || digit_ok) {
1524 char z, digit_string[2];
1527 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, ("#"), 1);
1529 digit_string[1] = '\0';
1531 digit_string[0] = ch;
1532 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1);
1537 do { /* loop until we get a non-digit */
1538 z = lowc(readchar());
1540 value = (10 * value) + (z - '0');
1542 break; /* overflow: try again */
1543 digit_string[0] = z;
1544 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1);
1546 } else if (z == 'y' || index(quitchars, z)) {
1548 value = -1; /* abort */
1549 z = '\n'; /* break */
1550 } else if (z == '\b') {
1556 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string,
1561 value = -1; /* abort */
1565 } while (z != '\n');
1568 else if (value == 0)
1569 ch = 'n'; /* 0 => "no" */
1570 else { /* remove number from top line, then try again */
1571 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -n_len);
1579 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1580 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1582 /* display selection in the message window */
1583 if (isprint(ch) && ch != '#') {
1586 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1);
1593 getlin(const char *ques, char *input)
1594 -- Prints ques as a prompt and reads a single line of text,
1595 up to a newline. The string entered is returned without the
1596 newline. ESC is used to cancel, in which case the string
1597 "\033\000" is returned.
1598 -- getlin() must call flush_screen(1) before doing anything.
1599 -- This uses the top line in the tty window-port, other
1600 ports might use a popup.
1603 mswin_getlin(const char *question, char *input)
1605 logDebug("mswin_getlin(%s, %p)\n", question, input);
1607 if (!iflags.wc_popup_dialog) {
1614 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1615 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1617 mswin_clear_nhwindow(WIN_MESSAGE);
1618 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, question, 0);
1619 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, " ", 1);
1622 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1625 c = mswin_nhgetch();
1628 strcpy(input, "\033");
1638 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, -len);
1647 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, 1);
1651 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1653 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1654 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1656 if (mswin_getlin_window(question, input, BUFSZ) == IDCANCEL) {
1657 strcpy(input, "\033");
1663 int get_ext_cmd(void)
1664 -- Get an extended command in a window-port specific way.
1665 An index into extcmdlist[] is returned on a successful
1666 selection, -1 otherwise.
1672 logDebug("mswin_get_ext_cmd()\n");
1674 if (!iflags.wc_popup_dialog) {
1681 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1682 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1686 mswin_clear_nhwindow(WIN_MESSAGE);
1687 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, "#", 0);
1689 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1691 int oindex, com_index;
1692 c = mswin_nhgetch();
1700 for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++)
1701 if (!strcmpi(cmd, extcmdlist[i].ef_txt))
1704 if (extcmdlist[i].ef_txt == (char *) 0) {
1705 pline("%s: unknown extended command.", cmd);
1711 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd,
1712 -(int) strlen(cmd));
1720 /* Find a command with this prefix in extcmdlist */
1722 for (oindex = 0; extcmdlist[oindex].ef_txt != (char *) 0;
1724 if (!strncmpi(cmd, extcmdlist[oindex].ef_txt, len)) {
1725 if (com_index == -1) /* no matches yet */
1729 -2; /* two matches, don't complete */
1732 if (com_index >= 0) {
1733 Strcpy(cmd, extcmdlist[com_index].ef_txt);
1736 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, 1);
1740 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1742 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1743 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1746 if (mswin_ext_cmd_window(&ret) == IDCANCEL)
1755 -- Initialize the number pad to the given state.
1758 mswin_number_pad(int state)
1761 logDebug("mswin_number_pad(%d)\n", state);
1765 delay_output() -- Causes a visible delay of 50ms in the output.
1766 Conceptually, this is similar to wait_synch() followed
1767 by a nap(50ms), but allows asynchronous operation.
1770 mswin_delay_output()
1772 logDebug("mswin_delay_output()\n");
1777 mswin_change_color()
1779 logDebug("mswin_change_color()\n");
1783 mswin_get_color_string()
1785 logDebug("mswin_get_color_string()\n");
1790 start_screen() -- Only used on Unix tty ports, but must be declared for
1791 completeness. Sets up the tty to work in full-screen
1792 graphics mode. Look at win/tty/termcap.c for an
1793 example. If your window-port does not need this function
1794 just declare an empty function.
1797 mswin_start_screen()
1800 logDebug("mswin_start_screen()\n");
1804 end_screen() -- Only used on Unix tty ports, but must be declared for
1805 completeness. The complement of start_screen().
1811 logDebug("mswin_end_screen()\n");
1815 outrip(winid, int, when)
1816 -- The tombstone code. If you want the traditional code use
1817 genl_outrip for the value and check the #if in rip.c.
1819 #define STONE_LINE_LEN 16
1821 mswin_outrip(winid wid, int how, time_t when)
1826 logDebug("mswin_outrip(%d, %d, %ld)\n", wid, how, (long) when);
1827 if ((wid >= 0) && (wid < MAXWINDOWS)) {
1828 DestroyWindow(GetNHApp()->windowlist[wid].win);
1829 GetNHApp()->windowlist[wid].win = mswin_init_RIP_window();
1830 GetNHApp()->windowlist[wid].type = NHW_RIP;
1831 GetNHApp()->windowlist[wid].dead = 0;
1834 /* Put name on stone */
1835 Sprintf(buf, "%s", plname);
1836 buf[STONE_LINE_LEN] = 0;
1837 putstr(wid, 0, buf);
1839 /* Put $ on stone */
1840 Sprintf(buf, "%ld Au", done_money);
1841 buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
1842 putstr(wid, 0, buf);
1844 /* Put together death description */
1845 formatkiller(buf, sizeof buf, how);
1847 /* Put death type on stone */
1848 putstr(wid, 0, buf);
1850 /* Put year on stone */
1851 year = yyyymmdd(when) / 10000L;
1852 Sprintf(buf, "%4ld", year);
1853 putstr(wid, 0, buf);
1854 mswin_finish_rip_text(wid);
1857 /* handle options updates here */
1859 mswin_preference_update(const char *pref)
1864 if (stricmp(pref, "font_menu") == 0
1865 || stricmp(pref, "font_size_menu") == 0) {
1866 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
1867 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
1868 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
1870 hdc = GetDC(GetNHApp()->hMainWnd);
1871 mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE);
1872 mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE);
1873 mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE);
1874 mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE);
1875 mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE);
1876 mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE);
1877 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1879 mswin_layout_main_window(NULL);
1883 if (stricmp(pref, "font_status") == 0
1884 || stricmp(pref, "font_size_status") == 0) {
1885 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
1886 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
1887 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
1889 hdc = GetDC(GetNHApp()->hMainWnd);
1890 mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE);
1891 mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE);
1892 mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE);
1893 mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE);
1894 mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE);
1895 mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE);
1896 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1898 for (i = 1; i < MAXWINDOWS; i++) {
1899 if (GetNHApp()->windowlist[i].type == NHW_STATUS
1900 && GetNHApp()->windowlist[i].win != NULL) {
1901 InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE);
1904 mswin_layout_main_window(NULL);
1908 if (stricmp(pref, "font_message") == 0
1909 || stricmp(pref, "font_size_message") == 0) {
1910 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
1911 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
1912 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
1914 hdc = GetDC(GetNHApp()->hMainWnd);
1915 mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE);
1916 mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE);
1917 mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE);
1918 mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE);
1919 mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE);
1920 mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE);
1921 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1923 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1924 mswin_layout_main_window(NULL);
1928 if (stricmp(pref, "font_text") == 0
1929 || stricmp(pref, "font_size_text") == 0) {
1930 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
1931 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
1932 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
1934 hdc = GetDC(GetNHApp()->hMainWnd);
1935 mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE);
1936 mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE);
1937 mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE);
1938 mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE);
1939 mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE);
1940 mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE);
1941 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1943 mswin_layout_main_window(NULL);
1947 if (stricmp(pref, "scroll_amount") == 0) {
1948 mswin_cliparound(u.ux, u.uy);
1952 if (stricmp(pref, "scroll_margin") == 0) {
1953 mswin_cliparound(u.ux, u.uy);
1957 if (stricmp(pref, "map_mode") == 0) {
1958 mswin_select_map_mode(iflags.wc_map_mode);
1962 if (stricmp(pref, "hilite_pet") == 0) {
1963 InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE);
1967 if (stricmp(pref, "align_message") == 0
1968 || stricmp(pref, "align_status") == 0) {
1969 mswin_layout_main_window(NULL);
1973 if (stricmp(pref, "vary_msgcount") == 0) {
1974 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1975 mswin_layout_main_window(NULL);
1980 #define TEXT_BUFFER_SIZE 4096
1982 mswin_getmsghistory(BOOLEAN_P init)
1984 static PMSNHMsgGetText text = 0;
1985 static char *next_message = 0;
1988 text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText)
1989 + TEXT_BUFFER_SIZE);
1992 - 1; /* make sure we always have 0 at the end of the buffer */
1994 ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
1995 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1996 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
1998 next_message = text->buffer;
2001 if (!(next_message && next_message[0])) {
2006 char *retval = next_message;
2008 next_message = p = strchr(next_message, '\n');
2012 while (p >= retval && isspace(*p))
2013 *p-- = (char) 0; /* delete trailing whitespace */
2019 mswin_putmsghistory(const char *msg, BOOLEAN_P restoring)
2021 BOOL save_sound_opt;
2023 UNREFERENCED_PARAMETER(restoring);
2026 return; /* end of message history restore */
2027 save_sound_opt = GetNHApp()->bNoSounds;
2028 GetNHApp()->bNoSounds =
2029 TRUE; /* disable sounds while restoring message history */
2030 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, msg, 0);
2031 clear_nhwindow(WIN_MESSAGE); /* it is in fact end-of-turn indication so
2032 each message will print on the new line */
2033 GetNHApp()->bNoSounds = save_sound_opt; /* restore sounds option */
2041 while (!mswin_have_input() && GetMessage(&msg, NULL, 0, 0) != 0) {
2042 if (GetNHApp()->regNetHackMode
2043 || !TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable,
2045 TranslateMessage(&msg);
2046 DispatchMessage(&msg);
2051 /* clean up and quit */
2053 bail(const char *mesg)
2056 mswin_exit_nhwindows(mesg);
2057 terminate(EXIT_SUCCESS);
2066 TCHAR wbuf[MAX_PATH];
2069 extern int total_tiles_used;
2071 /* no file - no tile */
2072 if (!(iflags.wc_tile_file && *iflags.wc_tile_file))
2076 hBmp = LoadImage(GetNHApp()->hApp,
2077 NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH),
2078 IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
2081 "Cannot load tiles from the file. Reverting back to default.");
2085 /* calculate tile dimensions */
2086 GetObject(hBmp, sizeof(BITMAP), (LPVOID) &bm);
2087 if (bm.bmWidth % iflags.wc_tile_width
2088 || bm.bmHeight % iflags.wc_tile_height) {
2090 raw_print("Tiles bitmap does not match tile_width and tile_height "
2091 "options. Reverting back to default.");
2095 tl_num = (bm.bmWidth / iflags.wc_tile_width)
2096 * (bm.bmHeight / iflags.wc_tile_height);
2097 if (tl_num < total_tiles_used) {
2099 raw_print("Number of tiles in the bitmap is less than required by "
2100 "the game. Reverting back to default.");
2104 /* set the tile information */
2105 if (GetNHApp()->bmpMapTiles != GetNHApp()->bmpTiles) {
2106 DeleteObject(GetNHApp()->bmpMapTiles);
2109 GetNHApp()->bmpMapTiles = hBmp;
2110 GetNHApp()->mapTile_X = iflags.wc_tile_width;
2111 GetNHApp()->mapTile_Y = iflags.wc_tile_height;
2112 GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width;
2114 map_size.cx = GetNHApp()->mapTile_X * COLNO;
2115 map_size.cy = GetNHApp()->mapTile_Y * ROWNO;
2116 mswin_map_stretch(mswin_hwnd_from_winid(WIN_MAP), &map_size, TRUE);
2121 mswin_popup_display(HWND hWnd, int *done_indicator)
2129 /* activate the menu window */
2130 GetNHApp()->hPopupWnd = hWnd;
2132 mswin_layout_main_window(hWnd);
2134 /* disable game windows */
2135 for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild;
2136 hChild = GetWindow(hChild, GW_HWNDNEXT)) {
2138 EnableWindow(hChild, FALSE);
2142 hMenu = GetMenu(GetNHApp()->hMainWnd);
2143 mi_count = GetMenuItemCount(hMenu);
2144 for (i = 0; i < mi_count; i++) {
2145 EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_GRAYED);
2147 DrawMenuBar(GetNHApp()->hMainWnd);
2149 /* bring menu window on top */
2150 SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
2151 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2154 /* go into message loop */
2155 while (IsWindow(hWnd) && (done_indicator == NULL || !*done_indicator)
2156 && GetMessage(&msg, NULL, 0, 0) != 0) {
2157 if (!IsDialogMessage(hWnd, &msg)) {
2158 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable,
2160 TranslateMessage(&msg);
2161 DispatchMessage(&msg);
2168 mswin_popup_destroy(HWND hWnd)
2175 /* enable game windows */
2176 for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild;
2177 hChild = GetWindow(hChild, GW_HWNDNEXT)) {
2178 if (hChild != hWnd) {
2179 EnableWindow(hChild, TRUE);
2184 hMenu = GetMenu(GetNHApp()->hMainWnd);
2185 mi_count = GetMenuItemCount(hMenu);
2186 for (i = 0; i < mi_count; i++) {
2187 EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_ENABLED);
2189 DrawMenuBar(GetNHApp()->hMainWnd);
2191 ShowWindow(hWnd, SW_HIDE);
2192 GetNHApp()->hPopupWnd = NULL;
2194 mswin_layout_main_window(hWnd);
2196 SetFocus(GetNHApp()->hMainWnd);
2204 logDebug(const char *fmt, ...)
2208 if (!showdebug(NHTRACE_LOG) || !_s_debugfp)
2211 va_start(args, fmt);
2212 vfprintf(_s_debugfp, fmt, args);
2219 /* Reading and writing settings from the registry. */
2220 #define CATEGORYKEY "Software"
2221 #define COMPANYKEY "NetHack"
2222 #define PRODUCTKEY "NetHack 3.6.0"
2223 #define SETTINGSKEY "Settings"
2224 #define MAINSHOWSTATEKEY "MainShowState"
2225 #define MAINMINXKEY "MainMinX"
2226 #define MAINMINYKEY "MainMinY"
2227 #define MAINMAXXKEY "MainMaxX"
2228 #define MAINMAXYKEY "MainMaxY"
2229 #define MAINLEFTKEY "MainLeft"
2230 #define MAINRIGHTKEY "MainRight"
2231 #define MAINTOPKEY "MainTop"
2232 #define MAINBOTTOMKEY "MainBottom"
2233 #define MAINAUTOLAYOUT "AutoLayout"
2234 #define MAPLEFT "MapLeft"
2235 #define MAPRIGHT "MapRight"
2236 #define MAPTOP "MapTop"
2237 #define MAPBOTTOM "MapBottom"
2238 #define MSGLEFT "MsgLeft"
2239 #define MSGRIGHT "MsgRight"
2240 #define MSGTOP "MsgTop"
2241 #define MSGBOTTOM "MsgBottom"
2242 #define STATUSLEFT "StatusLeft"
2243 #define STATUSRIGHT "StatusRight"
2244 #define STATUSTOP "StatusTop"
2245 #define STATUSBOTTOM "StatusBottom"
2246 #define MENULEFT "MenuLeft"
2247 #define MENURIGHT "MenuRight"
2248 #define MENUTOP "MenuTop"
2249 #define MENUBOTTOM "MenuBottom"
2250 #define TEXTLEFT "TextLeft"
2251 #define TEXTRIGHT "TextRight"
2252 #define TEXTTOP "TextTop"
2253 #define TEXTBOTTOM "TextBottom"
2254 #define INVENTLEFT "InventLeft"
2255 #define INVENTRIGHT "InventRight"
2256 #define INVENTTOP "InventTop"
2257 #define INVENTBOTTOM "InventBottom"
2259 /* #define all the subkeys here */
2260 #define INTFKEY "Interface"
2268 char keystring[MAX_PATH];
2270 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY,
2273 /* Set the defaults here. The very first time the app is started, nothing
2275 read from the registry, so these defaults apply. */
2276 GetNHApp()->saveRegistrySettings = 1; /* Normally, we always save */
2277 GetNHApp()->regNetHackMode = 0;
2279 if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key)
2283 size = sizeof(DWORD);
2285 #define NHGETREG_DWORD(name, val) \
2286 RegQueryValueEx(key, (name), 0, NULL, (unsigned char *)(&safe_buf), \
2290 /* read the keys here */
2291 NHGETREG_DWORD(INTFKEY, GetNHApp()->regNetHackMode);
2293 /* read window placement */
2294 NHGETREG_DWORD(MAINSHOWSTATEKEY, GetNHApp()->regMainShowState);
2295 NHGETREG_DWORD(MAINMINXKEY, GetNHApp()->regMainMinX);
2296 NHGETREG_DWORD(MAINMINYKEY, GetNHApp()->regMainMinY);
2297 NHGETREG_DWORD(MAINMAXXKEY, GetNHApp()->regMainMaxX);
2298 NHGETREG_DWORD(MAINMAXYKEY, GetNHApp()->regMainMaxY);
2299 NHGETREG_DWORD(MAINLEFTKEY, GetNHApp()->regMainLeft);
2300 NHGETREG_DWORD(MAINRIGHTKEY, GetNHApp()->regMainRight);
2301 NHGETREG_DWORD(MAINTOPKEY, GetNHApp()->regMainTop);
2302 NHGETREG_DWORD(MAINBOTTOMKEY, GetNHApp()->regMainBottom);
2304 NHGETREG_DWORD(MAINAUTOLAYOUT, GetNHApp()->bAutoLayout);
2305 NHGETREG_DWORD(MAPLEFT, GetNHApp()->rtMapWindow.left);
2306 NHGETREG_DWORD(MAPRIGHT, GetNHApp()->rtMapWindow.right);
2307 NHGETREG_DWORD(MAPTOP, GetNHApp()->rtMapWindow.top);
2308 NHGETREG_DWORD(MAPBOTTOM, GetNHApp()->rtMapWindow.bottom);
2309 NHGETREG_DWORD(MSGLEFT, GetNHApp()->rtMsgWindow.left);
2310 NHGETREG_DWORD(MSGRIGHT, GetNHApp()->rtMsgWindow.right);
2311 NHGETREG_DWORD(MSGTOP, GetNHApp()->rtMsgWindow.top);
2312 NHGETREG_DWORD(MSGBOTTOM, GetNHApp()->rtMsgWindow.bottom);
2313 NHGETREG_DWORD(STATUSLEFT, GetNHApp()->rtStatusWindow.left);
2314 NHGETREG_DWORD(STATUSRIGHT, GetNHApp()->rtStatusWindow.right);
2315 NHGETREG_DWORD(STATUSTOP, GetNHApp()->rtStatusWindow.top);
2316 NHGETREG_DWORD(STATUSBOTTOM, GetNHApp()->rtStatusWindow.bottom);
2317 NHGETREG_DWORD(MENULEFT, GetNHApp()->rtMenuWindow.left);
2318 NHGETREG_DWORD(MENURIGHT, GetNHApp()->rtMenuWindow.right);
2319 NHGETREG_DWORD(MENUTOP, GetNHApp()->rtMenuWindow.top);
2320 NHGETREG_DWORD(MENUBOTTOM, GetNHApp()->rtMenuWindow.bottom);
2321 NHGETREG_DWORD(TEXTLEFT, GetNHApp()->rtTextWindow.left);
2322 NHGETREG_DWORD(TEXTRIGHT, GetNHApp()->rtTextWindow.right);
2323 NHGETREG_DWORD(TEXTTOP, GetNHApp()->rtTextWindow.top);
2324 NHGETREG_DWORD(TEXTBOTTOM, GetNHApp()->rtTextWindow.bottom);
2325 NHGETREG_DWORD(INVENTLEFT, GetNHApp()->rtInvenWindow.left);
2326 NHGETREG_DWORD(INVENTRIGHT, GetNHApp()->rtInvenWindow.right);
2327 NHGETREG_DWORD(INVENTTOP, GetNHApp()->rtInvenWindow.top);
2328 NHGETREG_DWORD(INVENTBOTTOM, GetNHApp()->rtInvenWindow.bottom);
2329 #undef NHGETREG_DWORD
2333 /* check the data for validity */
2334 if (IsRectEmpty(&GetNHApp()->rtMapWindow)
2335 || IsRectEmpty(&GetNHApp()->rtMsgWindow)
2336 || IsRectEmpty(&GetNHApp()->rtStatusWindow)
2337 || IsRectEmpty(&GetNHApp()->rtMenuWindow)
2338 || IsRectEmpty(&GetNHApp()->rtTextWindow)
2339 || IsRectEmpty(&GetNHApp()->rtInvenWindow)) {
2340 GetNHApp()->bAutoLayout = TRUE;
2350 if (GetNHApp()->saveRegistrySettings) {
2351 char keystring[MAX_PATH];
2354 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY,
2355 PRODUCTKEY, SETTINGSKEY);
2357 if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key)
2359 RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "",
2360 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2361 &key, &disposition);
2364 #define NHSETREG_DWORD(name, val) \
2365 RegSetValueEx(key, (name), 0, REG_DWORD, \
2366 (unsigned char *)((safe_buf = (val)), &safe_buf), \
2369 /* Write the keys here */
2370 NHSETREG_DWORD(INTFKEY, GetNHApp()->regNetHackMode);
2372 /* Main window placement */
2373 NHSETREG_DWORD(MAINSHOWSTATEKEY, GetNHApp()->regMainShowState);
2374 NHSETREG_DWORD(MAINMINXKEY, GetNHApp()->regMainMinX);
2375 NHSETREG_DWORD(MAINMINYKEY, GetNHApp()->regMainMinY);
2376 NHSETREG_DWORD(MAINMAXXKEY, GetNHApp()->regMainMaxX);
2377 NHSETREG_DWORD(MAINMAXYKEY, GetNHApp()->regMainMaxY);
2378 NHSETREG_DWORD(MAINLEFTKEY, GetNHApp()->regMainLeft);
2379 NHSETREG_DWORD(MAINRIGHTKEY, GetNHApp()->regMainRight);
2380 NHSETREG_DWORD(MAINTOPKEY, GetNHApp()->regMainTop);
2381 NHSETREG_DWORD(MAINBOTTOMKEY, GetNHApp()->regMainBottom);
2383 NHSETREG_DWORD(MAINAUTOLAYOUT, GetNHApp()->bAutoLayout);
2384 NHSETREG_DWORD(MAPLEFT, GetNHApp()->rtMapWindow.left);
2385 NHSETREG_DWORD(MAPRIGHT, GetNHApp()->rtMapWindow.right);
2386 NHSETREG_DWORD(MAPTOP, GetNHApp()->rtMapWindow.top);
2387 NHSETREG_DWORD(MAPBOTTOM, GetNHApp()->rtMapWindow.bottom);
2388 NHSETREG_DWORD(MSGLEFT, GetNHApp()->rtMsgWindow.left);
2389 NHSETREG_DWORD(MSGRIGHT, GetNHApp()->rtMsgWindow.right);
2390 NHSETREG_DWORD(MSGTOP, GetNHApp()->rtMsgWindow.top);
2391 NHSETREG_DWORD(MSGBOTTOM, GetNHApp()->rtMsgWindow.bottom);
2392 NHSETREG_DWORD(STATUSLEFT, GetNHApp()->rtStatusWindow.left);
2393 NHSETREG_DWORD(STATUSRIGHT, GetNHApp()->rtStatusWindow.right);
2394 NHSETREG_DWORD(STATUSTOP, GetNHApp()->rtStatusWindow.top);
2395 NHSETREG_DWORD(STATUSBOTTOM, GetNHApp()->rtStatusWindow.bottom);
2396 NHSETREG_DWORD(MENULEFT, GetNHApp()->rtMenuWindow.left);
2397 NHSETREG_DWORD(MENURIGHT, GetNHApp()->rtMenuWindow.right);
2398 NHSETREG_DWORD(MENUTOP, GetNHApp()->rtMenuWindow.top);
2399 NHSETREG_DWORD(MENUBOTTOM, GetNHApp()->rtMenuWindow.bottom);
2400 NHSETREG_DWORD(TEXTLEFT, GetNHApp()->rtTextWindow.left);
2401 NHSETREG_DWORD(TEXTRIGHT, GetNHApp()->rtTextWindow.right);
2402 NHSETREG_DWORD(TEXTTOP, GetNHApp()->rtTextWindow.top);
2403 NHSETREG_DWORD(TEXTBOTTOM, GetNHApp()->rtTextWindow.bottom);
2404 NHSETREG_DWORD(INVENTLEFT, GetNHApp()->rtInvenWindow.left);
2405 NHSETREG_DWORD(INVENTRIGHT, GetNHApp()->rtInvenWindow.right);
2406 NHSETREG_DWORD(INVENTTOP, GetNHApp()->rtInvenWindow.top);
2407 NHSETREG_DWORD(INVENTBOTTOM, GetNHApp()->rtInvenWindow.bottom);
2408 #undef NHSETREG_DWORD
2417 char keystring[MAX_PATH];
2421 /* Delete keys one by one, as NT does not delete trees */
2422 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY,
2424 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2425 sprintf(keystring, "%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY);
2426 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2427 /* The company key will also contain information about newer versions
2428 of nethack (e.g. a subkey called NetHack 4.0), so only delete that
2429 if it's empty now. */
2430 sprintf(keystring, "%s\\%s", CATEGORYKEY, COMPANYKEY);
2431 /* If we cannot open it, we probably cannot delete it either... Just
2432 go on and see what happens. */
2433 RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key);
2435 RegQueryInfoKey(key, NULL, NULL, NULL, &nrsubkeys, NULL, NULL, NULL, NULL,
2439 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2441 /* Prevent saving on exit */
2442 GetNHApp()->saveRegistrySettings = 0;
2445 typedef struct ctv {
2446 const char *colorstring;
2447 COLORREF colorvalue;
2448 } color_table_value;
2451 * The color list here is a combination of:
2452 * NetHack colors. (See mhmap.c)
2453 * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 )
2456 static color_table_value color_table[] = {
2457 /* NetHack colors */
2458 { "black", RGB(0x55, 0x55, 0x55) },
2459 { "red", RGB(0xFF, 0x00, 0x00) },
2460 { "green", RGB(0x00, 0x80, 0x00) },
2461 { "brown", RGB(0xA5, 0x2A, 0x2A) },
2462 { "blue", RGB(0x00, 0x00, 0xFF) },
2463 { "magenta", RGB(0xFF, 0x00, 0xFF) },
2464 { "cyan", RGB(0x00, 0xFF, 0xFF) },
2465 { "orange", RGB(0xFF, 0xA5, 0x00) },
2466 { "brightgreen", RGB(0x00, 0xFF, 0x00) },
2467 { "yellow", RGB(0xFF, 0xFF, 0x00) },
2468 { "brightblue", RGB(0x00, 0xC0, 0xFF) },
2469 { "brightmagenta", RGB(0xFF, 0x80, 0xFF) },
2470 { "brightcyan", RGB(0x80, 0xFF, 0xFF) },
2471 { "white", RGB(0xFF, 0xFF, 0xFF) },
2472 /* Remaining HTML colors */
2473 { "trueblack", RGB(0x00, 0x00, 0x00) },
2474 { "gray", RGB(0x80, 0x80, 0x80) },
2475 { "grey", RGB(0x80, 0x80, 0x80) },
2476 { "purple", RGB(0x80, 0x00, 0x80) },
2477 { "silver", RGB(0xC0, 0xC0, 0xC0) },
2478 { "maroon", RGB(0x80, 0x00, 0x00) },
2479 { "fuchsia", RGB(0xFF, 0x00, 0xFF) }, /* = NetHack magenta */
2480 { "lime", RGB(0x00, 0xFF, 0x00) }, /* = NetHack bright green */
2481 { "olive", RGB(0x80, 0x80, 0x00) },
2482 { "navy", RGB(0x00, 0x00, 0x80) },
2483 { "teal", RGB(0x00, 0x80, 0x80) },
2484 { "aqua", RGB(0x00, 0xFF, 0xFF) }, /* = NetHack cyan */
2485 { "", RGB(0x00, 0x00, 0x00) },
2488 typedef struct ctbv {
2491 } color_table_brush_value;
2493 static color_table_brush_value color_table_brush[] = {
2494 { "activeborder", COLOR_ACTIVEBORDER },
2495 { "activecaption", COLOR_ACTIVECAPTION },
2496 { "appworkspace", COLOR_APPWORKSPACE },
2497 { "background", COLOR_BACKGROUND },
2498 { "btnface", COLOR_BTNFACE },
2499 { "btnshadow", COLOR_BTNSHADOW },
2500 { "btntext", COLOR_BTNTEXT },
2501 { "captiontext", COLOR_CAPTIONTEXT },
2502 { "graytext", COLOR_GRAYTEXT },
2503 { "greytext", COLOR_GRAYTEXT },
2504 { "highlight", COLOR_HIGHLIGHT },
2505 { "highlighttext", COLOR_HIGHLIGHTTEXT },
2506 { "inactiveborder", COLOR_INACTIVEBORDER },
2507 { "inactivecaption", COLOR_INACTIVECAPTION },
2508 { "menu", COLOR_MENU },
2509 { "menutext", COLOR_MENUTEXT },
2510 { "scrollbar", COLOR_SCROLLBAR },
2511 { "window", COLOR_WINDOW },
2512 { "windowframe", COLOR_WINDOWFRAME },
2513 { "windowtext", COLOR_WINDOWTEXT },
2518 mswin_color_from_string(char *colorstring, HBRUSH *brushptr,
2521 color_table_value *ctv_ptr = color_table;
2522 color_table_brush_value *ctbv_ptr = color_table_brush;
2523 int red_value, blue_value, green_value;
2524 static char *hexadecimals = "0123456789abcdef";
2526 if (colorstring == NULL)
2528 if (*colorstring == '#') {
2529 if (strlen(++colorstring) != 6)
2532 red_value = (int) (index(hexadecimals, tolower(*colorstring++))
2535 red_value += (int) (index(hexadecimals, tolower(*colorstring++))
2538 green_value = (int) (index(hexadecimals, tolower(*colorstring++))
2541 green_value += (int) (index(hexadecimals, tolower(*colorstring++))
2544 blue_value = (int) (index(hexadecimals, tolower(*colorstring++))
2547 blue_value += (int) (index(hexadecimals, tolower(*colorstring++))
2550 *colorptr = RGB(red_value, green_value, blue_value);
2552 while (*ctv_ptr->colorstring
2553 && stricmp(ctv_ptr->colorstring, colorstring))
2555 if (*ctv_ptr->colorstring) {
2556 *colorptr = ctv_ptr->colorvalue;
2558 while (*ctbv_ptr->colorstring
2559 && stricmp(ctbv_ptr->colorstring, colorstring))
2561 if (*ctbv_ptr->colorstring) {
2562 *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue);
2563 *colorptr = GetSysColor(ctbv_ptr->syscolorvalue);
2567 if (max_brush > TOTAL_BRUSHES)
2568 panic("Too many colors!");
2569 *brushptr = CreateSolidBrush(*colorptr);
2570 brush_table[max_brush++] = *brushptr;
2574 mswin_get_window_placement(int type, LPRECT rt)
2578 *rt = GetNHApp()->rtMapWindow;
2582 *rt = GetNHApp()->rtMsgWindow;
2586 *rt = GetNHApp()->rtStatusWindow;
2590 *rt = GetNHApp()->rtMenuWindow;
2594 *rt = GetNHApp()->rtTextWindow;
2598 *rt = GetNHApp()->rtInvenWindow;
2602 SetRect(rt, 0, 0, 0, 0);
2608 mswin_update_window_placement(int type, LPRECT rt)
2610 LPRECT rt_conf = NULL;
2614 rt_conf = &GetNHApp()->rtMapWindow;
2618 rt_conf = &GetNHApp()->rtMsgWindow;
2622 rt_conf = &GetNHApp()->rtStatusWindow;
2626 rt_conf = &GetNHApp()->rtMenuWindow;
2630 rt_conf = &GetNHApp()->rtTextWindow;
2634 rt_conf = &GetNHApp()->rtInvenWindow;
2638 if (rt_conf && !IsRectEmpty(rt) && !EqualRect(rt_conf, rt)) {
2644 NHMessageBox(HWND hWnd, LPCTSTR text, UINT type)
2646 TCHAR title[MAX_LOADSTRING];
2648 LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING);
2650 return MessageBox(hWnd, text, title, type);
2653 #ifdef STATUS_VIA_WINDOWPORT
2654 static const char *_status_fieldnm[MAXBLSTATS];
2655 static const char *_status_fieldfmt[MAXBLSTATS];
2656 static char *_status_vals[MAXBLSTATS];
2657 static int _status_colors[MAXBLSTATS];
2658 static boolean _status_activefields[MAXBLSTATS];
2659 extern winid WIN_STATUS;
2661 #ifdef STATUS_HILITES
2662 typedef struct hilite_data_struct {
2669 static hilite_data_t _status_hilites[MAXBLSTATS];
2670 #endif /* STATUS_HILITES */
2672 status_init() -- core calls this to notify the window port that a status
2673 display is required. The window port should perform
2674 the necessary initialization in here, allocate memory, etc.
2677 mswin_status_init(void)
2680 logDebug("mswin_status_init()\n");
2681 for (i = 0; i < MAXBLSTATS; ++i) {
2682 _status_vals[i] = (char *) alloc(BUFSZ);
2683 *_status_vals[i] = '\0';
2684 _status_activefields[i] = FALSE;
2685 _status_fieldfmt[i] = (const char *) 0;
2686 _status_colors[i] = CLR_MAX; /* no color */
2687 #ifdef STATUS_HILITES
2688 _status_hilites[i].thresholdtype = 0;
2689 _status_hilites[i].behavior = BL_TH_NONE;
2690 _status_hilites[i].under = BL_HILITE_NONE;
2691 _status_hilites[i].over = BL_HILITE_NONE;
2692 #endif /* STATUS_HILITES */
2694 /* Use a window for the genl version; backward port compatibility */
2695 WIN_STATUS = create_nhwindow(NHW_STATUS);
2696 display_nhwindow(WIN_STATUS, FALSE);
2700 status_finish() -- called when it is time for the window port to tear down
2701 the status display and free allocated memory, etc.
2704 mswin_status_finish(void)
2706 /* tear down routine */
2709 logDebug("mswin_status_finish()\n");
2711 /* free alloc'd memory here */
2712 for (i = 0; i < MAXBLSTATS; ++i) {
2713 if (_status_vals[i])
2714 free((genericptr_t) _status_vals[i]);
2715 _status_vals[i] = (char *) 0;
2720 status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable)
2721 -- notifies the window port which fields it is authorized to
2723 -- This may be called at any time, and is used
2724 to disable as well as enable fields, depending on the
2725 value of the final argument (TRUE = enable).
2726 -- fldindex could be one of the following from botl.h:
2727 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2728 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2729 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2730 BL_LEVELDESC, BL_EXP, BL_CONDITION
2731 -- There are MAXBLSTATS status fields (from botl.h)
2734 mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt,
2737 logDebug("mswin_status_enablefield(%d, %s, %s, %d)\n", fieldidx, nm, fmt,
2739 _status_fieldfmt[fieldidx] = fmt;
2740 _status_fieldnm[fieldidx] = nm;
2741 _status_activefields[fieldidx] = enable;
2744 #ifdef STATUS_HILITES
2746 status_threshold(int fldidx, int threshholdtype, anything threshold,
2747 int behavior, int under, int over)
2748 -- called when a hiliting preference is added, changed, or
2750 -- the fldindex identifies which field is having its hiliting
2751 preference set. It is an integer index value from botl.h
2752 -- fldindex could be any one of the following from botl.h:
2753 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2754 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2755 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2756 BL_LEVELDESC, BL_EXP, BL_CONDITION
2757 -- datatype is P_INT, P_UINT, P_LONG, or P_MASK.
2758 -- threshold is an "anything" union which can contain the
2760 -- behavior is used to define how threshold is used and can
2761 be BL_TH_NONE, BL_TH_VAL_PERCENTAGE, BL_TH_VAL_ABSOLUTE,
2762 or BL_TH_UPDOWN. BL_TH_NONE means don't do anything above
2763 or below the threshold. BL_TH_VAL_PERCENTAGE treats the
2764 threshold value as a precentage of the maximum possible
2765 value. BL_TH_VAL_ABSOLUTE means that the threshold is an
2766 actual value. BL_TH_UPDOWN means that threshold is not
2767 used, and the two below/above hilite values indicate how
2768 to display something going down (under) or rising (over).
2769 -- under is the hilite attribute used if value is below the
2770 threshold. The attribute can be BL_HILITE_NONE,
2771 BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one
2772 of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN,
2773 CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY,
2774 CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE,
2775 CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15).
2776 -- over is the hilite attribute used if value is at or above
2777 the threshold. The attribute can be BL_HILITE_NONE,
2778 BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one
2779 of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN,
2780 CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY,
2781 CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE,
2782 CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15).
2785 mswin_status_threshold(int fldidx, int thresholdtype, anything threshold,
2786 int behavior, int under, int over)
2788 logDebug("mswin_status_threshold(%d, %d, %d, %d, %d)\n", fldidx,
2789 thresholdtype, behavior, under, over);
2790 assert(fldidx >= 0 && fldidx < MAXBLSTATS);
2791 _status_hilites[fldidx].thresholdtype = thresholdtype;
2792 _status_hilites[fldidx].threshold = threshold;
2793 _status_hilites[fldidx].behavior = behavior;
2794 _status_hilites[fldidx].under = under;
2795 _status_hilites[fldidx].over = over;
2797 #endif /* STATUS_HILITES */
2801 status_update(int fldindex, genericptr_t ptr, int chg, int percentage)
2802 -- update the value of a status field.
2803 -- the fldindex identifies which field is changing and
2804 is an integer index value from botl.h
2805 -- fldindex could be any one of the following from botl.h:
2806 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2807 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2808 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2809 BL_LEVELDESC, BL_EXP, BL_CONDITION
2810 -- fldindex could also be BL_FLUSH (-1), which is not really
2811 a field index, but is a special trigger to tell the
2812 windowport that it should redisplay all its status fields,
2813 even if no changes have been presented to it.
2814 -- ptr is usually a "char *", unless fldindex is BL_CONDITION.
2815 If fldindex is BL_CONDITION, then ptr is a long value with
2816 any or none of the following bits set (from botl.h):
2817 BL_MASK_BLIND 0x00000001L
2818 BL_MASK_CONF 0x00000002L
2819 BL_MASK_FOODPOIS 0x00000004L
2820 BL_MASK_ILL 0x00000008L
2821 BL_MASK_HALLU 0x00000010L
2822 BL_MASK_STUNNED 0x00000020L
2823 BL_MASK_SLIMED 0x00000040L
2824 -- The value passed for BL_GOLD includes a leading
2825 symbol for GOLD "$:nnn". If the window port needs to use
2826 the textual gold amount without the leading "$:" the port
2827 will have to add 2 to the passed "ptr" for the BL_GOLD
2831 mswin_status_update(int idx, genericptr_t ptr, int chg, int percent)
2833 long cond, *condptr = (long *) ptr;
2834 char *text = (char *) ptr;
2835 MSNHMsgUpdateStatus update_cmd_data;
2840 logDebug("mswin_status_update(%d, %p, %d, %d)\n", idx, ptr, chg, percent);
2842 if (idx != BL_FLUSH) {
2843 if (!_status_activefields[idx])
2846 case BL_CONDITION: {
2848 *_status_vals[idx] = '\0';
2849 if (cond & BL_MASK_BLIND)
2850 Strcat(_status_vals[idx], " Blind");
2851 if (cond & BL_MASK_CONF)
2852 Strcat(_status_vals[idx], " Conf");
2853 if (cond & BL_MASK_FOODPOIS)
2854 Strcat(_status_vals[idx], " FoodPois");
2855 if (cond & BL_MASK_ILL)
2856 Strcat(_status_vals[idx], " Ill");
2857 if (cond & BL_MASK_STUNNED)
2858 Strcat(_status_vals[idx], " Stun");
2859 if (cond & BL_MASK_HALLU)
2860 Strcat(_status_vals[idx], " Hallu");
2861 if (cond & BL_MASK_SLIMED)
2862 Strcat(_status_vals[idx], " Slime");
2868 ZeroMemory(buf, sizeof(buf));
2869 mapglyph(objnum_to_glyph(GOLD_PIECE), &ochar, &ocolor, &ospecial,
2872 p = strchr(text, ':');
2874 strncpy(buf + 1, p, sizeof(buf) - 2);
2875 value = atol(p + 1);
2878 strncpy(buf + 2, text, sizeof(buf) - 2);
2881 Sprintf(_status_vals[idx],
2882 _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s",
2887 Sprintf(_status_vals[idx],
2888 _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s",
2894 #ifdef STATUS_HILITES
2895 switch (_status_hilites[idx].behavior) {
2897 _status_colors[idx] = CLR_MAX;
2900 case BL_TH_UPDOWN: {
2902 _status_colors[idx] = _status_hilites[idx].over;
2904 _status_colors[idx] = _status_hilites[idx].under;
2906 _status_colors[idx] = CLR_MAX;
2909 case BL_TH_VAL_PERCENTAGE: {
2911 if (_status_hilites[idx].thresholdtype != ANY_INT) {
2912 impossible("mswin_status_update: unsupported percentage "
2913 "threshold type %d",
2914 _status_hilites[idx].thresholdtype);
2917 pct_th = _status_hilites[idx].threshold.a_int;
2918 _status_colors[idx] = (percent >= pct_th)
2919 ? _status_hilites[idx].over
2920 : _status_hilites[idx].under;
2923 case BL_TH_VAL_ABSOLUTE: {
2925 int o = _status_hilites[idx].over;
2926 int u = _status_hilites[idx].under;
2927 anything *t = &_status_hilites[idx].threshold;
2928 switch (_status_hilites[idx].thresholdtype) {
2930 c = (value >= t->a_long) ? o : u;
2933 c = (value >= t->a_int) ? o : u;
2936 c = ((unsigned long) value >= t->a_uint) ? o : u;
2939 c = ((unsigned long) value >= t->a_ulong) ? o : u;
2942 c = (value & t->a_ulong) ? o : u;
2945 impossible("mswin_status_update: unsupported absolute threshold "
2947 _status_hilites[idx].thresholdtype);
2950 _status_colors[idx] = c;
2953 #endif /* STATUS_HILITES */
2955 /* send command to status window */
2956 ZeroMemory(&update_cmd_data, sizeof(update_cmd_data));
2957 update_cmd_data.n_fields = MAXBLSTATS;
2958 update_cmd_data.vals = _status_vals;
2959 update_cmd_data.activefields = _status_activefields;
2960 update_cmd_data.colors = _status_colors;
2961 SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND,
2962 (WPARAM) MSNH_MSG_UPDATE_STATUS, (LPARAM) &update_cmd_data);
2965 #endif /*STATUS_VIA_WINDOWPORT*/