miscellaneous formatting
[aNetHack.git] / win / win32 / mswproc.c
blobfe3ce07b57e6aabf06fdf167599667956f8ea0e3
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 /*
6 * This file implements the interface between the window port specific
7 * code in the mswin port and the rest of the nethack game engine.
8 */
10 #include "hack.h"
11 #include "color.h"
12 #include "dlb.h"
13 #include "func_tab.h" /* for extended commands */
14 #include "winMS.h"
15 #include <assert.h>
16 #include <mmsystem.h>
17 #include "mhmap.h"
18 #include "mhstatus.h"
19 #include "mhtext.h"
20 #include "mhmsgwnd.h"
21 #include "mhmenu.h"
22 #include "mhsplash.h"
23 #include "mhmsg.h"
24 #include "mhinput.h"
25 #include "mhaskyn.h"
26 #include "mhdlg.h"
27 #include "mhrip.h"
28 #include "mhmain.h"
29 #include "mhfont.h"
30 #include "resource.h"
32 #define LLEN 128
34 #define NHTRACE_LOG "nhtrace.log"
36 #ifdef DEBUG
37 # ifdef _DEBUG
38 static FILE* _s_debugfp = NULL;
39 extern void logDebug(const char *fmt, ...);
40 # endif
41 #endif
43 #ifndef _DEBUG
44 void
45 logDebug(const char *fmt, ...)
48 #endif
50 static void mswin_main_loop(void);
51 static BOOL initMapTiles(void);
52 static void mswin_color_from_string(char *colorstring, HBRUSH *brushptr,
53 COLORREF *colorptr);
54 static void prompt_for_player_selection(void);
56 #define TOTAL_BRUSHES 10
57 HBRUSH brush_table[TOTAL_BRUSHES];
58 int max_brush = 0;
60 HBRUSH menu_bg_brush = NULL;
61 HBRUSH menu_fg_brush = NULL;
62 HBRUSH text_bg_brush = NULL;
63 HBRUSH text_fg_brush = NULL;
64 HBRUSH status_bg_brush = NULL;
65 HBRUSH status_fg_brush = NULL;
66 HBRUSH message_bg_brush = NULL;
67 HBRUSH message_fg_brush = NULL;
69 COLORREF menu_bg_color = RGB(0, 0, 0);
70 COLORREF menu_fg_color = RGB(0xFF, 0xFF, 0xFF);
71 COLORREF text_bg_color = RGB(0, 0, 0);
72 COLORREF text_fg_color = RGB(0xFF, 0xFF, 0xFF);
73 COLORREF status_bg_color = RGB(0, 0, 0);
74 COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF);
75 COLORREF message_bg_color = RGB(0, 0, 0);
76 COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF);
78 /* Interface definition, for windows.c */
79 struct window_procs mswin_procs = {
80 "MSWIN",
81 WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE
82 | WC_SCROLL_AMOUNT | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE
83 | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONT_MAP
84 | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU
85 | WC_FONTSIZ_TEXT | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE
86 | WC_VARY_MSGCOUNT | WC_WINDOWCOLORS | WC_PLAYER_SELECTION
87 | WC_SPLASH_SCREEN | WC_POPUP_DIALOG,
88 0L, mswin_init_nhwindows, mswin_player_selection, mswin_askname,
89 mswin_get_nh_event, mswin_exit_nhwindows, mswin_suspend_nhwindows,
90 mswin_resume_nhwindows, mswin_create_nhwindow, mswin_clear_nhwindow,
91 mswin_display_nhwindow, mswin_destroy_nhwindow, mswin_curs, mswin_putstr,
92 genl_putmixed, mswin_display_file, mswin_start_menu, mswin_add_menu,
93 mswin_end_menu, mswin_select_menu,
94 genl_message_menu, /* no need for X-specific handling */
95 mswin_update_inventory, mswin_mark_synch, mswin_wait_synch,
96 #ifdef CLIPPING
97 mswin_cliparound,
98 #endif
99 #ifdef POSITIONBAR
100 donull,
101 #endif
102 mswin_print_glyph, mswin_raw_print, mswin_raw_print_bold, mswin_nhgetch,
103 mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function,
104 mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output,
105 #ifdef CHANGE_COLOR /* only a Mac option currently */
106 mswin, mswin_change_background,
107 #endif
108 /* other defs that really should go away (they're tty specific) */
109 mswin_start_screen, mswin_end_screen, mswin_outrip,
110 mswin_preference_update, mswin_getmsghistory, mswin_putmsghistory,
111 #ifdef STATUS_VIA_WINDOWPORT
112 mswin_status_init, mswin_status_finish, mswin_status_enablefield,
113 mswin_status_update,
114 #ifdef STATUS_HILITES
115 mswin_status_threshold,
116 #endif
117 #endif
118 genl_can_suspend_yes,
122 init_nhwindows(int* argcp, char** argv)
123 -- Initialize the windows used by NetHack. This can also
124 create the standard windows listed at the top, but does
125 not display them.
126 -- Any commandline arguments relevant to the windowport
127 should be interpreted, and *argcp and *argv should
128 be changed to remove those arguments.
129 -- When the message window is created, the variable
130 iflags.window_inited needs to be set to TRUE. Otherwise
131 all plines() will be done via raw_print().
132 ** Why not have init_nhwindows() create all of the "standard"
133 ** windows? Or at least all but WIN_INFO? -dean
135 void
136 mswin_init_nhwindows(int *argc, char **argv)
138 UNREFERENCED_PARAMETER(argc);
139 UNREFERENCED_PARAMETER(argv);
141 #ifdef DEBUG
142 # ifdef _DEBUG
143 if (showdebug(NHTRACE_LOG) && !_s_debugfp) {
144 /* truncate trace file */
145 _s_debugfp = fopen(NHTRACE_LOG, "w");
147 # endif
148 #endif
149 logDebug("mswin_init_nhwindows()\n");
151 mswin_nh_input_init();
153 /* set it to WIN_ERR so we can detect attempts to
154 use this ID before it is inialized */
155 WIN_MAP = WIN_ERR;
157 /* Read Windows settings from the reqistry */
158 /* First set safe defaults */
159 GetNHApp()->regMainMinX = CW_USEDEFAULT;
160 mswin_read_reg();
161 /* Create the main window */
162 GetNHApp()->hMainWnd = mswin_init_main_window();
163 if (!GetNHApp()->hMainWnd) {
164 panic("Cannot create main window");
167 /* Set menu check mark for interface mode */
168 mswin_menu_check_intf_mode();
170 /* check default values */
171 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
172 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
173 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
175 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
176 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
177 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
179 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
180 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
181 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
183 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
184 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
185 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
187 if (iflags.wc_align_message == 0)
188 iflags.wc_align_message = ALIGN_TOP;
189 if (iflags.wc_align_status == 0)
190 iflags.wc_align_status = ALIGN_BOTTOM;
191 if (iflags.wc_scroll_margin == 0)
192 iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
193 if (iflags.wc_scroll_amount == 0)
194 iflags.wc_scroll_amount = DEF_CLIPAROUND_AMOUNT;
195 if (iflags.wc_tile_width == 0)
196 iflags.wc_tile_width = TILE_X;
197 if (iflags.wc_tile_height == 0)
198 iflags.wc_tile_height = TILE_Y;
200 if (iflags.wc_vary_msgcount == 0)
201 iflags.wc_vary_msgcount = 4;
203 /* force tabs in menus */
204 iflags.menu_tab_sep = 1;
206 /* force toptenwin to be true. toptenwin is the option that decides
207 * whether to
208 * write output to a window or stdout. stdout doesn't make sense on
209 * Windows
210 * non-console applications
212 iflags.toptenwin = 1;
213 set_option_mod_status("toptenwin", SET_IN_FILE);
214 //set_option_mod_status("perm_invent", SET_IN_FILE);
216 /* initialize map tiles bitmap */
217 initMapTiles();
219 /* set tile-related options to readonly */
220 set_wc_option_mod_status(WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE,
221 DISP_IN_GAME);
223 /* set font-related options to change in the game */
224 set_wc_option_mod_status(
225 WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_SCROLL_AMOUNT
226 | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE
227 | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT
228 | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU
229 | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT,
230 SET_IN_GAME);
232 mswin_color_from_string(iflags.wc_foregrnd_menu, &menu_fg_brush,
233 &menu_fg_color);
234 mswin_color_from_string(iflags.wc_foregrnd_message, &message_fg_brush,
235 &message_fg_color);
236 mswin_color_from_string(iflags.wc_foregrnd_status, &status_fg_brush,
237 &status_fg_color);
238 mswin_color_from_string(iflags.wc_foregrnd_text, &text_fg_brush,
239 &text_fg_color);
240 mswin_color_from_string(iflags.wc_backgrnd_menu, &menu_bg_brush,
241 &menu_bg_color);
242 mswin_color_from_string(iflags.wc_backgrnd_message, &message_bg_brush,
243 &message_bg_color);
244 mswin_color_from_string(iflags.wc_backgrnd_status, &status_bg_brush,
245 &status_bg_color);
246 mswin_color_from_string(iflags.wc_backgrnd_text, &text_bg_brush,
247 &text_bg_color);
249 if (iflags.wc_splash_screen)
250 mswin_display_splash_window(FALSE);
252 iflags.window_inited = TRUE;
255 /* Do a window-port specific player type selection. If player_selection()
256 offers a Quit option, it is its responsibility to clean up and terminate
257 the process. You need to fill in pl_character[0].
259 void
260 mswin_player_selection(void)
262 int nRole;
264 logDebug("mswin_player_selection()\n");
266 if (iflags.wc_player_selection == VIA_DIALOG) {
267 /* pick player type randomly (use pre-selected
268 * role/race/gender/alignment) */
269 if (flags.randomall) {
270 if (flags.initrole < 0) {
271 flags.initrole = pick_role(flags.initrace, flags.initgend,
272 flags.initalign, PICK_RANDOM);
273 if (flags.initrole < 0) {
274 raw_print("Incompatible role!");
275 flags.initrole = randrole();
279 if (flags.initrace < 0
280 || !validrace(flags.initrole, flags.initrace)) {
281 flags.initrace = pick_race(flags.initrole, flags.initgend,
282 flags.initalign, PICK_RANDOM);
283 if (flags.initrace < 0) {
284 raw_print("Incompatible race!");
285 flags.initrace = randrace(flags.initrole);
289 if (flags.initgend < 0
290 || !validgend(flags.initrole, flags.initrace,
291 flags.initgend)) {
292 flags.initgend = pick_gend(flags.initrole, flags.initrace,
293 flags.initalign, PICK_RANDOM);
294 if (flags.initgend < 0) {
295 raw_print("Incompatible gender!");
296 flags.initgend = randgend(flags.initrole, flags.initrace);
300 if (flags.initalign < 0
301 || !validalign(flags.initrole, flags.initrace,
302 flags.initalign)) {
303 flags.initalign = pick_align(flags.initrole, flags.initrace,
304 flags.initgend, PICK_RANDOM);
305 if (flags.initalign < 0) {
306 raw_print("Incompatible alignment!");
307 flags.initalign =
308 randalign(flags.initrole, flags.initrace);
311 } else {
312 /* select a role */
313 if (mswin_player_selection_window(&nRole) == IDCANCEL) {
314 bail(0);
317 } else { /* iflags.wc_player_selection == VIA_PROMPTS */
318 prompt_for_player_selection();
322 void
323 prompt_for_player_selection(void)
325 int i, k, n;
326 char pick4u = 'n', thisch, lastch = 0;
327 char pbuf[QBUFSZ], plbuf[QBUFSZ];
328 winid win;
329 anything any;
330 menu_item *selected = 0;
331 DWORD box_result;
333 logDebug("prompt_for_player_selection()\n");
335 /* prevent an unnecessary prompt */
336 rigid_role_checks();
338 /* Should we randomly pick for the player? */
339 if (!flags.randomall
340 && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE
341 || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
342 /* int echoline; */
343 char *prompt = build_plselection_prompt(
344 pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend,
345 flags.initalign);
347 /* tty_putstr(BASE_WINDOW, 0, ""); */
348 /* echoline = wins[BASE_WINDOW]->cury; */
349 box_result = NHMessageBox(NULL, prompt, MB_YESNOCANCEL | MB_DEFBUTTON1
350 | MB_ICONQUESTION);
351 pick4u =
352 (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033';
353 /* tty_putstr(BASE_WINDOW, 0, prompt); */
354 do {
355 /* pick4u = lowc(readchar()); */
356 if (index(quitchars, pick4u))
357 pick4u = 'y';
358 } while (!index(ynqchars, pick4u));
359 if ((int) strlen(prompt) + 1 < CO) {
360 /* Echo choice and move back down line */
361 /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline,
362 * pick4u); */
363 /* tty_putstr(BASE_WINDOW, 0, ""); */
364 } else
365 /* Otherwise it's hard to tell where to echo, and things are
366 * wrapping a bit messily anyway, so (try to) make sure the next
367 * question shows up well and doesn't get wrapped at the
368 * bottom of the window.
370 /* tty_clear_nhwindow(BASE_WINDOW) */;
372 if (pick4u != 'y' && pick4u != 'n') {
373 give_up: /* Quit */
374 if (selected)
375 free((genericptr_t) selected);
376 bail((char *) 0);
377 /*NOTREACHED*/
378 return;
382 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
383 flags.initrace, flags.initgend,
384 flags.initalign);
386 /* Select a role, if necessary */
387 /* we'll try to be compatible with pre-selected race/gender/alignment,
388 * but may not succeed */
389 if (flags.initrole < 0) {
390 char rolenamebuf[QBUFSZ];
391 /* Process the choice */
392 if (pick4u == 'y' || flags.initrole == ROLE_RANDOM
393 || flags.randomall) {
394 /* Pick a random role */
395 flags.initrole = pick_role(flags.initrace, flags.initgend,
396 flags.initalign, PICK_RANDOM);
397 if (flags.initrole < 0) {
398 /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
399 flags.initrole = randrole();
401 } else {
402 /* tty_clear_nhwindow(BASE_WINDOW); */
403 /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
404 /* Prompt for a role */
405 win = create_nhwindow(NHW_MENU);
406 start_menu(win);
407 any = zeroany; /* zero out all bits */
408 for (i = 0; roles[i].name.m; i++) {
409 if (ok_role(i, flags.initrace, flags.initgend,
410 flags.initalign)) {
411 any.a_int = i + 1; /* must be non-zero */
412 thisch = lowc(roles[i].name.m[0]);
413 if (thisch == lastch)
414 thisch = highc(thisch);
415 if (flags.initgend != ROLE_NONE
416 && flags.initgend != ROLE_RANDOM) {
417 if (flags.initgend == 1 && roles[i].name.f)
418 Strcpy(rolenamebuf, roles[i].name.f);
419 else
420 Strcpy(rolenamebuf, roles[i].name.m);
421 } else {
422 if (roles[i].name.f) {
423 Strcpy(rolenamebuf, roles[i].name.m);
424 Strcat(rolenamebuf, "/");
425 Strcat(rolenamebuf, roles[i].name.f);
426 } else
427 Strcpy(rolenamebuf, roles[i].name.m);
429 add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE,
430 an(rolenamebuf), MENU_UNSELECTED);
431 lastch = thisch;
434 any.a_int = pick_role(flags.initrace, flags.initgend,
435 flags.initalign, PICK_RANDOM) + 1;
436 if (any.a_int == 0) /* must be non-zero */
437 any.a_int = randrole() + 1;
438 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
439 MENU_UNSELECTED);
440 any.a_int = i + 1; /* must be non-zero */
441 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
442 MENU_UNSELECTED);
443 Sprintf(pbuf, "Pick a role for your %s", plbuf);
444 end_menu(win, pbuf);
445 n = select_menu(win, PICK_ONE, &selected);
446 destroy_nhwindow(win);
448 /* Process the choice */
449 if (n != 1 || selected[0].item.a_int == any.a_int)
450 goto give_up; /* Selected quit */
452 flags.initrole = selected[0].item.a_int - 1;
453 free((genericptr_t) selected), selected = 0;
455 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
456 flags.initrace, flags.initgend,
457 flags.initalign);
460 /* Select a race, if necessary */
461 /* force compatibility with role, try for compatibility with
462 * pre-selected gender/alignment */
463 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
464 /* pre-selected race not valid */
465 if (pick4u == 'y' || flags.initrace == ROLE_RANDOM
466 || flags.randomall) {
467 flags.initrace = pick_race(flags.initrole, flags.initgend,
468 flags.initalign, PICK_RANDOM);
469 if (flags.initrace < 0) {
470 /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
471 flags.initrace = randrace(flags.initrole);
473 } else { /* pick4u == 'n' */
474 /* Count the number of valid races */
475 n = 0; /* number valid */
476 k = 0; /* valid race */
477 for (i = 0; races[i].noun; i++) {
478 if (ok_race(flags.initrole, i, flags.initgend,
479 flags.initalign)) {
480 n++;
481 k = i;
484 if (n == 0) {
485 for (i = 0; races[i].noun; i++) {
486 if (validrace(flags.initrole, i)) {
487 n++;
488 k = i;
493 /* Permit the user to pick, if there is more than one */
494 if (n > 1) {
495 /* tty_clear_nhwindow(BASE_WINDOW); */
496 /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
497 win = create_nhwindow(NHW_MENU);
498 start_menu(win);
499 any = zeroany; /* zero out all bits */
500 for (i = 0; races[i].noun; i++)
501 if (ok_race(flags.initrole, i, flags.initgend,
502 flags.initalign)) {
503 any.a_int = i + 1; /* must be non-zero */
504 add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0,
505 ATR_NONE, races[i].noun, MENU_UNSELECTED);
507 any.a_int = pick_race(flags.initrole, flags.initgend,
508 flags.initalign, PICK_RANDOM) + 1;
509 if (any.a_int == 0) /* must be non-zero */
510 any.a_int = randrace(flags.initrole) + 1;
511 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
512 MENU_UNSELECTED);
513 any.a_int = i + 1; /* must be non-zero */
514 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
515 MENU_UNSELECTED);
516 Sprintf(pbuf, "Pick the race of your %s", plbuf);
517 end_menu(win, pbuf);
518 n = select_menu(win, PICK_ONE, &selected);
519 destroy_nhwindow(win);
520 if (n != 1 || selected[0].item.a_int == any.a_int)
521 goto give_up; /* Selected quit */
523 k = selected[0].item.a_int - 1;
524 free((genericptr_t) selected), selected = 0;
526 flags.initrace = k;
528 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
529 flags.initrace, flags.initgend,
530 flags.initalign);
533 /* Select a gender, if necessary */
534 /* force compatibility with role/race, try for compatibility with
535 * pre-selected alignment */
536 if (flags.initgend < 0
537 || !validgend(flags.initrole, flags.initrace, flags.initgend)) {
538 /* pre-selected gender not valid */
539 if (pick4u == 'y' || flags.initgend == ROLE_RANDOM
540 || flags.randomall) {
541 flags.initgend = pick_gend(flags.initrole, flags.initrace,
542 flags.initalign, PICK_RANDOM);
543 if (flags.initgend < 0) {
544 /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
545 flags.initgend = randgend(flags.initrole, flags.initrace);
547 } else { /* pick4u == 'n' */
548 /* Count the number of valid genders */
549 n = 0; /* number valid */
550 k = 0; /* valid gender */
551 for (i = 0; i < ROLE_GENDERS; i++) {
552 if (ok_gend(flags.initrole, flags.initrace, i,
553 flags.initalign)) {
554 n++;
555 k = i;
558 if (n == 0) {
559 for (i = 0; i < ROLE_GENDERS; i++) {
560 if (validgend(flags.initrole, flags.initrace, i)) {
561 n++;
562 k = i;
567 /* Permit the user to pick, if there is more than one */
568 if (n > 1) {
569 /* tty_clear_nhwindow(BASE_WINDOW); */
570 /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
571 win = create_nhwindow(NHW_MENU);
572 start_menu(win);
573 any = zeroany; /* zero out all bits */
574 for (i = 0; i < ROLE_GENDERS; i++)
575 if (ok_gend(flags.initrole, flags.initrace, i,
576 flags.initalign)) {
577 any.a_int = i + 1;
578 add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0,
579 ATR_NONE, genders[i].adj, MENU_UNSELECTED);
581 any.a_int = pick_gend(flags.initrole, flags.initrace,
582 flags.initalign, PICK_RANDOM) + 1;
583 if (any.a_int == 0) /* must be non-zero */
584 any.a_int = randgend(flags.initrole, flags.initrace) + 1;
585 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
586 MENU_UNSELECTED);
587 any.a_int = i + 1; /* must be non-zero */
588 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
589 MENU_UNSELECTED);
590 Sprintf(pbuf, "Pick the gender of your %s", plbuf);
591 end_menu(win, pbuf);
592 n = select_menu(win, PICK_ONE, &selected);
593 destroy_nhwindow(win);
594 if (n != 1 || selected[0].item.a_int == any.a_int)
595 goto give_up; /* Selected quit */
597 k = selected[0].item.a_int - 1;
598 free((genericptr_t) selected), selected = 0;
600 flags.initgend = k;
602 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
603 flags.initrace, flags.initgend,
604 flags.initalign);
607 /* Select an alignment, if necessary */
608 /* force compatibility with role/race/gender */
609 if (flags.initalign < 0
610 || !validalign(flags.initrole, flags.initrace, flags.initalign)) {
611 /* pre-selected alignment not valid */
612 if (pick4u == 'y' || flags.initalign == ROLE_RANDOM
613 || flags.randomall) {
614 flags.initalign = pick_align(flags.initrole, flags.initrace,
615 flags.initgend, PICK_RANDOM);
616 if (flags.initalign < 0) {
617 /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
618 flags.initalign = randalign(flags.initrole, flags.initrace);
620 } else { /* pick4u == 'n' */
621 /* Count the number of valid alignments */
622 n = 0; /* number valid */
623 k = 0; /* valid alignment */
624 for (i = 0; i < ROLE_ALIGNS; i++) {
625 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
626 i)) {
627 n++;
628 k = i;
631 if (n == 0) {
632 for (i = 0; i < ROLE_ALIGNS; i++) {
633 if (validalign(flags.initrole, flags.initrace, i)) {
634 n++;
635 k = i;
640 /* Permit the user to pick, if there is more than one */
641 if (n > 1) {
642 /* tty_clear_nhwindow(BASE_WINDOW); */
643 /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
644 win = create_nhwindow(NHW_MENU);
645 start_menu(win);
646 any = zeroany; /* zero out all bits */
647 for (i = 0; i < ROLE_ALIGNS; i++)
648 if (ok_align(flags.initrole, flags.initrace,
649 flags.initgend, i)) {
650 any.a_int = i + 1;
651 add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0,
652 ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
654 any.a_int = pick_align(flags.initrole, flags.initrace,
655 flags.initgend, PICK_RANDOM) + 1;
656 if (any.a_int == 0) /* must be non-zero */
657 any.a_int = randalign(flags.initrole, flags.initrace) + 1;
658 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
659 MENU_UNSELECTED);
660 any.a_int = i + 1; /* must be non-zero */
661 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
662 MENU_UNSELECTED);
663 Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
664 end_menu(win, pbuf);
665 n = select_menu(win, PICK_ONE, &selected);
666 destroy_nhwindow(win);
667 if (n != 1 || selected[0].item.a_int == any.a_int)
668 goto give_up; /* Selected quit */
670 k = selected[0].item.a_int - 1;
671 free((genericptr_t) selected), selected = 0;
673 flags.initalign = k;
676 /* Success! */
677 /* tty_display_nhwindow(BASE_WINDOW, FALSE); */
680 /* Ask the user for a player name. */
681 void
682 mswin_askname(void)
684 logDebug("mswin_askname()\n");
686 if (mswin_getlin_window("Who are you?", plname, PL_NSIZ) == IDCANCEL) {
687 bail("bye-bye");
688 /* not reached */
692 /* Does window event processing (e.g. exposure events).
693 A noop for the tty and X window-ports.
695 void
696 mswin_get_nh_event(void)
698 MSG msg;
700 logDebug("mswin_get_nh_event()\n");
702 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
703 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
704 TranslateMessage(&msg);
705 DispatchMessage(&msg);
708 return;
711 /* Exits the window system. This should dismiss all windows,
712 except the "window" used for raw_print(). str is printed if possible.
714 void
715 mswin_exit_nhwindows(const char *str)
717 logDebug("mswin_exit_nhwindows(%s)\n", str);
719 /* Write Window settings to the registry */
720 mswin_write_reg();
721 while (max_brush)
722 DeleteObject(brush_table[--max_brush]);
725 /* Prepare the window to be suspended. */
726 void
727 mswin_suspend_nhwindows(const char *str)
729 logDebug("mswin_suspend_nhwindows(%s)\n", str);
731 return;
734 /* Restore the windows after being suspended. */
735 void
736 mswin_resume_nhwindows()
738 logDebug("mswin_resume_nhwindows()\n");
740 return;
743 /* Create a window of type "type" which can be
744 NHW_MESSAGE (top line)
745 NHW_STATUS (bottom lines)
746 NHW_MAP (main dungeon)
747 NHW_MENU (inventory or other "corner" windows)
748 NHW_TEXT (help/text, full screen paged window)
750 winid
751 mswin_create_nhwindow(int type)
753 winid i = 0;
754 MSNHMsgAddWnd data;
756 logDebug("mswin_create_nhwindow(%d)\n", type);
758 /* Return the next available winid
761 for (i = 1; i < MAXWINDOWS; i++)
762 if (GetNHApp()->windowlist[i].win == NULL
763 && !GetNHApp()->windowlist[i].dead)
764 break;
765 if (i == MAXWINDOWS)
766 panic("ERROR: No windows available...\n");
768 switch (type) {
769 case NHW_MAP: {
770 GetNHApp()->windowlist[i].win = mswin_init_map_window();
771 GetNHApp()->windowlist[i].type = type;
772 GetNHApp()->windowlist[i].dead = 0;
773 break;
775 case NHW_MESSAGE: {
776 GetNHApp()->windowlist[i].win = mswin_init_message_window();
777 GetNHApp()->windowlist[i].type = type;
778 GetNHApp()->windowlist[i].dead = 0;
779 break;
781 case NHW_STATUS: {
782 GetNHApp()->windowlist[i].win = mswin_init_status_window();
783 GetNHApp()->windowlist[i].type = type;
784 GetNHApp()->windowlist[i].dead = 0;
785 break;
787 case NHW_MENU: {
788 GetNHApp()->windowlist[i].win = NULL; // will create later
789 GetNHApp()->windowlist[i].type = type;
790 GetNHApp()->windowlist[i].dead = 1;
791 break;
793 case NHW_TEXT: {
794 GetNHApp()->windowlist[i].win = mswin_init_text_window();
795 GetNHApp()->windowlist[i].type = type;
796 GetNHApp()->windowlist[i].dead = 0;
797 break;
801 ZeroMemory(&data, sizeof(data));
802 data.wid = i;
803 SendMessage(GetNHApp()->hMainWnd, WM_MSNH_COMMAND,
804 (WPARAM) MSNH_MSG_ADDWND, (LPARAM) &data);
805 return i;
808 /* Clear the given window, when asked to. */
809 void
810 mswin_clear_nhwindow(winid wid)
812 logDebug("mswin_clear_nhwindow(%d)\n", wid);
814 if ((wid >= 0) && (wid < MAXWINDOWS)
815 && (GetNHApp()->windowlist[wid].win != NULL)) {
816 if (GetNHApp()->windowlist[wid].type == NHW_MAP) {
817 if (Is_rogue_level(&u.uz))
818 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP),
819 ROGUE_LEVEL_MAP_MODE);
820 else
821 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP),
822 iflags.wc_map_mode);
825 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
826 (WPARAM) MSNH_MSG_CLEAR_WINDOW, (LPARAM) NULL);
830 /* -- Display the window on the screen. If there is data
831 pending for output in that window, it should be sent.
832 If blocking is TRUE, display_nhwindow() will not
833 return until the data has been displayed on the screen,
834 and acknowledged by the user where appropriate.
835 -- All calls are blocking in the tty window-port.
836 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
837 --more--, if necessary, in the tty window-port.
839 void
840 mswin_display_nhwindow(winid wid, BOOLEAN_P block)
842 logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block);
843 if (GetNHApp()->windowlist[wid].win != NULL) {
844 ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW);
845 mswin_layout_main_window(GetNHApp()->windowlist[wid].win);
846 if (GetNHApp()->windowlist[wid].type == NHW_MENU) {
847 MENU_ITEM_P *p;
848 mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win,
849 PICK_NONE, &p, TRUE);
851 if (GetNHApp()->windowlist[wid].type == NHW_TEXT) {
852 mswin_display_text_window(GetNHApp()->windowlist[wid].win);
854 if (GetNHApp()->windowlist[wid].type == NHW_RIP) {
855 mswin_display_RIP_window(GetNHApp()->windowlist[wid].win);
856 } else {
857 if (!block) {
858 UpdateWindow(GetNHApp()->windowlist[wid].win);
859 } else {
860 if (GetNHApp()->windowlist[wid].type == NHW_MAP) {
861 (void) mswin_nhgetch();
865 SetFocus(GetNHApp()->hMainWnd);
869 HWND
870 mswin_hwnd_from_winid(winid wid)
872 if (wid >= 0 && wid < MAXWINDOWS) {
873 return GetNHApp()->windowlist[wid].win;
874 } else {
875 return NULL;
879 winid
880 mswin_winid_from_handle(HWND hWnd)
882 winid i = 0;
884 for (i = 1; i < MAXWINDOWS; i++)
885 if (GetNHApp()->windowlist[i].win == hWnd)
886 return i;
887 return -1;
890 winid
891 mswin_winid_from_type(int type)
893 winid i = 0;
895 for (i = 1; i < MAXWINDOWS; i++)
896 if (GetNHApp()->windowlist[i].type == type)
897 return i;
898 return -1;
901 void
902 mswin_window_mark_dead(winid wid)
904 if (wid >= 0 && wid < MAXWINDOWS) {
905 GetNHApp()->windowlist[wid].win = NULL;
906 GetNHApp()->windowlist[wid].dead = 1;
910 /* Destroy will dismiss the window if the window has not
911 * already been dismissed.
913 void
914 mswin_destroy_nhwindow(winid wid)
916 logDebug("mswin_destroy_nhwindow(%d)\n", wid);
918 if ((GetNHApp()->windowlist[wid].type == NHW_MAP)
919 || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE)
920 || (GetNHApp()->windowlist[wid].type == NHW_STATUS)) {
921 /* main windows is going to take care of those */
922 return;
925 if (wid != -1) {
926 if (!GetNHApp()->windowlist[wid].dead
927 && GetNHApp()->windowlist[wid].win != NULL)
928 DestroyWindow(GetNHApp()->windowlist[wid].win);
929 GetNHApp()->windowlist[wid].win = NULL;
930 GetNHApp()->windowlist[wid].type = 0;
931 GetNHApp()->windowlist[wid].dead = 0;
935 /* Next output to window will start at (x,y), also moves
936 displayable cursor to (x,y). For backward compatibility,
937 1 <= x < cols, 0 <= y < rows, where cols and rows are
938 the size of window.
940 void
941 mswin_curs(winid wid, int x, int y)
943 logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y);
945 if ((wid >= 0) && (wid < MAXWINDOWS)
946 && (GetNHApp()->windowlist[wid].win != NULL)) {
947 MSNHMsgCursor data;
948 data.x = x;
949 data.y = y;
950 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
951 (WPARAM) MSNH_MSG_CURSOR, (LPARAM) &data);
956 putstr(window, attr, str)
957 -- Print str on the window with the given attribute. Only
958 printable ASCII characters (040-0126) must be supported.
959 Multiple putstr()s are output on separate lines.
960 Attributes
961 can be one of
962 ATR_NONE (or 0)
963 ATR_ULINE
964 ATR_BOLD
965 ATR_BLINK
966 ATR_INVERSE
967 If a window-port does not support all of these, it may map
968 unsupported attributes to a supported one (e.g. map them
969 all to ATR_INVERSE). putstr() may compress spaces out of
970 str, break str, or truncate str, if necessary for the
971 display. Where putstr() breaks a line, it has to clear
972 to end-of-line.
973 -- putstr should be implemented such that if two putstr()s
974 are done consecutively the user will see the first and
975 then the second. In the tty port, pline() achieves this
976 by calling more() or displaying both on the same line.
978 void
979 mswin_putstr(winid wid, int attr, const char *text)
981 logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text);
983 mswin_putstr_ex(wid, attr, text, 0);
986 void
987 mswin_putstr_ex(winid wid, int attr, const char *text, int app)
989 if ((wid >= 0) && (wid < MAXWINDOWS)) {
990 if (GetNHApp()->windowlist[wid].win == NULL
991 && GetNHApp()->windowlist[wid].type == NHW_MENU) {
992 GetNHApp()->windowlist[wid].win =
993 mswin_init_menu_window(MENU_TYPE_TEXT);
994 GetNHApp()->windowlist[wid].dead = 0;
997 if (GetNHApp()->windowlist[wid].win != NULL) {
998 MSNHMsgPutstr data;
999 ZeroMemory(&data, sizeof(data));
1000 data.attr = attr;
1001 data.text = text;
1002 data.append = app;
1003 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1004 (WPARAM) MSNH_MSG_PUTSTR, (LPARAM) &data);
1006 /* yield a bit so it gets done immediately */
1007 mswin_get_nh_event();
1008 } else {
1009 // build text to display later in message box
1010 GetNHApp()->saved_text =
1011 realloc(GetNHApp()->saved_text,
1012 strlen(text) + strlen(GetNHApp()->saved_text) + 1);
1013 strcat(GetNHApp()->saved_text, text);
1017 /* Display the file named str. Complain about missing files
1018 iff complain is TRUE.
1020 void
1021 mswin_display_file(const char *filename, BOOLEAN_P must_exist)
1023 dlb *f;
1024 TCHAR wbuf[BUFSZ];
1026 logDebug("mswin_display_file(%s, %d)\n", filename, must_exist);
1028 f = dlb_fopen(filename, RDTMODE);
1029 if (!f) {
1030 if (must_exist) {
1031 TCHAR message[90];
1032 _stprintf(message, TEXT("Warning! Could not find file: %s\n"),
1033 NH_A2W(filename, wbuf, sizeof(wbuf)));
1034 NHMessageBox(GetNHApp()->hMainWnd, message,
1035 MB_OK | MB_ICONEXCLAMATION);
1037 } else {
1038 winid text;
1039 char line[LLEN];
1041 text = mswin_create_nhwindow(NHW_TEXT);
1043 while (dlb_fgets(line, LLEN, f)) {
1044 size_t len;
1045 len = strlen(line);
1046 if (line[len - 1] == '\n')
1047 line[len - 1] = '\x0';
1048 mswin_putstr(text, ATR_NONE, line);
1050 (void) dlb_fclose(f);
1052 mswin_display_nhwindow(text, 1);
1053 mswin_destroy_nhwindow(text);
1057 /* Start using window as a menu. You must call start_menu()
1058 before add_menu(). After calling start_menu() you may not
1059 putstr() to the window. Only windows of type NHW_MENU may
1060 be used for menus.
1062 void
1063 mswin_start_menu(winid wid)
1065 logDebug("mswin_start_menu(%d)\n", wid);
1066 if ((wid >= 0) && (wid < MAXWINDOWS)) {
1067 if (GetNHApp()->windowlist[wid].win == NULL
1068 && GetNHApp()->windowlist[wid].type == NHW_MENU) {
1069 GetNHApp()->windowlist[wid].win =
1070 mswin_init_menu_window(MENU_TYPE_MENU);
1071 GetNHApp()->windowlist[wid].dead = 0;
1074 if (GetNHApp()->windowlist[wid].win != NULL) {
1075 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1076 (WPARAM) MSNH_MSG_STARTMENU, (LPARAM) NULL);
1082 add_menu(windid window, int glyph, const anything identifier,
1083 char accelerator, char groupacc,
1084 int attr, char *str, boolean preselected)
1085 -- Add a text line str to the given menu window. If
1086 identifier
1087 is 0, then the line cannot be selected (e.g. a title).
1088 Otherwise, identifier is the value returned if the line is
1089 selected. Accelerator is a keyboard key that can be used
1090 to select the line. If the accelerator of a selectable
1091 item is 0, the window system is free to select its own
1092 accelerator. It is up to the window-port to make the
1093 accelerator visible to the user (e.g. put "a - " in front
1094 of str). The value attr is the same as in putstr().
1095 Glyph is an optional glyph to accompany the line. If
1096 window port cannot or does not want to display it, this
1097 is OK. If there is no glyph applicable, then this
1098 value will be NO_GLYPH.
1099 -- All accelerators should be in the range [A-Za-z].
1100 -- It is expected that callers do not mix accelerator
1101 choices. Either all selectable items have an accelerator
1102 or let the window system pick them. Don't do both.
1103 -- Groupacc is a group accelerator. It may be any character
1104 outside of the standard accelerator (see above) or a
1105 number. If 0, the item is unaffected by any group
1106 accelerator. If this accelerator conflicts with
1107 the menu command (or their user defined alises), it loses.
1108 The menu commands and aliases take care not to interfere
1109 with the default object class symbols.
1110 -- If you want this choice to be preselected when the
1111 menu is displayed, set preselected to TRUE.
1113 void
1114 mswin_add_menu(winid wid, int glyph, const ANY_P *identifier,
1115 CHAR_P accelerator, CHAR_P group_accel, int attr,
1116 const char *str, BOOLEAN_P presel)
1118 logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph,
1119 identifier, (char) accelerator, (char) group_accel, attr, str,
1120 presel);
1121 if ((wid >= 0) && (wid < MAXWINDOWS)
1122 && (GetNHApp()->windowlist[wid].win != NULL)) {
1123 MSNHMsgAddMenu data;
1124 ZeroMemory(&data, sizeof(data));
1125 data.glyph = glyph;
1126 data.identifier = identifier;
1127 data.accelerator = accelerator;
1128 data.group_accel = group_accel;
1129 data.attr = attr;
1130 data.str = str;
1131 data.presel = presel;
1133 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1134 (WPARAM) MSNH_MSG_ADDMENU, (LPARAM) &data);
1139 end_menu(window, prompt)
1140 -- Stop adding entries to the menu and flushes the window
1141 to the screen (brings to front?). Prompt is a prompt
1142 to give the user. If prompt is NULL, no prompt will
1143 be printed.
1144 ** This probably shouldn't flush the window any more (if
1145 ** it ever did). That should be select_menu's job. -dean
1147 void
1148 mswin_end_menu(winid wid, const char *prompt)
1150 logDebug("mswin_end_menu(%d, %s)\n", wid, prompt);
1151 if ((wid >= 0) && (wid < MAXWINDOWS)
1152 && (GetNHApp()->windowlist[wid].win != NULL)) {
1153 MSNHMsgEndMenu data;
1154 ZeroMemory(&data, sizeof(data));
1155 data.text = prompt;
1157 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1158 (WPARAM) MSNH_MSG_ENDMENU, (LPARAM) &data);
1163 int select_menu(windid window, int how, menu_item **selected)
1164 -- Return the number of items selected; 0 if none were chosen,
1165 -1 when explicitly cancelled. If items were selected, then
1166 selected is filled in with an allocated array of menu_item
1167 structures, one for each selected line. The caller must
1168 free this array when done with it. The "count" field
1169 of selected is a user supplied count. If the user did
1170 not supply a count, then the count field is filled with
1171 -1 (meaning all). A count of zero is equivalent to not
1172 being selected and should not be in the list. If no items
1173 were selected, then selected is NULL'ed out. How is the
1174 mode of the menu. Three valid values are PICK_NONE,
1175 PICK_ONE, and PICK_N, meaning: nothing is selectable,
1176 only one thing is selectable, and any number valid items
1177 may selected. If how is PICK_NONE, this function should
1178 never return anything but 0 or -1.
1179 -- You may call select_menu() on a window multiple times --
1180 the menu is saved until start_menu() or destroy_nhwindow()
1181 is called on the window.
1182 -- Note that NHW_MENU windows need not have select_menu()
1183 called for them. There is no way of knowing whether
1184 select_menu() will be called for the window at
1185 create_nhwindow() time.
1188 mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected)
1190 int nReturned = -1;
1192 logDebug("mswin_select_menu(%d, %d)\n", wid, how);
1194 if ((wid >= 0) && (wid < MAXWINDOWS)
1195 && (GetNHApp()->windowlist[wid].win != NULL)) {
1196 ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW);
1197 nReturned = mswin_menu_window_select_menu(
1198 GetNHApp()->windowlist[wid].win, how, selected,
1199 !(flags.perm_invent && wid == WIN_INVEN
1200 && how == PICK_NONE) /* don't activate inventory window if
1201 perm_invent is on */
1204 return nReturned;
1208 -- Indicate to the window port that the inventory has been changed.
1209 -- Merely calls display_inventory() for window-ports that leave the
1210 window up, otherwise empty.
1212 void
1213 mswin_update_inventory()
1215 logDebug("mswin_update_inventory()\n");
1216 if (flags.perm_invent && program_state.something_worth_saving
1217 && iflags.window_inited && WIN_INVEN != WIN_ERR)
1218 display_inventory(NULL, FALSE);
1222 mark_synch() -- Don't go beyond this point in I/O on any channel until
1223 all channels are caught up to here. Can be an empty call
1224 for the moment
1226 void
1227 mswin_mark_synch()
1229 logDebug("mswin_mark_synch()\n");
1233 wait_synch() -- Wait until all pending output is complete (*flush*() for
1234 streams goes here).
1235 -- May also deal with exposure events etc. so that the
1236 display is OK when return from wait_synch().
1238 void
1239 mswin_wait_synch()
1241 logDebug("mswin_wait_synch()\n");
1245 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
1246 screen if the playing area is larger than the screen.
1247 -- This function is only defined if CLIPPING is defined.
1249 void
1250 mswin_cliparound(int x, int y)
1252 winid wid = WIN_MAP;
1254 logDebug("mswin_cliparound(%d, %d)\n", x, y);
1256 if ((wid >= 0) && (wid < MAXWINDOWS)
1257 && (GetNHApp()->windowlist[wid].win != NULL)) {
1258 MSNHMsgClipAround data;
1259 data.x = x;
1260 data.y = y;
1261 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1262 (WPARAM) MSNH_MSG_CLIPAROUND, (LPARAM) &data);
1267 print_glyph(window, x, y, glyph, bkglyph)
1268 -- Print the glyph at (x,y) on the given window. Glyphs are
1269 integers at the interface, mapped to whatever the window-
1270 port wants (symbol, font, color, attributes, ...there's
1271 a 1-1 map between glyphs and distinct things on the map).
1272 -- bkglyph is a background glyph for potential use by some
1273 graphical or tiled environments to allow the depiction
1274 to fall against a background consistent with the grid
1275 around x,y.
1278 void
1279 mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph)
1281 logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid, x, y, glyph, bkglyph);
1283 if ((wid >= 0) && (wid < MAXWINDOWS)
1284 && (GetNHApp()->windowlist[wid].win != NULL)) {
1285 MSNHMsgPrintGlyph data;
1287 ZeroMemory(&data, sizeof(data));
1288 data.x = x;
1289 data.y = y;
1290 data.glyph = glyph;
1291 data.bkglyph = bkglyph;
1292 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1293 (WPARAM) MSNH_MSG_PRINT_GLYPH, (LPARAM) &data);
1298 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
1299 the user sees str. raw_print() appends a newline to str.
1300 It need not recognize ASCII control characters. This is
1301 used during startup (before windowing system initialization
1302 -- maybe this means only error startup messages are raw),
1303 for error messages, and maybe other "msg" uses. E.g.
1304 updating status for micros (i.e, "saving").
1306 void
1307 mswin_raw_print(const char *str)
1309 TCHAR wbuf[255];
1310 logDebug("mswin_raw_print(%s)\n", str);
1311 if (str && *str) {
1312 extern int redirect_stdout;
1313 if (!redirect_stdout)
1314 NHMessageBox(GetNHApp()->hMainWnd,
1315 NH_A2W(str, wbuf, sizeof(wbuf)),
1316 MB_ICONINFORMATION | MB_OK);
1317 else
1318 fprintf(stdout, "%s", str);
1323 raw_print_bold(str)
1324 -- Like raw_print(), but prints in bold/standout (if
1325 possible).
1327 void
1328 mswin_raw_print_bold(const char *str)
1330 TCHAR wbuf[255];
1331 logDebug("mswin_raw_print_bold(%s)\n", str);
1332 if (str && *str)
1333 NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)),
1334 MB_ICONINFORMATION | MB_OK);
1338 int nhgetch() -- Returns a single character input from the user.
1339 -- In the tty window-port, nhgetch() assumes that tgetch()
1340 will be the routine the OS provides to read a character.
1341 Returned character _must_ be non-zero.
1344 mswin_nhgetch()
1346 PMSNHEvent event;
1347 int key = 0;
1349 logDebug("mswin_nhgetch()\n");
1351 while ((event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR)
1352 mswin_main_loop();
1354 key = event->kbd.ch;
1355 return (key);
1359 int nh_poskey(int *x, int *y, int *mod)
1360 -- Returns a single character input from the user or a
1361 a positioning event (perhaps from a mouse). If the
1362 return value is non-zero, a character was typed, else,
1363 a position in the MAP window is returned in x, y and mod.
1364 mod may be one of
1366 CLICK_1 -- mouse click type 1
1367 CLICK_2 -- mouse click type 2
1369 The different click types can map to whatever the
1370 hardware supports. If no mouse is supported, this
1371 routine always returns a non-zero character.
1374 mswin_nh_poskey(int *x, int *y, int *mod)
1376 PMSNHEvent event;
1377 int key;
1379 logDebug("mswin_nh_poskey()\n");
1381 while ((event = mswin_input_pop()) == NULL)
1382 mswin_main_loop();
1384 if (event->type == NHEVENT_MOUSE) {
1385 *mod = event->ms.mod;
1386 *x = event->ms.x;
1387 *y = event->ms.y;
1388 key = 0;
1389 } else {
1390 key = event->kbd.ch;
1392 return (key);
1396 nhbell() -- Beep at user. [This will exist at least until sounds are
1397 redone, since sounds aren't attributable to windows
1398 anyway.]
1400 void
1401 mswin_nhbell()
1403 logDebug("mswin_nhbell()\n");
1407 doprev_message()
1408 -- Display previous messages. Used by the ^P command.
1409 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1412 mswin_doprev_message()
1414 logDebug("mswin_doprev_message()\n");
1415 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL,
1416 MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
1417 return 0;
1421 char yn_function(const char *ques, const char *choices, char default)
1422 -- Print a prompt made up of ques, choices and default.
1423 Read a single character response that is contained in
1424 choices or default. If choices is NULL, all possible
1425 inputs are accepted and returned. This overrides
1426 everything else. The choices are expected to be in
1427 lower case. Entering ESC always maps to 'q', or 'n',
1428 in that order, if present in choices, otherwise it maps
1429 to default. Entering any other quit character (SPACE,
1430 RETURN, NEWLINE) maps to default.
1431 -- If the choices string contains ESC, then anything after
1432 it is an acceptable response, but the ESC and whatever
1433 follows is not included in the prompt.
1434 -- If the choices string contains a '#' then accept a count.
1435 Place this value in the global "yn_number" and return '#'.
1436 -- This uses the top line in the tty window-port, other
1437 ports might use a popup.
1439 char
1440 mswin_yn_function(const char *question, const char *choices, CHAR_P def)
1442 char ch;
1443 char yn_esc_map = '\033';
1444 char message[BUFSZ];
1445 char res_ch[2];
1446 int createcaret;
1447 boolean digit_ok, allow_num;
1449 logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def);
1451 if (WIN_MESSAGE == WIN_ERR && choices == ynchars) {
1452 char *text =
1453 realloc(strdup(GetNHApp()->saved_text),
1454 strlen(question) + strlen(GetNHApp()->saved_text) + 1);
1455 DWORD box_result;
1456 strcat(text, question);
1457 box_result =
1458 NHMessageBox(NULL, NH_W2A(text, message, sizeof(message)),
1459 MB_ICONQUESTION | MB_YESNOCANCEL
1460 | ((def == 'y') ? MB_DEFBUTTON1
1461 : (def == 'n') ? MB_DEFBUTTON2
1462 : MB_DEFBUTTON3));
1463 free(text);
1464 GetNHApp()->saved_text = strdup("");
1465 return box_result == IDYES ? 'y' : box_result == IDNO ? 'n' : '\033';
1468 if (choices) {
1469 char *cb, choicebuf[QBUFSZ];
1471 allow_num = (index(choices, '#') != 0);
1473 Strcpy(choicebuf, choices);
1474 if ((cb = index(choicebuf, '\033')) != 0) {
1475 /* anything beyond <esc> is hidden */
1476 *cb = '\0';
1478 (void) strncpy(message, question, QBUFSZ - 1);
1479 message[QBUFSZ - 1] = '\0';
1480 sprintf(eos(message), " [%s]", choicebuf);
1481 if (def)
1482 sprintf(eos(message), " (%c)", def);
1483 Strcat(message, " ");
1484 /* escape maps to 'q' or 'n' or default, in that order */
1485 yn_esc_map =
1486 (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def));
1487 } else {
1488 Strcpy(message, question);
1489 Strcat(message, " ");
1492 createcaret = 1;
1493 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1494 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1496 mswin_clear_nhwindow(WIN_MESSAGE);
1497 mswin_putstr(WIN_MESSAGE, ATR_BOLD, message);
1499 /* Only here if main window is not present */
1500 ch = 0;
1501 do {
1502 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1503 ch = mswin_nhgetch();
1504 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1505 if (choices)
1506 ch = lowc(ch);
1507 else
1508 break; /* If choices is NULL, all possible inputs are accepted and
1509 returned. */
1511 digit_ok = allow_num && digit(ch);
1512 if (ch == '\033') {
1513 if (index(choices, 'q'))
1514 ch = 'q';
1515 else if (index(choices, 'n'))
1516 ch = 'n';
1517 else
1518 ch = def;
1519 break;
1520 } else if (index(quitchars, ch)) {
1521 ch = def;
1522 break;
1523 } else if (!index(choices, ch) && !digit_ok) {
1524 mswin_nhbell();
1525 ch = (char) 0;
1526 /* and try again... */
1527 } else if (ch == '#' || digit_ok) {
1528 char z, digit_string[2];
1529 int n_len = 0;
1530 long value = 0;
1531 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, ("#"), 1);
1532 n_len++;
1533 digit_string[1] = '\0';
1534 if (ch != '#') {
1535 digit_string[0] = ch;
1536 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1);
1537 n_len++;
1538 value = ch - '0';
1539 ch = '#';
1541 do { /* loop until we get a non-digit */
1542 z = lowc(readchar());
1543 if (digit(z)) {
1544 value = (10 * value) + (z - '0');
1545 if (value < 0)
1546 break; /* overflow: try again */
1547 digit_string[0] = z;
1548 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1);
1549 n_len++;
1550 } else if (z == 'y' || index(quitchars, z)) {
1551 if (z == '\033')
1552 value = -1; /* abort */
1553 z = '\n'; /* break */
1554 } else if (z == '\b') {
1555 if (n_len <= 1) {
1556 value = -1;
1557 break;
1558 } else {
1559 value /= 10;
1560 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string,
1561 -1);
1562 n_len--;
1564 } else {
1565 value = -1; /* abort */
1566 mswin_nhbell();
1567 break;
1569 } while (z != '\n');
1570 if (value > 0)
1571 yn_number = value;
1572 else if (value == 0)
1573 ch = 'n'; /* 0 => "no" */
1574 else { /* remove number from top line, then try again */
1575 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -n_len);
1576 n_len = 0;
1577 ch = (char) 0;
1580 } while (!ch);
1582 createcaret = 0;
1583 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1584 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1586 /* display selection in the message window */
1587 if (isprint((uchar) ch) && ch != '#') {
1588 res_ch[0] = ch;
1589 res_ch[1] = '\x0';
1590 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1);
1593 return ch;
1597 getlin(const char *ques, char *input)
1598 -- Prints ques as a prompt and reads a single line of text,
1599 up to a newline. The string entered is returned without the
1600 newline. ESC is used to cancel, in which case the string
1601 "\033\000" is returned.
1602 -- getlin() must call flush_screen(1) before doing anything.
1603 -- This uses the top line in the tty window-port, other
1604 ports might use a popup.
1606 void
1607 mswin_getlin(const char *question, char *input)
1609 logDebug("mswin_getlin(%s, %p)\n", question, input);
1611 if (!iflags.wc_popup_dialog) {
1612 char c;
1613 int len;
1614 int done;
1615 int createcaret;
1617 createcaret = 1;
1618 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1619 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1621 mswin_clear_nhwindow(WIN_MESSAGE);
1622 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, question, 0);
1623 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, " ", 1);
1624 input[0] = '\0';
1625 len = 0;
1626 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1627 done = FALSE;
1628 while (!done) {
1629 c = mswin_nhgetch();
1630 switch (c) {
1631 case VK_ESCAPE:
1632 strcpy(input, "\033");
1633 done = TRUE;
1634 break;
1635 case '\n':
1636 case '\r':
1637 case -115:
1638 done = TRUE;
1639 break;
1640 default:
1641 if (input[0])
1642 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, -len);
1643 if (c == VK_BACK) {
1644 if (len > 0)
1645 len--;
1646 input[len] = '\0';
1647 } else if (len>=(BUFSZ-1)) {
1648 PlaySound((LPCSTR)SND_ALIAS_SYSTEMEXCLAMATION, NULL, SND_ALIAS_ID|SND_ASYNC);
1649 } else {
1650 input[len++] = c;
1651 input[len] = '\0';
1653 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, 1);
1654 break;
1657 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1658 createcaret = 0;
1659 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1660 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1661 } else {
1662 if (mswin_getlin_window(question, input, BUFSZ) == IDCANCEL) {
1663 strcpy(input, "\033");
1669 int get_ext_cmd(void)
1670 -- Get an extended command in a window-port specific way.
1671 An index into extcmdlist[] is returned on a successful
1672 selection, -1 otherwise.
1675 mswin_get_ext_cmd()
1677 int ret;
1678 logDebug("mswin_get_ext_cmd()\n");
1680 if (!iflags.wc_popup_dialog) {
1681 char c;
1682 char cmd[BUFSZ];
1683 int i, len;
1684 int createcaret;
1686 createcaret = 1;
1687 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1688 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1690 cmd[0] = '\0';
1691 i = -2;
1692 mswin_clear_nhwindow(WIN_MESSAGE);
1693 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, "#", 0);
1694 len = 0;
1695 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1696 while (i == -2) {
1697 int oindex, com_index;
1698 c = mswin_nhgetch();
1699 switch (c) {
1700 case VK_ESCAPE:
1701 i = -1;
1702 break;
1703 case '\n':
1704 case '\r':
1705 case -115:
1706 for (i = 0; extcmdlist[i].ef_txt != (char *) 0; i++)
1707 if (!strcmpi(cmd, extcmdlist[i].ef_txt))
1708 break;
1710 if (extcmdlist[i].ef_txt == (char *) 0) {
1711 pline("%s: unknown extended command.", cmd);
1712 i = -1;
1714 break;
1715 default:
1716 if (cmd[0])
1717 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd,
1718 -(int) strlen(cmd));
1719 if (c == VK_BACK) {
1720 if (len > 0)
1721 len--;
1722 cmd[len] = '\0';
1723 } else {
1724 cmd[len++] = c;
1725 cmd[len] = '\0';
1726 /* Find a command with this prefix in extcmdlist */
1727 com_index = -1;
1728 for (oindex = 0; extcmdlist[oindex].ef_txt != (char *) 0;
1729 oindex++) {
1730 if ((extcmdlist[oindex].flags & AUTOCOMPLETE)
1731 && !(!wizard && (extcmdlist[oindex].flags & WIZMODECMD))
1732 && !strncmpi(cmd, extcmdlist[oindex].ef_txt, len)) {
1733 if (com_index == -1) /* no matches yet */
1734 com_index = oindex;
1735 else
1736 com_index =
1737 -2; /* two matches, don't complete */
1740 if (com_index >= 0) {
1741 Strcpy(cmd, extcmdlist[com_index].ef_txt);
1744 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, 1);
1745 break;
1748 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE));
1749 createcaret = 0;
1750 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1751 (WPARAM) MSNH_MSG_CARET, (LPARAM) &createcaret);
1752 return i;
1753 } else {
1754 if (mswin_ext_cmd_window(&ret) == IDCANCEL)
1755 return -1;
1756 else
1757 return ret;
1762 number_pad(state)
1763 -- Initialize the number pad to the given state.
1765 void
1766 mswin_number_pad(int state)
1768 /* Do Nothing */
1769 logDebug("mswin_number_pad(%d)\n", state);
1773 delay_output() -- Causes a visible delay of 50ms in the output.
1774 Conceptually, this is similar to wait_synch() followed
1775 by a nap(50ms), but allows asynchronous operation.
1777 void
1778 mswin_delay_output()
1780 logDebug("mswin_delay_output()\n");
1781 Sleep(50);
1784 void
1785 mswin_change_color()
1787 logDebug("mswin_change_color()\n");
1790 char *
1791 mswin_get_color_string()
1793 logDebug("mswin_get_color_string()\n");
1794 return ("");
1798 start_screen() -- Only used on Unix tty ports, but must be declared for
1799 completeness. Sets up the tty to work in full-screen
1800 graphics mode. Look at win/tty/termcap.c for an
1801 example. If your window-port does not need this function
1802 just declare an empty function.
1804 void
1805 mswin_start_screen()
1807 /* Do Nothing */
1808 logDebug("mswin_start_screen()\n");
1812 end_screen() -- Only used on Unix tty ports, but must be declared for
1813 completeness. The complement of start_screen().
1815 void
1816 mswin_end_screen()
1818 /* Do Nothing */
1819 logDebug("mswin_end_screen()\n");
1823 outrip(winid, int, when)
1824 -- The tombstone code. If you want the traditional code use
1825 genl_outrip for the value and check the #if in rip.c.
1827 #define STONE_LINE_LEN 16
1828 void
1829 mswin_outrip(winid wid, int how, time_t when)
1831 char buf[BUFSZ];
1832 long year;
1834 logDebug("mswin_outrip(%d, %d, %ld)\n", wid, how, (long) when);
1835 if ((wid >= 0) && (wid < MAXWINDOWS)) {
1836 DestroyWindow(GetNHApp()->windowlist[wid].win);
1837 GetNHApp()->windowlist[wid].win = mswin_init_RIP_window();
1838 GetNHApp()->windowlist[wid].type = NHW_RIP;
1839 GetNHApp()->windowlist[wid].dead = 0;
1842 /* Put name on stone */
1843 Sprintf(buf, "%s", plname);
1844 buf[STONE_LINE_LEN] = 0;
1845 putstr(wid, 0, buf);
1847 /* Put $ on stone */
1848 Sprintf(buf, "%ld Au", done_money);
1849 buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
1850 putstr(wid, 0, buf);
1852 /* Put together death description */
1853 formatkiller(buf, sizeof buf, how, FALSE);
1855 /* Put death type on stone */
1856 putstr(wid, 0, buf);
1858 /* Put year on stone */
1859 year = yyyymmdd(when) / 10000L;
1860 Sprintf(buf, "%4ld", year);
1861 putstr(wid, 0, buf);
1862 mswin_finish_rip_text(wid);
1865 /* handle options updates here */
1866 void
1867 mswin_preference_update(const char *pref)
1869 HDC hdc;
1870 int i;
1872 if (stricmp(pref, "font_menu") == 0
1873 || stricmp(pref, "font_size_menu") == 0) {
1874 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
1875 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
1876 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
1878 hdc = GetDC(GetNHApp()->hMainWnd);
1879 mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE);
1880 mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE);
1881 mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE);
1882 mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE);
1883 mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE);
1884 mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE);
1885 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1887 mswin_layout_main_window(NULL);
1888 return;
1891 if (stricmp(pref, "font_status") == 0
1892 || stricmp(pref, "font_size_status") == 0) {
1893 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
1894 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
1895 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
1897 hdc = GetDC(GetNHApp()->hMainWnd);
1898 mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE);
1899 mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE);
1900 mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE);
1901 mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE);
1902 mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE);
1903 mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE);
1904 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1906 for (i = 1; i < MAXWINDOWS; i++) {
1907 if (GetNHApp()->windowlist[i].type == NHW_STATUS
1908 && GetNHApp()->windowlist[i].win != NULL) {
1909 InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE);
1912 mswin_layout_main_window(NULL);
1913 return;
1916 if (stricmp(pref, "font_message") == 0
1917 || stricmp(pref, "font_size_message") == 0) {
1918 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
1919 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
1920 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
1922 hdc = GetDC(GetNHApp()->hMainWnd);
1923 mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE);
1924 mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE);
1925 mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE);
1926 mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE);
1927 mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE);
1928 mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE);
1929 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1931 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1932 mswin_layout_main_window(NULL);
1933 return;
1936 if (stricmp(pref, "font_text") == 0
1937 || stricmp(pref, "font_size_text") == 0) {
1938 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
1939 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
1940 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
1942 hdc = GetDC(GetNHApp()->hMainWnd);
1943 mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE);
1944 mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE);
1945 mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE);
1946 mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE);
1947 mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE);
1948 mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE);
1949 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1951 mswin_layout_main_window(NULL);
1952 return;
1955 if (stricmp(pref, "scroll_amount") == 0) {
1956 mswin_cliparound(u.ux, u.uy);
1957 return;
1960 if (stricmp(pref, "scroll_margin") == 0) {
1961 mswin_cliparound(u.ux, u.uy);
1962 return;
1965 if (stricmp(pref, "map_mode") == 0) {
1966 mswin_select_map_mode(iflags.wc_map_mode);
1967 return;
1970 if (stricmp(pref, "hilite_pet") == 0) {
1971 InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE);
1972 return;
1975 if (stricmp(pref, "align_message") == 0
1976 || stricmp(pref, "align_status") == 0) {
1977 mswin_layout_main_window(NULL);
1978 return;
1981 if (stricmp(pref, "vary_msgcount") == 0) {
1982 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1983 mswin_layout_main_window(NULL);
1984 return;
1987 if (stricmp(pref, "perm_invent") == 0) {
1988 mswin_update_inventory();
1989 return;
1993 #define TEXT_BUFFER_SIZE 4096
1994 char *
1995 mswin_getmsghistory(BOOLEAN_P init)
1997 static PMSNHMsgGetText text = 0;
1998 static char *next_message = 0;
2000 if (init) {
2001 text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText)
2002 + TEXT_BUFFER_SIZE);
2003 text->max_size =
2004 TEXT_BUFFER_SIZE
2005 - 1; /* make sure we always have 0 at the end of the buffer */
2007 ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
2008 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
2009 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
2011 next_message = text->buffer;
2014 if (!(next_message && next_message[0])) {
2015 free(text);
2016 next_message = 0;
2017 return (char *) 0;
2018 } else {
2019 char *retval = next_message;
2020 char *p;
2021 next_message = p = strchr(next_message, '\n');
2022 if (next_message)
2023 next_message++;
2024 if (p)
2025 while (p >= retval && isspace((uchar) *p))
2026 *p-- = (char) 0; /* delete trailing whitespace */
2027 return retval;
2031 void
2032 mswin_putmsghistory(const char *msg, BOOLEAN_P restoring)
2034 BOOL save_sound_opt;
2036 UNREFERENCED_PARAMETER(restoring);
2038 if (!msg)
2039 return; /* end of message history restore */
2040 save_sound_opt = GetNHApp()->bNoSounds;
2041 GetNHApp()->bNoSounds =
2042 TRUE; /* disable sounds while restoring message history */
2043 mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, msg, 0);
2044 clear_nhwindow(WIN_MESSAGE); /* it is in fact end-of-turn indication so
2045 each message will print on the new line */
2046 GetNHApp()->bNoSounds = save_sound_opt; /* restore sounds option */
2049 void
2050 mswin_main_loop()
2052 MSG msg;
2054 while (!mswin_have_input() && GetMessage(&msg, NULL, 0, 0) != 0) {
2055 if (GetNHApp()->regNetHackMode
2056 || !TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable,
2057 &msg)) {
2058 TranslateMessage(&msg);
2059 DispatchMessage(&msg);
2064 /* clean up and quit */
2065 void
2066 bail(const char *mesg)
2068 clearlocks();
2069 mswin_exit_nhwindows(mesg);
2070 terminate(EXIT_SUCCESS);
2071 /*NOTREACHED*/
2074 BOOL
2075 initMapTiles(void)
2077 HBITMAP hBmp;
2078 BITMAP bm;
2079 TCHAR wbuf[MAX_PATH];
2080 int tl_num;
2081 SIZE map_size;
2082 extern int total_tiles_used;
2084 /* no file - no tile */
2085 if (!(iflags.wc_tile_file && *iflags.wc_tile_file))
2086 return TRUE;
2088 /* load bitmap */
2089 hBmp = LoadImage(GetNHApp()->hApp,
2090 NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH),
2091 IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
2092 if (hBmp == NULL) {
2093 raw_print(
2094 "Cannot load tiles from the file. Reverting back to default.");
2095 return FALSE;
2098 /* calculate tile dimensions */
2099 GetObject(hBmp, sizeof(BITMAP), (LPVOID) &bm);
2100 if (bm.bmWidth % iflags.wc_tile_width
2101 || bm.bmHeight % iflags.wc_tile_height) {
2102 DeleteObject(hBmp);
2103 raw_print("Tiles bitmap does not match tile_width and tile_height "
2104 "options. Reverting back to default.");
2105 return FALSE;
2108 tl_num = (bm.bmWidth / iflags.wc_tile_width)
2109 * (bm.bmHeight / iflags.wc_tile_height);
2110 if (tl_num < total_tiles_used) {
2111 DeleteObject(hBmp);
2112 raw_print("Number of tiles in the bitmap is less than required by "
2113 "the game. Reverting back to default.");
2114 return FALSE;
2117 /* set the tile information */
2118 if (GetNHApp()->bmpMapTiles != GetNHApp()->bmpTiles) {
2119 DeleteObject(GetNHApp()->bmpMapTiles);
2122 GetNHApp()->bmpMapTiles = hBmp;
2123 GetNHApp()->mapTile_X = iflags.wc_tile_width;
2124 GetNHApp()->mapTile_Y = iflags.wc_tile_height;
2125 GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width;
2127 map_size.cx = GetNHApp()->mapTile_X * COLNO;
2128 map_size.cy = GetNHApp()->mapTile_Y * ROWNO;
2129 mswin_map_stretch(mswin_hwnd_from_winid(WIN_MAP), &map_size, TRUE);
2130 return TRUE;
2133 void
2134 mswin_popup_display(HWND hWnd, int *done_indicator)
2136 MSG msg;
2137 HWND hChild;
2138 HMENU hMenu;
2139 int mi_count;
2140 int i;
2142 /* activate the menu window */
2143 GetNHApp()->hPopupWnd = hWnd;
2145 mswin_layout_main_window(hWnd);
2147 /* disable game windows */
2148 for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild;
2149 hChild = GetWindow(hChild, GW_HWNDNEXT)) {
2150 if (hChild != hWnd)
2151 EnableWindow(hChild, FALSE);
2154 /* disable menu */
2155 hMenu = GetMenu(GetNHApp()->hMainWnd);
2156 mi_count = GetMenuItemCount(hMenu);
2157 for (i = 0; i < mi_count; i++) {
2158 EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_GRAYED);
2160 DrawMenuBar(GetNHApp()->hMainWnd);
2162 /* bring menu window on top */
2163 SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
2164 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
2165 SetFocus(hWnd);
2167 /* go into message loop */
2168 while (IsWindow(hWnd) && (done_indicator == NULL || !*done_indicator)
2169 && GetMessage(&msg, NULL, 0, 0) != 0) {
2170 if (!IsDialogMessage(hWnd, &msg)) {
2171 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable,
2172 &msg)) {
2173 TranslateMessage(&msg);
2174 DispatchMessage(&msg);
2180 void
2181 mswin_popup_destroy(HWND hWnd)
2183 HWND hChild;
2184 HMENU hMenu;
2185 int mi_count;
2186 int i;
2188 /* enable game windows */
2189 for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild;
2190 hChild = GetWindow(hChild, GW_HWNDNEXT)) {
2191 if (hChild != hWnd) {
2192 EnableWindow(hChild, TRUE);
2196 /* enable menu */
2197 hMenu = GetMenu(GetNHApp()->hMainWnd);
2198 mi_count = GetMenuItemCount(hMenu);
2199 for (i = 0; i < mi_count; i++) {
2200 EnableMenuItem(hMenu, i, MF_BYPOSITION | MF_ENABLED);
2202 DrawMenuBar(GetNHApp()->hMainWnd);
2204 ShowWindow(hWnd, SW_HIDE);
2205 GetNHApp()->hPopupWnd = NULL;
2207 mswin_layout_main_window(hWnd);
2209 SetFocus(GetNHApp()->hMainWnd);
2212 #ifdef DEBUG
2213 # ifdef _DEBUG
2214 #include <stdarg.h>
2216 void
2217 logDebug(const char *fmt, ...)
2219 va_list args;
2221 if (!showdebug(NHTRACE_LOG) || !_s_debugfp)
2222 return;
2224 va_start(args, fmt);
2225 vfprintf(_s_debugfp, fmt, args);
2226 va_end(args);
2227 fflush(_s_debugfp);
2229 # endif
2230 #endif
2232 /* Reading and writing settings from the registry. */
2233 #define CATEGORYKEY "Software"
2234 #define COMPANYKEY "NetHack"
2235 #define PRODUCTKEY "NetHack 3.6.1"
2236 #define SETTINGSKEY "Settings"
2237 #define MAINSHOWSTATEKEY "MainShowState"
2238 #define MAINMINXKEY "MainMinX"
2239 #define MAINMINYKEY "MainMinY"
2240 #define MAINMAXXKEY "MainMaxX"
2241 #define MAINMAXYKEY "MainMaxY"
2242 #define MAINLEFTKEY "MainLeft"
2243 #define MAINRIGHTKEY "MainRight"
2244 #define MAINTOPKEY "MainTop"
2245 #define MAINBOTTOMKEY "MainBottom"
2246 #define MAINAUTOLAYOUT "AutoLayout"
2247 #define MAPLEFT "MapLeft"
2248 #define MAPRIGHT "MapRight"
2249 #define MAPTOP "MapTop"
2250 #define MAPBOTTOM "MapBottom"
2251 #define MSGLEFT "MsgLeft"
2252 #define MSGRIGHT "MsgRight"
2253 #define MSGTOP "MsgTop"
2254 #define MSGBOTTOM "MsgBottom"
2255 #define STATUSLEFT "StatusLeft"
2256 #define STATUSRIGHT "StatusRight"
2257 #define STATUSTOP "StatusTop"
2258 #define STATUSBOTTOM "StatusBottom"
2259 #define MENULEFT "MenuLeft"
2260 #define MENURIGHT "MenuRight"
2261 #define MENUTOP "MenuTop"
2262 #define MENUBOTTOM "MenuBottom"
2263 #define TEXTLEFT "TextLeft"
2264 #define TEXTRIGHT "TextRight"
2265 #define TEXTTOP "TextTop"
2266 #define TEXTBOTTOM "TextBottom"
2267 #define INVENTLEFT "InventLeft"
2268 #define INVENTRIGHT "InventRight"
2269 #define INVENTTOP "InventTop"
2270 #define INVENTBOTTOM "InventBottom"
2272 /* #define all the subkeys here */
2273 #define INTFKEY "Interface"
2275 void
2276 mswin_read_reg()
2278 HKEY key;
2279 DWORD size;
2280 DWORD safe_buf;
2281 char keystring[MAX_PATH];
2282 int i;
2283 COLORREF default_mapcolors[CLR_MAX] = {
2284 RGB(0x55, 0x55, 0x55), /* CLR_BLACK */
2285 RGB(0xFF, 0x00, 0x00), /* CLR_RED */
2286 RGB(0x00, 0x80, 0x00), /* CLR_GREEN */
2287 RGB(0xA5, 0x2A, 0x2A), /* CLR_BROWN */
2288 RGB(0x00, 0x00, 0xFF), /* CLR_BLUE */
2289 RGB(0xFF, 0x00, 0xFF), /* CLR_MAGENTA */
2290 RGB(0x00, 0xFF, 0xFF), /* CLR_CYAN */
2291 RGB(0xC0, 0xC0, 0xC0), /* CLR_GRAY */
2292 RGB(0xFF, 0xFF, 0xFF), /* NO_COLOR */
2293 RGB(0xFF, 0xA5, 0x00), /* CLR_ORANGE */
2294 RGB(0x00, 0xFF, 0x00), /* CLR_BRIGHT_GREEN */
2295 RGB(0xFF, 0xFF, 0x00), /* CLR_YELLOW */
2296 RGB(0x00, 0xC0, 0xFF), /* CLR_BRIGHT_BLUE */
2297 RGB(0xFF, 0x80, 0xFF), /* CLR_BRIGHT_MAGENTA */
2298 RGB(0x80, 0xFF, 0xFF), /* CLR_BRIGHT_CYAN */
2299 RGB(0xFF, 0xFF, 0xFF) /* CLR_WHITE */
2302 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY,
2303 SETTINGSKEY);
2305 /* Set the defaults here. The very first time the app is started, nothing
2307 read from the registry, so these defaults apply. */
2308 GetNHApp()->saveRegistrySettings = 1; /* Normally, we always save */
2309 GetNHApp()->regNetHackMode = TRUE;
2311 for (i = 0; i < CLR_MAX; i++)
2312 GetNHApp()->regMapColors[i] = default_mapcolors[i];
2314 if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key)
2315 != ERROR_SUCCESS)
2316 return;
2318 size = sizeof(DWORD);
2320 #define NHGETREG_DWORD(name, val) \
2321 RegQueryValueEx(key, (name), 0, NULL, (unsigned char *)(&safe_buf), \
2322 &size); \
2323 (val) = safe_buf;
2325 /* read the keys here */
2326 NHGETREG_DWORD(INTFKEY, GetNHApp()->regNetHackMode);
2328 /* read window placement */
2329 NHGETREG_DWORD(MAINSHOWSTATEKEY, GetNHApp()->regMainShowState);
2330 NHGETREG_DWORD(MAINMINXKEY, GetNHApp()->regMainMinX);
2331 NHGETREG_DWORD(MAINMINYKEY, GetNHApp()->regMainMinY);
2332 NHGETREG_DWORD(MAINMAXXKEY, GetNHApp()->regMainMaxX);
2333 NHGETREG_DWORD(MAINMAXYKEY, GetNHApp()->regMainMaxY);
2334 NHGETREG_DWORD(MAINLEFTKEY, GetNHApp()->regMainLeft);
2335 NHGETREG_DWORD(MAINRIGHTKEY, GetNHApp()->regMainRight);
2336 NHGETREG_DWORD(MAINTOPKEY, GetNHApp()->regMainTop);
2337 NHGETREG_DWORD(MAINBOTTOMKEY, GetNHApp()->regMainBottom);
2339 NHGETREG_DWORD(MAINAUTOLAYOUT, GetNHApp()->bAutoLayout);
2340 NHGETREG_DWORD(MAPLEFT, GetNHApp()->rtMapWindow.left);
2341 NHGETREG_DWORD(MAPRIGHT, GetNHApp()->rtMapWindow.right);
2342 NHGETREG_DWORD(MAPTOP, GetNHApp()->rtMapWindow.top);
2343 NHGETREG_DWORD(MAPBOTTOM, GetNHApp()->rtMapWindow.bottom);
2344 NHGETREG_DWORD(MSGLEFT, GetNHApp()->rtMsgWindow.left);
2345 NHGETREG_DWORD(MSGRIGHT, GetNHApp()->rtMsgWindow.right);
2346 NHGETREG_DWORD(MSGTOP, GetNHApp()->rtMsgWindow.top);
2347 NHGETREG_DWORD(MSGBOTTOM, GetNHApp()->rtMsgWindow.bottom);
2348 NHGETREG_DWORD(STATUSLEFT, GetNHApp()->rtStatusWindow.left);
2349 NHGETREG_DWORD(STATUSRIGHT, GetNHApp()->rtStatusWindow.right);
2350 NHGETREG_DWORD(STATUSTOP, GetNHApp()->rtStatusWindow.top);
2351 NHGETREG_DWORD(STATUSBOTTOM, GetNHApp()->rtStatusWindow.bottom);
2352 NHGETREG_DWORD(MENULEFT, GetNHApp()->rtMenuWindow.left);
2353 NHGETREG_DWORD(MENURIGHT, GetNHApp()->rtMenuWindow.right);
2354 NHGETREG_DWORD(MENUTOP, GetNHApp()->rtMenuWindow.top);
2355 NHGETREG_DWORD(MENUBOTTOM, GetNHApp()->rtMenuWindow.bottom);
2356 NHGETREG_DWORD(TEXTLEFT, GetNHApp()->rtTextWindow.left);
2357 NHGETREG_DWORD(TEXTRIGHT, GetNHApp()->rtTextWindow.right);
2358 NHGETREG_DWORD(TEXTTOP, GetNHApp()->rtTextWindow.top);
2359 NHGETREG_DWORD(TEXTBOTTOM, GetNHApp()->rtTextWindow.bottom);
2360 NHGETREG_DWORD(INVENTLEFT, GetNHApp()->rtInvenWindow.left);
2361 NHGETREG_DWORD(INVENTRIGHT, GetNHApp()->rtInvenWindow.right);
2362 NHGETREG_DWORD(INVENTTOP, GetNHApp()->rtInvenWindow.top);
2363 NHGETREG_DWORD(INVENTBOTTOM, GetNHApp()->rtInvenWindow.bottom);
2364 #undef NHGETREG_DWORD
2366 for (i = 0; i < CLR_MAX; i++) {
2367 COLORREF cl;
2368 char mapcolorkey[64];
2369 sprintf(mapcolorkey, "MapColor%02d", i);
2370 if (RegQueryValueEx(key, mapcolorkey, NULL, NULL, (BYTE *)&cl, &size) == ERROR_SUCCESS)
2371 GetNHApp()->regMapColors[i] = cl;
2374 RegCloseKey(key);
2376 /* check the data for validity */
2377 if (IsRectEmpty(&GetNHApp()->rtMapWindow)
2378 || IsRectEmpty(&GetNHApp()->rtMsgWindow)
2379 || IsRectEmpty(&GetNHApp()->rtStatusWindow)
2380 || IsRectEmpty(&GetNHApp()->rtMenuWindow)
2381 || IsRectEmpty(&GetNHApp()->rtTextWindow)
2382 || IsRectEmpty(&GetNHApp()->rtInvenWindow)) {
2383 GetNHApp()->bAutoLayout = TRUE;
2387 void
2388 mswin_write_reg()
2390 HKEY key;
2391 DWORD disposition;
2392 int i;
2394 if (GetNHApp()->saveRegistrySettings) {
2395 char keystring[MAX_PATH];
2396 DWORD safe_buf;
2398 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY,
2399 PRODUCTKEY, SETTINGSKEY);
2401 if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key)
2402 != ERROR_SUCCESS) {
2403 RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "",
2404 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
2405 &key, &disposition);
2408 #define NHSETREG_DWORD(name, val) \
2409 RegSetValueEx(key, (name), 0, REG_DWORD, \
2410 (unsigned char *)((safe_buf = (val)), &safe_buf), \
2411 sizeof(DWORD));
2413 /* Write the keys here */
2414 NHSETREG_DWORD(INTFKEY, GetNHApp()->regNetHackMode);
2416 /* Main window placement */
2417 NHSETREG_DWORD(MAINSHOWSTATEKEY, GetNHApp()->regMainShowState);
2418 NHSETREG_DWORD(MAINMINXKEY, GetNHApp()->regMainMinX);
2419 NHSETREG_DWORD(MAINMINYKEY, GetNHApp()->regMainMinY);
2420 NHSETREG_DWORD(MAINMAXXKEY, GetNHApp()->regMainMaxX);
2421 NHSETREG_DWORD(MAINMAXYKEY, GetNHApp()->regMainMaxY);
2422 NHSETREG_DWORD(MAINLEFTKEY, GetNHApp()->regMainLeft);
2423 NHSETREG_DWORD(MAINRIGHTKEY, GetNHApp()->regMainRight);
2424 NHSETREG_DWORD(MAINTOPKEY, GetNHApp()->regMainTop);
2425 NHSETREG_DWORD(MAINBOTTOMKEY, GetNHApp()->regMainBottom);
2427 NHSETREG_DWORD(MAINAUTOLAYOUT, GetNHApp()->bAutoLayout);
2428 NHSETREG_DWORD(MAPLEFT, GetNHApp()->rtMapWindow.left);
2429 NHSETREG_DWORD(MAPRIGHT, GetNHApp()->rtMapWindow.right);
2430 NHSETREG_DWORD(MAPTOP, GetNHApp()->rtMapWindow.top);
2431 NHSETREG_DWORD(MAPBOTTOM, GetNHApp()->rtMapWindow.bottom);
2432 NHSETREG_DWORD(MSGLEFT, GetNHApp()->rtMsgWindow.left);
2433 NHSETREG_DWORD(MSGRIGHT, GetNHApp()->rtMsgWindow.right);
2434 NHSETREG_DWORD(MSGTOP, GetNHApp()->rtMsgWindow.top);
2435 NHSETREG_DWORD(MSGBOTTOM, GetNHApp()->rtMsgWindow.bottom);
2436 NHSETREG_DWORD(STATUSLEFT, GetNHApp()->rtStatusWindow.left);
2437 NHSETREG_DWORD(STATUSRIGHT, GetNHApp()->rtStatusWindow.right);
2438 NHSETREG_DWORD(STATUSTOP, GetNHApp()->rtStatusWindow.top);
2439 NHSETREG_DWORD(STATUSBOTTOM, GetNHApp()->rtStatusWindow.bottom);
2440 NHSETREG_DWORD(MENULEFT, GetNHApp()->rtMenuWindow.left);
2441 NHSETREG_DWORD(MENURIGHT, GetNHApp()->rtMenuWindow.right);
2442 NHSETREG_DWORD(MENUTOP, GetNHApp()->rtMenuWindow.top);
2443 NHSETREG_DWORD(MENUBOTTOM, GetNHApp()->rtMenuWindow.bottom);
2444 NHSETREG_DWORD(TEXTLEFT, GetNHApp()->rtTextWindow.left);
2445 NHSETREG_DWORD(TEXTRIGHT, GetNHApp()->rtTextWindow.right);
2446 NHSETREG_DWORD(TEXTTOP, GetNHApp()->rtTextWindow.top);
2447 NHSETREG_DWORD(TEXTBOTTOM, GetNHApp()->rtTextWindow.bottom);
2448 NHSETREG_DWORD(INVENTLEFT, GetNHApp()->rtInvenWindow.left);
2449 NHSETREG_DWORD(INVENTRIGHT, GetNHApp()->rtInvenWindow.right);
2450 NHSETREG_DWORD(INVENTTOP, GetNHApp()->rtInvenWindow.top);
2451 NHSETREG_DWORD(INVENTBOTTOM, GetNHApp()->rtInvenWindow.bottom);
2452 #undef NHSETREG_DWORD
2454 for (i = 0; i < CLR_MAX; i++) {
2455 COLORREF cl = GetNHApp()->regMapColors[i];
2456 char mapcolorkey[64];
2457 sprintf(mapcolorkey, "MapColor%02d", i);
2458 RegSetValueEx(key, mapcolorkey, 0, REG_DWORD, (BYTE *)&cl, sizeof(DWORD));
2461 RegCloseKey(key);
2465 void
2466 mswin_destroy_reg()
2468 char keystring[MAX_PATH];
2469 HKEY key;
2470 DWORD nrsubkeys;
2472 /* Delete keys one by one, as NT does not delete trees */
2473 sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY,
2474 SETTINGSKEY);
2475 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2476 sprintf(keystring, "%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY);
2477 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2478 /* The company key will also contain information about newer versions
2479 of nethack (e.g. a subkey called NetHack 4.0), so only delete that
2480 if it's empty now. */
2481 sprintf(keystring, "%s\\%s", CATEGORYKEY, COMPANYKEY);
2482 /* If we cannot open it, we probably cannot delete it either... Just
2483 go on and see what happens. */
2484 RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key);
2485 nrsubkeys = 0;
2486 RegQueryInfoKey(key, NULL, NULL, NULL, &nrsubkeys, NULL, NULL, NULL, NULL,
2487 NULL, NULL, NULL);
2488 RegCloseKey(key);
2489 if (nrsubkeys == 0)
2490 RegDeleteKey(HKEY_CURRENT_USER, keystring);
2492 /* Prevent saving on exit */
2493 GetNHApp()->saveRegistrySettings = 0;
2496 typedef struct ctv {
2497 const char *colorstring;
2498 COLORREF colorvalue;
2499 } color_table_value;
2502 * The color list here is a combination of:
2503 * NetHack colors. (See mhmap.c)
2504 * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 )
2507 static color_table_value color_table[] = {
2508 /* NetHack colors */
2509 { "black", RGB(0x55, 0x55, 0x55) },
2510 { "red", RGB(0xFF, 0x00, 0x00) },
2511 { "green", RGB(0x00, 0x80, 0x00) },
2512 { "brown", RGB(0xA5, 0x2A, 0x2A) },
2513 { "blue", RGB(0x00, 0x00, 0xFF) },
2514 { "magenta", RGB(0xFF, 0x00, 0xFF) },
2515 { "cyan", RGB(0x00, 0xFF, 0xFF) },
2516 { "orange", RGB(0xFF, 0xA5, 0x00) },
2517 { "brightgreen", RGB(0x00, 0xFF, 0x00) },
2518 { "yellow", RGB(0xFF, 0xFF, 0x00) },
2519 { "brightblue", RGB(0x00, 0xC0, 0xFF) },
2520 { "brightmagenta", RGB(0xFF, 0x80, 0xFF) },
2521 { "brightcyan", RGB(0x80, 0xFF, 0xFF) },
2522 { "white", RGB(0xFF, 0xFF, 0xFF) },
2523 /* Remaining HTML colors */
2524 { "trueblack", RGB(0x00, 0x00, 0x00) },
2525 { "gray", RGB(0x80, 0x80, 0x80) },
2526 { "grey", RGB(0x80, 0x80, 0x80) },
2527 { "purple", RGB(0x80, 0x00, 0x80) },
2528 { "silver", RGB(0xC0, 0xC0, 0xC0) },
2529 { "maroon", RGB(0x80, 0x00, 0x00) },
2530 { "fuchsia", RGB(0xFF, 0x00, 0xFF) }, /* = NetHack magenta */
2531 { "lime", RGB(0x00, 0xFF, 0x00) }, /* = NetHack bright green */
2532 { "olive", RGB(0x80, 0x80, 0x00) },
2533 { "navy", RGB(0x00, 0x00, 0x80) },
2534 { "teal", RGB(0x00, 0x80, 0x80) },
2535 { "aqua", RGB(0x00, 0xFF, 0xFF) }, /* = NetHack cyan */
2536 { "", RGB(0x00, 0x00, 0x00) },
2539 typedef struct ctbv {
2540 char *colorstring;
2541 int syscolorvalue;
2542 } color_table_brush_value;
2544 static color_table_brush_value color_table_brush[] = {
2545 { "activeborder", COLOR_ACTIVEBORDER },
2546 { "activecaption", COLOR_ACTIVECAPTION },
2547 { "appworkspace", COLOR_APPWORKSPACE },
2548 { "background", COLOR_BACKGROUND },
2549 { "btnface", COLOR_BTNFACE },
2550 { "btnshadow", COLOR_BTNSHADOW },
2551 { "btntext", COLOR_BTNTEXT },
2552 { "captiontext", COLOR_CAPTIONTEXT },
2553 { "graytext", COLOR_GRAYTEXT },
2554 { "greytext", COLOR_GRAYTEXT },
2555 { "highlight", COLOR_HIGHLIGHT },
2556 { "highlighttext", COLOR_HIGHLIGHTTEXT },
2557 { "inactiveborder", COLOR_INACTIVEBORDER },
2558 { "inactivecaption", COLOR_INACTIVECAPTION },
2559 { "menu", COLOR_MENU },
2560 { "menutext", COLOR_MENUTEXT },
2561 { "scrollbar", COLOR_SCROLLBAR },
2562 { "window", COLOR_WINDOW },
2563 { "windowframe", COLOR_WINDOWFRAME },
2564 { "windowtext", COLOR_WINDOWTEXT },
2565 { "", -1 },
2568 static void
2569 mswin_color_from_string(char *colorstring, HBRUSH *brushptr,
2570 COLORREF *colorptr)
2572 color_table_value *ctv_ptr = color_table;
2573 color_table_brush_value *ctbv_ptr = color_table_brush;
2574 int red_value, blue_value, green_value;
2575 static char *hexadecimals = "0123456789abcdef";
2577 if (colorstring == NULL)
2578 return;
2579 if (*colorstring == '#') {
2580 if (strlen(++colorstring) != 6)
2581 return;
2583 red_value = (int) (index(hexadecimals, tolower((uchar) *colorstring))
2584 - hexadecimals);
2585 ++colorstring;
2586 red_value *= 16;
2587 red_value += (int) (index(hexadecimals, tolower((uchar) *colorstring))
2588 - hexadecimals);
2589 ++colorstring;
2591 green_value = (int) (index(hexadecimals,
2592 tolower((uchar) *colorstring))
2593 - hexadecimals);
2594 ++colorstring;
2595 green_value *= 16;
2596 green_value += (int) (index(hexadecimals,
2597 tolower((uchar) *colorstring))
2598 - hexadecimals);
2599 ++colorstring;
2601 blue_value = (int) (index(hexadecimals, tolower((uchar) *colorstring))
2602 - hexadecimals);
2603 ++colorstring;
2604 blue_value *= 16;
2605 blue_value += (int) (index(hexadecimals,
2606 tolower((uchar) *colorstring))
2607 - hexadecimals);
2608 ++colorstring;
2610 *colorptr = RGB(red_value, green_value, blue_value);
2611 } else {
2612 while (*ctv_ptr->colorstring
2613 && stricmp(ctv_ptr->colorstring, colorstring))
2614 ++ctv_ptr;
2615 if (*ctv_ptr->colorstring) {
2616 *colorptr = ctv_ptr->colorvalue;
2617 } else {
2618 while (*ctbv_ptr->colorstring
2619 && stricmp(ctbv_ptr->colorstring, colorstring))
2620 ++ctbv_ptr;
2621 if (*ctbv_ptr->colorstring) {
2622 *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue);
2623 *colorptr = GetSysColor(ctbv_ptr->syscolorvalue);
2627 if (max_brush > TOTAL_BRUSHES)
2628 panic("Too many colors!");
2629 *brushptr = CreateSolidBrush(*colorptr);
2630 brush_table[max_brush++] = *brushptr;
2633 void
2634 mswin_get_window_placement(int type, LPRECT rt)
2636 switch (type) {
2637 case NHW_MAP:
2638 *rt = GetNHApp()->rtMapWindow;
2639 break;
2641 case NHW_MESSAGE:
2642 *rt = GetNHApp()->rtMsgWindow;
2643 break;
2645 case NHW_STATUS:
2646 *rt = GetNHApp()->rtStatusWindow;
2647 break;
2649 case NHW_MENU:
2650 *rt = GetNHApp()->rtMenuWindow;
2651 break;
2653 case NHW_TEXT:
2654 *rt = GetNHApp()->rtTextWindow;
2655 break;
2657 case NHW_INVEN:
2658 *rt = GetNHApp()->rtInvenWindow;
2659 break;
2661 default:
2662 SetRect(rt, 0, 0, 0, 0);
2663 break;
2667 void
2668 mswin_update_window_placement(int type, LPRECT rt)
2670 LPRECT rt_conf = NULL;
2672 switch (type) {
2673 case NHW_MAP:
2674 rt_conf = &GetNHApp()->rtMapWindow;
2675 break;
2677 case NHW_MESSAGE:
2678 rt_conf = &GetNHApp()->rtMsgWindow;
2679 break;
2681 case NHW_STATUS:
2682 rt_conf = &GetNHApp()->rtStatusWindow;
2683 break;
2685 case NHW_MENU:
2686 rt_conf = &GetNHApp()->rtMenuWindow;
2687 break;
2689 case NHW_TEXT:
2690 rt_conf = &GetNHApp()->rtTextWindow;
2691 break;
2693 case NHW_INVEN:
2694 rt_conf = &GetNHApp()->rtInvenWindow;
2695 break;
2698 if (rt_conf && !IsRectEmpty(rt) && !EqualRect(rt_conf, rt)) {
2699 *rt_conf = *rt;
2704 NHMessageBox(HWND hWnd, LPCTSTR text, UINT type)
2706 TCHAR title[MAX_LOADSTRING];
2708 LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING);
2710 return MessageBox(hWnd, text, title, type);
2713 #ifdef STATUS_VIA_WINDOWPORT
2714 static const char *_status_fieldnm[MAXBLSTATS];
2715 static const char *_status_fieldfmt[MAXBLSTATS];
2716 static char *_status_vals[MAXBLSTATS];
2717 static int _status_colors[MAXBLSTATS];
2718 static boolean _status_activefields[MAXBLSTATS];
2719 extern winid WIN_STATUS;
2721 #ifdef STATUS_HILITES
2722 typedef struct hilite_data_struct {
2723 int thresholdtype;
2724 anything threshold;
2725 int behavior;
2726 int under;
2727 int over;
2728 } hilite_data_t;
2729 static hilite_data_t _status_hilites[MAXBLSTATS];
2730 #endif /* STATUS_HILITES */
2732 status_init() -- core calls this to notify the window port that a status
2733 display is required. The window port should perform
2734 the necessary initialization in here, allocate memory, etc.
2736 void
2737 mswin_status_init(void)
2739 int i;
2740 logDebug("mswin_status_init()\n");
2741 for (i = 0; i < MAXBLSTATS; ++i) {
2742 _status_vals[i] = (char *) alloc(BUFSZ);
2743 *_status_vals[i] = '\0';
2744 _status_activefields[i] = FALSE;
2745 _status_fieldfmt[i] = (const char *) 0;
2746 _status_colors[i] = CLR_MAX; /* no color */
2747 #ifdef STATUS_HILITES
2748 _status_hilites[i].thresholdtype = 0;
2749 _status_hilites[i].behavior = BL_TH_NONE;
2750 _status_hilites[i].under = BL_HILITE_NONE;
2751 _status_hilites[i].over = BL_HILITE_NONE;
2752 #endif /* STATUS_HILITES */
2754 /* Use a window for the genl version; backward port compatibility */
2755 WIN_STATUS = create_nhwindow(NHW_STATUS);
2756 display_nhwindow(WIN_STATUS, FALSE);
2760 status_finish() -- called when it is time for the window port to tear down
2761 the status display and free allocated memory, etc.
2763 void
2764 mswin_status_finish(void)
2766 /* tear down routine */
2767 int i;
2769 logDebug("mswin_status_finish()\n");
2771 /* free alloc'd memory here */
2772 for (i = 0; i < MAXBLSTATS; ++i) {
2773 if (_status_vals[i])
2774 free((genericptr_t) _status_vals[i]);
2775 _status_vals[i] = (char *) 0;
2780 status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable)
2781 -- notifies the window port which fields it is authorized to
2782 display.
2783 -- This may be called at any time, and is used
2784 to disable as well as enable fields, depending on the
2785 value of the final argument (TRUE = enable).
2786 -- fldindex could be one of the following from botl.h:
2787 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2788 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2789 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2790 BL_LEVELDESC, BL_EXP, BL_CONDITION
2791 -- There are MAXBLSTATS status fields (from botl.h)
2793 void
2794 mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt,
2795 boolean enable)
2797 logDebug("mswin_status_enablefield(%d, %s, %s, %d)\n", fieldidx, nm, fmt,
2798 (int) enable);
2799 _status_fieldfmt[fieldidx] = fmt;
2800 _status_fieldnm[fieldidx] = nm;
2801 _status_activefields[fieldidx] = enable;
2804 #ifdef STATUS_HILITES
2806 status_threshold(int fldidx, int threshholdtype, anything threshold,
2807 int behavior, int under, int over)
2808 -- called when a hiliting preference is added, changed, or
2809 removed.
2810 -- the fldindex identifies which field is having its hiliting
2811 preference set. It is an integer index value from botl.h
2812 -- fldindex could be any one of the following from botl.h:
2813 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2814 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2815 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2816 BL_LEVELDESC, BL_EXP, BL_CONDITION
2817 -- datatype is P_INT, P_UINT, P_LONG, or P_MASK.
2818 -- threshold is an "anything" union which can contain the
2819 datatype value.
2820 -- behavior is used to define how threshold is used and can
2821 be BL_TH_NONE, BL_TH_VAL_PERCENTAGE, BL_TH_VAL_ABSOLUTE,
2822 or BL_TH_UPDOWN. BL_TH_NONE means don't do anything above
2823 or below the threshold. BL_TH_VAL_PERCENTAGE treats the
2824 threshold value as a precentage of the maximum possible
2825 value. BL_TH_VAL_ABSOLUTE means that the threshold is an
2826 actual value. BL_TH_UPDOWN means that threshold is not
2827 used, and the two below/above hilite values indicate how
2828 to display something going down (under) or rising (over).
2829 -- under is the hilite attribute used if value is below the
2830 threshold. The attribute can be BL_HILITE_NONE,
2831 BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one
2832 of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN,
2833 CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY,
2834 CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE,
2835 CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15).
2836 -- over is the hilite attribute used if value is at or above
2837 the threshold. The attribute can be BL_HILITE_NONE,
2838 BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one
2839 of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN,
2840 CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY,
2841 CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE,
2842 CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15).
2844 void
2845 mswin_status_threshold(int fldidx, int thresholdtype, anything threshold,
2846 int behavior, int under, int over)
2848 logDebug("mswin_status_threshold(%d, %d, %d, %d, %d)\n", fldidx,
2849 thresholdtype, behavior, under, over);
2850 assert(fldidx >= 0 && fldidx < MAXBLSTATS);
2851 _status_hilites[fldidx].thresholdtype = thresholdtype;
2852 _status_hilites[fldidx].threshold = threshold;
2853 _status_hilites[fldidx].behavior = behavior;
2854 _status_hilites[fldidx].under = under;
2855 _status_hilites[fldidx].over = over;
2857 #endif /* STATUS_HILITES */
2861 status_update(int fldindex, genericptr_t ptr, int chg, int percentage)
2862 -- update the value of a status field.
2863 -- the fldindex identifies which field is changing and
2864 is an integer index value from botl.h
2865 -- fldindex could be any one of the following from botl.h:
2866 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2867 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2868 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2869 BL_LEVELDESC, BL_EXP, BL_CONDITION
2870 -- fldindex could also be BL_FLUSH (-1), which is not really
2871 a field index, but is a special trigger to tell the
2872 windowport that it should redisplay all its status fields,
2873 even if no changes have been presented to it.
2874 -- ptr is usually a "char *", unless fldindex is BL_CONDITION.
2875 If fldindex is BL_CONDITION, then ptr is a long value with
2876 any or none of the following bits set (from botl.h):
2877 BL_MASK_STONE 0x00000001L
2878 BL_MASK_SLIME 0x00000002L
2879 BL_MASK_STRNGL 0x00000004L
2880 BL_MASK_FOODPOIS 0x00000008L
2881 BL_MASK_TERMILL 0x00000010L
2882 BL_MASK_BLIND 0x00000020L
2883 BL_MASK_DEAF 0x00000040L
2884 BL_MASK_STUN 0x00000080L
2885 BL_MASK_CONF 0x00000100L
2886 BL_MASK_HALLU 0x00000200L
2887 BL_MASK_LEV 0x00000400L
2888 BL_MASK_FLY 0x00000800L
2889 BL_MASK_RIDE 0x00001000L
2890 -- The value passed for BL_GOLD includes an encoded leading
2891 symbol for GOLD "\GXXXXNNNN:nnn". If window port needs
2892 textual gold amount without the leading "$:" the port will
2893 have to skip past ':' in passed "ptr" for the BL_GOLD case.
2895 void
2896 mswin_status_update(int idx, genericptr_t ptr, int chg, int percent)
2898 long cond, *condptr = (long *) ptr;
2899 char *text = (char *) ptr;
2900 MSNHMsgUpdateStatus update_cmd_data;
2901 int ocolor, ochar;
2902 unsigned ospecial;
2903 long value = -1;
2905 logDebug("mswin_status_update(%d, %p, %d, %d)\n", idx, ptr, chg, percent);
2907 if (idx != BL_FLUSH) {
2908 if (!_status_activefields[idx])
2909 return;
2910 switch (idx) {
2911 case BL_CONDITION: {
2912 cond = *condptr;
2913 *_status_vals[idx] = '\0';
2914 if (cond & BL_MASK_STONE)
2915 Strcat(_status_vals[idx], " Stone");
2916 if (cond & BL_MASK_SLIME)
2917 Strcat(_status_vals[idx], " Slime");
2918 if (cond & BL_MASK_STRNGL)
2919 Strcat(_status_vals[idx], " Strngl");
2920 if (cond & BL_MASK_FOODPOIS)
2921 Strcat(_status_vals[idx], " FoodPois");
2922 if (cond & BL_MASK_TERMILL)
2923 Strcat(_status_vals[idx], " TermIll");
2924 if (cond & BL_MASK_BLIND)
2925 Strcat(_status_vals[idx], " Blind");
2926 if (cond & BL_MASK_DEAF)
2927 Strcat(_status_vals[idx], " Deaf");
2928 if (cond & BL_MASK_STUN)
2929 Strcat(_status_vals[idx], " Stun");
2930 if (cond & BL_MASK_CONF)
2931 Strcat(_status_vals[idx], " Conf");
2932 if (cond & BL_MASK_HALLU)
2933 Strcat(_status_vals[idx], " Hallu");
2934 if (cond & BL_MASK_LEV)
2935 Strcat(_status_vals[idx], " Lev");
2936 if (cond & BL_MASK_FLY)
2937 Strcat(_status_vals[idx], " Fly");
2938 if (cond & BL_MASK_RIDE)
2939 Strcat(_status_vals[idx], " Ride");
2940 value = cond;
2941 } break;
2942 case BL_GOLD: {
2943 char buf[BUFSZ];
2944 char *p;
2945 ZeroMemory(buf, sizeof(buf));
2946 mapglyph(objnum_to_glyph(GOLD_PIECE), &ochar, &ocolor, &ospecial,
2947 0, 0);
2948 buf[0] = ochar;
2949 p = strchr(text, ':');
2950 if (p) {
2951 strncpy(buf + 1, p, sizeof(buf) - 2);
2952 value = atol(p + 1);
2953 } else {
2954 buf[1] = ':';
2955 strncpy(buf + 2, text, sizeof(buf) - 2);
2956 value = atol(text);
2958 Sprintf(_status_vals[idx],
2959 _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s",
2960 buf);
2961 } break;
2962 default: {
2963 value = atol(text);
2964 Sprintf(_status_vals[idx],
2965 _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s",
2966 text);
2967 } break;
2971 #ifdef STATUS_HILITES
2972 switch (_status_hilites[idx].behavior) {
2973 case BL_TH_NONE: {
2974 _status_colors[idx] = CLR_MAX;
2975 } break;
2977 case BL_TH_UPDOWN: {
2978 if (chg > 0)
2979 _status_colors[idx] = _status_hilites[idx].over;
2980 else if (chg < 0)
2981 _status_colors[idx] = _status_hilites[idx].under;
2982 else
2983 _status_colors[idx] = CLR_MAX;
2984 } break;
2986 case BL_TH_VAL_PERCENTAGE: {
2987 int pct_th = 0;
2988 if (_status_hilites[idx].thresholdtype != ANY_INT) {
2989 impossible("mswin_status_update: unsupported percentage "
2990 "threshold type %d",
2991 _status_hilites[idx].thresholdtype);
2992 break;
2994 pct_th = _status_hilites[idx].threshold.a_int;
2995 _status_colors[idx] = (percent >= pct_th)
2996 ? _status_hilites[idx].over
2997 : _status_hilites[idx].under;
2998 } break;
3000 case BL_TH_VAL_ABSOLUTE: {
3001 int c = CLR_MAX;
3002 int o = _status_hilites[idx].over;
3003 int u = _status_hilites[idx].under;
3004 anything *t = &_status_hilites[idx].threshold;
3005 switch (_status_hilites[idx].thresholdtype) {
3006 case ANY_LONG:
3007 c = (value >= t->a_long) ? o : u;
3008 break;
3009 case ANY_INT:
3010 c = (value >= t->a_int) ? o : u;
3011 break;
3012 case ANY_UINT:
3013 c = ((unsigned long) value >= t->a_uint) ? o : u;
3014 break;
3015 case ANY_ULONG:
3016 c = ((unsigned long) value >= t->a_ulong) ? o : u;
3017 break;
3018 case ANY_MASK32:
3019 c = (value & t->a_ulong) ? o : u;
3020 break;
3021 default:
3022 impossible("mswin_status_update: unsupported absolute threshold "
3023 "type %d\n",
3024 _status_hilites[idx].thresholdtype);
3025 break;
3027 _status_colors[idx] = c;
3028 } break;
3030 #endif /* STATUS_HILITES */
3032 /* send command to status window */
3033 ZeroMemory(&update_cmd_data, sizeof(update_cmd_data));
3034 update_cmd_data.n_fields = MAXBLSTATS;
3035 update_cmd_data.vals = _status_vals;
3036 update_cmd_data.activefields = _status_activefields;
3037 update_cmd_data.colors = _status_colors;
3038 SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND,
3039 (WPARAM) MSNH_MSG_UPDATE_STATUS, (LPARAM) &update_cmd_data);
3042 #endif /*STATUS_VIA_WINDOWPORT*/