OSDN Git Service

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