1 /* NetHack 3.6 mswproc.c $NHDT-Date: 1451611595 2016/01/01 01:26:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* For 3.6-, Copyright (c) SHIRAKATA Kentaro, 2016 */
7 /* JNetHack may be freely redistributed. See license for details. */
10 * This file implements the interface between the window port specific
11 * code in the mswin port and the rest of the nethack game engine.
17 #include "func_tab.h" /* for extended commands */
38 #define NHTRACE_LOG "nhtrace.log"
42 static FILE* _s_debugfp = NULL;
43 extern void logDebug(const char *fmt, ...);
49 logDebug(const char *fmt, ...)
54 static void mswin_main_loop(void);
55 static BOOL initMapTiles(void);
56 static void mswin_color_from_string(char *colorstring, HBRUSH *brushptr,
58 static void prompt_for_player_selection(void);
60 #define TOTAL_BRUSHES 10
61 HBRUSH brush_table[TOTAL_BRUSHES];
64 HBRUSH menu_bg_brush = NULL;
65 HBRUSH menu_fg_brush = NULL;
66 HBRUSH text_bg_brush = NULL;
67 HBRUSH text_fg_brush = NULL;
68 HBRUSH status_bg_brush = NULL;
69 HBRUSH status_fg_brush = NULL;
70 HBRUSH message_bg_brush = NULL;
71 HBRUSH message_fg_brush = NULL;
73 COLORREF menu_bg_color = RGB(0, 0, 0);
74 COLORREF menu_fg_color = RGB(0xFF, 0xFF, 0xFF);
75 COLORREF text_bg_color = RGB(0, 0, 0);
76 COLORREF text_fg_color = RGB(0xFF, 0xFF, 0xFF);
77 COLORREF status_bg_color = RGB(0, 0, 0);
78 COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF);
79 COLORREF message_bg_color = RGB(0, 0, 0);
80 COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF);
82 strbuf_t raw_print_strbuf = { 0 };
84 /* Interface definition, for windows.c */
85 struct window_procs mswin_procs = {
87 WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE
88 | WC_SCROLL_AMOUNT | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE
89 | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONT_MAP
90 | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU
91 | WC_FONTSIZ_TEXT | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE
92 | WC_VARY_MSGCOUNT | WC_WINDOWCOLORS | WC_PLAYER_SELECTION
93 | WC_SPLASH_SCREEN | WC_POPUP_DIALOG | WC_MOUSE_SUPPORT,
95 WC2_HITPOINTBAR | WC2_FLUSH_STATUS | WC2_HILITE_STATUS |
97 0L, mswin_init_nhwindows, mswin_player_selection, mswin_askname,
98 mswin_get_nh_event, mswin_exit_nhwindows, mswin_suspend_nhwindows,
99 mswin_resume_nhwindows, mswin_create_nhwindow, mswin_clear_nhwindow,
100 mswin_display_nhwindow, mswin_destroy_nhwindow, mswin_curs, mswin_putstr,
101 genl_putmixed, mswin_display_file, mswin_start_menu, mswin_add_menu,
102 mswin_end_menu, mswin_select_menu,
103 genl_message_menu, /* no need for X-specific handling */
104 mswin_update_inventory, mswin_mark_synch, mswin_wait_synch,
111 mswin_print_glyph, mswin_raw_print, mswin_raw_print_bold, mswin_nhgetch,
112 mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function,
113 mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output,
114 #ifdef CHANGE_COLOR /* only a Mac option currently */
115 mswin, mswin_change_background,
117 /* other defs that really should go away (they're tty specific) */
118 mswin_start_screen, mswin_end_screen, mswin_outrip,
119 mswin_preference_update, mswin_getmsghistory, mswin_putmsghistory,
120 mswin_status_init, mswin_status_finish, mswin_status_enablefield,
122 genl_can_suspend_yes,
126 init_nhwindows(int* argcp, char** argv)
127 -- Initialize the windows used by NetHack. This can also
128 create the standard windows listed at the top, but does
130 -- Any commandline arguments relevant to the windowport
131 should be interpreted, and *argcp and *argv should
132 be changed to remove those arguments.
133 -- When the message window is created, the variable
134 iflags.window_inited needs to be set to TRUE. Otherwise
135 all plines() will be done via raw_print().
136 ** Why not have init_nhwindows() create all of the "standard"
137 ** windows? Or at least all but WIN_INFO? -dean
140 mswin_init_nhwindows(int *argc, char **argv)
142 UNREFERENCED_PARAMETER(argc);
143 UNREFERENCED_PARAMETER(argv);
147 if (showdebug(NHTRACE_LOG) && !_s_debugfp) {
148 /* truncate trace file */
149 _s_debugfp = fopen(NHTRACE_LOG, "w");
153 logDebug("mswin_init_nhwindows()\n");
155 mswin_nh_input_init();
157 /* set it to WIN_ERR so we can detect attempts to
158 use this ID before it is inialized */
161 /* Read Windows settings from the reqistry */
162 /* First set safe defaults */
163 GetNHApp()->regMainMinX = CW_USEDEFAULT;
165 /* Create the main window */
166 GetNHApp()->hMainWnd = mswin_init_main_window();
167 if (!GetNHApp()->hMainWnd) {
168 panic("Cannot create main window");
171 /* Set menu check mark for interface mode */
172 mswin_menu_check_intf_mode();
174 /* check default values */
175 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
176 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
177 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
179 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
180 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
181 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
183 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
184 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
185 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
187 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
188 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
189 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
191 if (iflags.wc_align_message == 0)
192 iflags.wc_align_message = ALIGN_TOP;
193 if (iflags.wc_align_status == 0)
194 iflags.wc_align_status = ALIGN_BOTTOM;
195 if (iflags.wc_scroll_margin == 0)
196 iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
197 if (iflags.wc_scroll_amount == 0)
198 iflags.wc_scroll_amount = DEF_CLIPAROUND_AMOUNT;
199 if (iflags.wc_tile_width == 0)
200 iflags.wc_tile_width = TILE_X;
201 if (iflags.wc_tile_height == 0)
202 iflags.wc_tile_height = TILE_Y;
204 if (iflags.wc_vary_msgcount == 0)
205 iflags.wc_vary_msgcount = 4;
207 /* force tabs in menus */
208 iflags.menu_tab_sep = 1;
210 /* force toptenwin to be true. toptenwin is the option that decides
212 * write output to a window or stdout. stdout doesn't make sense on
214 * non-console applications
216 iflags.toptenwin = 1;
217 set_option_mod_status("toptenwin", SET_IN_FILE);
218 //set_option_mod_status("perm_invent", SET_IN_FILE);
219 set_option_mod_status("mouse_support", SET_IN_GAME);
221 /* initialize map tiles bitmap */
224 /* set tile-related options to readonly */
225 set_wc_option_mod_status(WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE,
228 /* set font-related options to change in the game */
229 set_wc_option_mod_status(
230 WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_SCROLL_AMOUNT
231 | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE
232 | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT
233 | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU
234 | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT,
237 mswin_color_from_string(iflags.wc_foregrnd_menu, &menu_fg_brush,
239 mswin_color_from_string(iflags.wc_foregrnd_message, &message_fg_brush,
241 mswin_color_from_string(iflags.wc_foregrnd_status, &status_fg_brush,
243 mswin_color_from_string(iflags.wc_foregrnd_text, &text_fg_brush,
245 mswin_color_from_string(iflags.wc_backgrnd_menu, &menu_bg_brush,
247 mswin_color_from_string(iflags.wc_backgrnd_message, &message_bg_brush,
249 mswin_color_from_string(iflags.wc_backgrnd_status, &status_bg_brush,
251 mswin_color_from_string(iflags.wc_backgrnd_text, &text_bg_brush,
254 if (iflags.wc_splash_screen)
255 mswin_display_splash_window(FALSE);
257 iflags.window_inited = TRUE;
260 /* Do a window-port specific player type selection. If player_selection()
261 offers a Quit option, it is its responsibility to clean up and terminate
262 the process. You need to fill in pl_character[0].
265 mswin_player_selection(void)
267 logDebug("mswin_player_selection()\n");
269 if (iflags.wc_player_selection == VIA_DIALOG) {
270 /* pick player type randomly (use pre-selected
271 * role/race/gender/alignment) */
272 if (flags.randomall) {
273 if (flags.initrole < 0) {
274 flags.initrole = pick_role(flags.initrace, flags.initgend,
275 flags.initalign, PICK_RANDOM);
276 if (flags.initrole < 0) {
277 raw_print("Incompatible role!");
278 flags.initrole = randrole();
282 if (flags.initrace < 0
283 || !validrace(flags.initrole, flags.initrace)) {
284 flags.initrace = pick_race(flags.initrole, flags.initgend,
285 flags.initalign, PICK_RANDOM);
286 if (flags.initrace < 0) {
287 raw_print("Incompatible race!");
288 flags.initrace = randrace(flags.initrole);
292 if (flags.initgend < 0
293 || !validgend(flags.initrole, flags.initrace,
295 flags.initgend = pick_gend(flags.initrole, flags.initrace,
296 flags.initalign, PICK_RANDOM);
297 if (flags.initgend < 0) {
298 raw_print("Incompatible gender!");
299 flags.initgend = randgend(flags.initrole, flags.initrace);
303 if (flags.initalign < 0
304 || !validalign(flags.initrole, flags.initrace,
306 flags.initalign = pick_align(flags.initrole, flags.initrace,
307 flags.initgend, PICK_RANDOM);
308 if (flags.initalign < 0) {
309 raw_print("Incompatible alignment!");
311 randalign(flags.initrole, flags.initrace);
316 if (!mswin_player_selection_window()) {
320 } else { /* iflags.wc_player_selection == VIA_PROMPTS */
321 prompt_for_player_selection();
326 prompt_for_player_selection(void)
329 char pick4u = 'n', thisch, lastch = 0;
330 char pbuf[QBUFSZ], plbuf[QBUFSZ];
333 menu_item *selected = 0;
336 logDebug("prompt_for_player_selection()\n");
338 /* prevent an unnecessary prompt */
341 /* Should we randomly pick for the player? */
343 && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE
344 || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
346 char *prompt = build_plselection_prompt(
347 pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend,
350 /* tty_putstr(BASE_WINDOW, 0, ""); */
351 /* echoline = wins[BASE_WINDOW]->cury; */
352 box_result = NHMessageBox(NULL, prompt, MB_YESNOCANCEL | MB_DEFBUTTON1
355 (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033';
356 /* tty_putstr(BASE_WINDOW, 0, prompt); */
358 /* pick4u = lowc(readchar()); */
359 if (index(quitchars, pick4u))
361 } while (!index(ynqchars, pick4u));
362 if ((int) strlen(prompt) + 1 < CO) {
363 /* Echo choice and move back down line */
364 /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline,
366 /* tty_putstr(BASE_WINDOW, 0, ""); */
368 /* Otherwise it's hard to tell where to echo, and things are
369 * wrapping a bit messily anyway, so (try to) make sure the next
370 * question shows up well and doesn't get wrapped at the
371 * bottom of the window.
373 /* tty_clear_nhwindow(BASE_WINDOW) */;
375 if (pick4u != 'y' && pick4u != 'n') {
378 free((genericptr_t) selected);
385 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
386 flags.initrace, flags.initgend,
389 /* Select a role, if necessary */
390 /* we'll try to be compatible with pre-selected race/gender/alignment,
391 * but may not succeed */
392 if (flags.initrole < 0) {
393 char rolenamebuf[QBUFSZ];
394 /* Process the choice */
395 if (pick4u == 'y' || flags.initrole == ROLE_RANDOM
396 || flags.randomall) {
397 /* Pick a random role */
398 flags.initrole = pick_role(flags.initrace, flags.initgend,
399 flags.initalign, PICK_RANDOM);
400 if (flags.initrole < 0) {
401 /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
402 flags.initrole = randrole();
405 /* tty_clear_nhwindow(BASE_WINDOW); */
406 /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
407 /* Prompt for a role */
408 win = create_nhwindow(NHW_MENU);
410 any = zeroany; /* zero out all bits */
411 for (i = 0; roles[i].name.m; i++) {
412 if (ok_role(i, flags.initrace, flags.initgend,
414 any.a_int = i + 1; /* must be non-zero */
415 thisch = lowc(roles[i].name.m[0]);
416 if (thisch == lastch)
417 thisch = highc(thisch);
418 if (flags.initgend != ROLE_NONE
419 && flags.initgend != ROLE_RANDOM) {
420 if (flags.initgend == 1 && roles[i].name.f)
421 Strcpy(rolenamebuf, roles[i].name.f);
423 Strcpy(rolenamebuf, roles[i].name.m);
425 if (roles[i].name.f) {
426 Strcpy(rolenamebuf, roles[i].name.m);
427 Strcat(rolenamebuf, "/");
428 Strcat(rolenamebuf, roles[i].name.f);
430 Strcpy(rolenamebuf, roles[i].name.m);
432 add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE,
433 an(rolenamebuf), MENU_UNSELECTED);
437 any.a_int = pick_role(flags.initrace, flags.initgend,
438 flags.initalign, PICK_RANDOM) + 1;
439 if (any.a_int == 0) /* must be non-zero */
440 any.a_int = randrole() + 1;
441 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
443 any.a_int = i + 1; /* must be non-zero */
444 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
446 Sprintf(pbuf, "Pick a role for your %s", plbuf);
448 n = select_menu(win, PICK_ONE, &selected);
449 destroy_nhwindow(win);
451 /* Process the choice */
452 if (n != 1 || selected[0].item.a_int == any.a_int)
453 goto give_up; /* Selected quit */
455 flags.initrole = selected[0].item.a_int - 1;
456 free((genericptr_t) selected), selected = 0;
458 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
459 flags.initrace, flags.initgend,
463 /* Select a race, if necessary */
464 /* force compatibility with role, try for compatibility with
465 * pre-selected gender/alignment */
466 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
467 /* pre-selected race not valid */
468 if (pick4u == 'y' || flags.initrace == ROLE_RANDOM
469 || flags.randomall) {
470 flags.initrace = pick_race(flags.initrole, flags.initgend,
471 flags.initalign, PICK_RANDOM);
472 if (flags.initrace < 0) {
473 /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
474 flags.initrace = randrace(flags.initrole);
476 } else { /* pick4u == 'n' */
477 /* Count the number of valid races */
478 n = 0; /* number valid */
479 k = 0; /* valid race */
480 for (i = 0; races[i].noun; i++) {
481 if (ok_race(flags.initrole, i, flags.initgend,
488 for (i = 0; races[i].noun; i++) {
489 if (validrace(flags.initrole, i)) {
496 /* Permit the user to pick, if there is more than one */
498 /* tty_clear_nhwindow(BASE_WINDOW); */
499 /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
500 win = create_nhwindow(NHW_MENU);
502 any = zeroany; /* zero out all bits */
503 for (i = 0; races[i].noun; i++)
504 if (ok_race(flags.initrole, i, flags.initgend,
506 any.a_int = i + 1; /* must be non-zero */
507 add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0,
508 ATR_NONE, races[i].noun, MENU_UNSELECTED);
510 any.a_int = pick_race(flags.initrole, flags.initgend,
511 flags.initalign, PICK_RANDOM) + 1;
512 if (any.a_int == 0) /* must be non-zero */
513 any.a_int = randrace(flags.initrole) + 1;
514 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
516 any.a_int = i + 1; /* must be non-zero */
517 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
519 Sprintf(pbuf, "Pick the race of your %s", plbuf);
521 n = select_menu(win, PICK_ONE, &selected);
522 destroy_nhwindow(win);
523 if (n != 1 || selected[0].item.a_int == any.a_int)
524 goto give_up; /* Selected quit */
526 k = selected[0].item.a_int - 1;
527 free((genericptr_t) selected), selected = 0;
531 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
532 flags.initrace, flags.initgend,
536 /* Select a gender, if necessary */
537 /* force compatibility with role/race, try for compatibility with
538 * pre-selected alignment */
539 if (flags.initgend < 0
540 || !validgend(flags.initrole, flags.initrace, flags.initgend)) {
541 /* pre-selected gender not valid */
542 if (pick4u == 'y' || flags.initgend == ROLE_RANDOM
543 || flags.randomall) {
544 flags.initgend = pick_gend(flags.initrole, flags.initrace,
545 flags.initalign, PICK_RANDOM);
546 if (flags.initgend < 0) {
547 /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
548 flags.initgend = randgend(flags.initrole, flags.initrace);
550 } else { /* pick4u == 'n' */
551 /* Count the number of valid genders */
552 n = 0; /* number valid */
553 k = 0; /* valid gender */
554 for (i = 0; i < ROLE_GENDERS; i++) {
555 if (ok_gend(flags.initrole, flags.initrace, i,
562 for (i = 0; i < ROLE_GENDERS; i++) {
563 if (validgend(flags.initrole, flags.initrace, i)) {
570 /* Permit the user to pick, if there is more than one */
572 /* tty_clear_nhwindow(BASE_WINDOW); */
573 /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
574 win = create_nhwindow(NHW_MENU);
576 any = zeroany; /* zero out all bits */
577 for (i = 0; i < ROLE_GENDERS; i++)
578 if (ok_gend(flags.initrole, flags.initrace, i,
581 add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0,
582 ATR_NONE, genders[i].adj, MENU_UNSELECTED);
584 any.a_int = pick_gend(flags.initrole, flags.initrace,
585 flags.initalign, PICK_RANDOM) + 1;
586 if (any.a_int == 0) /* must be non-zero */
587 any.a_int = randgend(flags.initrole, flags.initrace) + 1;
588 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
590 any.a_int = i + 1; /* must be non-zero */
591 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
593 Sprintf(pbuf, "Pick the gender of your %s", plbuf);
595 n = select_menu(win, PICK_ONE, &selected);
596 destroy_nhwindow(win);
597 if (n != 1 || selected[0].item.a_int == any.a_int)
598 goto give_up; /* Selected quit */
600 k = selected[0].item.a_int - 1;
601 free((genericptr_t) selected), selected = 0;
605 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
606 flags.initrace, flags.initgend,
610 /* Select an alignment, if necessary */
611 /* force compatibility with role/race/gender */
612 if (flags.initalign < 0
613 || !validalign(flags.initrole, flags.initrace, flags.initalign)) {
614 /* pre-selected alignment not valid */
615 if (pick4u == 'y' || flags.initalign == ROLE_RANDOM
616 || flags.randomall) {
617 flags.initalign = pick_align(flags.initrole, flags.initrace,
618 flags.initgend, PICK_RANDOM);
619 if (flags.initalign < 0) {
620 /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
621 flags.initalign = randalign(flags.initrole, flags.initrace);
623 } else { /* pick4u == 'n' */
624 /* Count the number of valid alignments */
625 n = 0; /* number valid */
626 k = 0; /* valid alignment */
627 for (i = 0; i < ROLE_ALIGNS; i++) {
628 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
635 for (i = 0; i < ROLE_ALIGNS; i++) {
636 if (validalign(flags.initrole, flags.initrace, i)) {
643 /* Permit the user to pick, if there is more than one */
645 /* tty_clear_nhwindow(BASE_WINDOW); */
646 /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
647 win = create_nhwindow(NHW_MENU);
649 any = zeroany; /* zero out all bits */
650 for (i = 0; i < ROLE_ALIGNS; i++)
651 if (ok_align(flags.initrole, flags.initrace,
652 flags.initgend, i)) {
654 add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0,
655 ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
657 any.a_int = pick_align(flags.initrole, flags.initrace,
658 flags.initgend, PICK_RANDOM) + 1;
659 if (any.a_int == 0) /* must be non-zero */
660 any.a_int = randalign(flags.initrole, flags.initrace) + 1;
661 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
663 any.a_int = i + 1; /* must be non-zero */
664 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
666 Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
668 n = select_menu(win, PICK_ONE, &selected);
669 destroy_nhwindow(win);
670 if (n != 1 || selected[0].item.a_int == any.a_int)
671 goto give_up; /* Selected quit */
673 k = selected[0].item.a_int - 1;
674 free((genericptr_t) selected), selected = 0;
680 /* tty_display_nhwindow(BASE_WINDOW, FALSE); */
683 /* Ask the user for a player name. */
687 logDebug("mswin_askname()\n");
689 if (mswin_getlin_window("Who are you?", plname, PL_NSIZ) == IDCANCEL) {
695 /* Does window event processing (e.g. exposure events).
696 A noop for the tty and X window-ports.
699 mswin_get_nh_event(void)
703 logDebug("mswin_get_nh_event()\n");
705 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
706 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
707 TranslateMessage(&msg);
708 DispatchMessage(&msg);
714 /* Exits the window system. This should dismiss all windows,
715 except the "window" used for raw_print(). str is printed if possible.
718 mswin_exit_nhwindows(const char *str)
720 logDebug("mswin_exit_nhwindows(%s)\n", str);
722 /* Write Window settings to the registry */
727 /* Prepare the window to be suspended. */
729 mswin_suspend_nhwindows(const char *str)
731 logDebug("mswin_suspend_nhwindows(%s)\n", str);
736 /* Restore the windows after being suspended. */
738 mswin_resume_nhwindows()
740 logDebug("mswin_resume_nhwindows()\n");
745 /* Create a window of type "type" which can be
746 NHW_MESSAGE (top line)
747 NHW_STATUS (bottom lines)
748 NHW_MAP (main dungeon)
749 NHW_MENU (inventory or other "corner" windows)
750 NHW_TEXT (help/text, full screen paged window)
753 mswin_create_nhwindow(int type)
758 logDebug("mswin_create_nhwindow(%d)\n", type);
760 /* Return the next available winid
763 for (i = 1; i < MAXWINDOWS; i++)
764 if (GetNHApp()->windowlist[i].win == NULL
765 && !GetNHApp()->windowlist[i].dead)
768 panic("ERROR: No windows available...\n");
772 GetNHApp()->windowlist[i].win = mswin_init_map_window();
773 GetNHApp()->windowlist[i].type = type;
774 GetNHApp()->windowlist[i].dead = 0;
778 GetNHApp()->windowlist[i].win = mswin_init_message_window();
779 GetNHApp()->windowlist[i].type = type;
780 GetNHApp()->windowlist[i].dead = 0;
784 GetNHApp()->windowlist[i].win = mswin_init_status_window();
785 GetNHApp()->windowlist[i].type = type;
786 GetNHApp()->windowlist[i].dead = 0;
790 GetNHApp()->windowlist[i].win = NULL; // will create later
791 GetNHApp()->windowlist[i].type = type;
792 GetNHApp()->windowlist[i].dead = 1;
796 GetNHApp()->windowlist[i].win = mswin_init_text_window();
797 GetNHApp()->windowlist[i].type = type;
798 GetNHApp()->windowlist[i].dead = 0;
803 ZeroMemory(&data, sizeof(data));
805 SendMessage(GetNHApp()->hMainWnd, WM_MSNH_COMMAND,
806 (WPARAM) MSNH_MSG_ADDWND, (LPARAM) &data);
810 /* Clear the given window, when asked to. */
812 mswin_clear_nhwindow(winid wid)
814 logDebug("mswin_clear_nhwindow(%d)\n", wid);
816 if ((wid >= 0) && (wid < MAXWINDOWS)
817 && (GetNHApp()->windowlist[wid].win != NULL)) {
818 if (GetNHApp()->windowlist[wid].type == NHW_MAP) {
819 if (Is_rogue_level(&u.uz))
820 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP),
821 ROGUE_LEVEL_MAP_MODE);
823 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP),
827 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
828 (WPARAM) MSNH_MSG_CLEAR_WINDOW, (LPARAM) NULL);
832 /* -- Display the window on the screen. If there is data
833 pending for output in that window, it should be sent.
834 If blocking is TRUE, display_nhwindow() will not
835 return until the data has been displayed on the screen,
836 and acknowledged by the user where appropriate.
837 -- All calls are blocking in the tty window-port.
838 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
839 --more--, if necessary, in the tty window-port.
842 mswin_display_nhwindow(winid wid, BOOLEAN_P block)
844 logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block);
845 if (GetNHApp()->windowlist[wid].win != NULL) {
846 ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW);
847 mswin_layout_main_window(GetNHApp()->windowlist[wid].win);
848 if (GetNHApp()->windowlist[wid].type == NHW_MENU) {
850 mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win,
851 PICK_NONE, &p, TRUE);
853 if (GetNHApp()->windowlist[wid].type == NHW_TEXT) {
854 mswin_display_text_window(GetNHApp()->windowlist[wid].win);
856 if (GetNHApp()->windowlist[wid].type == NHW_RIP) {
857 mswin_display_RIP_window(GetNHApp()->windowlist[wid].win);
860 UpdateWindow(GetNHApp()->windowlist[wid].win);
862 if (GetNHApp()->windowlist[wid].type == NHW_MAP) {
863 (void) mswin_nhgetch();
867 SetFocus(GetNHApp()->hMainWnd);
872 mswin_hwnd_from_winid(winid wid)
874 if (wid >= 0 && wid < MAXWINDOWS) {
875 return GetNHApp()->windowlist[wid].win;
882 mswin_winid_from_handle(HWND hWnd)
886 for (i = 1; i < MAXWINDOWS; i++)
887 if (GetNHApp()->windowlist[i].win == hWnd)
893 mswin_winid_from_type(int type)
897 for (i = 1; i < MAXWINDOWS; i++)
898 if (GetNHApp()->windowlist[i].type == type)
904 mswin_window_mark_dead(winid wid)
906 if (wid >= 0 && wid < MAXWINDOWS) {
907 GetNHApp()->windowlist[wid].win = NULL;
908 GetNHApp()->windowlist[wid].dead = 1;
912 /* Destroy will dismiss the window if the window has not
913 * already been dismissed.
916 mswin_destroy_nhwindow(winid wid)
918 logDebug("mswin_destroy_nhwindow(%d)\n", wid);
920 if ((GetNHApp()->windowlist[wid].type == NHW_MAP)
921 || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE)
922 || (GetNHApp()->windowlist[wid].type == NHW_STATUS)) {
923 /* main windows is going to take care of those */
928 if (!GetNHApp()->windowlist[wid].dead
929 && GetNHApp()->windowlist[wid].win != NULL)
930 DestroyWindow(GetNHApp()->windowlist[wid].win);
931 GetNHApp()->windowlist[wid].win = NULL;
932 GetNHApp()->windowlist[wid].type = 0;
933 GetNHApp()->windowlist[wid].dead = 0;
937 /* Next output to window will start at (x,y), also moves
938 displayable cursor to (x,y). For backward compatibility,
939 1 <= x < cols, 0 <= y < rows, where cols and rows are
943 mswin_curs(winid wid, int x, int y)
945 logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y);
947 if ((wid >= 0) && (wid < MAXWINDOWS)
948 && (GetNHApp()->windowlist[wid].win != NULL)) {
952 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
953 (WPARAM) MSNH_MSG_CURSOR, (LPARAM) &data);
958 putstr(window, attr, str)
959 -- Print str on the window with the given attribute. Only
960 printable ASCII characters (040-0126) must be supported.
961 Multiple putstr()s are output on separate lines.
969 If a window-port does not support all of these, it may map
970 unsupported attributes to a supported one (e.g. map them
971 all to ATR_INVERSE). putstr() may compress spaces out of
972 str, break str, or truncate str, if necessary for the
973 display. Where putstr() breaks a line, it has to clear
975 -- putstr should be implemented such that if two putstr()s
976 are done consecutively the user will see the first and
977 then the second. In the tty port, pline() achieves this
978 by calling more() or displaying both on the same line.
981 mswin_putstr(winid wid, int attr, const char *text)
983 logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text);
985 mswin_putstr_ex(wid, attr, text, 0);
989 mswin_putstr_ex(winid wid, int attr, const char *text, int app)
991 if ((wid >= 0) && (wid < MAXWINDOWS)) {
992 if (GetNHApp()->windowlist[wid].win == NULL
993 && GetNHApp()->windowlist[wid].type == NHW_MENU) {
994 GetNHApp()->windowlist[wid].win =
995 mswin_init_menu_window(MENU_TYPE_TEXT);
996 GetNHApp()->windowlist[wid].dead = 0;
999 if (GetNHApp()->windowlist[wid].win != NULL) {
1001 ZeroMemory(&data, sizeof(data));
1005 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1006 (WPARAM) MSNH_MSG_PUTSTR, (LPARAM) &data);
1008 /* yield a bit so it gets done immediately */
1009 mswin_get_nh_event();
1011 // build text to display later in message box
1012 GetNHApp()->saved_text =
1013 realloc(GetNHApp()->saved_text,
1014 strlen(text) + strlen(GetNHApp()->saved_text) + 1);
1015 strcat(GetNHApp()->saved_text, text);
1019 /* Display the file named str. Complain about missing files
1020 iff complain is TRUE.
1023 mswin_display_file(const char *filename, BOOLEAN_P must_exist)
1028 logDebug("mswin_display_file(%s, %d)\n", filename, must_exist);
1030 f = dlb_fopen(filename, RDTMODE);
1034 _stprintf(message, TEXT("Warning! Could not find file: %s\n"),
1035 NH_A2W(filename, wbuf, sizeof(wbuf)));
1036 NHMessageBox(GetNHApp()->hMainWnd, message,
1037 MB_OK | MB_ICONEXCLAMATION);
1043 text = mswin_create_nhwindow(NHW_TEXT);
1045 while (dlb_fgets(line, LLEN, f)) {
1048 if (line[len - 1] == '\n')
1049 line[len - 1] = '\x0';
1050 mswin_putstr(text, ATR_NONE, line);
1052 (void) dlb_fclose(f);
1054 mswin_display_nhwindow(text, 1);
1055 mswin_destroy_nhwindow(text);
1059 /* Start using window as a menu. You must call start_menu()
1060 before add_menu(). After calling start_menu() you may not
1061 putstr() to the window. Only windows of type NHW_MENU may
1065 mswin_start_menu(winid wid)
1067 logDebug("mswin_start_menu(%d)\n", wid);
1068 if ((wid >= 0) && (wid < MAXWINDOWS)) {
1069 if (GetNHApp()->windowlist[wid].win == NULL
1070 && GetNHApp()->windowlist[wid].type == NHW_MENU) {
1071 GetNHApp()->windowlist[wid].win =
1072 mswin_init_menu_window(MENU_TYPE_MENU);
1073 GetNHApp()->windowlist[wid].dead = 0;
1076 if (GetNHApp()->windowlist[wid].win != NULL) {
1077 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1078 (WPARAM) MSNH_MSG_STARTMENU, (LPARAM) NULL);
1084 add_menu(windid window, int glyph, const anything identifier,
1085 char accelerator, char groupacc,
1086 int attr, char *str, boolean preselected)
1087 -- Add a text line str to the given menu window. If
1089 is 0, then the line cannot be selected (e.g. a title).
1090 Otherwise, identifier is the value returned if the line is
1091 selected. Accelerator is a keyboard key that can be used
1092 to select the line. If the accelerator of a selectable
1093 item is 0, the window system is free to select its own
1094 accelerator. It is up to the window-port to make the
1095 accelerator visible to the user (e.g. put "a - " in front
1096 of str). The value attr is the same as in putstr().
1097 Glyph is an optional glyph to accompany the line. If
1098 window port cannot or does not want to display it, this
1099 is OK. If there is no glyph applicable, then this
1100 value will be NO_GLYPH.
1101 -- All accelerators should be in the range [A-Za-z].
1102 -- It is expected that callers do not mix accelerator
1103 choices. Either all selectable items have an accelerator
1104 or let the window system pick them. Don't do both.
1105 -- Groupacc is a group accelerator. It may be any character
1106 outside of the standard accelerator (see above) or a
1107 number. If 0, the item is unaffected by any group
1108 accelerator. If this accelerator conflicts with
1109 the menu command (or their user defined alises), it loses.
1110 The menu commands and aliases take care not to interfere
1111 with the default object class symbols.
1112 -- If you want this choice to be preselected when the
1113 menu is displayed, set preselected to TRUE.
1116 mswin_add_menu(winid wid, int glyph, const ANY_P *identifier,
1117 CHAR_P accelerator, CHAR_P group_accel, int attr,
1118 const char *str, BOOLEAN_P presel)
1120 logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph,
1121 identifier, (char) accelerator, (char) group_accel, attr, str,
1123 if ((wid >= 0) && (wid < MAXWINDOWS)
1124 && (GetNHApp()->windowlist[wid].win != NULL)) {
1125 MSNHMsgAddMenu data;
1126 ZeroMemory(&data, sizeof(data));
1128 data.identifier = identifier;
1129 data.accelerator = accelerator;
1130 data.group_accel = group_accel;
1133 data.presel = presel;
1135 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1136 (WPARAM) MSNH_MSG_ADDMENU, (LPARAM) &data);
1141 end_menu(window, prompt)
1142 -- Stop adding entries to the menu and flushes the window
1143 to the screen (brings to front?). Prompt is a prompt
1144 to give the user. If prompt is NULL, no prompt will
1146 ** This probably shouldn't flush the window any more (if
1147 ** it ever did). That should be select_menu's job. -dean
1150 mswin_end_menu(winid wid, const char *prompt)
1152 logDebug("mswin_end_menu(%d, %s)\n", wid, prompt);
1153 if ((wid >= 0) && (wid < MAXWINDOWS)
1154 && (GetNHApp()->windowlist[wid].win != NULL)) {
1155 MSNHMsgEndMenu data;
1156 ZeroMemory(&data, sizeof(data));
1159 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1160 (WPARAM) MSNH_MSG_ENDMENU, (LPARAM) &data);
1165 int select_menu(windid window, int how, menu_item **selected)
1166 -- Return the number of items selected; 0 if none were chosen,
1167 -1 when explicitly cancelled. If items were selected, then
1168 selected is filled in with an allocated array of menu_item
1169 structures, one for each selected line. The caller must
1170 free this array when done with it. The "count" field
1171 of selected is a user supplied count. If the user did
1172 not supply a count, then the count field is filled with
1173 -1 (meaning all). A count of zero is equivalent to not
1174 being selected and should not be in the list. If no items
1175 were selected, then selected is NULL'ed out. How is the
1176 mode of the menu. Three valid values are PICK_NONE,
1177 PICK_ONE, and PICK_N, meaning: nothing is selectable,
1178 only one thing is selectable, and any number valid items
1179 may selected. If how is PICK_NONE, this function should
1180 never return anything but 0 or -1.
1181 -- You may call select_menu() on a window multiple times --
1182 the menu is saved until start_menu() or destroy_nhwindow()
1183 is called on the window.
1184 -- Note that NHW_MENU windows need not have select_menu()
1185 called for them. There is no way of knowing whether
1186 select_menu() will be called for the window at
1187 create_nhwindow() time.
1190 mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected)
1194 logDebug("mswin_select_menu(%d, %d)\n", wid, how);
1196 if ((wid >= 0) && (wid < MAXWINDOWS)
1197 && (GetNHApp()->windowlist[wid].win != NULL)) {
1198 ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW);
1199 nReturned = mswin_menu_window_select_menu(
1200 GetNHApp()->windowlist[wid].win, how, selected,
1201 !(flags.perm_invent && wid == WIN_INVEN
1202 && how == PICK_NONE) /* don't activate inventory window if
1203 perm_invent is on */
1210 -- Indicate to the window port that the inventory has been changed.
1211 -- Merely calls display_inventory() for window-ports that leave the
1212 window up, otherwise empty.
1215 mswin_update_inventory()
1217 logDebug("mswin_update_inventory()\n");
1218 if (flags.perm_invent && program_state.something_worth_saving
1219 && iflags.window_inited && WIN_INVEN != WIN_ERR)
1220 display_inventory(NULL, FALSE);
1224 mark_synch() -- Don't go beyond this point in I/O on any channel until
1225 all channels are caught up to here. Can be an empty call
1231 logDebug("mswin_mark_synch()\n");
1235 wait_synch() -- Wait until all pending output is complete (*flush*() for
1237 -- May also deal with exposure events etc. so that the
1238 display is OK when return from wait_synch().
1243 logDebug("mswin_wait_synch()\n");
1244 mswin_raw_print_flush();
1248 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
1249 screen if the playing area is larger than the screen.
1250 -- This function is only defined if CLIPPING is defined.
1253 mswin_cliparound(int x, int y)
1255 winid wid = WIN_MAP;
1257 logDebug("mswin_cliparound(%d, %d)\n", x, y);
1259 if ((wid >= 0) && (wid < MAXWINDOWS)
1260 && (GetNHApp()->windowlist[wid].win != NULL)) {
1261 MSNHMsgClipAround data;
1264 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1265 (WPARAM) MSNH_MSG_CLIPAROUND, (LPARAM) &data);
1270 print_glyph(window, x, y, glyph, bkglyph)
1271 -- Print the glyph at (x,y) on the given window. Glyphs are
1272 integers at the interface, mapped to whatever the window-
1273 port wants (symbol, font, color, attributes, ...there's
1274 a 1-1 map between glyphs and distinct things on the map).
1275 -- bkglyph is a background glyph for potential use by some
1276 graphical or tiled environments to allow the depiction
1277 to fall against a background consistent with the grid
1282 mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph)
1284 logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid, x, y, glyph, bkglyph);
1286 if ((wid >= 0) && (wid < MAXWINDOWS)
1287 && (GetNHApp()->windowlist[wid].win != NULL)) {
1288 MSNHMsgPrintGlyph data;
1290 ZeroMemory(&data, sizeof(data));
1294 data.bkglyph = bkglyph;
1295 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1296 (WPARAM) MSNH_MSG_PRINT_GLYPH, (LPARAM) &data);
1301 * mswin_raw_print_accumulate() accumulate the given text into
1305 mswin_raw_print_accumulate(const char * str, boolean bold)
1307 bold; // ignored for now
1309 if (raw_print_strbuf.str != NULL) strbuf_append(&raw_print_strbuf, "\n");
1310 strbuf_append(&raw_print_strbuf, str);
1314 * mswin_raw_print_flush() - display any text found in raw_print_strbuf in a
1315 * dialog box and clear raw_print_strbuf.
1318 mswin_raw_print_flush()
1320 if (raw_print_strbuf.str != NULL) {
1321 int wlen = strlen(raw_print_strbuf.str) + 1;
1322 TCHAR * wbuf = (TCHAR *) alloc(wlen * sizeof(TCHAR));
1324 NHMessageBox(GetNHApp()->hMainWnd,
1325 NH_A2W(raw_print_strbuf.str, wbuf, wlen),
1326 MB_ICONINFORMATION | MB_OK);
1329 strbuf_empty(&raw_print_strbuf);
1335 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
1336 the user sees str. raw_print() appends a newline to str.
1337 It need not recognize ASCII control characters. This is
1338 used during startup (before windowing system initialization
1339 -- maybe this means only error startup messages are raw),
1340 for error messages, and maybe other "msg" uses. E.g.
1341 updating status for micros (i.e, "saving").
1344 mswin_raw_print(const char *str)
1346 logDebug("mswin_raw_print(%s)\n", str);
1349 extern int redirect_stdout;
1350 if (!redirect_stdout)
1351 mswin_raw_print_accumulate(str, FALSE);
1353 fprintf(stdout, "%s", str);
1359 -- Like raw_print(), but prints in bold/standout (if
1363 mswin_raw_print_bold(const char *str)
1365 logDebug("mswin_raw_print_bold(%s)\n", str);
1367 extern int redirect_stdout;
1368 if (!redirect_stdout)
1369 mswin_raw_print_accumulate(str, TRUE);
1371 fprintf(stdout, "%s", str);
1376 int nhgetch() -- Returns a single character input from the user.
1377 -- In the tty window-port, nhgetch() assumes that tgetch()
1378 will be the routine the OS provides to read a character.
1379 Returned character _must_ be non-zero.
1387 logDebug("mswin_nhgetch()\n");
1389 while ((event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR)
1392 key = event->kbd.ch;
1397 int nh_poskey(int *x, int *y, int *mod)
1398 -- Returns a single character input from the user or a
1399 a positioning event (perhaps from a mouse). If the
1400 return value is non-zero, a character was typed, else,
1401 a position in the MAP window is returned in x, y and mod.
1404 CLICK_1 -- mouse click type 1
1405 CLICK_2 -- mouse click type 2
1407 The different click types can map to whatever the
1408 hardware supports. If no mouse is supported, this
1409 routine always returns a non-zero character.
1412 mswin_nh_poskey(int *x, int *y, int *mod)
1417 logDebug("mswin_nh_poskey()\n");
1419 while ((event = mswin_input_pop()) == NULL)
1422 if (event->type == NHEVENT_MOUSE) {
1423 if (iflags.wc_mouse_support) {
1424 *mod = event->ms.mod;
1430 key = event->kbd.ch;
1436 nhbell() -- Beep at user. [This will exist at least until sounds are
1437 redone, since sounds aren't attributable to windows
1443 logDebug("mswin_nhbell()\n");
1448 -- Display previous messages. Used by the ^P command.
1449 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1452 mswin_doprev_message()
1454 logDebug("mswin_doprev_message()\n");
1455 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL,
1456 MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
1461 char yn_function(const char *ques, const char *choices, char default)
1462 -- Print a prompt made up of ques, choices and default.
1463 Read a single character response that is contained in
1464 choices or default. If choices is NULL, all possible
1465 inputs are accepted and returned. This overrides
1466 everything else. The choices are expected to be in
1467 lower case. Entering ESC always maps to 'q', or 'n',
1468 in that order, if present in choices, otherwise it maps
1469 to default. Entering any other quit character (SPACE,
1470 RETURN, NEWLINE) maps to default.
1471 -- If the choices string contains ESC, then anything after
1472 it is an acceptable response, but the ESC and whatever
1473 follows is not included in the prompt.
1474 -- If the choices string contains a '#' then accept a count.
1475 Place this value in the global "yn_number" and return '#'.
1476 -- This uses the top line in the tty window-port, other
1477 ports might use a popup.
1480 mswin_yn_function(const char *question, const char *choices, CHAR_P def)
1483 char yn_esc_map = '\033';
1484 char message[BUFSZ];
1487 boolean digit_ok, allow_num;
1489 logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def);
1491 if (WIN_MESSAGE == WIN_ERR && choices == ynchars) {
1493 realloc(strdup(GetNHApp()->saved_text),
1494 strlen(question) + strlen(GetNHApp()->saved_text) + 1);
1496 strcat(text, question);
1498 NHMessageBox(NULL, NH_W2A(text, message, sizeof(message)),
1499 MB_ICONQUESTION | MB_YESNOCANCEL
1500 | ((def == 'y') ? MB_DEFBUTTON1
1501 : (def == 'n') ? MB_DEFBUTTON2
1504 GetNHApp()->saved_text = strdup("");
1505 return box_result == IDYES ? 'y' : box_result == IDNO ? 'n' : '\033';
1509 char *cb, choicebuf[QBUFSZ];
1511 allow_num = (index(choices, '#') != 0);
1513 Strcpy(choicebuf, choices);
1514 if ((cb = index(choicebuf, '\033')) != 0) {
1515 /* anything beyond <esc> is hidden */
1518 (void) strncpy(message, question, QBUFSZ - 1);
1519 message[QBUFSZ - 1] = '\0';
1520 sprintf(eos(message), " [%s]", choicebuf);
1522 sprintf(eos(message), " (%c)", def);
1523 Strcat(message, " ");
1524 /* escape maps to 'q' or 'n' or default, in that order */
1526 (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def));
1528 Strcpy(message, question);
1529 Strcat(message, " ");
1533 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1534 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1536 mswin_clear_nhwindow(WIN_MESSAGE);
1537 mswin_putstr(WIN_MESSAGE, ATR_BOLD, message);
1539 /* Only here if main window is not present */
1542 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1543 ch = mswin_nhgetch();
1544 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1548 break; /* If choices is NULL, all possible inputs are accepted and
1551 digit_ok = allow_num && digit(ch);
1553 if (index(choices, 'q'))
1555 else if (index(choices, 'n'))
1560 } else if (index(quitchars, ch)) {
1563 } else if (!index(choices, ch) && !digit_ok) {
1566 /* and try again... */
1567 } else if (ch == '#' || digit_ok) {
1568 char z, digit_string[2];
1571 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, ("#"), 1);
1573 digit_string[1] = '\0';
1575 digit_string[0] = ch;
1576 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1);
1581 do { /* loop until we get a non-digit */
1582 z = lowc(readchar());
1584 value = (10 * value) + (z - '0');
1586 break; /* overflow: try again */
1587 digit_string[0] = z;
1588 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1);
1590 } else if (z == 'y' || index(quitchars, z)) {
1592 value = -1; /* abort */
1593 z = '\n'; /* break */
1594 } else if (z == '\b') {
1600 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string,
1605 value = -1; /* abort */
1609 } while (z != '\n');
1612 else if (value == 0)
1613 ch = 'n'; /* 0 => "no" */
1614 else { /* remove number from top line, then try again */
1615 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -n_len);
1623 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1624 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1626 /* display selection in the message window */
1627 if (isprint((uchar) ch) && ch != '#') {
1630 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1);
1637 getlin(const char *ques, char *input)
1638 -- Prints ques as a prompt and reads a single line of text,
1639 up to a newline. The string entered is returned without the
1640 newline. ESC is used to cancel, in which case the string
1641 "\033\000" is returned.
1642 -- getlin() must call flush_screen(1) before doing anything.
1643 -- This uses the top line in the tty window-port, other
1644 ports might use a popup.
1647 mswin_getlin(const char *question, char *input)
1649 logDebug("mswin_getlin(%s, %p)\n", question, input);
1651 if (!iflags.wc_popup_dialog) {
1662 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1663 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1665 /* mswin_clear_nhwindow(WIN_MESSAGE); */
1666 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, question, 0);
1667 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, " ", 1);
1669 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, input, 0);
1670 len = strlen(input);
1675 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1678 c = mswin_nhgetch();
1681 strcpy(input, "\033");
1691 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, -len);
1695 #if 1 /*JP*//*2
\83o
\83C
\83g
\95¶
\8e\9a\82È
\82ç
\82à
\82¤1
\83o
\83C
\83g
\8fÁ
\82·*/
1696 if (len > 0 && is_kanji2(input, len))
1700 } else if (len>=(BUFSZ-1)) {
1701 PlaySound((LPCSTR)SND_ALIAS_SYSTEMEXCLAMATION, NULL, SND_ALIAS_ID|SND_ASYNC);
1704 #if 1 /*JP*//*2
\83o
\83C
\83g
\95¶
\8e\9a\82È
\82ç
\82»
\82Ì
\8fê
\82Å
\82à
\82¤1
\83o
\83C
\83g
\93Ç
\82Ý
\8d\9e\82Þ*/
1706 c = mswin_nhgetch();
1712 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, 1);
1716 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1718 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1719 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1721 if (mswin_getlin_window(question, input, BUFSZ) == IDCANCEL) {
1722 strcpy(input, "\033");
1728 int get_ext_cmd(void)
1729 -- Get an extended command in a window-port specific way.
1730 An index into extcmdlist[] is returned on a successful
1731 selection, -1 otherwise.
1737 logDebug("mswin_get_ext_cmd()\n");
1739 if (!iflags.wc_popup_dialog) {
1746 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1747 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1751 mswin_clear_nhwindow(WIN_MESSAGE);
1752 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, "#", 0);
1754 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1756 int oindex, com_index;
1757 c = mswin_nhgetch();
1765 for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++)
1766 if (!strcmpi(cmd, extcmdlist[i].ef_txt))
1769 if (extcmdlist[i].ef_txt == (char *) 0) {
1770 pline("%s: unknown extended command.", cmd);
1776 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd,
1777 -(int) strlen(cmd));
1785 /* Find a command with this prefix in extcmdlist */
1787 for (oindex = 0; extcmdlist[oindex].ef_txt != (char *) 0;
1789 if ((extcmdlist[oindex].flags & AUTOCOMPLETE)
1790 && !(!wizard && (extcmdlist[oindex].flags & WIZMODECMD))
1791 && !strncmpi(cmd, extcmdlist[oindex].ef_txt, len)) {
1792 if (com_index == -1) /* no matches yet */
1796 -2; /* two matches, don't complete */
1799 if (com_index >= 0) {
1800 Strcpy(cmd, extcmdlist[com_index].ef_txt);
1803 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, 1);
1807 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1809 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1810 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1813 if (mswin_ext_cmd_window(&ret) == IDCANCEL)
1822 -- Initialize the number pad to the given state.
1825 mswin_number_pad(int state)
1828 logDebug("mswin_number_pad(%d)\n", state);
1832 delay_output() -- Causes a visible delay of 50ms in the output.
1833 Conceptually, this is similar to wait_synch() followed
1834 by a nap(50ms), but allows asynchronous operation.
1837 mswin_delay_output()
1839 logDebug("mswin_delay_output()\n");
1844 mswin_change_color()
1846 logDebug("mswin_change_color()\n");
1850 mswin_get_color_string()
1852 logDebug("mswin_get_color_string()\n");
1857 start_screen() -- Only used on Unix tty ports, but must be declared for
1858 completeness. Sets up the tty to work in full-screen
1859 graphics mode. Look at win/tty/termcap.c for an
1860 example. If your window-port does not need this function
1861 just declare an empty function.
1864 mswin_start_screen()
1867 logDebug("mswin_start_screen()\n");
1871 end_screen() -- Only used on Unix tty ports, but must be declared for
1872 completeness. The complement of start_screen().
1878 logDebug("mswin_end_screen()\n");
1882 outrip(winid, int, when)
1883 -- The tombstone code. If you want the traditional code use
1884 genl_outrip for the value and check the #if in rip.c.
1886 #define STONE_LINE_LEN 16
1888 mswin_outrip(winid wid, int how, time_t when)
1893 logDebug("mswin_outrip(%d, %d, %ld)\n", wid, how, (long) when);
1894 if ((wid >= 0) && (wid < MAXWINDOWS)) {
1895 DestroyWindow(GetNHApp()->windowlist[wid].win);
1896 GetNHApp()->windowlist[wid].win = mswin_init_RIP_window();
1897 GetNHApp()->windowlist[wid].type = NHW_RIP;
1898 GetNHApp()->windowlist[wid].dead = 0;
1901 /* Put name on stone */
1902 Sprintf(buf, "%s", plname);
1903 buf[STONE_LINE_LEN] = 0;
1904 putstr(wid, 0, buf);
1906 /* Put $ on stone */
1907 Sprintf(buf, "%ld Au", done_money);
1908 buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
1909 putstr(wid, 0, buf);
1911 /* Put together death description */
1912 formatkiller(buf, sizeof buf, how, FALSE);
1914 /* Put death type on stone */
1915 putstr(wid, 0, buf);
1917 /* Put year on stone */
1918 year = yyyymmdd(when) / 10000L;
1919 Sprintf(buf, "%4ld", year);
1920 putstr(wid, 0, buf);
1921 mswin_finish_rip_text(wid);
1924 /* handle options updates here */
1926 mswin_preference_update(const char *pref)
1931 if (stricmp(pref, "font_menu") == 0
1932 || stricmp(pref, "font_size_menu") == 0) {
1933 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
1934 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
1935 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
1937 hdc = GetDC(GetNHApp()->hMainWnd);
1938 mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE);
1939 mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE);
1940 mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE);
1941 mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE);
1942 mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE);
1943 mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE);
1944 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1946 mswin_layout_main_window(NULL);
1950 if (stricmp(pref, "font_status") == 0
1951 || stricmp(pref, "font_size_status") == 0) {
1952 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
1953 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
1954 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
1956 hdc = GetDC(GetNHApp()->hMainWnd);
1957 mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE);
1958 mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE);
1959 mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE);
1960 mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE);
1961 mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE);
1962 mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE);
1963 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1965 for (i = 1; i < MAXWINDOWS; i++) {
1966 if (GetNHApp()->windowlist[i].type == NHW_STATUS
1967 && GetNHApp()->windowlist[i].win != NULL) {
1968 InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE);
1971 mswin_layout_main_window(NULL);
1975 if (stricmp(pref, "font_message") == 0
1976 || stricmp(pref, "font_size_message") == 0) {
1977 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
1978 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
1979 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
1981 hdc = GetDC(GetNHApp()->hMainWnd);
1982 mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE);
1983 mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE);
1984 mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE);
1985 mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE);
1986 mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE);
1987 mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE);
1988 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1990 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1991 mswin_layout_main_window(NULL);
1995 if (stricmp(pref, "font_text") == 0
1996 || stricmp(pref, "font_size_text") == 0) {
1997 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
1998 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
1999 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
2001 hdc = GetDC(GetNHApp()->hMainWnd);
2002 mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE);
2003 mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE);
2004 mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE);
2005 mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE);
2006 mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE);
2007 mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE);
2008 ReleaseDC(GetNHApp()->hMainWnd, hdc);
2010 mswin_layout_main_window(NULL);
2014 if (stricmp(pref, "scroll_amount") == 0) {
2015 mswin_cliparound(u.ux, u.uy);
2019 if (stricmp(pref, "scroll_margin") == 0) {
2020 mswin_cliparound(u.ux, u.uy);
2024 if (stricmp(pref, "map_mode") == 0) {
2025 mswin_select_map_mode(iflags.wc_map_mode);
2029 if (stricmp(pref, "hilite_pet") == 0) {
2030 InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE);
2034 if (stricmp(pref, "align_message") == 0
2035 || stricmp(pref, "align_status") == 0) {
2036 mswin_layout_main_window(NULL);
2040 if (stricmp(pref, "vary_msgcount") == 0) {
2041 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
2042 mswin_layout_main_window(NULL);
2046 if (stricmp(pref, "perm_invent") == 0) {
2047 mswin_update_inventory();
2052 #define TEXT_BUFFER_SIZE 4096
2054 mswin_getmsghistory(BOOLEAN_P init)
2056 static PMSNHMsgGetText text = 0;
2057 static char *next_message = 0;
2060 text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText)
2061 + TEXT_BUFFER_SIZE);
2064 - 1; /* make sure we always have 0 at the end of the buffer */
2066 ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
2067 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
2068 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
2070 next_message = text->buffer;
2073 if (!(next_message && next_message[0])) {
2078 char *retval = next_message;
2080 next_message = p = strchr(next_message, '\n');
2084 while (p >= retval && isspace((uchar) *p))
2085 *p-- = (char) 0; /* delete trailing whitespace */
2091 mswin_putmsghistory(const char *msg, BOOLEAN_P restoring)
2093 BOOL save_sound_opt;
2095 UNREFERENCED_PARAMETER(restoring);
2098 return; /* end of message history restore */
2099 save_sound_opt = GetNHApp()->bNoSounds;
2100 GetNHApp()->bNoSounds =
2101 TRUE; /* disable sounds while restoring message history */
2102 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, msg, 0);
2103 clear_nhwindow(WIN_MESSAGE); /* it is in fact end-of-turn indication so
2104 each message will print on the new line */
2105 GetNHApp()->bNoSounds = save_sound_opt; /* restore sounds option */
2113 while (!mswin_have_input() && GetMessage(&msg, NULL, 0, 0) != 0) {
2114 if (GetNHApp()->regNetHackMode
2115 || !TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable,
2117 TranslateMessage(&msg);
2118 DispatchMessage(&msg);
2123 /* clean up and quit */
2125 bail(const char *mesg)
2128 mswin_exit_nhwindows(mesg);
2129 nh_terminate(EXIT_SUCCESS);
2138 TCHAR wbuf[MAX_PATH];
2141 extern int total_tiles_used;
2143 /* no file - no tile */
2144 if (!(iflags.wc_tile_file && *iflags.wc_tile_file))
2148 hBmp = LoadImage(GetNHApp()->hApp,
2149 NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH),
2150 IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
2153 "Cannot load tiles from the file. Reverting back to default.");
2157 /* calculate tile dimensions */
2158 GetObject(hBmp, sizeof(BITMAP), (LPVOID) &bm);
2159 if (bm.bmWidth % iflags.wc_tile_width
2160 || bm.bmHeight % iflags.wc_tile_height) {
2162 raw_print("Tiles bitmap does not match tile_width and tile_height "
2163 "options. Reverting back to default.");
2167 tl_num = (bm.bmWidth / iflags.wc_tile_width)
2168 * (bm.bmHeight / iflags.wc_tile_height);
2169 if (tl_num < total_tiles_used) {
2171 raw_print("Number of tiles in the bitmap is less than required by "
2172 "the game. Reverting back to default.");
2176 /* set the tile information */
2177 if (GetNHApp()->bmpMapTiles != GetNHApp()->bmpTiles) {
2178 DeleteObject(GetNHApp()->bmpMapTiles);
2181 GetNHApp()->bmpMapTiles = hBmp;
2182 GetNHApp()->mapTile_X = iflags.wc_tile_width;
2183 GetNHApp()->mapTile_Y = iflags.wc_tile_height;
2184 GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width;
2186 map_size.cx = GetNHApp()->mapTile_X * COLNO;
2187 map_size.cy = GetNHApp()->mapTile_Y * ROWNO;
2188 mswin_map_stretch(mswin_hwnd_from_winid(WIN_MAP), &map_size, TRUE);
2193 mswin_popup_display(HWND hWnd, int *done_indicator)
2201 /* activate the menu window */
2202 GetNHApp()->hPopupWnd = hWnd;
2204 mswin_layout_main_window(hWnd);
2206 /* disable game windows */
2207 for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild;
2208 hChild = GetWindow(hChild, GW_HWNDNEXT)) {
2210 EnableWindow(hChild, FALSE);
2214 hMenu = GetMenu(GetNHApp()->hMainWnd);
2215 mi_count = GetMenuItemCount(hMenu);
2216 for (i = 0; i < mi_count; i++) {
2217 EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_GRAYED);
2219 DrawMenuBar(GetNHApp()->hMainWnd);
2221 /* bring menu window on top */
2222 SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
2223 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2226 /* go into message loop */
2227 while (IsWindow(hWnd) && (done_indicator == NULL || !*done_indicator)
2228 && GetMessage(&msg, NULL, 0, 0) != 0) {
2229 if (!IsDialogMessage(hWnd, &msg)) {
2230 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable,
2232 TranslateMessage(&msg);
2233 DispatchMessage(&msg);
2240 mswin_popup_destroy(HWND hWnd)
2247 /* enable game windows */
2248 for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild;
2249 hChild = GetWindow(hChild, GW_HWNDNEXT)) {
2250 if (hChild != hWnd) {
2251 EnableWindow(hChild, TRUE);
2256 hMenu = GetMenu(GetNHApp()->hMainWnd);
2257 mi_count = GetMenuItemCount(hMenu);
2258 for (i = 0; i < mi_count; i++) {
2259 EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_ENABLED);
2261 DrawMenuBar(GetNHApp()->hMainWnd);
2263 /* Don't hide the permanent inventory window ... leave it showing */
2264 if (!flags.perm_invent || mswin_winid_from_handle(hWnd) != WIN_INVEN)
2265 ShowWindow(hWnd, SW_HIDE);
2267 GetNHApp()->hPopupWnd = NULL;
2269 mswin_layout_main_window(hWnd);
2271 SetFocus(GetNHApp()->hMainWnd);
2279 logDebug(const char *fmt, ...)
2283 if (!showdebug(NHTRACE_LOG) || !_s_debugfp)
2286 va_start(args, fmt);
2287 vfprintf(_s_debugfp, fmt, args);
2294 /* Reading and writing settings from the registry. */
2295 #define CATEGORYKEY "Software"
2296 #define COMPANYKEY "NetHack"
2297 #define PRODUCTKEY "NetHack 3.6.1"
2298 #define SETTINGSKEY "Settings"
2299 #define MAINSHOWSTATEKEY "MainShowState"
2300 #define MAINMINXKEY "MainMinX"
2301 #define MAINMINYKEY "MainMinY"
2302 #define MAINMAXXKEY "MainMaxX"
2303 #define MAINMAXYKEY "MainMaxY"
2304 #define MAINLEFTKEY "MainLeft"
2305 #define MAINRIGHTKEY "MainRight"
2306 #define MAINTOPKEY "MainTop"
2307 #define MAINBOTTOMKEY "MainBottom"
2308 #define MAINAUTOLAYOUT "AutoLayout"
2309 #define MAPLEFT "MapLeft"
2310 #define MAPRIGHT "MapRight"
2311 #define MAPTOP "MapTop"
2312 #define MAPBOTTOM "MapBottom"
2313 #define MSGLEFT "MsgLeft"
2314 #define MSGRIGHT "MsgRight"
2315 #define MSGTOP "MsgTop"
2316 #define MSGBOTTOM "MsgBottom"
2317 #define STATUSLEFT "StatusLeft"
2318 #define STATUSRIGHT "StatusRight"
2319 #define STATUSTOP "StatusTop"
2320 #define STATUSBOTTOM "StatusBottom"
2321 #define MENULEFT "MenuLeft"
2322 #define MENURIGHT "MenuRight"
2323 #define MENUTOP "MenuTop"
2324 #define MENUBOTTOM "MenuBottom"
2325 #define TEXTLEFT "TextLeft"
2326 #define TEXTRIGHT "TextRight"
2327 #define TEXTTOP "TextTop"
2328 #define TEXTBOTTOM "TextBottom"
2329 #define INVENTLEFT "InventLeft"
2330 #define INVENTRIGHT "InventRight"
2331 #define INVENTTOP "InventTop"
2332 #define INVENTBOTTOM "InventBottom"
2334 /* #define all the subkeys here */
2335 #define INTFKEY "Interface"
2343 char keystring[MAX_PATH];
2345 COLORREF default_mapcolors[CLR_MAX] = {
2346 RGB(0x55, 0x55, 0x55), /* CLR_BLACK */
2347 RGB(0xFF, 0x00, 0x00), /* CLR_RED */
2348 RGB(0x00, 0x80, 0x00), /* CLR_GREEN */
2349 RGB(0xA5, 0x2A, 0x2A), /* CLR_BROWN */
2350 RGB(0x00, 0x00, 0xFF), /* CLR_BLUE */
2351 RGB(0xFF, 0x00, 0xFF), /* CLR_MAGENTA */
2352 RGB(0x00, 0xFF, 0xFF), /* CLR_CYAN */
2353 RGB(0xC0, 0xC0, 0xC0), /* CLR_GRAY */
2354 RGB(0xFF, 0xFF, 0xFF), /* NO_COLOR */
2355 RGB(0xFF, 0xA5, 0x00), /* CLR_ORANGE */
2356 RGB(0x00, 0xFF, 0x00), /* CLR_BRIGHT_GREEN */
2357 RGB(0xFF, 0xFF, 0x00), /* CLR_YELLOW */
2358 RGB(0x00, 0xC0, 0xFF), /* CLR_BRIGHT_BLUE */
2359 RGB(0xFF, 0x80, 0xFF), /* CLR_BRIGHT_MAGENTA */
2360 RGB(0x80, 0xFF, 0xFF), /* CLR_BRIGHT_CYAN */
2361 RGB(0xFF, 0xFF, 0xFF) /* CLR_WHITE */
2364 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY,
2367 /* Set the defaults here. The very first time the app is started, nothing
2369 read from the registry, so these defaults apply. */
2370 GetNHApp()->saveRegistrySettings = 1; /* Normally, we always save */
2371 GetNHApp()->regNetHackMode = TRUE;
2373 for (i = 0; i < CLR_MAX; i++)
2374 GetNHApp()->regMapColors[i] = default_mapcolors[i];
2376 if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key)
2380 size = sizeof(DWORD);
2382 #define NHGETREG_DWORD(name, val) \
2383 RegQueryValueEx(key, (name), 0, NULL, (unsigned char *)(&safe_buf), \
2387 /* read the keys here */
2388 NHGETREG_DWORD(INTFKEY, GetNHApp()->regNetHackMode);
2390 /* read window placement */
2391 NHGETREG_DWORD(MAINSHOWSTATEKEY, GetNHApp()->regMainShowState);
2392 NHGETREG_DWORD(MAINMINXKEY, GetNHApp()->regMainMinX);
2393 NHGETREG_DWORD(MAINMINYKEY, GetNHApp()->regMainMinY);
2394 NHGETREG_DWORD(MAINMAXXKEY, GetNHApp()->regMainMaxX);
2395 NHGETREG_DWORD(MAINMAXYKEY, GetNHApp()->regMainMaxY);
2396 NHGETREG_DWORD(MAINLEFTKEY, GetNHApp()->regMainLeft);
2397 NHGETREG_DWORD(MAINRIGHTKEY, GetNHApp()->regMainRight);
2398 NHGETREG_DWORD(MAINTOPKEY, GetNHApp()->regMainTop);
2399 NHGETREG_DWORD(MAINBOTTOMKEY, GetNHApp()->regMainBottom);
2401 NHGETREG_DWORD(MAINAUTOLAYOUT, GetNHApp()->bAutoLayout);
2402 NHGETREG_DWORD(MAPLEFT, GetNHApp()->rtMapWindow.left);
2403 NHGETREG_DWORD(MAPRIGHT, GetNHApp()->rtMapWindow.right);
2404 NHGETREG_DWORD(MAPTOP, GetNHApp()->rtMapWindow.top);
2405 NHGETREG_DWORD(MAPBOTTOM, GetNHApp()->rtMapWindow.bottom);
2406 NHGETREG_DWORD(MSGLEFT, GetNHApp()->rtMsgWindow.left);
2407 NHGETREG_DWORD(MSGRIGHT, GetNHApp()->rtMsgWindow.right);
2408 NHGETREG_DWORD(MSGTOP, GetNHApp()->rtMsgWindow.top);
2409 NHGETREG_DWORD(MSGBOTTOM, GetNHApp()->rtMsgWindow.bottom);
2410 NHGETREG_DWORD(STATUSLEFT, GetNHApp()->rtStatusWindow.left);
2411 NHGETREG_DWORD(STATUSRIGHT, GetNHApp()->rtStatusWindow.right);
2412 NHGETREG_DWORD(STATUSTOP, GetNHApp()->rtStatusWindow.top);
2413 NHGETREG_DWORD(STATUSBOTTOM, GetNHApp()->rtStatusWindow.bottom);
2414 NHGETREG_DWORD(MENULEFT, GetNHApp()->rtMenuWindow.left);
2415 NHGETREG_DWORD(MENURIGHT, GetNHApp()->rtMenuWindow.right);
2416 NHGETREG_DWORD(MENUTOP, GetNHApp()->rtMenuWindow.top);
2417 NHGETREG_DWORD(MENUBOTTOM, GetNHApp()->rtMenuWindow.bottom);
2418 NHGETREG_DWORD(TEXTLEFT, GetNHApp()->rtTextWindow.left);
2419 NHGETREG_DWORD(TEXTRIGHT, GetNHApp()->rtTextWindow.right);
2420 NHGETREG_DWORD(TEXTTOP, GetNHApp()->rtTextWindow.top);
2421 NHGETREG_DWORD(TEXTBOTTOM, GetNHApp()->rtTextWindow.bottom);
2422 NHGETREG_DWORD(INVENTLEFT, GetNHApp()->rtInvenWindow.left);
2423 NHGETREG_DWORD(INVENTRIGHT, GetNHApp()->rtInvenWindow.right);
2424 NHGETREG_DWORD(INVENTTOP, GetNHApp()->rtInvenWindow.top);
2425 NHGETREG_DWORD(INVENTBOTTOM, GetNHApp()->rtInvenWindow.bottom);
2426 #undef NHGETREG_DWORD
2428 for (i = 0; i < CLR_MAX; i++) {
2430 char mapcolorkey[64];
2431 sprintf(mapcolorkey, "MapColor%02d", i);
2432 if (RegQueryValueEx(key, mapcolorkey, NULL, NULL, (BYTE *)&cl, &size) == ERROR_SUCCESS)
2433 GetNHApp()->regMapColors[i] = cl;
2438 /* check the data for validity */
2439 if (IsRectEmpty(&GetNHApp()->rtMapWindow)
2440 || IsRectEmpty(&GetNHApp()->rtMsgWindow)
2441 || IsRectEmpty(&GetNHApp()->rtStatusWindow)
2442 || IsRectEmpty(&GetNHApp()->rtMenuWindow)
2443 || IsRectEmpty(&GetNHApp()->rtTextWindow)
2444 || IsRectEmpty(&GetNHApp()->rtInvenWindow)) {
2445 GetNHApp()->bAutoLayout = TRUE;
2456 if (GetNHApp()->saveRegistrySettings) {
2457 char keystring[MAX_PATH];
2460 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY,
2461 PRODUCTKEY, SETTINGSKEY);
2463 if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key)
2465 RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "",
2466 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2467 &key, &disposition);
2470 #define NHSETREG_DWORD(name, val) \
2471 RegSetValueEx(key, (name), 0, REG_DWORD, \
2472 (unsigned char *)((safe_buf = (val)), &safe_buf), \
2475 /* Write the keys here */
2476 NHSETREG_DWORD(INTFKEY, GetNHApp()->regNetHackMode);
2478 /* Main window placement */
2479 NHSETREG_DWORD(MAINSHOWSTATEKEY, GetNHApp()->regMainShowState);
2480 NHSETREG_DWORD(MAINMINXKEY, GetNHApp()->regMainMinX);
2481 NHSETREG_DWORD(MAINMINYKEY, GetNHApp()->regMainMinY);
2482 NHSETREG_DWORD(MAINMAXXKEY, GetNHApp()->regMainMaxX);
2483 NHSETREG_DWORD(MAINMAXYKEY, GetNHApp()->regMainMaxY);
2484 NHSETREG_DWORD(MAINLEFTKEY, GetNHApp()->regMainLeft);
2485 NHSETREG_DWORD(MAINRIGHTKEY, GetNHApp()->regMainRight);
2486 NHSETREG_DWORD(MAINTOPKEY, GetNHApp()->regMainTop);
2487 NHSETREG_DWORD(MAINBOTTOMKEY, GetNHApp()->regMainBottom);
2489 NHSETREG_DWORD(MAINAUTOLAYOUT, GetNHApp()->bAutoLayout);
2490 NHSETREG_DWORD(MAPLEFT, GetNHApp()->rtMapWindow.left);
2491 NHSETREG_DWORD(MAPRIGHT, GetNHApp()->rtMapWindow.right);
2492 NHSETREG_DWORD(MAPTOP, GetNHApp()->rtMapWindow.top);
2493 NHSETREG_DWORD(MAPBOTTOM, GetNHApp()->rtMapWindow.bottom);
2494 NHSETREG_DWORD(MSGLEFT, GetNHApp()->rtMsgWindow.left);
2495 NHSETREG_DWORD(MSGRIGHT, GetNHApp()->rtMsgWindow.right);
2496 NHSETREG_DWORD(MSGTOP, GetNHApp()->rtMsgWindow.top);
2497 NHSETREG_DWORD(MSGBOTTOM, GetNHApp()->rtMsgWindow.bottom);
2498 NHSETREG_DWORD(STATUSLEFT, GetNHApp()->rtStatusWindow.left);
2499 NHSETREG_DWORD(STATUSRIGHT, GetNHApp()->rtStatusWindow.right);
2500 NHSETREG_DWORD(STATUSTOP, GetNHApp()->rtStatusWindow.top);
2501 NHSETREG_DWORD(STATUSBOTTOM, GetNHApp()->rtStatusWindow.bottom);
2502 NHSETREG_DWORD(MENULEFT, GetNHApp()->rtMenuWindow.left);
2503 NHSETREG_DWORD(MENURIGHT, GetNHApp()->rtMenuWindow.right);
2504 NHSETREG_DWORD(MENUTOP, GetNHApp()->rtMenuWindow.top);
2505 NHSETREG_DWORD(MENUBOTTOM, GetNHApp()->rtMenuWindow.bottom);
2506 NHSETREG_DWORD(TEXTLEFT, GetNHApp()->rtTextWindow.left);
2507 NHSETREG_DWORD(TEXTRIGHT, GetNHApp()->rtTextWindow.right);
2508 NHSETREG_DWORD(TEXTTOP, GetNHApp()->rtTextWindow.top);
2509 NHSETREG_DWORD(TEXTBOTTOM, GetNHApp()->rtTextWindow.bottom);
2510 NHSETREG_DWORD(INVENTLEFT, GetNHApp()->rtInvenWindow.left);
2511 NHSETREG_DWORD(INVENTRIGHT, GetNHApp()->rtInvenWindow.right);
2512 NHSETREG_DWORD(INVENTTOP, GetNHApp()->rtInvenWindow.top);
2513 NHSETREG_DWORD(INVENTBOTTOM, GetNHApp()->rtInvenWindow.bottom);
2514 #undef NHSETREG_DWORD
2516 for (i = 0; i < CLR_MAX; i++) {
2517 COLORREF cl = GetNHApp()->regMapColors[i];
2518 char mapcolorkey[64];
2519 sprintf(mapcolorkey, "MapColor%02d", i);
2520 RegSetValueEx(key, mapcolorkey, 0, REG_DWORD, (BYTE *)&cl, sizeof(DWORD));
2530 char keystring[MAX_PATH];
2534 /* Delete keys one by one, as NT does not delete trees */
2535 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY,
2537 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2538 sprintf(keystring, "%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY);
2539 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2540 /* The company key will also contain information about newer versions
2541 of nethack (e.g. a subkey called NetHack 4.0), so only delete that
2542 if it's empty now. */
2543 sprintf(keystring, "%s\\%s", CATEGORYKEY, COMPANYKEY);
2544 /* If we cannot open it, we probably cannot delete it either... Just
2545 go on and see what happens. */
2546 RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key);
2548 RegQueryInfoKey(key, NULL, NULL, NULL, &nrsubkeys, NULL, NULL, NULL, NULL,
2552 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2554 /* Prevent saving on exit */
2555 GetNHApp()->saveRegistrySettings = 0;
2558 typedef struct ctv {
2559 const char *colorstring;
2560 COLORREF colorvalue;
2561 } color_table_value;
2564 * The color list here is a combination of:
2565 * NetHack colors. (See mhmap.c)
2566 * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 )
2569 static color_table_value color_table[] = {
2570 /* NetHack colors */
2571 { "black", RGB(0x55, 0x55, 0x55) },
2572 { "red", RGB(0xFF, 0x00, 0x00) },
2573 { "green", RGB(0x00, 0x80, 0x00) },
2574 { "brown", RGB(0xA5, 0x2A, 0x2A) },
2575 { "blue", RGB(0x00, 0x00, 0xFF) },
2576 { "magenta", RGB(0xFF, 0x00, 0xFF) },
2577 { "cyan", RGB(0x00, 0xFF, 0xFF) },
2578 { "orange", RGB(0xFF, 0xA5, 0x00) },
2579 { "brightgreen", RGB(0x00, 0xFF, 0x00) },
2580 { "yellow", RGB(0xFF, 0xFF, 0x00) },
2581 { "brightblue", RGB(0x00, 0xC0, 0xFF) },
2582 { "brightmagenta", RGB(0xFF, 0x80, 0xFF) },
2583 { "brightcyan", RGB(0x80, 0xFF, 0xFF) },
2584 { "white", RGB(0xFF, 0xFF, 0xFF) },
2585 /* Remaining HTML colors */
2586 { "trueblack", RGB(0x00, 0x00, 0x00) },
2587 { "gray", RGB(0x80, 0x80, 0x80) },
2588 { "grey", RGB(0x80, 0x80, 0x80) },
2589 { "purple", RGB(0x80, 0x00, 0x80) },
2590 { "silver", RGB(0xC0, 0xC0, 0xC0) },
2591 { "maroon", RGB(0x80, 0x00, 0x00) },
2592 { "fuchsia", RGB(0xFF, 0x00, 0xFF) }, /* = NetHack magenta */
2593 { "lime", RGB(0x00, 0xFF, 0x00) }, /* = NetHack bright green */
2594 { "olive", RGB(0x80, 0x80, 0x00) },
2595 { "navy", RGB(0x00, 0x00, 0x80) },
2596 { "teal", RGB(0x00, 0x80, 0x80) },
2597 { "aqua", RGB(0x00, 0xFF, 0xFF) }, /* = NetHack cyan */
2598 { "", RGB(0x00, 0x00, 0x00) },
2601 typedef struct ctbv {
2604 } color_table_brush_value;
2606 static color_table_brush_value color_table_brush[] = {
2607 { "activeborder", COLOR_ACTIVEBORDER },
2608 { "activecaption", COLOR_ACTIVECAPTION },
2609 { "appworkspace", COLOR_APPWORKSPACE },
2610 { "background", COLOR_BACKGROUND },
2611 { "btnface", COLOR_BTNFACE },
2612 { "btnshadow", COLOR_BTNSHADOW },
2613 { "btntext", COLOR_BTNTEXT },
2614 { "captiontext", COLOR_CAPTIONTEXT },
2615 { "graytext", COLOR_GRAYTEXT },
2616 { "greytext", COLOR_GRAYTEXT },
2617 { "highlight", COLOR_HIGHLIGHT },
2618 { "highlighttext", COLOR_HIGHLIGHTTEXT },
2619 { "inactiveborder", COLOR_INACTIVEBORDER },
2620 { "inactivecaption", COLOR_INACTIVECAPTION },
2621 { "menu", COLOR_MENU },
2622 { "menutext", COLOR_MENUTEXT },
2623 { "scrollbar", COLOR_SCROLLBAR },
2624 { "window", COLOR_WINDOW },
2625 { "windowframe", COLOR_WINDOWFRAME },
2626 { "windowtext", COLOR_WINDOWTEXT },
2631 mswin_color_from_string(char *colorstring, HBRUSH *brushptr,
2634 color_table_value *ctv_ptr = color_table;
2635 color_table_brush_value *ctbv_ptr = color_table_brush;
2636 int red_value, blue_value, green_value;
2637 static char *hexadecimals = "0123456789abcdef";
2639 if (colorstring == NULL)
2641 if (*colorstring == '#') {
2642 if (strlen(++colorstring) != 6)
2645 red_value = (int) (index(hexadecimals, tolower((uchar) *colorstring))
2649 red_value += (int) (index(hexadecimals, tolower((uchar) *colorstring))
2653 green_value = (int) (index(hexadecimals,
2654 tolower((uchar) *colorstring))
2658 green_value += (int) (index(hexadecimals,
2659 tolower((uchar) *colorstring))
2663 blue_value = (int) (index(hexadecimals, tolower((uchar) *colorstring))
2667 blue_value += (int) (index(hexadecimals,
2668 tolower((uchar) *colorstring))
2672 *colorptr = RGB(red_value, green_value, blue_value);
2674 while (*ctv_ptr->colorstring
2675 && stricmp(ctv_ptr->colorstring, colorstring))
2677 if (*ctv_ptr->colorstring) {
2678 *colorptr = ctv_ptr->colorvalue;
2680 while (*ctbv_ptr->colorstring
2681 && stricmp(ctbv_ptr->colorstring, colorstring))
2683 if (*ctbv_ptr->colorstring) {
2684 *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue);
2685 *colorptr = GetSysColor(ctbv_ptr->syscolorvalue);
2689 if (max_brush > TOTAL_BRUSHES)
2690 panic("Too many colors!");
2691 *brushptr = CreateSolidBrush(*colorptr);
2692 brush_table[max_brush++] = *brushptr;
2696 mswin_get_window_placement(int type, LPRECT rt)
2700 *rt = GetNHApp()->rtMapWindow;
2704 *rt = GetNHApp()->rtMsgWindow;
2708 *rt = GetNHApp()->rtStatusWindow;
2712 *rt = GetNHApp()->rtMenuWindow;
2716 *rt = GetNHApp()->rtTextWindow;
2720 *rt = GetNHApp()->rtInvenWindow;
2724 SetRect(rt, 0, 0, 0, 0);
2730 mswin_update_window_placement(int type, LPRECT rt)
2732 LPRECT rt_conf = NULL;
2736 rt_conf = &GetNHApp()->rtMapWindow;
2740 rt_conf = &GetNHApp()->rtMsgWindow;
2744 rt_conf = &GetNHApp()->rtStatusWindow;
2748 rt_conf = &GetNHApp()->rtMenuWindow;
2752 rt_conf = &GetNHApp()->rtTextWindow;
2756 rt_conf = &GetNHApp()->rtInvenWindow;
2760 if (rt_conf && !IsRectEmpty(rt) && !EqualRect(rt_conf, rt)) {
2766 NHMessageBox(HWND hWnd, LPCTSTR text, UINT type)
2768 TCHAR title[MAX_LOADSTRING];
2770 LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING);
2772 return MessageBox(hWnd, text, title, type);
2775 static const char *_status_fieldnm[MAXBLSTATS];
2776 static const char *_status_fieldfmt[MAXBLSTATS];
2777 static char *_status_vals[MAXBLSTATS];
2778 static int _status_colors[MAXBLSTATS];
2779 static int _status_percents[MAXBLSTATS];
2780 static boolean _status_activefields[MAXBLSTATS];
2781 extern winid WIN_STATUS;
2783 #ifdef STATUS_HILITES
2784 typedef struct hilite_data_struct {
2791 static hilite_data_t _status_hilites[MAXBLSTATS];
2792 #endif /* STATUS_HILITES */
2794 status_init() -- core calls this to notify the window port that a status
2795 display is required. The window port should perform
2796 the necessary initialization in here, allocate memory, etc.
2799 mswin_status_init(void)
2802 logDebug("mswin_status_init()\n");
2803 for (i = 0; i < MAXBLSTATS; ++i) {
2804 _status_vals[i] = (char *) alloc(BUFSZ);
2805 *_status_vals[i] = '\0';
2806 _status_activefields[i] = FALSE;
2807 _status_fieldfmt[i] = (const char *) 0;
2808 _status_colors[i] = CLR_MAX; /* no color */
2809 _status_percents[i] = 0;
2810 #ifdef STATUS_HILITES
2811 _status_hilites[i].thresholdtype = 0;
2812 _status_hilites[i].behavior = BL_TH_NONE;
2813 _status_hilites[i].under = BL_HILITE_NONE;
2814 _status_hilites[i].over = BL_HILITE_NONE;
2815 #endif /* STATUS_HILITES */
2817 /* Use a window for the genl version; backward port compatibility */
2818 WIN_STATUS = create_nhwindow(NHW_STATUS);
2819 display_nhwindow(WIN_STATUS, FALSE);
2823 status_finish() -- called when it is time for the window port to tear down
2824 the status display and free allocated memory, etc.
2827 mswin_status_finish(void)
2829 /* tear down routine */
2832 logDebug("mswin_status_finish()\n");
2834 /* free alloc'd memory here */
2835 for (i = 0; i < MAXBLSTATS; ++i) {
2836 if (_status_vals[i])
2837 free((genericptr_t) _status_vals[i]);
2838 _status_vals[i] = (char *) 0;
2843 status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable)
2844 -- notifies the window port which fields it is authorized to
2846 -- This may be called at any time, and is used
2847 to disable as well as enable fields, depending on the
2848 value of the final argument (TRUE = enable).
2849 -- fldindex could be one of the following from botl.h:
2850 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2851 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2852 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2853 BL_LEVELDESC, BL_EXP, BL_CONDITION
2854 -- There are MAXBLSTATS status fields (from botl.h)
2857 mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt,
2860 logDebug("mswin_status_enablefield(%d, %s, %s, %d)\n", fieldidx, nm, fmt,
2862 _status_fieldfmt[fieldidx] = fmt;
2863 _status_fieldnm[fieldidx] = nm;
2864 _status_activefields[fieldidx] = enable;
2869 status_update(int fldindex, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks)
2870 -- update the value of a status field.
2871 -- the fldindex identifies which field is changing and
2872 is an integer index value from botl.h
2873 -- fldindex could be any one of the following from botl.h:
2874 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2875 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2876 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2877 BL_LEVELDESC, BL_EXP, BL_CONDITION
2878 -- fldindex could also be BL_FLUSH (-1), which is not really
2879 a field index, but is a special trigger to tell the
2880 windowport that it should redisplay all its status fields,
2881 even if no changes have been presented to it.
2882 -- ptr is usually a "char *", unless fldindex is BL_CONDITION.
2883 If fldindex is BL_CONDITION, then ptr is a long value with
2884 any or none of the following bits set (from botl.h):
2885 BL_MASK_STONE 0x00000001L
2886 BL_MASK_SLIME 0x00000002L
2887 BL_MASK_STRNGL 0x00000004L
2888 BL_MASK_FOODPOIS 0x00000008L
2889 BL_MASK_TERMILL 0x00000010L
2890 BL_MASK_BLIND 0x00000020L
2891 BL_MASK_DEAF 0x00000040L
2892 BL_MASK_STUN 0x00000080L
2893 BL_MASK_CONF 0x00000100L
2894 BL_MASK_HALLU 0x00000200L
2895 BL_MASK_LEV 0x00000400L
2896 BL_MASK_FLY 0x00000800L
2897 BL_MASK_RIDE 0x00001000L
2898 -- The value passed for BL_GOLD includes an encoded leading
2899 symbol for GOLD "\GXXXXNNNN:nnn". If window port needs
2900 textual gold amount without the leading "$:" the port will
2901 have to skip past ':' in passed "ptr" for the BL_GOLD case.
2902 -- color is the color that the NetHack core is telling you to
2903 use to display the text.
2904 -- colormasks is a pointer to a set of CLR_MAX unsigned longs
2905 telling you which fields should be displayed in each color.
2908 mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks)
2910 long cond, *condptr = (long *) ptr;
2911 char *text = (char *) ptr;
2912 MSNHMsgUpdateStatus update_cmd_data;
2917 logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", idx, ptr, chg, percent, color, colormasks);
2919 if (idx != BL_FLUSH) {
2920 if (!_status_activefields[idx])
2922 _status_percents[idx] = percent;
2924 case BL_CONDITION: {
2926 *_status_vals[idx] = '\0';
2927 if (cond & BL_MASK_STONE)
2928 Strcat(_status_vals[idx], " Stone");
2929 if (cond & BL_MASK_SLIME)
2930 Strcat(_status_vals[idx], " Slime");
2931 if (cond & BL_MASK_STRNGL)
2932 Strcat(_status_vals[idx], " Strngl");
2933 if (cond & BL_MASK_FOODPOIS)
2934 Strcat(_status_vals[idx], " FoodPois");
2935 if (cond & BL_MASK_TERMILL)
2936 Strcat(_status_vals[idx], " TermIll");
2937 if (cond & BL_MASK_BLIND)
2938 Strcat(_status_vals[idx], " Blind");
2939 if (cond & BL_MASK_DEAF)
2940 Strcat(_status_vals[idx], " Deaf");
2941 if (cond & BL_MASK_STUN)
2942 Strcat(_status_vals[idx], " Stun");
2943 if (cond & BL_MASK_CONF)
2944 Strcat(_status_vals[idx], " Conf");
2945 if (cond & BL_MASK_HALLU)
2946 Strcat(_status_vals[idx], " Hallu");
2947 if (cond & BL_MASK_LEV)
2948 Strcat(_status_vals[idx], " Lev");
2949 if (cond & BL_MASK_FLY)
2950 Strcat(_status_vals[idx], " Fly");
2951 if (cond & BL_MASK_RIDE)
2952 Strcat(_status_vals[idx], " Ride");
2958 ZeroMemory(buf, sizeof(buf));
2959 mapglyph(objnum_to_glyph(GOLD_PIECE), &ochar, &ocolor, &ospecial,
2962 p = strchr(text, ':');
2964 strncpy(buf + 1, p, sizeof(buf) - 2);
2965 value = atol(p + 1);
2968 strncpy(buf + 2, text, sizeof(buf) - 2);
2971 Sprintf(_status_vals[idx],
2972 _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s",
2977 Sprintf(_status_vals[idx],
2978 _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s",
2984 _status_colors[idx] = color;
2986 /* send command to status window */
2987 ZeroMemory(&update_cmd_data, sizeof(update_cmd_data));
2988 update_cmd_data.n_fields = MAXBLSTATS;
2989 update_cmd_data.vals = _status_vals;
2990 update_cmd_data.activefields = _status_activefields;
2991 update_cmd_data.percents = _status_percents;
2992 update_cmd_data.colors = _status_colors;
2993 SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND,
2994 (WPARAM) MSNH_MSG_UPDATE_STATUS, (LPARAM) &update_cmd_data);