OSDN Git Service

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