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. */
6 * This file implements the interface between the window port specific
7 * code in the mswin port and the rest of the nethack game engine.
12 #include "func_tab.h" /* for extended commands */
33 #define NHTRACE_LOG "nhtrace.log"
37 static FILE* _s_debugfp
= NULL
;
38 extern void logDebug(const char *fmt
, ...);
44 logDebug(const char *fmt
, ...)
49 static void mswin_main_loop(void);
50 static BOOL
initMapTiles(void);
51 static void mswin_color_from_string(char *colorstring
, HBRUSH
*brushptr
,
53 static void prompt_for_player_selection(void);
55 #define TOTAL_BRUSHES 10
56 HBRUSH brush_table
[TOTAL_BRUSHES
];
59 HBRUSH menu_bg_brush
= NULL
;
60 HBRUSH menu_fg_brush
= NULL
;
61 HBRUSH text_bg_brush
= NULL
;
62 HBRUSH text_fg_brush
= NULL
;
63 HBRUSH status_bg_brush
= NULL
;
64 HBRUSH status_fg_brush
= NULL
;
65 HBRUSH message_bg_brush
= NULL
;
66 HBRUSH message_fg_brush
= NULL
;
68 COLORREF menu_bg_color
= RGB(0, 0, 0);
69 COLORREF menu_fg_color
= RGB(0xFF, 0xFF, 0xFF);
70 COLORREF text_bg_color
= RGB(0, 0, 0);
71 COLORREF text_fg_color
= RGB(0xFF, 0xFF, 0xFF);
72 COLORREF status_bg_color
= RGB(0, 0, 0);
73 COLORREF status_fg_color
= RGB(0xFF, 0xFF, 0xFF);
74 COLORREF message_bg_color
= RGB(0, 0, 0);
75 COLORREF message_fg_color
= RGB(0xFF, 0xFF, 0xFF);
77 /* Interface definition, for windows.c */
78 struct window_procs mswin_procs
= {
80 WC_COLOR
| WC_HILITE_PET
| WC_ALIGN_MESSAGE
| WC_ALIGN_STATUS
| WC_INVERSE
81 | WC_SCROLL_AMOUNT
| WC_SCROLL_MARGIN
| WC_MAP_MODE
| WC_FONT_MESSAGE
82 | WC_FONT_STATUS
| WC_FONT_MENU
| WC_FONT_TEXT
| WC_FONT_MAP
83 | WC_FONTSIZ_MESSAGE
| WC_FONTSIZ_STATUS
| WC_FONTSIZ_MENU
84 | WC_FONTSIZ_TEXT
| WC_TILE_WIDTH
| WC_TILE_HEIGHT
| WC_TILE_FILE
85 | WC_VARY_MSGCOUNT
| WC_WINDOWCOLORS
| WC_PLAYER_SELECTION
86 | WC_SPLASH_SCREEN
| WC_POPUP_DIALOG
,
87 0L, mswin_init_nhwindows
, mswin_player_selection
, mswin_askname
,
88 mswin_get_nh_event
, mswin_exit_nhwindows
, mswin_suspend_nhwindows
,
89 mswin_resume_nhwindows
, mswin_create_nhwindow
, mswin_clear_nhwindow
,
90 mswin_display_nhwindow
, mswin_destroy_nhwindow
, mswin_curs
, mswin_putstr
,
91 genl_putmixed
, mswin_display_file
, mswin_start_menu
, mswin_add_menu
,
92 mswin_end_menu
, mswin_select_menu
,
93 genl_message_menu
, /* no need for X-specific handling */
94 mswin_update_inventory
, mswin_mark_synch
, mswin_wait_synch
,
101 mswin_print_glyph
, mswin_raw_print
, mswin_raw_print_bold
, mswin_nhgetch
,
102 mswin_nh_poskey
, mswin_nhbell
, mswin_doprev_message
, mswin_yn_function
,
103 mswin_getlin
, mswin_get_ext_cmd
, mswin_number_pad
, mswin_delay_output
,
104 #ifdef CHANGE_COLOR /* only a Mac option currently */
105 mswin
, mswin_change_background
,
107 /* other defs that really should go away (they're tty specific) */
108 mswin_start_screen
, mswin_end_screen
, mswin_outrip
,
109 mswin_preference_update
, mswin_getmsghistory
, mswin_putmsghistory
,
110 #ifdef STATUS_VIA_WINDOWPORT
111 mswin_status_init
, mswin_status_finish
, mswin_status_enablefield
,
113 #ifdef STATUS_HILITES
114 mswin_status_threshold
,
117 genl_can_suspend_yes
,
121 init_nhwindows(int* argcp, char** argv)
122 -- Initialize the windows used by NetHack. This can also
123 create the standard windows listed at the top, but does
125 -- Any commandline arguments relevant to the windowport
126 should be interpreted, and *argcp and *argv should
127 be changed to remove those arguments.
128 -- When the message window is created, the variable
129 iflags.window_inited needs to be set to TRUE. Otherwise
130 all plines() will be done via raw_print().
131 ** Why not have init_nhwindows() create all of the "standard"
132 ** windows? Or at least all but WIN_INFO? -dean
135 mswin_init_nhwindows(int *argc
, char **argv
)
137 UNREFERENCED_PARAMETER(argc
);
138 UNREFERENCED_PARAMETER(argv
);
142 if (showdebug(NHTRACE_LOG
) && !_s_debugfp
) {
143 /* truncate trace file */
144 _s_debugfp
= fopen(NHTRACE_LOG
, "w");
148 logDebug("mswin_init_nhwindows()\n");
150 mswin_nh_input_init();
152 /* set it to WIN_ERR so we can detect attempts to
153 use this ID before it is inialized */
156 /* Read Windows settings from the reqistry */
157 /* First set safe defaults */
158 GetNHApp()->regMainMinX
= CW_USEDEFAULT
;
160 /* Create the main window */
161 GetNHApp()->hMainWnd
= mswin_init_main_window();
162 if (!GetNHApp()->hMainWnd
) {
163 panic("Cannot create main window");
166 /* Set menu check mark for interface mode */
167 mswin_menu_check_intf_mode();
169 /* check default values */
170 if (iflags
.wc_fontsiz_status
< NHFONT_SIZE_MIN
171 || iflags
.wc_fontsiz_status
> NHFONT_SIZE_MAX
)
172 iflags
.wc_fontsiz_status
= NHFONT_DEFAULT_SIZE
;
174 if (iflags
.wc_fontsiz_message
< NHFONT_SIZE_MIN
175 || iflags
.wc_fontsiz_message
> NHFONT_SIZE_MAX
)
176 iflags
.wc_fontsiz_message
= NHFONT_DEFAULT_SIZE
;
178 if (iflags
.wc_fontsiz_text
< NHFONT_SIZE_MIN
179 || iflags
.wc_fontsiz_text
> NHFONT_SIZE_MAX
)
180 iflags
.wc_fontsiz_text
= NHFONT_DEFAULT_SIZE
;
182 if (iflags
.wc_fontsiz_menu
< NHFONT_SIZE_MIN
183 || iflags
.wc_fontsiz_menu
> NHFONT_SIZE_MAX
)
184 iflags
.wc_fontsiz_menu
= NHFONT_DEFAULT_SIZE
;
186 if (iflags
.wc_align_message
== 0)
187 iflags
.wc_align_message
= ALIGN_TOP
;
188 if (iflags
.wc_align_status
== 0)
189 iflags
.wc_align_status
= ALIGN_BOTTOM
;
190 if (iflags
.wc_scroll_margin
== 0)
191 iflags
.wc_scroll_margin
= DEF_CLIPAROUND_MARGIN
;
192 if (iflags
.wc_scroll_amount
== 0)
193 iflags
.wc_scroll_amount
= DEF_CLIPAROUND_AMOUNT
;
194 if (iflags
.wc_tile_width
== 0)
195 iflags
.wc_tile_width
= TILE_X
;
196 if (iflags
.wc_tile_height
== 0)
197 iflags
.wc_tile_height
= TILE_Y
;
199 if (iflags
.wc_vary_msgcount
== 0)
200 iflags
.wc_vary_msgcount
= 4;
202 /* force tabs in menus */
203 iflags
.menu_tab_sep
= 1;
205 /* force toptenwin to be true. toptenwin is the option that decides
207 * write output to a window or stdout. stdout doesn't make sense on
209 * non-console applications
211 iflags
.toptenwin
= 1;
212 set_option_mod_status("toptenwin", SET_IN_FILE
);
213 //set_option_mod_status("perm_invent", SET_IN_FILE);
215 /* initialize map tiles bitmap */
218 /* set tile-related options to readonly */
219 set_wc_option_mod_status(WC_TILE_WIDTH
| WC_TILE_HEIGHT
| WC_TILE_FILE
,
222 /* set font-related options to change in the game */
223 set_wc_option_mod_status(
224 WC_HILITE_PET
| WC_ALIGN_MESSAGE
| WC_ALIGN_STATUS
| WC_SCROLL_AMOUNT
225 | WC_SCROLL_MARGIN
| WC_MAP_MODE
| WC_FONT_MESSAGE
226 | WC_FONT_STATUS
| WC_FONT_MENU
| WC_FONT_TEXT
227 | WC_FONTSIZ_MESSAGE
| WC_FONTSIZ_STATUS
| WC_FONTSIZ_MENU
228 | WC_FONTSIZ_TEXT
| WC_VARY_MSGCOUNT
,
231 mswin_color_from_string(iflags
.wc_foregrnd_menu
, &menu_fg_brush
,
233 mswin_color_from_string(iflags
.wc_foregrnd_message
, &message_fg_brush
,
235 mswin_color_from_string(iflags
.wc_foregrnd_status
, &status_fg_brush
,
237 mswin_color_from_string(iflags
.wc_foregrnd_text
, &text_fg_brush
,
239 mswin_color_from_string(iflags
.wc_backgrnd_menu
, &menu_bg_brush
,
241 mswin_color_from_string(iflags
.wc_backgrnd_message
, &message_bg_brush
,
243 mswin_color_from_string(iflags
.wc_backgrnd_status
, &status_bg_brush
,
245 mswin_color_from_string(iflags
.wc_backgrnd_text
, &text_bg_brush
,
248 if (iflags
.wc_splash_screen
)
249 mswin_display_splash_window(FALSE
);
251 iflags
.window_inited
= TRUE
;
254 /* Do a window-port specific player type selection. If player_selection()
255 offers a Quit option, it is its responsibility to clean up and terminate
256 the process. You need to fill in pl_character[0].
259 mswin_player_selection(void)
263 logDebug("mswin_player_selection()\n");
265 if (iflags
.wc_player_selection
== VIA_DIALOG
) {
266 /* pick player type randomly (use pre-selected
267 * role/race/gender/alignment) */
268 if (flags
.randomall
) {
269 if (flags
.initrole
< 0) {
270 flags
.initrole
= pick_role(flags
.initrace
, flags
.initgend
,
271 flags
.initalign
, PICK_RANDOM
);
272 if (flags
.initrole
< 0) {
273 raw_print("Incompatible role!");
274 flags
.initrole
= randrole();
278 if (flags
.initrace
< 0
279 || !validrace(flags
.initrole
, flags
.initrace
)) {
280 flags
.initrace
= pick_race(flags
.initrole
, flags
.initgend
,
281 flags
.initalign
, PICK_RANDOM
);
282 if (flags
.initrace
< 0) {
283 raw_print("Incompatible race!");
284 flags
.initrace
= randrace(flags
.initrole
);
288 if (flags
.initgend
< 0
289 || !validgend(flags
.initrole
, flags
.initrace
,
291 flags
.initgend
= pick_gend(flags
.initrole
, flags
.initrace
,
292 flags
.initalign
, PICK_RANDOM
);
293 if (flags
.initgend
< 0) {
294 raw_print("Incompatible gender!");
295 flags
.initgend
= randgend(flags
.initrole
, flags
.initrace
);
299 if (flags
.initalign
< 0
300 || !validalign(flags
.initrole
, flags
.initrace
,
302 flags
.initalign
= pick_align(flags
.initrole
, flags
.initrace
,
303 flags
.initgend
, PICK_RANDOM
);
304 if (flags
.initalign
< 0) {
305 raw_print("Incompatible alignment!");
307 randalign(flags
.initrole
, flags
.initrace
);
312 if (mswin_player_selection_window(&nRole
) == IDCANCEL
) {
316 } else { /* iflags.wc_player_selection == VIA_PROMPTS */
317 prompt_for_player_selection();
322 prompt_for_player_selection(void)
325 char pick4u
= 'n', thisch
, lastch
= 0;
326 char pbuf
[QBUFSZ
], plbuf
[QBUFSZ
];
329 menu_item
*selected
= 0;
332 logDebug("prompt_for_player_selection()\n");
334 /* prevent an unnecessary prompt */
337 /* Should we randomly pick for the player? */
339 && (flags
.initrole
== ROLE_NONE
|| flags
.initrace
== ROLE_NONE
340 || flags
.initgend
== ROLE_NONE
|| flags
.initalign
== ROLE_NONE
)) {
342 char *prompt
= build_plselection_prompt(
343 pbuf
, QBUFSZ
, flags
.initrole
, flags
.initrace
, flags
.initgend
,
346 /* tty_putstr(BASE_WINDOW, 0, ""); */
347 /* echoline = wins[BASE_WINDOW]->cury; */
348 box_result
= NHMessageBox(NULL
, prompt
, MB_YESNOCANCEL
| MB_DEFBUTTON1
351 (box_result
== IDYES
) ? 'y' : (box_result
== IDNO
) ? 'n' : '\033';
352 /* tty_putstr(BASE_WINDOW, 0, prompt); */
354 /* pick4u = lowc(readchar()); */
355 if (index(quitchars
, pick4u
))
357 } while (!index(ynqchars
, pick4u
));
358 if ((int) strlen(prompt
) + 1 < CO
) {
359 /* Echo choice and move back down line */
360 /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline,
362 /* tty_putstr(BASE_WINDOW, 0, ""); */
364 /* Otherwise it's hard to tell where to echo, and things are
365 * wrapping a bit messily anyway, so (try to) make sure the next
366 * question shows up well and doesn't get wrapped at the
367 * bottom of the window.
369 /* tty_clear_nhwindow(BASE_WINDOW) */;
371 if (pick4u
!= 'y' && pick4u
!= 'n') {
374 free((genericptr_t
) selected
);
381 (void) root_plselection_prompt(plbuf
, QBUFSZ
- 1, flags
.initrole
,
382 flags
.initrace
, flags
.initgend
,
385 /* Select a role, if necessary */
386 /* we'll try to be compatible with pre-selected race/gender/alignment,
387 * but may not succeed */
388 if (flags
.initrole
< 0) {
389 char rolenamebuf
[QBUFSZ
];
390 /* Process the choice */
391 if (pick4u
== 'y' || flags
.initrole
== ROLE_RANDOM
392 || flags
.randomall
) {
393 /* Pick a random role */
394 flags
.initrole
= pick_role(flags
.initrace
, flags
.initgend
,
395 flags
.initalign
, PICK_RANDOM
);
396 if (flags
.initrole
< 0) {
397 /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
398 flags
.initrole
= randrole();
401 /* tty_clear_nhwindow(BASE_WINDOW); */
402 /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
403 /* Prompt for a role */
404 win
= create_nhwindow(NHW_MENU
);
406 any
= zeroany
; /* zero out all bits */
407 for (i
= 0; roles
[i
].name
.m
; i
++) {
408 if (ok_role(i
, flags
.initrace
, flags
.initgend
,
410 any
.a_int
= i
+ 1; /* must be non-zero */
411 thisch
= lowc(roles
[i
].name
.m
[0]);
412 if (thisch
== lastch
)
413 thisch
= highc(thisch
);
414 if (flags
.initgend
!= ROLE_NONE
415 && flags
.initgend
!= ROLE_RANDOM
) {
416 if (flags
.initgend
== 1 && roles
[i
].name
.f
)
417 Strcpy(rolenamebuf
, roles
[i
].name
.f
);
419 Strcpy(rolenamebuf
, roles
[i
].name
.m
);
421 if (roles
[i
].name
.f
) {
422 Strcpy(rolenamebuf
, roles
[i
].name
.m
);
423 Strcat(rolenamebuf
, "/");
424 Strcat(rolenamebuf
, roles
[i
].name
.f
);
426 Strcpy(rolenamebuf
, roles
[i
].name
.m
);
428 add_menu(win
, NO_GLYPH
, &any
, thisch
, 0, ATR_NONE
,
429 an(rolenamebuf
), MENU_UNSELECTED
);
433 any
.a_int
= pick_role(flags
.initrace
, flags
.initgend
,
434 flags
.initalign
, PICK_RANDOM
) + 1;
435 if (any
.a_int
== 0) /* must be non-zero */
436 any
.a_int
= randrole() + 1;
437 add_menu(win
, NO_GLYPH
, &any
, '*', 0, ATR_NONE
, "Random",
439 any
.a_int
= i
+ 1; /* must be non-zero */
440 add_menu(win
, NO_GLYPH
, &any
, 'q', 0, ATR_NONE
, "Quit",
442 Sprintf(pbuf
, "Pick a role for your %s", plbuf
);
444 n
= select_menu(win
, PICK_ONE
, &selected
);
445 destroy_nhwindow(win
);
447 /* Process the choice */
448 if (n
!= 1 || selected
[0].item
.a_int
== any
.a_int
)
449 goto give_up
; /* Selected quit */
451 flags
.initrole
= selected
[0].item
.a_int
- 1;
452 free((genericptr_t
) selected
), selected
= 0;
454 (void) root_plselection_prompt(plbuf
, QBUFSZ
- 1, flags
.initrole
,
455 flags
.initrace
, flags
.initgend
,
459 /* Select a race, if necessary */
460 /* force compatibility with role, try for compatibility with
461 * pre-selected gender/alignment */
462 if (flags
.initrace
< 0 || !validrace(flags
.initrole
, flags
.initrace
)) {
463 /* pre-selected race not valid */
464 if (pick4u
== 'y' || flags
.initrace
== ROLE_RANDOM
465 || flags
.randomall
) {
466 flags
.initrace
= pick_race(flags
.initrole
, flags
.initgend
,
467 flags
.initalign
, PICK_RANDOM
);
468 if (flags
.initrace
< 0) {
469 /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
470 flags
.initrace
= randrace(flags
.initrole
);
472 } else { /* pick4u == 'n' */
473 /* Count the number of valid races */
474 n
= 0; /* number valid */
475 k
= 0; /* valid race */
476 for (i
= 0; races
[i
].noun
; i
++) {
477 if (ok_race(flags
.initrole
, i
, flags
.initgend
,
484 for (i
= 0; races
[i
].noun
; i
++) {
485 if (validrace(flags
.initrole
, i
)) {
492 /* Permit the user to pick, if there is more than one */
494 /* tty_clear_nhwindow(BASE_WINDOW); */
495 /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
496 win
= create_nhwindow(NHW_MENU
);
498 any
= zeroany
; /* zero out all bits */
499 for (i
= 0; races
[i
].noun
; i
++)
500 if (ok_race(flags
.initrole
, i
, flags
.initgend
,
502 any
.a_int
= i
+ 1; /* must be non-zero */
503 add_menu(win
, NO_GLYPH
, &any
, races
[i
].noun
[0], 0,
504 ATR_NONE
, races
[i
].noun
, MENU_UNSELECTED
);
506 any
.a_int
= pick_race(flags
.initrole
, flags
.initgend
,
507 flags
.initalign
, PICK_RANDOM
) + 1;
508 if (any
.a_int
== 0) /* must be non-zero */
509 any
.a_int
= randrace(flags
.initrole
) + 1;
510 add_menu(win
, NO_GLYPH
, &any
, '*', 0, ATR_NONE
, "Random",
512 any
.a_int
= i
+ 1; /* must be non-zero */
513 add_menu(win
, NO_GLYPH
, &any
, 'q', 0, ATR_NONE
, "Quit",
515 Sprintf(pbuf
, "Pick the race of your %s", plbuf
);
517 n
= select_menu(win
, PICK_ONE
, &selected
);
518 destroy_nhwindow(win
);
519 if (n
!= 1 || selected
[0].item
.a_int
== any
.a_int
)
520 goto give_up
; /* Selected quit */
522 k
= selected
[0].item
.a_int
- 1;
523 free((genericptr_t
) selected
), selected
= 0;
527 (void) root_plselection_prompt(plbuf
, QBUFSZ
- 1, flags
.initrole
,
528 flags
.initrace
, flags
.initgend
,
532 /* Select a gender, if necessary */
533 /* force compatibility with role/race, try for compatibility with
534 * pre-selected alignment */
535 if (flags
.initgend
< 0
536 || !validgend(flags
.initrole
, flags
.initrace
, flags
.initgend
)) {
537 /* pre-selected gender not valid */
538 if (pick4u
== 'y' || flags
.initgend
== ROLE_RANDOM
539 || flags
.randomall
) {
540 flags
.initgend
= pick_gend(flags
.initrole
, flags
.initrace
,
541 flags
.initalign
, PICK_RANDOM
);
542 if (flags
.initgend
< 0) {
543 /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
544 flags
.initgend
= randgend(flags
.initrole
, flags
.initrace
);
546 } else { /* pick4u == 'n' */
547 /* Count the number of valid genders */
548 n
= 0; /* number valid */
549 k
= 0; /* valid gender */
550 for (i
= 0; i
< ROLE_GENDERS
; i
++) {
551 if (ok_gend(flags
.initrole
, flags
.initrace
, i
,
558 for (i
= 0; i
< ROLE_GENDERS
; i
++) {
559 if (validgend(flags
.initrole
, flags
.initrace
, i
)) {
566 /* Permit the user to pick, if there is more than one */
568 /* tty_clear_nhwindow(BASE_WINDOW); */
569 /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
570 win
= create_nhwindow(NHW_MENU
);
572 any
= zeroany
; /* zero out all bits */
573 for (i
= 0; i
< ROLE_GENDERS
; i
++)
574 if (ok_gend(flags
.initrole
, flags
.initrace
, i
,
577 add_menu(win
, NO_GLYPH
, &any
, genders
[i
].adj
[0], 0,
578 ATR_NONE
, genders
[i
].adj
, MENU_UNSELECTED
);
580 any
.a_int
= pick_gend(flags
.initrole
, flags
.initrace
,
581 flags
.initalign
, PICK_RANDOM
) + 1;
582 if (any
.a_int
== 0) /* must be non-zero */
583 any
.a_int
= randgend(flags
.initrole
, flags
.initrace
) + 1;
584 add_menu(win
, NO_GLYPH
, &any
, '*', 0, ATR_NONE
, "Random",
586 any
.a_int
= i
+ 1; /* must be non-zero */
587 add_menu(win
, NO_GLYPH
, &any
, 'q', 0, ATR_NONE
, "Quit",
589 Sprintf(pbuf
, "Pick the gender of your %s", plbuf
);
591 n
= select_menu(win
, PICK_ONE
, &selected
);
592 destroy_nhwindow(win
);
593 if (n
!= 1 || selected
[0].item
.a_int
== any
.a_int
)
594 goto give_up
; /* Selected quit */
596 k
= selected
[0].item
.a_int
- 1;
597 free((genericptr_t
) selected
), selected
= 0;
601 (void) root_plselection_prompt(plbuf
, QBUFSZ
- 1, flags
.initrole
,
602 flags
.initrace
, flags
.initgend
,
606 /* Select an alignment, if necessary */
607 /* force compatibility with role/race/gender */
608 if (flags
.initalign
< 0
609 || !validalign(flags
.initrole
, flags
.initrace
, flags
.initalign
)) {
610 /* pre-selected alignment not valid */
611 if (pick4u
== 'y' || flags
.initalign
== ROLE_RANDOM
612 || flags
.randomall
) {
613 flags
.initalign
= pick_align(flags
.initrole
, flags
.initrace
,
614 flags
.initgend
, PICK_RANDOM
);
615 if (flags
.initalign
< 0) {
616 /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
617 flags
.initalign
= randalign(flags
.initrole
, flags
.initrace
);
619 } else { /* pick4u == 'n' */
620 /* Count the number of valid alignments */
621 n
= 0; /* number valid */
622 k
= 0; /* valid alignment */
623 for (i
= 0; i
< ROLE_ALIGNS
; i
++) {
624 if (ok_align(flags
.initrole
, flags
.initrace
, flags
.initgend
,
631 for (i
= 0; i
< ROLE_ALIGNS
; i
++) {
632 if (validalign(flags
.initrole
, flags
.initrace
, i
)) {
639 /* Permit the user to pick, if there is more than one */
641 /* tty_clear_nhwindow(BASE_WINDOW); */
642 /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
643 win
= create_nhwindow(NHW_MENU
);
645 any
= zeroany
; /* zero out all bits */
646 for (i
= 0; i
< ROLE_ALIGNS
; i
++)
647 if (ok_align(flags
.initrole
, flags
.initrace
,
648 flags
.initgend
, i
)) {
650 add_menu(win
, NO_GLYPH
, &any
, aligns
[i
].adj
[0], 0,
651 ATR_NONE
, aligns
[i
].adj
, MENU_UNSELECTED
);
653 any
.a_int
= pick_align(flags
.initrole
, flags
.initrace
,
654 flags
.initgend
, PICK_RANDOM
) + 1;
655 if (any
.a_int
== 0) /* must be non-zero */
656 any
.a_int
= randalign(flags
.initrole
, flags
.initrace
) + 1;
657 add_menu(win
, NO_GLYPH
, &any
, '*', 0, ATR_NONE
, "Random",
659 any
.a_int
= i
+ 1; /* must be non-zero */
660 add_menu(win
, NO_GLYPH
, &any
, 'q', 0, ATR_NONE
, "Quit",
662 Sprintf(pbuf
, "Pick the alignment of your %s", plbuf
);
664 n
= select_menu(win
, PICK_ONE
, &selected
);
665 destroy_nhwindow(win
);
666 if (n
!= 1 || selected
[0].item
.a_int
== any
.a_int
)
667 goto give_up
; /* Selected quit */
669 k
= selected
[0].item
.a_int
- 1;
670 free((genericptr_t
) selected
), selected
= 0;
676 /* tty_display_nhwindow(BASE_WINDOW, FALSE); */
679 /* Ask the user for a player name. */
683 logDebug("mswin_askname()\n");
685 if (mswin_getlin_window("Who are you?", plname
, PL_NSIZ
) == IDCANCEL
) {
691 /* Does window event processing (e.g. exposure events).
692 A noop for the tty and X window-ports.
695 mswin_get_nh_event(void)
699 logDebug("mswin_get_nh_event()\n");
701 while (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
) != 0) {
702 if (!TranslateAccelerator(msg
.hwnd
, GetNHApp()->hAccelTable
, &msg
)) {
703 TranslateMessage(&msg
);
704 DispatchMessage(&msg
);
710 /* Exits the window system. This should dismiss all windows,
711 except the "window" used for raw_print(). str is printed if possible.
714 mswin_exit_nhwindows(const char *str
)
716 logDebug("mswin_exit_nhwindows(%s)\n", str
);
718 /* Write Window settings to the registry */
721 DeleteObject(brush_table
[--max_brush
]);
724 /* Prepare the window to be suspended. */
726 mswin_suspend_nhwindows(const char *str
)
728 logDebug("mswin_suspend_nhwindows(%s)\n", str
);
733 /* Restore the windows after being suspended. */
735 mswin_resume_nhwindows()
737 logDebug("mswin_resume_nhwindows()\n");
742 /* Create a window of type "type" which can be
743 NHW_MESSAGE (top line)
744 NHW_STATUS (bottom lines)
745 NHW_MAP (main dungeon)
746 NHW_MENU (inventory or other "corner" windows)
747 NHW_TEXT (help/text, full screen paged window)
750 mswin_create_nhwindow(int type
)
755 logDebug("mswin_create_nhwindow(%d)\n", type
);
757 /* Return the next available winid
760 for (i
= 1; i
< MAXWINDOWS
; i
++)
761 if (GetNHApp()->windowlist
[i
].win
== NULL
762 && !GetNHApp()->windowlist
[i
].dead
)
765 panic("ERROR: No windows available...\n");
769 GetNHApp()->windowlist
[i
].win
= mswin_init_map_window();
770 GetNHApp()->windowlist
[i
].type
= type
;
771 GetNHApp()->windowlist
[i
].dead
= 0;
775 GetNHApp()->windowlist
[i
].win
= mswin_init_message_window();
776 GetNHApp()->windowlist
[i
].type
= type
;
777 GetNHApp()->windowlist
[i
].dead
= 0;
781 GetNHApp()->windowlist
[i
].win
= mswin_init_status_window();
782 GetNHApp()->windowlist
[i
].type
= type
;
783 GetNHApp()->windowlist
[i
].dead
= 0;
787 GetNHApp()->windowlist
[i
].win
= NULL
; // will create later
788 GetNHApp()->windowlist
[i
].type
= type
;
789 GetNHApp()->windowlist
[i
].dead
= 1;
793 GetNHApp()->windowlist
[i
].win
= mswin_init_text_window();
794 GetNHApp()->windowlist
[i
].type
= type
;
795 GetNHApp()->windowlist
[i
].dead
= 0;
800 ZeroMemory(&data
, sizeof(data
));
802 SendMessage(GetNHApp()->hMainWnd
, WM_MSNH_COMMAND
,
803 (WPARAM
) MSNH_MSG_ADDWND
, (LPARAM
) &data
);
807 /* Clear the given window, when asked to. */
809 mswin_clear_nhwindow(winid wid
)
811 logDebug("mswin_clear_nhwindow(%d)\n", wid
);
813 if ((wid
>= 0) && (wid
< MAXWINDOWS
)
814 && (GetNHApp()->windowlist
[wid
].win
!= NULL
)) {
815 if (GetNHApp()->windowlist
[wid
].type
== NHW_MAP
) {
816 if (Is_rogue_level(&u
.uz
))
817 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP
),
818 ROGUE_LEVEL_MAP_MODE
);
820 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP
),
824 SendMessage(GetNHApp()->windowlist
[wid
].win
, WM_MSNH_COMMAND
,
825 (WPARAM
) MSNH_MSG_CLEAR_WINDOW
, (LPARAM
) NULL
);
829 /* -- Display the window on the screen. If there is data
830 pending for output in that window, it should be sent.
831 If blocking is TRUE, display_nhwindow() will not
832 return until the data has been displayed on the screen,
833 and acknowledged by the user where appropriate.
834 -- All calls are blocking in the tty window-port.
835 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
836 --more--, if necessary, in the tty window-port.
839 mswin_display_nhwindow(winid wid
, BOOLEAN_P block
)
841 logDebug("mswin_display_nhwindow(%d, %d)\n", wid
, block
);
842 if (GetNHApp()->windowlist
[wid
].win
!= NULL
) {
843 ShowWindow(GetNHApp()->windowlist
[wid
].win
, SW_SHOW
);
844 mswin_layout_main_window(GetNHApp()->windowlist
[wid
].win
);
845 if (GetNHApp()->windowlist
[wid
].type
== NHW_MENU
) {
847 mswin_menu_window_select_menu(GetNHApp()->windowlist
[wid
].win
,
848 PICK_NONE
, &p
, TRUE
);
850 if (GetNHApp()->windowlist
[wid
].type
== NHW_TEXT
) {
851 mswin_display_text_window(GetNHApp()->windowlist
[wid
].win
);
853 if (GetNHApp()->windowlist
[wid
].type
== NHW_RIP
) {
854 mswin_display_RIP_window(GetNHApp()->windowlist
[wid
].win
);
857 UpdateWindow(GetNHApp()->windowlist
[wid
].win
);
859 if (GetNHApp()->windowlist
[wid
].type
== NHW_MAP
) {
860 (void) mswin_nhgetch();
864 SetFocus(GetNHApp()->hMainWnd
);
869 mswin_hwnd_from_winid(winid wid
)
871 if (wid
>= 0 && wid
< MAXWINDOWS
) {
872 return GetNHApp()->windowlist
[wid
].win
;
879 mswin_winid_from_handle(HWND hWnd
)
883 for (i
= 1; i
< MAXWINDOWS
; i
++)
884 if (GetNHApp()->windowlist
[i
].win
== hWnd
)
890 mswin_winid_from_type(int type
)
894 for (i
= 1; i
< MAXWINDOWS
; i
++)
895 if (GetNHApp()->windowlist
[i
].type
== type
)
901 mswin_window_mark_dead(winid wid
)
903 if (wid
>= 0 && wid
< MAXWINDOWS
) {
904 GetNHApp()->windowlist
[wid
].win
= NULL
;
905 GetNHApp()->windowlist
[wid
].dead
= 1;
909 /* Destroy will dismiss the window if the window has not
910 * already been dismissed.
913 mswin_destroy_nhwindow(winid wid
)
915 logDebug("mswin_destroy_nhwindow(%d)\n", wid
);
917 if ((GetNHApp()->windowlist
[wid
].type
== NHW_MAP
)
918 || (GetNHApp()->windowlist
[wid
].type
== NHW_MESSAGE
)
919 || (GetNHApp()->windowlist
[wid
].type
== NHW_STATUS
)) {
920 /* main windows is going to take care of those */
925 if (!GetNHApp()->windowlist
[wid
].dead
926 && GetNHApp()->windowlist
[wid
].win
!= NULL
)
927 DestroyWindow(GetNHApp()->windowlist
[wid
].win
);
928 GetNHApp()->windowlist
[wid
].win
= NULL
;
929 GetNHApp()->windowlist
[wid
].type
= 0;
930 GetNHApp()->windowlist
[wid
].dead
= 0;
934 /* Next output to window will start at (x,y), also moves
935 displayable cursor to (x,y). For backward compatibility,
936 1 <= x < cols, 0 <= y < rows, where cols and rows are
940 mswin_curs(winid wid
, int x
, int y
)
942 logDebug("mswin_curs(%d, %d, %d)\n", wid
, x
, y
);
944 if ((wid
>= 0) && (wid
< MAXWINDOWS
)
945 && (GetNHApp()->windowlist
[wid
].win
!= NULL
)) {
949 SendMessage(GetNHApp()->windowlist
[wid
].win
, WM_MSNH_COMMAND
,
950 (WPARAM
) MSNH_MSG_CURSOR
, (LPARAM
) &data
);
955 putstr(window, attr, str)
956 -- Print str on the window with the given attribute. Only
957 printable ASCII characters (040-0126) must be supported.
958 Multiple putstr()s are output on separate lines.
966 If a window-port does not support all of these, it may map
967 unsupported attributes to a supported one (e.g. map them
968 all to ATR_INVERSE). putstr() may compress spaces out of
969 str, break str, or truncate str, if necessary for the
970 display. Where putstr() breaks a line, it has to clear
972 -- putstr should be implemented such that if two putstr()s
973 are done consecutively the user will see the first and
974 then the second. In the tty port, pline() achieves this
975 by calling more() or displaying both on the same line.
978 mswin_putstr(winid wid
, int attr
, const char *text
)
980 logDebug("mswin_putstr(%d, %d, %s)\n", wid
, attr
, text
);
982 mswin_putstr_ex(wid
, attr
, text
, 0);
986 mswin_putstr_ex(winid wid
, int attr
, const char *text
, int app
)
988 if ((wid
>= 0) && (wid
< MAXWINDOWS
)) {
989 if (GetNHApp()->windowlist
[wid
].win
== NULL
990 && GetNHApp()->windowlist
[wid
].type
== NHW_MENU
) {
991 GetNHApp()->windowlist
[wid
].win
=
992 mswin_init_menu_window(MENU_TYPE_TEXT
);
993 GetNHApp()->windowlist
[wid
].dead
= 0;
996 if (GetNHApp()->windowlist
[wid
].win
!= NULL
) {
998 ZeroMemory(&data
, sizeof(data
));
1002 SendMessage(GetNHApp()->windowlist
[wid
].win
, WM_MSNH_COMMAND
,
1003 (WPARAM
) MSNH_MSG_PUTSTR
, (LPARAM
) &data
);
1005 /* yield a bit so it gets done immediately */
1006 mswin_get_nh_event();
1008 // build text to display later in message box
1009 GetNHApp()->saved_text
=
1010 realloc(GetNHApp()->saved_text
,
1011 strlen(text
) + strlen(GetNHApp()->saved_text
) + 1);
1012 strcat(GetNHApp()->saved_text
, text
);
1016 /* Display the file named str. Complain about missing files
1017 iff complain is TRUE.
1020 mswin_display_file(const char *filename
, BOOLEAN_P must_exist
)
1025 logDebug("mswin_display_file(%s, %d)\n", filename
, must_exist
);
1027 f
= dlb_fopen(filename
, RDTMODE
);
1031 _stprintf(message
, TEXT("Warning! Could not find file: %s\n"),
1032 NH_A2W(filename
, wbuf
, sizeof(wbuf
)));
1033 NHMessageBox(GetNHApp()->hMainWnd
, message
,
1034 MB_OK
| MB_ICONEXCLAMATION
);
1040 text
= mswin_create_nhwindow(NHW_TEXT
);
1042 while (dlb_fgets(line
, LLEN
, f
)) {
1045 if (line
[len
- 1] == '\n')
1046 line
[len
- 1] = '\x0';
1047 mswin_putstr(text
, ATR_NONE
, line
);
1049 (void) dlb_fclose(f
);
1051 mswin_display_nhwindow(text
, 1);
1052 mswin_destroy_nhwindow(text
);
1056 /* Start using window as a menu. You must call start_menu()
1057 before add_menu(). After calling start_menu() you may not
1058 putstr() to the window. Only windows of type NHW_MENU may
1062 mswin_start_menu(winid wid
)
1064 logDebug("mswin_start_menu(%d)\n", wid
);
1065 if ((wid
>= 0) && (wid
< MAXWINDOWS
)) {
1066 if (GetNHApp()->windowlist
[wid
].win
== NULL
1067 && GetNHApp()->windowlist
[wid
].type
== NHW_MENU
) {
1068 GetNHApp()->windowlist
[wid
].win
=
1069 mswin_init_menu_window(MENU_TYPE_MENU
);
1070 GetNHApp()->windowlist
[wid
].dead
= 0;
1073 if (GetNHApp()->windowlist
[wid
].win
!= NULL
) {
1074 SendMessage(GetNHApp()->windowlist
[wid
].win
, WM_MSNH_COMMAND
,
1075 (WPARAM
) MSNH_MSG_STARTMENU
, (LPARAM
) NULL
);
1081 add_menu(windid window, int glyph, const anything identifier,
1082 char accelerator, char groupacc,
1083 int attr, char *str, boolean preselected)
1084 -- Add a text line str to the given menu window. If
1086 is 0, then the line cannot be selected (e.g. a title).
1087 Otherwise, identifier is the value returned if the line is
1088 selected. Accelerator is a keyboard key that can be used
1089 to select the line. If the accelerator of a selectable
1090 item is 0, the window system is free to select its own
1091 accelerator. It is up to the window-port to make the
1092 accelerator visible to the user (e.g. put "a - " in front
1093 of str). The value attr is the same as in putstr().
1094 Glyph is an optional glyph to accompany the line. If
1095 window port cannot or does not want to display it, this
1096 is OK. If there is no glyph applicable, then this
1097 value will be NO_GLYPH.
1098 -- All accelerators should be in the range [A-Za-z].
1099 -- It is expected that callers do not mix accelerator
1100 choices. Either all selectable items have an accelerator
1101 or let the window system pick them. Don't do both.
1102 -- Groupacc is a group accelerator. It may be any character
1103 outside of the standard accelerator (see above) or a
1104 number. If 0, the item is unaffected by any group
1105 accelerator. If this accelerator conflicts with
1106 the menu command (or their user defined alises), it loses.
1107 The menu commands and aliases take care not to interfere
1108 with the default object class symbols.
1109 -- If you want this choice to be preselected when the
1110 menu is displayed, set preselected to TRUE.
1113 mswin_add_menu(winid wid
, int glyph
, const ANY_P
*identifier
,
1114 CHAR_P accelerator
, CHAR_P group_accel
, int attr
,
1115 const char *str
, BOOLEAN_P presel
)
1117 logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid
, glyph
,
1118 identifier
, (char) accelerator
, (char) group_accel
, attr
, str
,
1120 if ((wid
>= 0) && (wid
< MAXWINDOWS
)
1121 && (GetNHApp()->windowlist
[wid
].win
!= NULL
)) {
1122 MSNHMsgAddMenu data
;
1123 ZeroMemory(&data
, sizeof(data
));
1125 data
.identifier
= identifier
;
1126 data
.accelerator
= accelerator
;
1127 data
.group_accel
= group_accel
;
1130 data
.presel
= presel
;
1132 SendMessage(GetNHApp()->windowlist
[wid
].win
, WM_MSNH_COMMAND
,
1133 (WPARAM
) MSNH_MSG_ADDMENU
, (LPARAM
) &data
);
1138 end_menu(window, prompt)
1139 -- Stop adding entries to the menu and flushes the window
1140 to the screen (brings to front?). Prompt is a prompt
1141 to give the user. If prompt is NULL, no prompt will
1143 ** This probably shouldn't flush the window any more (if
1144 ** it ever did). That should be select_menu's job. -dean
1147 mswin_end_menu(winid wid
, const char *prompt
)
1149 logDebug("mswin_end_menu(%d, %s)\n", wid
, prompt
);
1150 if ((wid
>= 0) && (wid
< MAXWINDOWS
)
1151 && (GetNHApp()->windowlist
[wid
].win
!= NULL
)) {
1152 MSNHMsgEndMenu data
;
1153 ZeroMemory(&data
, sizeof(data
));
1156 SendMessage(GetNHApp()->windowlist
[wid
].win
, WM_MSNH_COMMAND
,
1157 (WPARAM
) MSNH_MSG_ENDMENU
, (LPARAM
) &data
);
1162 int select_menu(windid window, int how, menu_item **selected)
1163 -- Return the number of items selected; 0 if none were chosen,
1164 -1 when explicitly cancelled. If items were selected, then
1165 selected is filled in with an allocated array of menu_item
1166 structures, one for each selected line. The caller must
1167 free this array when done with it. The "count" field
1168 of selected is a user supplied count. If the user did
1169 not supply a count, then the count field is filled with
1170 -1 (meaning all). A count of zero is equivalent to not
1171 being selected and should not be in the list. If no items
1172 were selected, then selected is NULL'ed out. How is the
1173 mode of the menu. Three valid values are PICK_NONE,
1174 PICK_ONE, and PICK_N, meaning: nothing is selectable,
1175 only one thing is selectable, and any number valid items
1176 may selected. If how is PICK_NONE, this function should
1177 never return anything but 0 or -1.
1178 -- You may call select_menu() on a window multiple times --
1179 the menu is saved until start_menu() or destroy_nhwindow()
1180 is called on the window.
1181 -- Note that NHW_MENU windows need not have select_menu()
1182 called for them. There is no way of knowing whether
1183 select_menu() will be called for the window at
1184 create_nhwindow() time.
1187 mswin_select_menu(winid wid
, int how
, MENU_ITEM_P
**selected
)
1191 logDebug("mswin_select_menu(%d, %d)\n", wid
, how
);
1193 if ((wid
>= 0) && (wid
< MAXWINDOWS
)
1194 && (GetNHApp()->windowlist
[wid
].win
!= NULL
)) {
1195 ShowWindow(GetNHApp()->windowlist
[wid
].win
, SW_SHOW
);
1196 nReturned
= mswin_menu_window_select_menu(
1197 GetNHApp()->windowlist
[wid
].win
, how
, selected
,
1198 !(flags
.perm_invent
&& wid
== WIN_INVEN
1199 && how
== PICK_NONE
) /* don't activate inventory window if
1200 perm_invent is on */
1207 -- Indicate to the window port that the inventory has been changed.
1208 -- Merely calls display_inventory() for window-ports that leave the
1209 window up, otherwise empty.
1212 mswin_update_inventory()
1214 logDebug("mswin_update_inventory()\n");
1215 if (flags
.perm_invent
&& program_state
.something_worth_saving
1216 && iflags
.window_inited
&& WIN_INVEN
!= WIN_ERR
)
1217 display_inventory(NULL
, FALSE
);
1221 mark_synch() -- Don't go beyond this point in I/O on any channel until
1222 all channels are caught up to here. Can be an empty call
1228 logDebug("mswin_mark_synch()\n");
1232 wait_synch() -- Wait until all pending output is complete (*flush*() for
1234 -- May also deal with exposure events etc. so that the
1235 display is OK when return from wait_synch().
1240 logDebug("mswin_wait_synch()\n");
1244 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
1245 screen if the playing area is larger than the screen.
1246 -- This function is only defined if CLIPPING is defined.
1249 mswin_cliparound(int x
, int y
)
1251 winid wid
= WIN_MAP
;
1253 logDebug("mswin_cliparound(%d, %d)\n", x
, y
);
1255 if ((wid
>= 0) && (wid
< MAXWINDOWS
)
1256 && (GetNHApp()->windowlist
[wid
].win
!= NULL
)) {
1257 MSNHMsgClipAround data
;
1260 SendMessage(GetNHApp()->windowlist
[wid
].win
, WM_MSNH_COMMAND
,
1261 (WPARAM
) MSNH_MSG_CLIPAROUND
, (LPARAM
) &data
);
1266 print_glyph(window, x, y, glyph, bkglyph)
1267 -- Print the glyph at (x,y) on the given window. Glyphs are
1268 integers at the interface, mapped to whatever the window-
1269 port wants (symbol, font, color, attributes, ...there's
1270 a 1-1 map between glyphs and distinct things on the map).
1271 -- bkglyph is a background glyph for potential use by some
1272 graphical or tiled environments to allow the depiction
1273 to fall against a background consistent with the grid
1278 mswin_print_glyph(winid wid
, XCHAR_P x
, XCHAR_P y
, int glyph
, int bkglyph
)
1280 logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid
, x
, y
, glyph
, bkglyph
);
1282 if ((wid
>= 0) && (wid
< MAXWINDOWS
)
1283 && (GetNHApp()->windowlist
[wid
].win
!= NULL
)) {
1284 MSNHMsgPrintGlyph data
;
1286 ZeroMemory(&data
, sizeof(data
));
1290 data
.bkglyph
= bkglyph
;
1291 SendMessage(GetNHApp()->windowlist
[wid
].win
, WM_MSNH_COMMAND
,
1292 (WPARAM
) MSNH_MSG_PRINT_GLYPH
, (LPARAM
) &data
);
1297 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
1298 the user sees str. raw_print() appends a newline to str.
1299 It need not recognize ASCII control characters. This is
1300 used during startup (before windowing system initialization
1301 -- maybe this means only error startup messages are raw),
1302 for error messages, and maybe other "msg" uses. E.g.
1303 updating status for micros (i.e, "saving").
1306 mswin_raw_print(const char *str
)
1309 logDebug("mswin_raw_print(%s)\n", str
);
1311 extern int redirect_stdout
;
1312 if (!redirect_stdout
)
1313 NHMessageBox(GetNHApp()->hMainWnd
,
1314 NH_A2W(str
, wbuf
, sizeof(wbuf
)),
1315 MB_ICONINFORMATION
| MB_OK
);
1317 fprintf(stdout
, "%s", str
);
1323 -- Like raw_print(), but prints in bold/standout (if
1327 mswin_raw_print_bold(const char *str
)
1330 logDebug("mswin_raw_print_bold(%s)\n", str
);
1332 NHMessageBox(GetNHApp()->hMainWnd
, NH_A2W(str
, wbuf
, sizeof(wbuf
)),
1333 MB_ICONINFORMATION
| MB_OK
);
1337 int nhgetch() -- Returns a single character input from the user.
1338 -- In the tty window-port, nhgetch() assumes that tgetch()
1339 will be the routine the OS provides to read a character.
1340 Returned character _must_ be non-zero.
1348 logDebug("mswin_nhgetch()\n");
1350 while ((event
= mswin_input_pop()) == NULL
|| event
->type
!= NHEVENT_CHAR
)
1353 key
= event
->kbd
.ch
;
1358 int nh_poskey(int *x, int *y, int *mod)
1359 -- Returns a single character input from the user or a
1360 a positioning event (perhaps from a mouse). If the
1361 return value is non-zero, a character was typed, else,
1362 a position in the MAP window is returned in x, y and mod.
1365 CLICK_1 -- mouse click type 1
1366 CLICK_2 -- mouse click type 2
1368 The different click types can map to whatever the
1369 hardware supports. If no mouse is supported, this
1370 routine always returns a non-zero character.
1373 mswin_nh_poskey(int *x
, int *y
, int *mod
)
1378 logDebug("mswin_nh_poskey()\n");
1380 while ((event
= mswin_input_pop()) == NULL
)
1383 if (event
->type
== NHEVENT_MOUSE
) {
1384 *mod
= event
->ms
.mod
;
1389 key
= event
->kbd
.ch
;
1395 nhbell() -- Beep at user. [This will exist at least until sounds are
1396 redone, since sounds aren't attributable to windows
1402 logDebug("mswin_nhbell()\n");
1407 -- Display previous messages. Used by the ^P command.
1408 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1411 mswin_doprev_message()
1413 logDebug("mswin_doprev_message()\n");
1414 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE
), WM_VSCROLL
,
1415 MAKEWPARAM(SB_LINEUP
, 0), (LPARAM
) NULL
);
1420 char yn_function(const char *ques, const char *choices, char default)
1421 -- Print a prompt made up of ques, choices and default.
1422 Read a single character response that is contained in
1423 choices or default. If choices is NULL, all possible
1424 inputs are accepted and returned. This overrides
1425 everything else. The choices are expected to be in
1426 lower case. Entering ESC always maps to 'q', or 'n',
1427 in that order, if present in choices, otherwise it maps
1428 to default. Entering any other quit character (SPACE,
1429 RETURN, NEWLINE) maps to default.
1430 -- If the choices string contains ESC, then anything after
1431 it is an acceptable response, but the ESC and whatever
1432 follows is not included in the prompt.
1433 -- If the choices string contains a '#' then accept a count.
1434 Place this value in the global "yn_number" and return '#'.
1435 -- This uses the top line in the tty window-port, other
1436 ports might use a popup.
1439 mswin_yn_function(const char *question
, const char *choices
, CHAR_P def
)
1442 char yn_esc_map
= '\033';
1443 char message
[BUFSZ
];
1446 boolean digit_ok
, allow_num
;
1448 logDebug("mswin_yn_function(%s, %s, %d)\n", question
, choices
, def
);
1450 if (WIN_MESSAGE
== WIN_ERR
&& choices
== ynchars
) {
1452 realloc(strdup(GetNHApp()->saved_text
),
1453 strlen(question
) + strlen(GetNHApp()->saved_text
) + 1);
1455 strcat(text
, question
);
1457 NHMessageBox(NULL
, NH_W2A(text
, message
, sizeof(message
)),
1458 MB_ICONQUESTION
| MB_YESNOCANCEL
1459 | ((def
== 'y') ? MB_DEFBUTTON1
1460 : (def
== 'n') ? MB_DEFBUTTON2
1463 GetNHApp()->saved_text
= strdup("");
1464 return box_result
== IDYES
? 'y' : box_result
== IDNO
? 'n' : '\033';
1468 char *cb
, choicebuf
[QBUFSZ
];
1470 allow_num
= (index(choices
, '#') != 0);
1472 Strcpy(choicebuf
, choices
);
1473 if ((cb
= index(choicebuf
, '\033')) != 0) {
1474 /* anything beyond <esc> is hidden */
1477 (void) strncpy(message
, question
, QBUFSZ
- 1);
1478 message
[QBUFSZ
- 1] = '\0';
1479 sprintf(eos(message
), " [%s]", choicebuf
);
1481 sprintf(eos(message
), " (%c)", def
);
1482 Strcat(message
, " ");
1483 /* escape maps to 'q' or 'n' or default, in that order */
1485 (index(choices
, 'q') ? 'q' : (index(choices
, 'n') ? 'n' : def
));
1487 Strcpy(message
, question
);
1488 Strcat(message
, " ");
1492 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE
), WM_MSNH_COMMAND
,
1493 (WPARAM
) MSNH_MSG_CARET
, (LPARAM
) &createcaret
);
1495 mswin_clear_nhwindow(WIN_MESSAGE
);
1496 mswin_putstr(WIN_MESSAGE
, ATR_BOLD
, message
);
1498 /* Only here if main window is not present */
1501 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE
));
1502 ch
= mswin_nhgetch();
1503 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE
));
1507 break; /* If choices is NULL, all possible inputs are accepted and
1510 digit_ok
= allow_num
&& digit(ch
);
1512 if (index(choices
, 'q'))
1514 else if (index(choices
, 'n'))
1519 } else if (index(quitchars
, ch
)) {
1522 } else if (!index(choices
, ch
) && !digit_ok
) {
1525 /* and try again... */
1526 } else if (ch
== '#' || digit_ok
) {
1527 char z
, digit_string
[2];
1530 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, ("#"), 1);
1532 digit_string
[1] = '\0';
1534 digit_string
[0] = ch
;
1535 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, digit_string
, 1);
1540 do { /* loop until we get a non-digit */
1541 z
= lowc(readchar());
1543 value
= (10 * value
) + (z
- '0');
1545 break; /* overflow: try again */
1546 digit_string
[0] = z
;
1547 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, digit_string
, 1);
1549 } else if (z
== 'y' || index(quitchars
, z
)) {
1551 value
= -1; /* abort */
1552 z
= '\n'; /* break */
1553 } else if (z
== '\b') {
1559 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, digit_string
,
1564 value
= -1; /* abort */
1568 } while (z
!= '\n');
1571 else if (value
== 0)
1572 ch
= 'n'; /* 0 => "no" */
1573 else { /* remove number from top line, then try again */
1574 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, digit_string
, -n_len
);
1582 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE
), WM_MSNH_COMMAND
,
1583 (WPARAM
) MSNH_MSG_CARET
, (LPARAM
) &createcaret
);
1585 /* display selection in the message window */
1586 if (isprint((uchar
) ch
) && ch
!= '#') {
1589 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, res_ch
, 1);
1596 getlin(const char *ques, char *input)
1597 -- Prints ques as a prompt and reads a single line of text,
1598 up to a newline. The string entered is returned without the
1599 newline. ESC is used to cancel, in which case the string
1600 "\033\000" is returned.
1601 -- getlin() must call flush_screen(1) before doing anything.
1602 -- This uses the top line in the tty window-port, other
1603 ports might use a popup.
1606 mswin_getlin(const char *question
, char *input
)
1608 logDebug("mswin_getlin(%s, %p)\n", question
, input
);
1610 if (!iflags
.wc_popup_dialog
) {
1617 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE
), WM_MSNH_COMMAND
,
1618 (WPARAM
) MSNH_MSG_CARET
, (LPARAM
) &createcaret
);
1620 mswin_clear_nhwindow(WIN_MESSAGE
);
1621 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, question
, 0);
1622 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, " ", 1);
1625 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE
));
1628 c
= mswin_nhgetch();
1631 strcpy(input
, "\033");
1641 mswin_putstr_ex(WIN_MESSAGE
, ATR_NONE
, input
, -len
);
1646 } else if (len
>=(BUFSZ
-1)) {
1647 PlaySound((LPCSTR
)SND_ALIAS_SYSTEMEXCLAMATION
, NULL
, SND_ALIAS_ID
|SND_ASYNC
);
1652 mswin_putstr_ex(WIN_MESSAGE
, ATR_NONE
, input
, 1);
1656 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE
));
1658 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE
), WM_MSNH_COMMAND
,
1659 (WPARAM
) MSNH_MSG_CARET
, (LPARAM
) &createcaret
);
1661 if (mswin_getlin_window(question
, input
, BUFSZ
) == IDCANCEL
) {
1662 strcpy(input
, "\033");
1668 int get_ext_cmd(void)
1669 -- Get an extended command in a window-port specific way.
1670 An index into extcmdlist[] is returned on a successful
1671 selection, -1 otherwise.
1677 logDebug("mswin_get_ext_cmd()\n");
1679 if (!iflags
.wc_popup_dialog
) {
1686 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE
), WM_MSNH_COMMAND
,
1687 (WPARAM
) MSNH_MSG_CARET
, (LPARAM
) &createcaret
);
1691 mswin_clear_nhwindow(WIN_MESSAGE
);
1692 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, "#", 0);
1694 ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE
));
1696 int oindex
, com_index
;
1697 c
= mswin_nhgetch();
1705 for (i
= 0; extcmdlist
[i
].ef_txt
!= (char *) 0; i
++)
1706 if (!strcmpi(cmd
, extcmdlist
[i
].ef_txt
))
1709 if (extcmdlist
[i
].ef_txt
== (char *) 0) {
1710 pline("%s: unknown extended command.", cmd
);
1716 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, cmd
,
1717 -(int) strlen(cmd
));
1725 /* Find a command with this prefix in extcmdlist */
1727 for (oindex
= 0; extcmdlist
[oindex
].ef_txt
!= (char *) 0;
1729 if ((extcmdlist
[oindex
].flags
& AUTOCOMPLETE
)
1730 && !(!wizard
&& (extcmdlist
[oindex
].flags
& WIZMODECMD
))
1731 && !strncmpi(cmd
, extcmdlist
[oindex
].ef_txt
, len
)) {
1732 if (com_index
== -1) /* no matches yet */
1736 -2; /* two matches, don't complete */
1739 if (com_index
>= 0) {
1740 Strcpy(cmd
, extcmdlist
[com_index
].ef_txt
);
1743 mswin_putstr_ex(WIN_MESSAGE
, ATR_BOLD
, cmd
, 1);
1747 HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE
));
1749 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE
), WM_MSNH_COMMAND
,
1750 (WPARAM
) MSNH_MSG_CARET
, (LPARAM
) &createcaret
);
1753 if (mswin_ext_cmd_window(&ret
) == IDCANCEL
)
1762 -- Initialize the number pad to the given state.
1765 mswin_number_pad(int state
)
1768 logDebug("mswin_number_pad(%d)\n", state
);
1772 delay_output() -- Causes a visible delay of 50ms in the output.
1773 Conceptually, this is similar to wait_synch() followed
1774 by a nap(50ms), but allows asynchronous operation.
1777 mswin_delay_output()
1779 logDebug("mswin_delay_output()\n");
1784 mswin_change_color()
1786 logDebug("mswin_change_color()\n");
1790 mswin_get_color_string()
1792 logDebug("mswin_get_color_string()\n");
1797 start_screen() -- Only used on Unix tty ports, but must be declared for
1798 completeness. Sets up the tty to work in full-screen
1799 graphics mode. Look at win/tty/termcap.c for an
1800 example. If your window-port does not need this function
1801 just declare an empty function.
1804 mswin_start_screen()
1807 logDebug("mswin_start_screen()\n");
1811 end_screen() -- Only used on Unix tty ports, but must be declared for
1812 completeness. The complement of start_screen().
1818 logDebug("mswin_end_screen()\n");
1822 outrip(winid, int, when)
1823 -- The tombstone code. If you want the traditional code use
1824 genl_outrip for the value and check the #if in rip.c.
1826 #define STONE_LINE_LEN 16
1828 mswin_outrip(winid wid
, int how
, time_t when
)
1833 logDebug("mswin_outrip(%d, %d, %ld)\n", wid
, how
, (long) when
);
1834 if ((wid
>= 0) && (wid
< MAXWINDOWS
)) {
1835 DestroyWindow(GetNHApp()->windowlist
[wid
].win
);
1836 GetNHApp()->windowlist
[wid
].win
= mswin_init_RIP_window();
1837 GetNHApp()->windowlist
[wid
].type
= NHW_RIP
;
1838 GetNHApp()->windowlist
[wid
].dead
= 0;
1841 /* Put name on stone */
1842 Sprintf(buf
, "%s", plname
);
1843 buf
[STONE_LINE_LEN
] = 0;
1844 putstr(wid
, 0, buf
);
1846 /* Put $ on stone */
1847 Sprintf(buf
, "%ld Au", done_money
);
1848 buf
[STONE_LINE_LEN
] = 0; /* It could be a *lot* of gold :-) */
1849 putstr(wid
, 0, buf
);
1851 /* Put together death description */
1852 formatkiller(buf
, sizeof buf
, how
, FALSE
);
1854 /* Put death type on stone */
1855 putstr(wid
, 0, buf
);
1857 /* Put year on stone */
1858 year
= yyyymmdd(when
) / 10000L;
1859 Sprintf(buf
, "%4ld", year
);
1860 putstr(wid
, 0, buf
);
1861 mswin_finish_rip_text(wid
);
1864 /* handle options updates here */
1866 mswin_preference_update(const char *pref
)
1871 if (stricmp(pref
, "font_menu") == 0
1872 || stricmp(pref
, "font_size_menu") == 0) {
1873 if (iflags
.wc_fontsiz_menu
< NHFONT_SIZE_MIN
1874 || iflags
.wc_fontsiz_menu
> NHFONT_SIZE_MAX
)
1875 iflags
.wc_fontsiz_menu
= NHFONT_DEFAULT_SIZE
;
1877 hdc
= GetDC(GetNHApp()->hMainWnd
);
1878 mswin_get_font(NHW_MENU
, ATR_NONE
, hdc
, TRUE
);
1879 mswin_get_font(NHW_MENU
, ATR_BOLD
, hdc
, TRUE
);
1880 mswin_get_font(NHW_MENU
, ATR_DIM
, hdc
, TRUE
);
1881 mswin_get_font(NHW_MENU
, ATR_ULINE
, hdc
, TRUE
);
1882 mswin_get_font(NHW_MENU
, ATR_BLINK
, hdc
, TRUE
);
1883 mswin_get_font(NHW_MENU
, ATR_INVERSE
, hdc
, TRUE
);
1884 ReleaseDC(GetNHApp()->hMainWnd
, hdc
);
1886 mswin_layout_main_window(NULL
);
1890 if (stricmp(pref
, "font_status") == 0
1891 || stricmp(pref
, "font_size_status") == 0) {
1892 if (iflags
.wc_fontsiz_status
< NHFONT_SIZE_MIN
1893 || iflags
.wc_fontsiz_status
> NHFONT_SIZE_MAX
)
1894 iflags
.wc_fontsiz_status
= NHFONT_DEFAULT_SIZE
;
1896 hdc
= GetDC(GetNHApp()->hMainWnd
);
1897 mswin_get_font(NHW_STATUS
, ATR_NONE
, hdc
, TRUE
);
1898 mswin_get_font(NHW_STATUS
, ATR_BOLD
, hdc
, TRUE
);
1899 mswin_get_font(NHW_STATUS
, ATR_DIM
, hdc
, TRUE
);
1900 mswin_get_font(NHW_STATUS
, ATR_ULINE
, hdc
, TRUE
);
1901 mswin_get_font(NHW_STATUS
, ATR_BLINK
, hdc
, TRUE
);
1902 mswin_get_font(NHW_STATUS
, ATR_INVERSE
, hdc
, TRUE
);
1903 ReleaseDC(GetNHApp()->hMainWnd
, hdc
);
1905 for (i
= 1; i
< MAXWINDOWS
; i
++) {
1906 if (GetNHApp()->windowlist
[i
].type
== NHW_STATUS
1907 && GetNHApp()->windowlist
[i
].win
!= NULL
) {
1908 InvalidateRect(GetNHApp()->windowlist
[i
].win
, NULL
, TRUE
);
1911 mswin_layout_main_window(NULL
);
1915 if (stricmp(pref
, "font_message") == 0
1916 || stricmp(pref
, "font_size_message") == 0) {
1917 if (iflags
.wc_fontsiz_message
< NHFONT_SIZE_MIN
1918 || iflags
.wc_fontsiz_message
> NHFONT_SIZE_MAX
)
1919 iflags
.wc_fontsiz_message
= NHFONT_DEFAULT_SIZE
;
1921 hdc
= GetDC(GetNHApp()->hMainWnd
);
1922 mswin_get_font(NHW_MESSAGE
, ATR_NONE
, hdc
, TRUE
);
1923 mswin_get_font(NHW_MESSAGE
, ATR_BOLD
, hdc
, TRUE
);
1924 mswin_get_font(NHW_MESSAGE
, ATR_DIM
, hdc
, TRUE
);
1925 mswin_get_font(NHW_MESSAGE
, ATR_ULINE
, hdc
, TRUE
);
1926 mswin_get_font(NHW_MESSAGE
, ATR_BLINK
, hdc
, TRUE
);
1927 mswin_get_font(NHW_MESSAGE
, ATR_INVERSE
, hdc
, TRUE
);
1928 ReleaseDC(GetNHApp()->hMainWnd
, hdc
);
1930 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE
), NULL
, TRUE
);
1931 mswin_layout_main_window(NULL
);
1935 if (stricmp(pref
, "font_text") == 0
1936 || stricmp(pref
, "font_size_text") == 0) {
1937 if (iflags
.wc_fontsiz_text
< NHFONT_SIZE_MIN
1938 || iflags
.wc_fontsiz_text
> NHFONT_SIZE_MAX
)
1939 iflags
.wc_fontsiz_text
= NHFONT_DEFAULT_SIZE
;
1941 hdc
= GetDC(GetNHApp()->hMainWnd
);
1942 mswin_get_font(NHW_TEXT
, ATR_NONE
, hdc
, TRUE
);
1943 mswin_get_font(NHW_TEXT
, ATR_BOLD
, hdc
, TRUE
);
1944 mswin_get_font(NHW_TEXT
, ATR_DIM
, hdc
, TRUE
);
1945 mswin_get_font(NHW_TEXT
, ATR_ULINE
, hdc
, TRUE
);
1946 mswin_get_font(NHW_TEXT
, ATR_BLINK
, hdc
, TRUE
);
1947 mswin_get_font(NHW_TEXT
, ATR_INVERSE
, hdc
, TRUE
);
1948 ReleaseDC(GetNHApp()->hMainWnd
, hdc
);
1950 mswin_layout_main_window(NULL
);
1954 if (stricmp(pref
, "scroll_amount") == 0) {
1955 mswin_cliparound(u
.ux
, u
.uy
);
1959 if (stricmp(pref
, "scroll_margin") == 0) {
1960 mswin_cliparound(u
.ux
, u
.uy
);
1964 if (stricmp(pref
, "map_mode") == 0) {
1965 mswin_select_map_mode(iflags
.wc_map_mode
);
1969 if (stricmp(pref
, "hilite_pet") == 0) {
1970 InvalidateRect(mswin_hwnd_from_winid(WIN_MAP
), NULL
, TRUE
);
1974 if (stricmp(pref
, "align_message") == 0
1975 || stricmp(pref
, "align_status") == 0) {
1976 mswin_layout_main_window(NULL
);
1980 if (stricmp(pref
, "vary_msgcount") == 0) {
1981 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE
), NULL
, TRUE
);
1982 mswin_layout_main_window(NULL
);
1986 if (stricmp(pref
, "perm_invent") == 0) {
1987 mswin_update_inventory();
1992 #define TEXT_BUFFER_SIZE 4096
1994 mswin_getmsghistory(BOOLEAN_P init
)
1996 static PMSNHMsgGetText text
= 0;
1997 static char *next_message
= 0;
2000 text
= (PMSNHMsgGetText
) malloc(sizeof(MSNHMsgGetText
)
2001 + TEXT_BUFFER_SIZE
);
2004 - 1; /* make sure we always have 0 at the end of the buffer */
2006 ZeroMemory(text
->buffer
, TEXT_BUFFER_SIZE
);
2007 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE
), WM_MSNH_COMMAND
,
2008 (WPARAM
) MSNH_MSG_GETTEXT
, (LPARAM
) text
);
2010 next_message
= text
->buffer
;
2013 if (!(next_message
&& next_message
[0])) {
2018 char *retval
= next_message
;
2020 next_message
= p
= strchr(next_message
, '\n');
2024 while (p
>= retval
&& isspace((uchar
) *p
))
2025 *p
-- = (char) 0; /* delete trailing whitespace */
2031 mswin_putmsghistory(const char *msg
, BOOLEAN_P restoring
)
2033 BOOL save_sound_opt
;
2035 UNREFERENCED_PARAMETER(restoring
);
2038 return; /* end of message history restore */
2039 save_sound_opt
= GetNHApp()->bNoSounds
;
2040 GetNHApp()->bNoSounds
=
2041 TRUE
; /* disable sounds while restoring message history */
2042 mswin_putstr_ex(WIN_MESSAGE
, ATR_NONE
, msg
, 0);
2043 clear_nhwindow(WIN_MESSAGE
); /* it is in fact end-of-turn indication so
2044 each message will print on the new line */
2045 GetNHApp()->bNoSounds
= save_sound_opt
; /* restore sounds option */
2053 while (!mswin_have_input() && GetMessage(&msg
, NULL
, 0, 0) != 0) {
2054 if (GetNHApp()->regNetHackMode
2055 || !TranslateAccelerator(msg
.hwnd
, GetNHApp()->hAccelTable
,
2057 TranslateMessage(&msg
);
2058 DispatchMessage(&msg
);
2063 /* clean up and quit */
2065 bail(const char *mesg
)
2068 mswin_exit_nhwindows(mesg
);
2069 terminate(EXIT_SUCCESS
);
2078 TCHAR wbuf
[MAX_PATH
];
2081 extern int total_tiles_used
;
2083 /* no file - no tile */
2084 if (!(iflags
.wc_tile_file
&& *iflags
.wc_tile_file
))
2088 hBmp
= LoadImage(GetNHApp()->hApp
,
2089 NH_A2W(iflags
.wc_tile_file
, wbuf
, MAX_PATH
),
2090 IMAGE_BITMAP
, 0, 0, LR_LOADFROMFILE
| LR_DEFAULTSIZE
);
2093 "Cannot load tiles from the file. Reverting back to default.");
2097 /* calculate tile dimensions */
2098 GetObject(hBmp
, sizeof(BITMAP
), (LPVOID
) &bm
);
2099 if (bm
.bmWidth
% iflags
.wc_tile_width
2100 || bm
.bmHeight
% iflags
.wc_tile_height
) {
2102 raw_print("Tiles bitmap does not match tile_width and tile_height "
2103 "options. Reverting back to default.");
2107 tl_num
= (bm
.bmWidth
/ iflags
.wc_tile_width
)
2108 * (bm
.bmHeight
/ iflags
.wc_tile_height
);
2109 if (tl_num
< total_tiles_used
) {
2111 raw_print("Number of tiles in the bitmap is less than required by "
2112 "the game. Reverting back to default.");
2116 /* set the tile information */
2117 if (GetNHApp()->bmpMapTiles
!= GetNHApp()->bmpTiles
) {
2118 DeleteObject(GetNHApp()->bmpMapTiles
);
2121 GetNHApp()->bmpMapTiles
= hBmp
;
2122 GetNHApp()->mapTile_X
= iflags
.wc_tile_width
;
2123 GetNHApp()->mapTile_Y
= iflags
.wc_tile_height
;
2124 GetNHApp()->mapTilesPerLine
= bm
.bmWidth
/ iflags
.wc_tile_width
;
2126 map_size
.cx
= GetNHApp()->mapTile_X
* COLNO
;
2127 map_size
.cy
= GetNHApp()->mapTile_Y
* ROWNO
;
2128 mswin_map_stretch(mswin_hwnd_from_winid(WIN_MAP
), &map_size
, TRUE
);
2133 mswin_popup_display(HWND hWnd
, int *done_indicator
)
2141 /* activate the menu window */
2142 GetNHApp()->hPopupWnd
= hWnd
;
2144 mswin_layout_main_window(hWnd
);
2146 /* disable game windows */
2147 for (hChild
= GetWindow(GetNHApp()->hMainWnd
, GW_CHILD
); hChild
;
2148 hChild
= GetWindow(hChild
, GW_HWNDNEXT
)) {
2150 EnableWindow(hChild
, FALSE
);
2154 hMenu
= GetMenu(GetNHApp()->hMainWnd
);
2155 mi_count
= GetMenuItemCount(hMenu
);
2156 for (i
= 0; i
< mi_count
; i
++) {
2157 EnableMenuItem(hMenu
, i
, MF_BYPOSITION
| MF_GRAYED
);
2159 DrawMenuBar(GetNHApp()->hMainWnd
);
2161 /* bring menu window on top */
2162 SetWindowPos(hWnd
, HWND_TOP
, 0, 0, 0, 0,
2163 SWP_NOMOVE
| SWP_NOSIZE
| SWP_SHOWWINDOW
);
2166 /* go into message loop */
2167 while (IsWindow(hWnd
) && (done_indicator
== NULL
|| !*done_indicator
)
2168 && GetMessage(&msg
, NULL
, 0, 0) != 0) {
2169 if (!IsDialogMessage(hWnd
, &msg
)) {
2170 if (!TranslateAccelerator(msg
.hwnd
, GetNHApp()->hAccelTable
,
2172 TranslateMessage(&msg
);
2173 DispatchMessage(&msg
);
2180 mswin_popup_destroy(HWND hWnd
)
2187 /* enable game windows */
2188 for (hChild
= GetWindow(GetNHApp()->hMainWnd
, GW_CHILD
); hChild
;
2189 hChild
= GetWindow(hChild
, GW_HWNDNEXT
)) {
2190 if (hChild
!= hWnd
) {
2191 EnableWindow(hChild
, TRUE
);
2196 hMenu
= GetMenu(GetNHApp()->hMainWnd
);
2197 mi_count
= GetMenuItemCount(hMenu
);
2198 for (i
= 0; i
< mi_count
; i
++) {
2199 EnableMenuItem(hMenu
, i
, MF_BYPOSITION
| MF_ENABLED
);
2201 DrawMenuBar(GetNHApp()->hMainWnd
);
2203 ShowWindow(hWnd
, SW_HIDE
);
2204 GetNHApp()->hPopupWnd
= NULL
;
2206 mswin_layout_main_window(hWnd
);
2208 SetFocus(GetNHApp()->hMainWnd
);
2216 logDebug(const char *fmt
, ...)
2220 if (!showdebug(NHTRACE_LOG
) || !_s_debugfp
)
2223 va_start(args
, fmt
);
2224 vfprintf(_s_debugfp
, fmt
, args
);
2231 /* Reading and writing settings from the registry. */
2232 #define CATEGORYKEY "Software"
2233 #define COMPANYKEY "NetHack"
2234 #define PRODUCTKEY "NetHack 3.6.1"
2235 #define SETTINGSKEY "Settings"
2236 #define MAINSHOWSTATEKEY "MainShowState"
2237 #define MAINMINXKEY "MainMinX"
2238 #define MAINMINYKEY "MainMinY"
2239 #define MAINMAXXKEY "MainMaxX"
2240 #define MAINMAXYKEY "MainMaxY"
2241 #define MAINLEFTKEY "MainLeft"
2242 #define MAINRIGHTKEY "MainRight"
2243 #define MAINTOPKEY "MainTop"
2244 #define MAINBOTTOMKEY "MainBottom"
2245 #define MAINAUTOLAYOUT "AutoLayout"
2246 #define MAPLEFT "MapLeft"
2247 #define MAPRIGHT "MapRight"
2248 #define MAPTOP "MapTop"
2249 #define MAPBOTTOM "MapBottom"
2250 #define MSGLEFT "MsgLeft"
2251 #define MSGRIGHT "MsgRight"
2252 #define MSGTOP "MsgTop"
2253 #define MSGBOTTOM "MsgBottom"
2254 #define STATUSLEFT "StatusLeft"
2255 #define STATUSRIGHT "StatusRight"
2256 #define STATUSTOP "StatusTop"
2257 #define STATUSBOTTOM "StatusBottom"
2258 #define MENULEFT "MenuLeft"
2259 #define MENURIGHT "MenuRight"
2260 #define MENUTOP "MenuTop"
2261 #define MENUBOTTOM "MenuBottom"
2262 #define TEXTLEFT "TextLeft"
2263 #define TEXTRIGHT "TextRight"
2264 #define TEXTTOP "TextTop"
2265 #define TEXTBOTTOM "TextBottom"
2266 #define INVENTLEFT "InventLeft"
2267 #define INVENTRIGHT "InventRight"
2268 #define INVENTTOP "InventTop"
2269 #define INVENTBOTTOM "InventBottom"
2271 /* #define all the subkeys here */
2272 #define INTFKEY "Interface"
2280 char keystring
[MAX_PATH
];
2282 sprintf(keystring
, "%s\\%s\\%s\\%s", CATEGORYKEY
, COMPANYKEY
, PRODUCTKEY
,
2285 /* Set the defaults here. The very first time the app is started, nothing
2287 read from the registry, so these defaults apply. */
2288 GetNHApp()->saveRegistrySettings
= 1; /* Normally, we always save */
2289 GetNHApp()->regNetHackMode
= TRUE
;
2291 if (RegOpenKeyEx(HKEY_CURRENT_USER
, keystring
, 0, KEY_READ
, &key
)
2295 size
= sizeof(DWORD
);
2297 #define NHGETREG_DWORD(name, val) \
2298 RegQueryValueEx(key, (name), 0, NULL, (unsigned char *)(&safe_buf), \
2302 /* read the keys here */
2303 NHGETREG_DWORD(INTFKEY
, GetNHApp()->regNetHackMode
);
2305 /* read window placement */
2306 NHGETREG_DWORD(MAINSHOWSTATEKEY
, GetNHApp()->regMainShowState
);
2307 NHGETREG_DWORD(MAINMINXKEY
, GetNHApp()->regMainMinX
);
2308 NHGETREG_DWORD(MAINMINYKEY
, GetNHApp()->regMainMinY
);
2309 NHGETREG_DWORD(MAINMAXXKEY
, GetNHApp()->regMainMaxX
);
2310 NHGETREG_DWORD(MAINMAXYKEY
, GetNHApp()->regMainMaxY
);
2311 NHGETREG_DWORD(MAINLEFTKEY
, GetNHApp()->regMainLeft
);
2312 NHGETREG_DWORD(MAINRIGHTKEY
, GetNHApp()->regMainRight
);
2313 NHGETREG_DWORD(MAINTOPKEY
, GetNHApp()->regMainTop
);
2314 NHGETREG_DWORD(MAINBOTTOMKEY
, GetNHApp()->regMainBottom
);
2316 NHGETREG_DWORD(MAINAUTOLAYOUT
, GetNHApp()->bAutoLayout
);
2317 NHGETREG_DWORD(MAPLEFT
, GetNHApp()->rtMapWindow
.left
);
2318 NHGETREG_DWORD(MAPRIGHT
, GetNHApp()->rtMapWindow
.right
);
2319 NHGETREG_DWORD(MAPTOP
, GetNHApp()->rtMapWindow
.top
);
2320 NHGETREG_DWORD(MAPBOTTOM
, GetNHApp()->rtMapWindow
.bottom
);
2321 NHGETREG_DWORD(MSGLEFT
, GetNHApp()->rtMsgWindow
.left
);
2322 NHGETREG_DWORD(MSGRIGHT
, GetNHApp()->rtMsgWindow
.right
);
2323 NHGETREG_DWORD(MSGTOP
, GetNHApp()->rtMsgWindow
.top
);
2324 NHGETREG_DWORD(MSGBOTTOM
, GetNHApp()->rtMsgWindow
.bottom
);
2325 NHGETREG_DWORD(STATUSLEFT
, GetNHApp()->rtStatusWindow
.left
);
2326 NHGETREG_DWORD(STATUSRIGHT
, GetNHApp()->rtStatusWindow
.right
);
2327 NHGETREG_DWORD(STATUSTOP
, GetNHApp()->rtStatusWindow
.top
);
2328 NHGETREG_DWORD(STATUSBOTTOM
, GetNHApp()->rtStatusWindow
.bottom
);
2329 NHGETREG_DWORD(MENULEFT
, GetNHApp()->rtMenuWindow
.left
);
2330 NHGETREG_DWORD(MENURIGHT
, GetNHApp()->rtMenuWindow
.right
);
2331 NHGETREG_DWORD(MENUTOP
, GetNHApp()->rtMenuWindow
.top
);
2332 NHGETREG_DWORD(MENUBOTTOM
, GetNHApp()->rtMenuWindow
.bottom
);
2333 NHGETREG_DWORD(TEXTLEFT
, GetNHApp()->rtTextWindow
.left
);
2334 NHGETREG_DWORD(TEXTRIGHT
, GetNHApp()->rtTextWindow
.right
);
2335 NHGETREG_DWORD(TEXTTOP
, GetNHApp()->rtTextWindow
.top
);
2336 NHGETREG_DWORD(TEXTBOTTOM
, GetNHApp()->rtTextWindow
.bottom
);
2337 NHGETREG_DWORD(INVENTLEFT
, GetNHApp()->rtInvenWindow
.left
);
2338 NHGETREG_DWORD(INVENTRIGHT
, GetNHApp()->rtInvenWindow
.right
);
2339 NHGETREG_DWORD(INVENTTOP
, GetNHApp()->rtInvenWindow
.top
);
2340 NHGETREG_DWORD(INVENTBOTTOM
, GetNHApp()->rtInvenWindow
.bottom
);
2341 #undef NHGETREG_DWORD
2345 /* check the data for validity */
2346 if (IsRectEmpty(&GetNHApp()->rtMapWindow
)
2347 || IsRectEmpty(&GetNHApp()->rtMsgWindow
)
2348 || IsRectEmpty(&GetNHApp()->rtStatusWindow
)
2349 || IsRectEmpty(&GetNHApp()->rtMenuWindow
)
2350 || IsRectEmpty(&GetNHApp()->rtTextWindow
)
2351 || IsRectEmpty(&GetNHApp()->rtInvenWindow
)) {
2352 GetNHApp()->bAutoLayout
= TRUE
;
2362 if (GetNHApp()->saveRegistrySettings
) {
2363 char keystring
[MAX_PATH
];
2366 sprintf(keystring
, "%s\\%s\\%s\\%s", CATEGORYKEY
, COMPANYKEY
,
2367 PRODUCTKEY
, SETTINGSKEY
);
2369 if (RegOpenKeyEx(HKEY_CURRENT_USER
, keystring
, 0, KEY_WRITE
, &key
)
2371 RegCreateKeyEx(HKEY_CURRENT_USER
, keystring
, 0, "",
2372 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
,
2373 &key
, &disposition
);
2376 #define NHSETREG_DWORD(name, val) \
2377 RegSetValueEx(key, (name), 0, REG_DWORD, \
2378 (unsigned char *)((safe_buf = (val)), &safe_buf), \
2381 /* Write the keys here */
2382 NHSETREG_DWORD(INTFKEY
, GetNHApp()->regNetHackMode
);
2384 /* Main window placement */
2385 NHSETREG_DWORD(MAINSHOWSTATEKEY
, GetNHApp()->regMainShowState
);
2386 NHSETREG_DWORD(MAINMINXKEY
, GetNHApp()->regMainMinX
);
2387 NHSETREG_DWORD(MAINMINYKEY
, GetNHApp()->regMainMinY
);
2388 NHSETREG_DWORD(MAINMAXXKEY
, GetNHApp()->regMainMaxX
);
2389 NHSETREG_DWORD(MAINMAXYKEY
, GetNHApp()->regMainMaxY
);
2390 NHSETREG_DWORD(MAINLEFTKEY
, GetNHApp()->regMainLeft
);
2391 NHSETREG_DWORD(MAINRIGHTKEY
, GetNHApp()->regMainRight
);
2392 NHSETREG_DWORD(MAINTOPKEY
, GetNHApp()->regMainTop
);
2393 NHSETREG_DWORD(MAINBOTTOMKEY
, GetNHApp()->regMainBottom
);
2395 NHSETREG_DWORD(MAINAUTOLAYOUT
, GetNHApp()->bAutoLayout
);
2396 NHSETREG_DWORD(MAPLEFT
, GetNHApp()->rtMapWindow
.left
);
2397 NHSETREG_DWORD(MAPRIGHT
, GetNHApp()->rtMapWindow
.right
);
2398 NHSETREG_DWORD(MAPTOP
, GetNHApp()->rtMapWindow
.top
);
2399 NHSETREG_DWORD(MAPBOTTOM
, GetNHApp()->rtMapWindow
.bottom
);
2400 NHSETREG_DWORD(MSGLEFT
, GetNHApp()->rtMsgWindow
.left
);
2401 NHSETREG_DWORD(MSGRIGHT
, GetNHApp()->rtMsgWindow
.right
);
2402 NHSETREG_DWORD(MSGTOP
, GetNHApp()->rtMsgWindow
.top
);
2403 NHSETREG_DWORD(MSGBOTTOM
, GetNHApp()->rtMsgWindow
.bottom
);
2404 NHSETREG_DWORD(STATUSLEFT
, GetNHApp()->rtStatusWindow
.left
);
2405 NHSETREG_DWORD(STATUSRIGHT
, GetNHApp()->rtStatusWindow
.right
);
2406 NHSETREG_DWORD(STATUSTOP
, GetNHApp()->rtStatusWindow
.top
);
2407 NHSETREG_DWORD(STATUSBOTTOM
, GetNHApp()->rtStatusWindow
.bottom
);
2408 NHSETREG_DWORD(MENULEFT
, GetNHApp()->rtMenuWindow
.left
);
2409 NHSETREG_DWORD(MENURIGHT
, GetNHApp()->rtMenuWindow
.right
);
2410 NHSETREG_DWORD(MENUTOP
, GetNHApp()->rtMenuWindow
.top
);
2411 NHSETREG_DWORD(MENUBOTTOM
, GetNHApp()->rtMenuWindow
.bottom
);
2412 NHSETREG_DWORD(TEXTLEFT
, GetNHApp()->rtTextWindow
.left
);
2413 NHSETREG_DWORD(TEXTRIGHT
, GetNHApp()->rtTextWindow
.right
);
2414 NHSETREG_DWORD(TEXTTOP
, GetNHApp()->rtTextWindow
.top
);
2415 NHSETREG_DWORD(TEXTBOTTOM
, GetNHApp()->rtTextWindow
.bottom
);
2416 NHSETREG_DWORD(INVENTLEFT
, GetNHApp()->rtInvenWindow
.left
);
2417 NHSETREG_DWORD(INVENTRIGHT
, GetNHApp()->rtInvenWindow
.right
);
2418 NHSETREG_DWORD(INVENTTOP
, GetNHApp()->rtInvenWindow
.top
);
2419 NHSETREG_DWORD(INVENTBOTTOM
, GetNHApp()->rtInvenWindow
.bottom
);
2420 #undef NHSETREG_DWORD
2429 char keystring
[MAX_PATH
];
2433 /* Delete keys one by one, as NT does not delete trees */
2434 sprintf(keystring
, "%s\\%s\\%s\\%s", CATEGORYKEY
, COMPANYKEY
, PRODUCTKEY
,
2436 RegDeleteKey(HKEY_CURRENT_USER
, keystring
);
2437 sprintf(keystring
, "%s\\%s\\%s", CATEGORYKEY
, COMPANYKEY
, PRODUCTKEY
);
2438 RegDeleteKey(HKEY_CURRENT_USER
, keystring
);
2439 /* The company key will also contain information about newer versions
2440 of nethack (e.g. a subkey called NetHack 4.0), so only delete that
2441 if it's empty now. */
2442 sprintf(keystring
, "%s\\%s", CATEGORYKEY
, COMPANYKEY
);
2443 /* If we cannot open it, we probably cannot delete it either... Just
2444 go on and see what happens. */
2445 RegOpenKeyEx(HKEY_CURRENT_USER
, keystring
, 0, KEY_READ
, &key
);
2447 RegQueryInfoKey(key
, NULL
, NULL
, NULL
, &nrsubkeys
, NULL
, NULL
, NULL
, NULL
,
2451 RegDeleteKey(HKEY_CURRENT_USER
, keystring
);
2453 /* Prevent saving on exit */
2454 GetNHApp()->saveRegistrySettings
= 0;
2457 typedef struct ctv
{
2458 const char *colorstring
;
2459 COLORREF colorvalue
;
2460 } color_table_value
;
2463 * The color list here is a combination of:
2464 * NetHack colors. (See mhmap.c)
2465 * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 )
2468 static color_table_value color_table
[] = {
2469 /* NetHack colors */
2470 { "black", RGB(0x55, 0x55, 0x55) },
2471 { "red", RGB(0xFF, 0x00, 0x00) },
2472 { "green", RGB(0x00, 0x80, 0x00) },
2473 { "brown", RGB(0xA5, 0x2A, 0x2A) },
2474 { "blue", RGB(0x00, 0x00, 0xFF) },
2475 { "magenta", RGB(0xFF, 0x00, 0xFF) },
2476 { "cyan", RGB(0x00, 0xFF, 0xFF) },
2477 { "orange", RGB(0xFF, 0xA5, 0x00) },
2478 { "brightgreen", RGB(0x00, 0xFF, 0x00) },
2479 { "yellow", RGB(0xFF, 0xFF, 0x00) },
2480 { "brightblue", RGB(0x00, 0xC0, 0xFF) },
2481 { "brightmagenta", RGB(0xFF, 0x80, 0xFF) },
2482 { "brightcyan", RGB(0x80, 0xFF, 0xFF) },
2483 { "white", RGB(0xFF, 0xFF, 0xFF) },
2484 /* Remaining HTML colors */
2485 { "trueblack", RGB(0x00, 0x00, 0x00) },
2486 { "gray", RGB(0x80, 0x80, 0x80) },
2487 { "grey", RGB(0x80, 0x80, 0x80) },
2488 { "purple", RGB(0x80, 0x00, 0x80) },
2489 { "silver", RGB(0xC0, 0xC0, 0xC0) },
2490 { "maroon", RGB(0x80, 0x00, 0x00) },
2491 { "fuchsia", RGB(0xFF, 0x00, 0xFF) }, /* = NetHack magenta */
2492 { "lime", RGB(0x00, 0xFF, 0x00) }, /* = NetHack bright green */
2493 { "olive", RGB(0x80, 0x80, 0x00) },
2494 { "navy", RGB(0x00, 0x00, 0x80) },
2495 { "teal", RGB(0x00, 0x80, 0x80) },
2496 { "aqua", RGB(0x00, 0xFF, 0xFF) }, /* = NetHack cyan */
2497 { "", RGB(0x00, 0x00, 0x00) },
2500 typedef struct ctbv
{
2503 } color_table_brush_value
;
2505 static color_table_brush_value color_table_brush
[] = {
2506 { "activeborder", COLOR_ACTIVEBORDER
},
2507 { "activecaption", COLOR_ACTIVECAPTION
},
2508 { "appworkspace", COLOR_APPWORKSPACE
},
2509 { "background", COLOR_BACKGROUND
},
2510 { "btnface", COLOR_BTNFACE
},
2511 { "btnshadow", COLOR_BTNSHADOW
},
2512 { "btntext", COLOR_BTNTEXT
},
2513 { "captiontext", COLOR_CAPTIONTEXT
},
2514 { "graytext", COLOR_GRAYTEXT
},
2515 { "greytext", COLOR_GRAYTEXT
},
2516 { "highlight", COLOR_HIGHLIGHT
},
2517 { "highlighttext", COLOR_HIGHLIGHTTEXT
},
2518 { "inactiveborder", COLOR_INACTIVEBORDER
},
2519 { "inactivecaption", COLOR_INACTIVECAPTION
},
2520 { "menu", COLOR_MENU
},
2521 { "menutext", COLOR_MENUTEXT
},
2522 { "scrollbar", COLOR_SCROLLBAR
},
2523 { "window", COLOR_WINDOW
},
2524 { "windowframe", COLOR_WINDOWFRAME
},
2525 { "windowtext", COLOR_WINDOWTEXT
},
2530 mswin_color_from_string(char *colorstring
, HBRUSH
*brushptr
,
2533 color_table_value
*ctv_ptr
= color_table
;
2534 color_table_brush_value
*ctbv_ptr
= color_table_brush
;
2535 int red_value
, blue_value
, green_value
;
2536 static char *hexadecimals
= "0123456789abcdef";
2538 if (colorstring
== NULL
)
2540 if (*colorstring
== '#') {
2541 if (strlen(++colorstring
) != 6)
2544 red_value
= (int) (index(hexadecimals
, tolower((uchar
) *colorstring
))
2548 red_value
+= (int) (index(hexadecimals
, tolower((uchar
) *colorstring
))
2552 green_value
= (int) (index(hexadecimals
,
2553 tolower((uchar
) *colorstring
))
2557 green_value
+= (int) (index(hexadecimals
,
2558 tolower((uchar
) *colorstring
))
2562 blue_value
= (int) (index(hexadecimals
, tolower((uchar
) *colorstring
))
2566 blue_value
+= (int) (index(hexadecimals
,
2567 tolower((uchar
) *colorstring
))
2571 *colorptr
= RGB(red_value
, green_value
, blue_value
);
2573 while (*ctv_ptr
->colorstring
2574 && stricmp(ctv_ptr
->colorstring
, colorstring
))
2576 if (*ctv_ptr
->colorstring
) {
2577 *colorptr
= ctv_ptr
->colorvalue
;
2579 while (*ctbv_ptr
->colorstring
2580 && stricmp(ctbv_ptr
->colorstring
, colorstring
))
2582 if (*ctbv_ptr
->colorstring
) {
2583 *brushptr
= SYSCLR_TO_BRUSH(ctbv_ptr
->syscolorvalue
);
2584 *colorptr
= GetSysColor(ctbv_ptr
->syscolorvalue
);
2588 if (max_brush
> TOTAL_BRUSHES
)
2589 panic("Too many colors!");
2590 *brushptr
= CreateSolidBrush(*colorptr
);
2591 brush_table
[max_brush
++] = *brushptr
;
2595 mswin_get_window_placement(int type
, LPRECT rt
)
2599 *rt
= GetNHApp()->rtMapWindow
;
2603 *rt
= GetNHApp()->rtMsgWindow
;
2607 *rt
= GetNHApp()->rtStatusWindow
;
2611 *rt
= GetNHApp()->rtMenuWindow
;
2615 *rt
= GetNHApp()->rtTextWindow
;
2619 *rt
= GetNHApp()->rtInvenWindow
;
2623 SetRect(rt
, 0, 0, 0, 0);
2629 mswin_update_window_placement(int type
, LPRECT rt
)
2631 LPRECT rt_conf
= NULL
;
2635 rt_conf
= &GetNHApp()->rtMapWindow
;
2639 rt_conf
= &GetNHApp()->rtMsgWindow
;
2643 rt_conf
= &GetNHApp()->rtStatusWindow
;
2647 rt_conf
= &GetNHApp()->rtMenuWindow
;
2651 rt_conf
= &GetNHApp()->rtTextWindow
;
2655 rt_conf
= &GetNHApp()->rtInvenWindow
;
2659 if (rt_conf
&& !IsRectEmpty(rt
) && !EqualRect(rt_conf
, rt
)) {
2665 NHMessageBox(HWND hWnd
, LPCTSTR text
, UINT type
)
2667 TCHAR title
[MAX_LOADSTRING
];
2669 LoadString(GetNHApp()->hApp
, IDS_APP_TITLE_SHORT
, title
, MAX_LOADSTRING
);
2671 return MessageBox(hWnd
, text
, title
, type
);
2674 #ifdef STATUS_VIA_WINDOWPORT
2675 static const char *_status_fieldnm
[MAXBLSTATS
];
2676 static const char *_status_fieldfmt
[MAXBLSTATS
];
2677 static char *_status_vals
[MAXBLSTATS
];
2678 static int _status_colors
[MAXBLSTATS
];
2679 static boolean _status_activefields
[MAXBLSTATS
];
2680 extern winid WIN_STATUS
;
2682 #ifdef STATUS_HILITES
2683 typedef struct hilite_data_struct
{
2690 static hilite_data_t _status_hilites
[MAXBLSTATS
];
2691 #endif /* STATUS_HILITES */
2693 status_init() -- core calls this to notify the window port that a status
2694 display is required. The window port should perform
2695 the necessary initialization in here, allocate memory, etc.
2698 mswin_status_init(void)
2701 logDebug("mswin_status_init()\n");
2702 for (i
= 0; i
< MAXBLSTATS
; ++i
) {
2703 _status_vals
[i
] = (char *) alloc(BUFSZ
);
2704 *_status_vals
[i
] = '\0';
2705 _status_activefields
[i
] = FALSE
;
2706 _status_fieldfmt
[i
] = (const char *) 0;
2707 _status_colors
[i
] = CLR_MAX
; /* no color */
2708 #ifdef STATUS_HILITES
2709 _status_hilites
[i
].thresholdtype
= 0;
2710 _status_hilites
[i
].behavior
= BL_TH_NONE
;
2711 _status_hilites
[i
].under
= BL_HILITE_NONE
;
2712 _status_hilites
[i
].over
= BL_HILITE_NONE
;
2713 #endif /* STATUS_HILITES */
2715 /* Use a window for the genl version; backward port compatibility */
2716 WIN_STATUS
= create_nhwindow(NHW_STATUS
);
2717 display_nhwindow(WIN_STATUS
, FALSE
);
2721 status_finish() -- called when it is time for the window port to tear down
2722 the status display and free allocated memory, etc.
2725 mswin_status_finish(void)
2727 /* tear down routine */
2730 logDebug("mswin_status_finish()\n");
2732 /* free alloc'd memory here */
2733 for (i
= 0; i
< MAXBLSTATS
; ++i
) {
2734 if (_status_vals
[i
])
2735 free((genericptr_t
) _status_vals
[i
]);
2736 _status_vals
[i
] = (char *) 0;
2741 status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable)
2742 -- notifies the window port which fields it is authorized to
2744 -- This may be called at any time, and is used
2745 to disable as well as enable fields, depending on the
2746 value of the final argument (TRUE = enable).
2747 -- fldindex could be one of the following from botl.h:
2748 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2749 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2750 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2751 BL_LEVELDESC, BL_EXP, BL_CONDITION
2752 -- There are MAXBLSTATS status fields (from botl.h)
2755 mswin_status_enablefield(int fieldidx
, const char *nm
, const char *fmt
,
2758 logDebug("mswin_status_enablefield(%d, %s, %s, %d)\n", fieldidx
, nm
, fmt
,
2760 _status_fieldfmt
[fieldidx
] = fmt
;
2761 _status_fieldnm
[fieldidx
] = nm
;
2762 _status_activefields
[fieldidx
] = enable
;
2765 #ifdef STATUS_HILITES
2767 status_threshold(int fldidx, int threshholdtype, anything threshold,
2768 int behavior, int under, int over)
2769 -- called when a hiliting preference is added, changed, or
2771 -- the fldindex identifies which field is having its hiliting
2772 preference set. It is an integer index value from botl.h
2773 -- fldindex could be any one of the following from botl.h:
2774 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2775 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2776 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2777 BL_LEVELDESC, BL_EXP, BL_CONDITION
2778 -- datatype is P_INT, P_UINT, P_LONG, or P_MASK.
2779 -- threshold is an "anything" union which can contain the
2781 -- behavior is used to define how threshold is used and can
2782 be BL_TH_NONE, BL_TH_VAL_PERCENTAGE, BL_TH_VAL_ABSOLUTE,
2783 or BL_TH_UPDOWN. BL_TH_NONE means don't do anything above
2784 or below the threshold. BL_TH_VAL_PERCENTAGE treats the
2785 threshold value as a precentage of the maximum possible
2786 value. BL_TH_VAL_ABSOLUTE means that the threshold is an
2787 actual value. BL_TH_UPDOWN means that threshold is not
2788 used, and the two below/above hilite values indicate how
2789 to display something going down (under) or rising (over).
2790 -- under is the hilite attribute used if value is below the
2791 threshold. The attribute can be BL_HILITE_NONE,
2792 BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one
2793 of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN,
2794 CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY,
2795 CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE,
2796 CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15).
2797 -- over is the hilite attribute used if value is at or above
2798 the threshold. The attribute can be BL_HILITE_NONE,
2799 BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one
2800 of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN,
2801 CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY,
2802 CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE,
2803 CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15).
2806 mswin_status_threshold(int fldidx
, int thresholdtype
, anything threshold
,
2807 int behavior
, int under
, int over
)
2809 logDebug("mswin_status_threshold(%d, %d, %d, %d, %d)\n", fldidx
,
2810 thresholdtype
, behavior
, under
, over
);
2811 assert(fldidx
>= 0 && fldidx
< MAXBLSTATS
);
2812 _status_hilites
[fldidx
].thresholdtype
= thresholdtype
;
2813 _status_hilites
[fldidx
].threshold
= threshold
;
2814 _status_hilites
[fldidx
].behavior
= behavior
;
2815 _status_hilites
[fldidx
].under
= under
;
2816 _status_hilites
[fldidx
].over
= over
;
2818 #endif /* STATUS_HILITES */
2822 status_update(int fldindex, genericptr_t ptr, int chg, int percentage)
2823 -- update the value of a status field.
2824 -- the fldindex identifies which field is changing and
2825 is an integer index value from botl.h
2826 -- fldindex could be any one of the following from botl.h:
2827 BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
2828 BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX,
2829 BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
2830 BL_LEVELDESC, BL_EXP, BL_CONDITION
2831 -- fldindex could also be BL_FLUSH (-1), which is not really
2832 a field index, but is a special trigger to tell the
2833 windowport that it should redisplay all its status fields,
2834 even if no changes have been presented to it.
2835 -- ptr is usually a "char *", unless fldindex is BL_CONDITION.
2836 If fldindex is BL_CONDITION, then ptr is a long value with
2837 any or none of the following bits set (from botl.h):
2838 BL_MASK_STONE 0x00000001L
2839 BL_MASK_SLIME 0x00000002L
2840 BL_MASK_STRNGL 0x00000004L
2841 BL_MASK_FOODPOIS 0x00000008L
2842 BL_MASK_TERMILL 0x00000010L
2843 BL_MASK_BLIND 0x00000020L
2844 BL_MASK_DEAF 0x00000040L
2845 BL_MASK_STUN 0x00000080L
2846 BL_MASK_CONF 0x00000100L
2847 BL_MASK_HALLU 0x00000200L
2848 BL_MASK_LEV 0x00000400L
2849 BL_MASK_FLY 0x00000800L
2850 BL_MASK_RIDE 0x00001000L
2851 -- The value passed for BL_GOLD includes an encoded leading
2852 symbol for GOLD "\GXXXXNNNN:nnn". If window port needs
2853 textual gold amount without the leading "$:" the port will
2854 have to skip past ':' in passed "ptr" for the BL_GOLD case.
2857 mswin_status_update(int idx
, genericptr_t ptr
, int chg
, int percent
)
2859 long cond
, *condptr
= (long *) ptr
;
2860 char *text
= (char *) ptr
;
2861 MSNHMsgUpdateStatus update_cmd_data
;
2866 logDebug("mswin_status_update(%d, %p, %d, %d)\n", idx
, ptr
, chg
, percent
);
2868 if (idx
!= BL_FLUSH
) {
2869 if (!_status_activefields
[idx
])
2872 case BL_CONDITION
: {
2874 *_status_vals
[idx
] = '\0';
2875 if (cond
& BL_MASK_STONE
)
2876 Strcat(_status_vals
[idx
], " Stone");
2877 if (cond
& BL_MASK_SLIME
)
2878 Strcat(_status_vals
[idx
], " Slime");
2879 if (cond
& BL_MASK_STRNGL
)
2880 Strcat(_status_vals
[idx
], " Strngl");
2881 if (cond
& BL_MASK_FOODPOIS
)
2882 Strcat(_status_vals
[idx
], " FoodPois");
2883 if (cond
& BL_MASK_TERMILL
)
2884 Strcat(_status_vals
[idx
], " TermIll");
2885 if (cond
& BL_MASK_BLIND
)
2886 Strcat(_status_vals
[idx
], " Blind");
2887 if (cond
& BL_MASK_DEAF
)
2888 Strcat(_status_vals
[idx
], " Deaf");
2889 if (cond
& BL_MASK_STUN
)
2890 Strcat(_status_vals
[idx
], " Stun");
2891 if (cond
& BL_MASK_CONF
)
2892 Strcat(_status_vals
[idx
], " Conf");
2893 if (cond
& BL_MASK_HALLU
)
2894 Strcat(_status_vals
[idx
], " Hallu");
2895 if (cond
& BL_MASK_LEV
)
2896 Strcat(_status_vals
[idx
], " Lev");
2897 if (cond
& BL_MASK_FLY
)
2898 Strcat(_status_vals
[idx
], " Fly");
2899 if (cond
& BL_MASK_RIDE
)
2900 Strcat(_status_vals
[idx
], " Ride");
2906 ZeroMemory(buf
, sizeof(buf
));
2907 mapglyph(objnum_to_glyph(GOLD_PIECE
), &ochar
, &ocolor
, &ospecial
,
2910 p
= strchr(text
, ':');
2912 strncpy(buf
+ 1, p
, sizeof(buf
) - 2);
2913 value
= atol(p
+ 1);
2916 strncpy(buf
+ 2, text
, sizeof(buf
) - 2);
2919 Sprintf(_status_vals
[idx
],
2920 _status_fieldfmt
[idx
] ? _status_fieldfmt
[idx
] : "%s",
2925 Sprintf(_status_vals
[idx
],
2926 _status_fieldfmt
[idx
] ? _status_fieldfmt
[idx
] : "%s",
2932 #ifdef STATUS_HILITES
2933 switch (_status_hilites
[idx
].behavior
) {
2935 _status_colors
[idx
] = CLR_MAX
;
2938 case BL_TH_UPDOWN
: {
2940 _status_colors
[idx
] = _status_hilites
[idx
].over
;
2942 _status_colors
[idx
] = _status_hilites
[idx
].under
;
2944 _status_colors
[idx
] = CLR_MAX
;
2947 case BL_TH_VAL_PERCENTAGE
: {
2949 if (_status_hilites
[idx
].thresholdtype
!= ANY_INT
) {
2950 impossible("mswin_status_update: unsupported percentage "
2951 "threshold type %d",
2952 _status_hilites
[idx
].thresholdtype
);
2955 pct_th
= _status_hilites
[idx
].threshold
.a_int
;
2956 _status_colors
[idx
] = (percent
>= pct_th
)
2957 ? _status_hilites
[idx
].over
2958 : _status_hilites
[idx
].under
;
2961 case BL_TH_VAL_ABSOLUTE
: {
2963 int o
= _status_hilites
[idx
].over
;
2964 int u
= _status_hilites
[idx
].under
;
2965 anything
*t
= &_status_hilites
[idx
].threshold
;
2966 switch (_status_hilites
[idx
].thresholdtype
) {
2968 c
= (value
>= t
->a_long
) ? o
: u
;
2971 c
= (value
>= t
->a_int
) ? o
: u
;
2974 c
= ((unsigned long) value
>= t
->a_uint
) ? o
: u
;
2977 c
= ((unsigned long) value
>= t
->a_ulong
) ? o
: u
;
2980 c
= (value
& t
->a_ulong
) ? o
: u
;
2983 impossible("mswin_status_update: unsupported absolute threshold "
2985 _status_hilites
[idx
].thresholdtype
);
2988 _status_colors
[idx
] = c
;
2991 #endif /* STATUS_HILITES */
2993 /* send command to status window */
2994 ZeroMemory(&update_cmd_data
, sizeof(update_cmd_data
));
2995 update_cmd_data
.n_fields
= MAXBLSTATS
;
2996 update_cmd_data
.vals
= _status_vals
;
2997 update_cmd_data
.activefields
= _status_activefields
;
2998 update_cmd_data
.colors
= _status_colors
;
2999 SendMessage(mswin_hwnd_from_winid(WIN_STATUS
), WM_MSNH_COMMAND
,
3000 (WPARAM
) MSNH_MSG_UPDATE_STATUS
, (LPARAM
) &update_cmd_data
);
3003 #endif /*STATUS_VIA_WINDOWPORT*/