NHDT->ANH, nethack->anethack, nhdat->anhdat
[aNetHack.git] / win / gem / wingem.c
blobef46c36457930e3c64daacae3b9a7ab0d14bf3a7
1 /* aNetHack 0.0.1 wingem.c $ANH-Date: 1450453304 2015/12/18 15:41:44 $ $ANH-Branch: aNetHack-3.6.0 $:$ANH-Revision: 1.26 $ */
2 /* Copyright (c) Christian Bressler, 1999 */
3 /* aNetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
6 #include "func_tab.h"
7 #include "dlb.h"
8 #include <ctype.h>
9 #ifdef SHORT_FILENAMES
10 #include "patchlev.h"
11 #else
12 #include "patchlevel.h"
13 #endif
15 #ifdef GEM_GRAPHICS
16 #include "wingem.h"
18 static char nullstr[] = "", winpanicstr[] = "Bad window id %d";
19 static int curr_status_line;
21 static char *FDECL(copy_of, (const char *));
22 static void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */
24 extern int mar_set_tile_mode(int);
25 extern void mar_set_font(int, const char *, int);
26 extern void mar_set_margin(int);
27 extern void mar_set_msg_visible(int);
28 extern void mar_set_status_align(int);
29 extern void mar_set_msg_align(int);
30 extern void mar_set_tilefile(char *);
31 extern void mar_set_tilex(int);
32 extern void mar_set_tiley(int);
33 extern short glyph2tile[MAX_GLYPH]; /* from tile.c */
34 extern void mar_display_nhwindow(winid); /* from wingem1.c */
36 void Gem_outrip(winid, int, time_t);
37 void Gem_preference_update(const char *);
38 /* Interface definition, for windows.c */
39 struct window_procs Gem_procs = {
40 "Gem",
41 WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE
42 | WC_SCROLL_MARGIN | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU
43 | WC_FONT_TEXT | WC_FONT_MAP | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS
44 | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_FONTSIZ_MAP | WC_TILE_WIDTH
45 | WC_TILE_HEIGHT | WC_TILE_FILE | WC_VARY_MSGCOUNT | WC_ASCII_MAP,
46 0L, Gem_init_nhwindows, Gem_player_selection, Gem_askname,
47 Gem_get_nh_event, Gem_exit_nhwindows, Gem_suspend_nhwindows,
48 Gem_resume_nhwindows, Gem_create_nhwindow, Gem_clear_nhwindow,
49 Gem_display_nhwindow, Gem_destroy_nhwindow, Gem_curs, Gem_putstr,
50 genl_putmixed, Gem_display_file, Gem_start_menu, Gem_add_menu,
51 Gem_end_menu, Gem_select_menu, genl_message_menu, Gem_update_inventory,
52 Gem_mark_synch, Gem_wait_synch,
53 #ifdef CLIPPING
54 Gem_cliparound,
55 #endif
56 #ifdef POSITIONBAR
57 Gem_update_positionbar,
58 #endif
59 Gem_print_glyph, Gem_raw_print, Gem_raw_print_bold, Gem_nhgetch,
60 Gem_nh_poskey, Gem_nhbell, Gem_doprev_message, Gem_yn_function,
61 Gem_getlin, Gem_get_ext_cmd, Gem_number_pad, Gem_delay_output,
62 #ifdef CHANGE_COLOR /* the Mac uses a palette device */
63 Gem_change_color,
64 #ifdef MAC
65 Gem_change_background, Gem_set_font_name,
66 #endif
67 Gem_get_color_string,
68 #endif
70 /* other defs that really should go away (they're tty specific) */
71 Gem_start_screen, Gem_end_screen, Gem_outrip, Gem_preference_update,
72 genl_getmsghistory, genl_putmsghistory
73 #ifdef STATUS_VIA_WINDOWPORT
74 genl_status_init,
75 genl_status_finish, genl_status_enablefield, genl_status_update,
76 #ifdef STATUS_HILITES
77 genl_status_threshold,
78 #endif
79 #endif
80 genl_can_suspend_no,
83 #ifdef MAC
84 void *
85 Gem_change_background(dummy)
86 int dummy;
90 short *
91 Gem_set_font_name(foo, bar)
92 winid foo;
93 char *bar;
96 #endif
98 /*************************** Proceduren *************************************/
101 mar_hp_query(void)
103 if (Upolyd)
104 return (u.mh ? u.mhmax / u.mh : -1);
105 return (u.uhp ? u.uhpmax / u.uhp : -1);
109 mar_iflags_numpad()
111 return (iflags.num_pad ? 1 : 0);
115 mar_get_msg_history()
117 return (iflags.msg_history);
121 mar_get_msg_visible()
123 return (iflags.wc_vary_msgcount);
125 /* clean up and quit */
126 static void
127 bail(mesg)
128 const char *mesg;
130 clearlocks();
131 Gem_exit_nhwindows(mesg);
132 terminate(EXIT_SUCCESS);
133 /*NOTREACHED*/
136 /*$$$*/
137 #define DEF_CLIPAROUND_MARGIN -1
138 #ifndef TILE_X
139 #define TILE_X 16
140 #endif
141 #define TILE_Y 16
142 #define TILES_PER_LINE 20
143 #define NHFONT_DEFAULT_SIZE 10
144 #define NHFONT_SIZE_MIN 3
145 #define NHFONT_SIZE_MAX 20
146 /*$$$*/
147 /*ARGSUSED*/
148 void
149 Gem_init_nhwindows(argcp, argv)
150 int *argcp;
151 char **argv;
153 argv = argv, argcp = argcp;
154 colors_changed = TRUE;
156 set_wc_option_mod_status(WC_ALIGN_MESSAGE | WC_ALIGN_STATUS
157 | WC_TILE_WIDTH | WC_TILE_HEIGHT
158 | WC_TILE_FILE,
159 DISP_IN_GAME);
160 set_wc_option_mod_status(
161 WC_HILITE_PET | WC_SCROLL_MARGIN | WC_FONT_MESSAGE | WC_FONT_MAP
162 | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT
163 | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_MAP | WC_FONTSIZ_STATUS
164 | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT,
165 SET_IN_GAME);
166 if (iflags.wc_align_message == 0)
167 iflags.wc_align_message = ALIGN_TOP;
168 if (iflags.wc_align_status == 0)
169 iflags.wc_align_status = ALIGN_BOTTOM;
170 if (iflags.wc_scroll_margin == 0)
171 iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
172 if (iflags.wc_tile_width == 0)
173 iflags.wc_tile_width = TILE_X;
174 if (iflags.wc_tile_height == 0)
175 iflags.wc_tile_height = TILE_Y;
176 if (iflags.wc_tile_file && *iflags.wc_tile_file)
177 mar_set_tilefile(iflags.wc_tile_file);
178 if (iflags.wc_vary_msgcount == 0)
179 iflags.wc_vary_msgcount = 3;
180 mar_set_tile_mode(
181 !iflags.wc_ascii_map); /* MAR -- 17.Mar 2002 True is tiles */
182 mar_set_tilex(iflags.wc_tile_width);
183 mar_set_tiley(iflags.wc_tile_height);
184 mar_set_msg_align(iflags.wc_align_message - ALIGN_BOTTOM);
185 mar_set_status_align(iflags.wc_align_status - ALIGN_BOTTOM);
186 if (mar_gem_init() == 0) {
187 bail((char *) 0);
188 /*NOTREACHED*/
190 iflags.window_inited = TRUE;
192 CO = 80; /* MAR -- whatsoever */
193 LI = 25;
195 add_menu_cmd_alias(' ', MENU_NEXT_PAGE);
196 mar_set_no_glyph(NO_GLYPH);
199 void
200 Gem_player_selection()
202 int i, k, n;
203 char pick4u = 'n', pbuf[QBUFSZ], lastch = 0, currch;
204 winid win;
205 anything any;
206 menu_item *selected = NULL;
208 /* avoid unnecessary prompts further down */
209 rigid_role_checks();
211 /* Should we randomly pick for the player? */
212 if (!flags.randomall
213 && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE
214 || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
215 /* pick4u = yn_function("Shall I pick a character for you?
216 * [ynq]",ynqchars,'n');*/
217 pick4u = yn_function(build_plselection_prompt(
218 pbuf, QBUFSZ, flags.initrole, flags.initrace,
219 flags.initgend, flags.initalign),
220 ynqchars, 'n');
221 if (pick4u == 'q') {
222 give_up: /* Just quit */
223 if (selected)
224 free((genericptr_t) selected);
225 bail((char *) 0);
226 /*NOTREACHED*/
227 return;
231 /* Select a role, if necessary */
232 if (flags.initrole < 0) {
233 /* Process the choice */
234 if (pick4u == 'y' || flags.initrole == ROLE_RANDOM
235 || flags.randomall) {
236 /* Pick a random role */
237 flags.initrole = pick_role(flags.initrace, flags.initgend,
238 flags.initalign, PICK_RANDOM);
239 if (flags.initrole < 0) {
240 mar_add_message("Incompatible role!");
241 mar_display_nhwindow(WIN_MESSAGE);
242 flags.initrole = randrole();
244 } else {
245 /* Prompt for a role */
246 win = create_nhwindow(NHW_MENU);
247 start_menu(win);
248 any.a_void = 0; /* zero out all bits */
249 for (i = 0; roles[i].name.m; i++) {
250 if (ok_role(i, flags.initrace, flags.initgend,
251 flags.initalign)) {
252 any.a_int = i + 1; /* must be non-zero */
253 currch = lowc(roles[i].name.m[0]);
254 if (currch == lastch)
255 currch = highc(currch);
256 add_menu(win, roles[i].malenum, &any, currch, 0, ATR_NONE,
257 an(roles[i].name.m), MENU_UNSELECTED);
258 lastch = currch;
261 any.a_int = pick_role(flags.initrace, flags.initgend,
262 flags.initalign, PICK_RANDOM) + 1;
263 if (any.a_int == 0) /* must be non-zero */
264 any.a_int = randrole() + 1;
265 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
266 MENU_UNSELECTED);
267 any.a_int = i + 1; /* must be non-zero */
268 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
269 MENU_UNSELECTED);
270 end_menu(win, "Pick a role");
271 n = select_menu(win, PICK_ONE, &selected);
272 destroy_nhwindow(win);
274 /* Process the choice */
275 if (n != 1 || selected[0].item.a_int == any.a_int)
276 goto give_up; /* Selected quit */
278 flags.initrole = selected[0].item.a_int - 1;
279 free((genericptr_t) selected), selected = 0;
283 /* Select a race, if necessary */
284 /* force compatibility with role, try for compatibility with
285 * pre-selected gender/alignment */
286 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
287 /* pre-selected race not valid */
288 if (pick4u == 'y' || flags.initrace == ROLE_RANDOM
289 || flags.randomall) {
290 flags.initrace = pick_race(flags.initrole, flags.initgend,
291 flags.initalign, PICK_RANDOM);
292 if (flags.initrace < 0) {
293 mar_add_message("Incompatible race!");
294 mar_display_nhwindow(WIN_MESSAGE);
295 flags.initrace = randrace(flags.initrole);
297 } else { /* pick4u == 'n' */
298 /* Count the number of valid races */
299 n = 0; /* number valid */
300 k = 0; /* valid race */
301 for (i = 0; races[i].noun; i++) {
302 if (ok_race(flags.initrole, i, flags.initgend,
303 flags.initalign)) {
304 n++;
305 k = i;
308 if (n == 0) {
309 for (i = 0; races[i].noun; i++) {
310 if (validrace(flags.initrole, i)) {
311 n++;
312 k = i;
316 /* Permit the user to pick, if there is more than one */
317 if (n > 1) {
318 win = create_nhwindow(NHW_MENU);
319 start_menu(win);
320 any.a_void = 0; /* zero out all bits */
321 for (i = 0; races[i].noun; i++)
322 if (ok_race(flags.initrole, i, flags.initgend,
323 flags.initalign)) {
324 any.a_int = i + 1; /* must be non-zero */
325 add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0,
326 ATR_NONE, races[i].noun, MENU_UNSELECTED);
328 any.a_int = pick_race(flags.initrole, flags.initgend,
329 flags.initalign, PICK_RANDOM) + 1;
330 if (any.a_int == 0) /* must be non-zero */
331 any.a_int = randrace(flags.initrole) + 1;
332 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
333 MENU_UNSELECTED);
334 any.a_int = i + 1; /* must be non-zero */
335 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
336 MENU_UNSELECTED);
337 Sprintf(pbuf, "Pick the race of your %s",
338 roles[flags.initrole].name.m);
339 end_menu(win, pbuf);
340 n = select_menu(win, PICK_ONE, &selected);
341 destroy_nhwindow(win);
342 if (n != 1 || selected[0].item.a_int == any.a_int)
343 goto give_up; /* Selected quit */
344 k = selected[0].item.a_int - 1;
345 free((genericptr_t) selected), selected = 0;
347 flags.initrace = k;
351 /* Select a gender, if necessary */
352 /* force compatibility with role/race, try for compatibility with
353 * pre-selected alignment */
354 if (flags.initgend < 0
355 || !validgend(flags.initrole, flags.initrace, flags.initgend)) {
356 /* pre-selected gender not valid */
357 if (pick4u == 'y' || flags.initgend == ROLE_RANDOM
358 || flags.randomall) {
359 flags.initgend = pick_gend(flags.initrole, flags.initrace,
360 flags.initalign, PICK_RANDOM);
361 if (flags.initgend < 0) {
362 mar_add_message("Incompatible gender!");
363 mar_display_nhwindow(WIN_MESSAGE);
364 flags.initgend = randgend(flags.initrole, flags.initrace);
366 } else { /* pick4u == 'n' */
367 /* Count the number of valid genders */
368 n = 0; /* number valid */
369 k = 0; /* valid gender */
370 for (i = 0; i < ROLE_GENDERS; i++) {
371 if (ok_gend(flags.initrole, flags.initrace, i,
372 flags.initalign)) {
373 n++;
374 k = i;
377 if (n == 0) {
378 for (i = 0; i < ROLE_GENDERS; i++) {
379 if (validgend(flags.initrole, flags.initrace, i)) {
380 n++;
381 k = i;
385 /* Permit the user to pick, if there is more than one */
386 if (n > 1) {
387 win = create_nhwindow(NHW_MENU);
388 start_menu(win);
389 any.a_void = 0; /* zero out all bits */
390 for (i = 0; i < ROLE_GENDERS; i++)
391 if (ok_gend(flags.initrole, flags.initrace, i,
392 flags.initalign)) {
393 any.a_int = i + 1;
394 add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0,
395 ATR_NONE, genders[i].adj, MENU_UNSELECTED);
397 any.a_int = pick_gend(flags.initrole, flags.initrace,
398 flags.initalign, PICK_RANDOM) + 1;
399 if (any.a_int == 0) /* must be non-zero */
400 any.a_int = randgend(flags.initrole, flags.initrace) + 1;
401 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
402 MENU_UNSELECTED);
403 any.a_int = i + 1; /* must be non-zero */
404 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
405 MENU_UNSELECTED);
406 Sprintf(pbuf, "Pick the gender of your %s %s",
407 races[flags.initrace].adj,
408 roles[flags.initrole].name.m);
409 end_menu(win, pbuf);
410 n = select_menu(win, PICK_ONE, &selected);
411 destroy_nhwindow(win);
412 if (n != 1 || selected[0].item.a_int == any.a_int)
413 goto give_up; /* Selected quit */
414 k = selected[0].item.a_int - 1;
415 free((genericptr_t) selected), selected = 0;
417 flags.initgend = k;
421 /* Select an alignment, if necessary */
422 /* force compatibility with role/race/gender */
423 if (flags.initalign < 0
424 || !validalign(flags.initrole, flags.initrace, flags.initalign)) {
425 /* pre-selected alignment not valid */
426 if (pick4u == 'y' || flags.initalign == ROLE_RANDOM
427 || flags.randomall) {
428 flags.initalign = pick_align(flags.initrole, flags.initrace,
429 flags.initgend, PICK_RANDOM);
430 if (flags.initalign < 0) {
431 mar_add_message("Incompatible alignment!");
432 mar_display_nhwindow(WIN_MESSAGE);
433 flags.initalign = randalign(flags.initrole, flags.initrace);
435 } else { /* pick4u == 'n' */
436 /* Count the number of valid alignments */
437 n = 0; /* number valid */
438 k = 0; /* valid alignment */
439 for (i = 0; i < ROLE_ALIGNS; i++) {
440 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
441 i)) {
442 n++;
443 k = i;
446 if (n == 0) {
447 for (i = 0; i < ROLE_ALIGNS; i++) {
448 if (validalign(flags.initrole, flags.initrace, i)) {
449 n++;
450 k = i;
454 /* Permit the user to pick, if there is more than one */
455 if (n > 1) {
456 win = create_nhwindow(NHW_MENU);
457 start_menu(win);
458 any.a_void = 0; /* zero out all bits */
459 for (i = 0; i < ROLE_ALIGNS; i++)
460 if (ok_align(flags.initrole, flags.initrace,
461 flags.initgend, i)) {
462 any.a_int = i + 1;
463 add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0,
464 ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
466 any.a_int = pick_align(flags.initrole, flags.initrace,
467 flags.initgend, PICK_RANDOM) + 1;
468 if (any.a_int == 0) /* must be non-zero */
469 any.a_int = randalign(flags.initrole, flags.initrace) + 1;
470 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
471 MENU_UNSELECTED);
472 any.a_int = i + 1; /* must be non-zero */
473 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
474 MENU_UNSELECTED);
475 Sprintf(pbuf, "Pick the alignment of your %s %s %s",
476 genders[flags.initgend].adj,
477 races[flags.initrace].adj,
478 (flags.initgend && roles[flags.initrole].name.f)
479 ? roles[flags.initrole].name.f
480 : roles[flags.initrole].name.m);
481 end_menu(win, pbuf);
482 n = select_menu(win, PICK_ONE, &selected);
483 destroy_nhwindow(win);
484 if (n != 1 || selected[0].item.a_int == any.a_int)
485 goto give_up; /* Selected quit */
486 k = selected[0].item.a_int - 1;
487 free((genericptr_t) selected), selected = 0;
489 flags.initalign = k;
493 /* Success! */
494 return;
498 * plname is filled either by an option (-u Player or -uPlayer) or
499 * explicitly (by being the wizard) or by askname.
500 * It may still contain a suffix denoting pl_character.
501 * Always called after init_nhwindows() and before display_gamewindows().
504 void
505 Gem_askname()
507 strncpy(plname, mar_ask_name(), PL_NSIZ);
510 void
511 Gem_get_nh_event()
515 void
516 Gem_suspend_nhwindows(str)
517 const char *str;
519 const char *foo;
521 foo = str; /* MAR -- And the compiler whines no more ... */
524 void
525 Gem_resume_nhwindows()
529 void
530 Gem_end_screen()
534 void
535 Gem_start_screen()
539 extern void mar_exit_nhwindows(void);
540 extern boolean run_from_desktop;
542 void
543 Gem_exit_nhwindows(str)
544 const char *str;
546 if (str)
547 Gem_raw_print(str);
548 mar_exit_nhwindows();
549 if (iflags.toptenwin)
550 run_from_desktop = FALSE;
551 iflags.window_inited = 0;
554 winid
555 Gem_create_nhwindow(type)
556 int type;
558 winid newid;
560 switch (type) {
561 case NHW_MESSAGE:
562 if (iflags.msg_history < 20)
563 iflags.msg_history = 20;
564 else if (iflags.msg_history > 60)
565 iflags.msg_history = 60;
566 break;
567 case NHW_STATUS:
568 case NHW_MAP:
569 case NHW_MENU:
570 case NHW_TEXT:
571 break;
572 default:
573 panic("Tried to create window type %d\n", (int) type);
574 return WIN_ERR;
577 newid = mar_create_window(type);
579 if (newid == MAXWIN) {
580 panic("No window slots!");
581 /* NOTREACHED */
584 return newid;
587 void
588 Gem_nhbell()
590 if (flags.silent)
591 return;
592 putchar('\007');
593 fflush(stdout);
596 extern void mar_clear_map(void);
598 void
599 Gem_clear_nhwindow(window)
600 winid window;
602 if (window == WIN_ERR)
603 panic(winpanicstr, window);
605 switch (mar_hol_win_type(window)) {
606 case NHW_MESSAGE:
607 mar_clear_messagewin();
608 break;
609 case NHW_MAP:
610 mar_clear_map();
611 break;
612 case NHW_STATUS:
613 case NHW_MENU:
614 case NHW_TEXT:
615 break;
619 extern void mar_more(void);
621 /*ARGSUSED*/
622 void
623 Gem_display_nhwindow(window, blocking)
624 winid window;
625 boolean blocking;
627 if (window == WIN_ERR)
628 panic(winpanicstr, window);
630 mar_display_nhwindow(window);
632 switch (mar_hol_win_type(window)) {
633 case NHW_MESSAGE:
634 if (blocking)
635 mar_more();
636 break;
637 case NHW_MAP:
638 if (blocking)
639 Gem_display_nhwindow(WIN_MESSAGE, TRUE);
640 break;
641 case NHW_STATUS:
642 case NHW_TEXT:
643 case NHW_MENU:
644 default:
645 break;
649 void
650 Gem_destroy_nhwindow(window)
651 winid window;
653 if (window == WIN_ERR) /* MAR -- test existence */
654 panic(winpanicstr, window);
656 mar_destroy_nhwindow(window);
659 extern void mar_curs(int, int); /* mar_curs is only for map */
661 void
662 Gem_curs(window, x, y)
663 winid window;
664 register int x, y;
666 if (window == WIN_ERR) /* MAR -- test existence */
667 panic(winpanicstr, window);
669 if (window == WIN_MAP)
670 mar_curs(x - 1, y); /*$$$*/
671 else if (window == WIN_STATUS)
672 curr_status_line = y;
675 extern void mar_add_status_str(const char *, int);
676 extern void mar_putstr_text(winid, int, const char *);
678 void
679 Gem_putstr(window, attr, str)
680 winid window;
681 int attr;
682 const char *str;
684 int win_type;
686 if (window == WIN_ERR) {
687 Gem_raw_print(str);
688 return;
691 if (str == (const char *) 0)
692 return;
694 switch ((win_type = mar_hol_win_type(window))) {
695 case NHW_MESSAGE:
696 mar_add_message(str);
697 break;
699 case NHW_STATUS:
700 mar_status_dirty();
701 mar_add_status_str(str, curr_status_line);
702 if (curr_status_line)
703 mar_display_nhwindow(WIN_STATUS);
704 break;
706 case NHW_MAP:
707 if (strcmp(str, "."))
708 Gem_putstr(WIN_MESSAGE, 0, str);
709 else
710 mar_map_curs_weiter();
711 mar_display_nhwindow(WIN_MESSAGE);
712 mar_display_nhwindow(WIN_STATUS);
713 break;
715 case NHW_MENU:
716 mar_change_menu_2_text(window);
717 /* Fallthru */
718 case NHW_TEXT:
719 mar_putstr_text(window, attr, str);
720 break;
721 } /* endswitch win_type */
724 void
725 Gem_display_file(fname, complain)
726 const char *fname;
727 boolean complain;
729 dlb *f;
730 char buf[BUFSZ];
731 char *cr;
733 f = dlb_fopen(fname, "r");
734 if (!f) {
735 if (complain)
736 pline("Cannot open \"%s\".", fname);
737 } else {
738 winid datawin;
740 datawin = Gem_create_nhwindow(NHW_TEXT);
741 while (dlb_fgets(buf, BUFSZ, f)) {
742 if ((cr = index(buf, '\n')) != 0)
743 *cr = 0;
744 if (index(buf, '\t') != 0)
745 (void) tabexpand(buf);
746 Gem_putstr(datawin, 0, buf);
748 (void) dlb_fclose(f);
749 Gem_display_nhwindow(datawin, FALSE);
750 Gem_destroy_nhwindow(datawin);
754 /*ARGSUSED*/
756 * Add a menu item to the beginning of the menu list. This list is reversed
757 * later.
759 void
760 Gem_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected)
761 winid window; /* window to use, must be of type NHW_MENU */
762 int glyph; /* glyph to display with item (unused) */
763 const anything *identifier; /* what to return if selected */
764 char ch; /* keyboard accelerator (0 = pick our own) */
765 char gch; /* group accelerator (0 = no group) */
766 int attr; /* attribute for string (like Gem_putstr()) */
767 const char *str; /* menu string */
768 boolean preselected; /* item is marked as selected */
770 Gem_menu_item *G_item;
771 const char *newstr;
772 char buf[QBUFSZ];
774 if (str == (const char *) 0)
775 return;
777 if (window == WIN_ERR) /* MAR -- test existence */
778 panic(winpanicstr, window);
780 if (identifier->a_void)
781 Sprintf(buf, "%c - %s", ch ? ch : '?', str);
782 else
783 Sprintf(buf, "%s", str);
784 newstr = buf;
786 G_item = (Gem_menu_item *) alloc(sizeof(Gem_menu_item));
787 G_item->Gmi_identifier = (long) identifier->a_void;
788 G_item->Gmi_glyph = glyph != NO_GLYPH ? glyph2tile[glyph] : NO_GLYPH;
789 G_item->Gmi_count = -1L;
790 G_item->Gmi_selected = preselected ? 1 : 0;
791 G_item->Gmi_accelerator = ch;
792 G_item->Gmi_groupacc = gch;
793 G_item->Gmi_attr = attr;
794 G_item->Gmi_str = copy_of(newstr);
795 mar_add_menu(window, G_item);
799 * End a menu in this window, window must a type NHW_MENU.
800 * We assign the keyboard accelerators as needed.
802 void
803 Gem_end_menu(window, prompt)
804 winid window; /* menu to use */
805 const char *prompt; /* prompt to for menu */
807 if (window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU)
808 panic(winpanicstr, window);
810 /* Reverse the list so that items are in correct order. */
811 mar_reverse_menu();
813 /* Put the prompt at the beginning of the menu. */
814 mar_set_menu_title(prompt);
816 mar_set_accelerators();
820 Gem_select_menu(window, how, menu_list)
821 winid window;
822 int how;
823 menu_item **menu_list;
825 Gem_menu_item *Gmit;
826 menu_item *mi;
827 int n;
829 if (window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU)
830 panic(winpanicstr, window);
832 *menu_list = (menu_item *) 0;
833 mar_set_menu_type(how);
834 Gem_display_nhwindow(window, TRUE);
836 for (n = 0, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next)
837 if (Gmit->Gmi_selected)
838 n++;
840 if (n > 0) {
841 *menu_list = (menu_item *) alloc(n * sizeof(menu_item));
842 for (mi = *menu_list, Gmit = mar_hol_inv(); Gmit;
843 Gmit = Gmit->Gmi_next)
844 if (Gmit->Gmi_selected) {
845 mi->item = (anything)(genericptr_t) Gmit->Gmi_identifier;
846 mi->count = Gmit->Gmi_count;
847 mi++;
851 return n;
854 void
855 Gem_update_inventory()
859 void
860 Gem_mark_synch()
862 mar_display_nhwindow(WIN_MESSAGE);
863 mar_display_nhwindow(WIN_MAP);
864 mar_display_nhwindow(WIN_STATUS);
867 void
868 Gem_wait_synch()
870 mar_display_nhwindow(WIN_MESSAGE);
871 mar_display_nhwindow(WIN_MAP);
872 mar_display_nhwindow(WIN_STATUS);
875 #ifdef CLIPPING
876 extern void mar_cliparound(void);
877 void
878 Gem_cliparound(x, y)
879 int x, y;
881 mar_curs(x - 1, y);
882 mar_cliparound();
884 #endif /* CLIPPING */
887 * Gem_print_glyph
889 * Print the glyph to the output device. Don't flush the output device.
891 * Since this is only called from show_glyph(), it is assumed that the
892 * position and glyph are always correct (checked there)!
895 void mar_print_gl_char(winid, xchar, xchar, int);
897 extern int mar_set_rogue(int);
899 extern void mar_add_pet_sign(winid, int, int);
901 void
902 Gem_print_glyph(window, x, y, glyph, bkglyph)
903 winid window;
904 xchar x, y;
905 int glyph, bkglyph;
907 /* Move the cursor. */
908 Gem_curs(window, x, y);
910 mar_set_rogue(Is_rogue_level(&u.uz) ? TRUE : FALSE);
912 x--; /* MAR -- because x ranges from 1 to COLNO */
913 if (mar_set_tile_mode(-1)) {
914 mar_print_glyph(window, x, y, glyph2tile[glyph], glyph2tile[bkglyph]);
915 if (
916 #ifdef TEXTCOLOR
917 iflags.hilite_pet &&
918 #endif
919 glyph_is_pet(glyph))
920 mar_add_pet_sign(window, x, y);
921 } else
922 mar_print_gl_char(window, x, y, glyph);
925 void mar_print_char(winid, xchar, xchar, char, int);
927 void
928 mar_print_gl_char(window, x, y, glyph)
929 winid window;
930 xchar x, y;
931 int glyph;
933 int ch;
934 int color;
935 unsigned special;
937 /* map glyph to character and color */
938 (void) mapglyph(glyph, &ch, &color, &special, x, y);
940 #ifdef TEXTCOLOR
941 /* Turn off color if rogue level. */
942 if (Is_rogue_level(&u.uz))
943 color = NO_COLOR;
944 #endif /* TEXTCOLOR */
946 mar_print_char(window, x, y, ch, color);
949 extern void mar_raw_print(const char *);
950 extern void mar_raw_print_bold(const char *);
952 void
953 Gem_raw_print(str)
954 const char *str;
956 if (str && *str) {
957 if (iflags.window_inited)
958 mar_raw_print(str);
959 else
960 printf("%s\n", str);
964 void
965 Gem_raw_print_bold(str)
966 const char *str;
968 if (str && *str) {
969 if (iflags.window_inited)
970 mar_raw_print_bold(str);
971 else
972 printf("%s\n", str);
976 extern void mar_update_value(void); /* wingem1.c */
979 Gem_nhgetch()
981 int i;
983 mar_update_value();
984 i = tgetch();
985 if (!i)
986 i = '\033'; /* map NUL to ESC since anethack doesn't expect NUL */
988 return i;
991 /* Get a extended command in windowport specific way.
992 returns index of the ext_cmd or -1.
993 called after '#'.
994 It's a menu with all the possibilities. */
996 Gem_get_ext_cmd()
998 winid wind;
999 int i, count, what, too_much = FALSE;
1000 menu_item *selected = NULL;
1001 anything any;
1002 char accelerator = 0, tmp_acc = 0;
1003 const char *ptr;
1005 wind = Gem_create_nhwindow(NHW_MENU);
1006 Gem_start_menu(wind);
1007 for (i = 0; (ptr = extcmdlist[i].ef_txt); i++) {
1008 any.a_int = i;
1009 accelerator = *ptr;
1010 if (tmp_acc == accelerator) {
1011 if (too_much)
1012 accelerator = '&'; /* MAR -- poor choice, anyone? */
1013 else
1014 accelerator += 'A' - 'a';
1015 too_much = TRUE;
1016 } else
1017 too_much = FALSE;
1018 tmp_acc = *ptr;
1019 Gem_add_menu(wind, NO_GLYPH, &any, accelerator, 0, ATR_NONE, ptr,
1020 FALSE);
1022 Gem_end_menu(wind, "What extended command?");
1023 count = Gem_select_menu(wind, PICK_ONE, &selected);
1024 what = count ? selected->item.a_int : -1;
1025 if (selected)
1026 free(selected);
1027 Gem_destroy_nhwindow(wind);
1028 return (what);
1031 void
1032 Gem_number_pad(state)
1033 int state;
1035 state = state;
1038 void
1039 win_Gem_init()
1043 #ifdef POSITIONBAR
1044 void
1045 Gem_update_positionbar(posbar)
1046 char *posbar;
1049 #endif
1051 /** Gem_outrip **/
1052 void mar_set_text_to_rip(winid);
1053 char **rip_line = 0;
1055 void
1056 Gem_outrip(w, how, when)
1057 winid w;
1058 int how;
1059 time_t when;
1061 /* Code from X11 windowport */
1062 #define STONE_LINE_LEN 15 /* # chars that fit on one line */
1063 #define NAME_LINE 0 /* line # for player name */
1064 #define GOLD_LINE 1 /* line # for amount of gold */
1065 #define DEATH_LINE 2 /* line # for death description */
1066 #define YEAR_LINE 6 /* line # for year */
1067 char buf[BUFSZ];
1068 char *dpx;
1069 int line;
1070 long year;
1072 if (!rip_line) {
1073 int i;
1074 rip_line = (char **) malloc((YEAR_LINE + 1) * sizeof(char *));
1075 for (i = 0; i < YEAR_LINE + 1; i++) {
1076 rip_line[i] =
1077 (char *) malloc((STONE_LINE_LEN + 1) * sizeof(char));
1080 /* Follows same algorithm as genl_outrip() */
1081 /* Put name on stone */
1082 Sprintf(rip_line[NAME_LINE], "%s", plname);
1083 /* Put $ on stone */
1084 Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money);
1085 /* Put together death description */
1086 formatkiller(buf, sizeof buf, how, FALSE);
1088 /* Put death type on stone */
1089 for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) {
1090 register int i, i0;
1091 char tmpchar;
1092 if ((i0 = strlen(dpx)) > STONE_LINE_LEN) {
1093 for (i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--)
1094 if (dpx[i] == ' ')
1095 i0 = i;
1096 if (!i)
1097 i0 = STONE_LINE_LEN;
1099 tmpchar = dpx[i0];
1100 dpx[i0] = 0;
1101 strcpy(rip_line[line], dpx);
1102 if (tmpchar != ' ') {
1103 dpx[i0] = tmpchar;
1104 dpx = &dpx[i0];
1105 } else
1106 dpx = &dpx[i0 + 1];
1108 /* Put year on stone */
1109 year = yyyymmdd(when) / 10000L;
1110 Sprintf(rip_line[YEAR_LINE], "%4ld", year);
1112 mar_set_text_to_rip(w);
1113 for (line = 0; line < 13; line++)
1114 putstr(w, 0, "");
1116 void
1117 mar_get_font(type, p_fname, psize)
1118 int type;
1119 char **p_fname;
1120 int *psize;
1122 switch (type) {
1123 case NHW_MESSAGE:
1124 *p_fname = iflags.wc_font_message;
1125 *psize = iflags.wc_fontsiz_message;
1126 break;
1127 case NHW_MAP:
1128 *p_fname = iflags.wc_font_map;
1129 *psize = iflags.wc_fontsiz_map;
1130 break;
1131 case NHW_STATUS:
1132 *p_fname = iflags.wc_font_status;
1133 *psize = iflags.wc_fontsiz_status;
1134 break;
1135 case NHW_MENU:
1136 *p_fname = iflags.wc_font_menu;
1137 *psize = iflags.wc_fontsiz_menu;
1138 break;
1139 case NHW_TEXT:
1140 *p_fname = iflags.wc_font_text;
1141 *psize = iflags.wc_fontsiz_text;
1142 break;
1143 default:
1144 break;
1147 void
1148 Gem_preference_update(pref)
1149 const char *pref;
1151 if (stricmp(pref, "font_message") == 0
1152 || stricmp(pref, "font_size_message") == 0) {
1153 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
1154 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
1155 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
1156 mar_set_font(NHW_MESSAGE, iflags.wc_font_message,
1157 iflags.wc_fontsiz_message);
1158 return;
1160 if (stricmp(pref, "font_map") == 0
1161 || stricmp(pref, "font_size_map") == 0) {
1162 if (iflags.wc_fontsiz_map < NHFONT_SIZE_MIN
1163 || iflags.wc_fontsiz_map > NHFONT_SIZE_MAX)
1164 iflags.wc_fontsiz_map = NHFONT_DEFAULT_SIZE;
1165 mar_set_font(NHW_MAP, iflags.wc_font_map, iflags.wc_fontsiz_map);
1166 return;
1168 if (stricmp(pref, "font_status") == 0
1169 || stricmp(pref, "font_size_status") == 0) {
1170 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
1171 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
1172 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
1173 mar_set_font(NHW_STATUS, iflags.wc_font_status,
1174 iflags.wc_fontsiz_status);
1175 return;
1177 if (stricmp(pref, "font_menu") == 0
1178 || stricmp(pref, "font_size_menu") == 0) {
1179 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
1180 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
1181 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
1182 mar_set_font(NHW_MENU, iflags.wc_font_menu, iflags.wc_fontsiz_menu);
1183 return;
1185 if (stricmp(pref, "font_text") == 0
1186 || stricmp(pref, "font_size_text") == 0) {
1187 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
1188 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
1189 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
1190 mar_set_font(NHW_TEXT, iflags.wc_font_text, iflags.wc_fontsiz_text);
1191 return;
1193 if (stricmp(pref, "scroll_margin") == 0) {
1194 mar_set_margin(iflags.wc_scroll_margin);
1195 Gem_cliparound(u.ux, u.uy);
1196 return;
1198 if (stricmp(pref, "ascii_map") == 0) {
1199 mar_set_tile_mode(!iflags.wc_ascii_map);
1200 doredraw();
1201 return;
1203 if (stricmp(pref, "hilite_pet") == 0) {
1204 /* MAR -- works without doing something here. */
1205 return;
1207 if (stricmp(pref, "align_message") == 0) {
1208 mar_set_msg_align(iflags.wc_align_message - ALIGN_BOTTOM);
1209 return;
1211 if (stricmp(pref, "align_status") == 0) {
1212 mar_set_status_align(iflags.wc_align_status - ALIGN_BOTTOM);
1213 return;
1215 if (stricmp(pref, "vary_msgcount") == 0) {
1216 mar_set_msg_visible(iflags.wc_vary_msgcount);
1217 return;
1221 * Allocate a copy of the given string. If null, return a string of
1222 * zero length.
1224 * This is an exact duplicate of copy_of() in X11/winmenu.c.
1226 static char *
1227 copy_of(s)
1228 const char *s;
1230 if (!s)
1231 s = nullstr;
1232 return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s);
1235 #endif /* GEM_GRAPHICS \
1237 /*wingem.c*/