OSDN Git Service

change potion un-id desc
[jnethack/source.git] / win / gem / wingem.c
1 /* NetHack 3.6  wingem.c        $NHDT-Date: 1433806613 2015/06/08 23:36:53 $  $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */
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 #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,
81 };
82
83 #ifdef MAC
84 void *
85 Gem_change_background(dummy)
86 int dummy;
87 {
88 }
89
90 short *
91 Gem_set_font_name(foo, bar)
92 winid foo;
93 char *bar;
94 {
95 }
96 #endif
97
98 /*************************** Proceduren *************************************/
99
100 int
101 mar_hp_query(void)
102 {
103     if (Upolyd)
104         return (u.mh ? u.mhmax / u.mh : -1);
105     return (u.uhp ? u.uhpmax / u.uhp : -1);
106 }
107
108 int
109 mar_iflags_numpad()
110 {
111     return (iflags.num_pad ? 1 : 0);
112 }
113
114 int
115 mar_get_msg_history()
116 {
117     return (iflags.msg_history);
118 }
119
120 int
121 mar_get_msg_visible()
122 {
123     return (iflags.wc_vary_msgcount);
124 }
125 /* clean up and quit */
126 static void
127 bail(mesg)
128 const char *mesg;
129 {
130     clearlocks();
131     Gem_exit_nhwindows(mesg);
132     terminate(EXIT_SUCCESS);
133     /*NOTREACHED*/
134 }
135
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;
152 {
153     argv = argv, argcp = argcp;
154     colors_changed = TRUE;
155
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*/
189     }
190     iflags.window_inited = TRUE;
191
192     CO = 80; /* MAR -- whatsoever */
193     LI = 25;
194
195     add_menu_cmd_alias(' ', MENU_NEXT_PAGE);
196     mar_set_no_glyph(NO_GLYPH);
197 }
198
199 void
200 Gem_player_selection()
201 {
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;
207
208     /* avoid unnecessary prompts further down */
209     rigid_role_checks();
210
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;
228         }
229     }
230
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();
243             }
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;
259                 }
260             }
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);
273
274             /* Process the choice */
275             if (n != 1 || selected[0].item.a_int == any.a_int)
276                 goto give_up; /* Selected quit */
277
278             flags.initrole = selected[0].item.a_int - 1;
279             free((genericptr_t) selected), selected = 0;
280         }
281     }
282
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);
296             }
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;
306                 }
307             }
308             if (n == 0) {
309                 for (i = 0; races[i].noun; i++) {
310                     if (validrace(flags.initrole, i)) {
311                         n++;
312                         k = i;
313                     }
314                 }
315             }
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);
327                     }
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;
346             }
347             flags.initrace = k;
348         }
349     }
350
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);
365             }
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;
375                 }
376             }
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;
382                     }
383                 }
384             }
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);
396                     }
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;
416             }
417             flags.initgend = k;
418         }
419     }
420
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);
434             }
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;
444                 }
445             }
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;
451                     }
452                 }
453             }
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);
465                     }
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;
488             }
489             flags.initalign = k;
490         }
491     }
492
493     /* Success! */
494     return;
495 }
496
497 /*
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().
502  */
503
504 void
505 Gem_askname()
506 {
507     strncpy(plname, mar_ask_name(), PL_NSIZ);
508 }
509
510 void
511 Gem_get_nh_event()
512 {
513 }
514
515 void
516 Gem_suspend_nhwindows(str)
517 const char *str;
518 {
519     const char *foo;
520
521     foo = str; /* MAR -- And the compiler whines no more ... */
522 }
523
524 void
525 Gem_resume_nhwindows()
526 {
527 }
528
529 void
530 Gem_end_screen()
531 {
532 }
533
534 void
535 Gem_start_screen()
536 {
537 }
538
539 extern void mar_exit_nhwindows(void);
540 extern boolean run_from_desktop;
541
542 void
543 Gem_exit_nhwindows(str)
544 const char *str;
545 {
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;
552 }
553
554 winid
555 Gem_create_nhwindow(type)
556 int type;
557 {
558     winid newid;
559
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;
575     }
576
577     newid = mar_create_window(type);
578
579     if (newid == MAXWIN) {
580         panic("No window slots!");
581         /* NOTREACHED */
582     }
583
584     return newid;
585 }
586
587 void
588 Gem_nhbell()
589 {
590     if (flags.silent)
591         return;
592     putchar('\007');
593     fflush(stdout);
594 }
595
596 extern void mar_clear_map(void);
597
598 void
599 Gem_clear_nhwindow(window)
600 winid window;
601 {
602     if (window == WIN_ERR)
603         panic(winpanicstr, window);
604
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;
616     }
617 }
618
619 extern void mar_more(void);
620
621 /*ARGSUSED*/
622 void
623 Gem_display_nhwindow(window, blocking)
624 winid window;
625 boolean blocking;
626 {
627     if (window == WIN_ERR)
628         panic(winpanicstr, window);
629
630     mar_display_nhwindow(window);
631
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;
646     }
647 }
648
649 void
650 Gem_destroy_nhwindow(window)
651 winid window;
652 {
653     if (window == WIN_ERR) /* MAR -- test existence */
654         panic(winpanicstr, window);
655
656     mar_destroy_nhwindow(window);
657 }
658
659 extern void mar_curs(int, int); /* mar_curs is only for map */
660
661 void
662 Gem_curs(window, x, y)
663 winid window;
664 register int x, y;
665 {
666     if (window == WIN_ERR) /* MAR -- test existence */
667         panic(winpanicstr, window);
668
669     if (window == WIN_MAP)
670         mar_curs(x - 1, y); /*$$$*/
671     else if (window == WIN_STATUS)
672         curr_status_line = y;
673 }
674
675 extern void mar_add_status_str(const char *, int);
676 extern void mar_putstr_text(winid, int, const char *);
677
678 void
679 Gem_putstr(window, attr, str)
680 winid window;
681 int attr;
682 const char *str;
683 {
684     int win_type;
685
686     if (window == WIN_ERR) {
687         Gem_raw_print(str);
688         return;
689     }
690
691     if (str == (const char *) 0)
692         return;
693
694     switch ((win_type = mar_hol_win_type(window))) {
695     case NHW_MESSAGE:
696         mar_add_message(str);
697         break;
698
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;
705
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;
714
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 */
722 }
723
724 void
725 Gem_display_file(fname, complain)
726 const char *fname;
727 boolean complain;
728 {
729     dlb *f;
730     char buf[BUFSZ];
731     char *cr;
732
733     f = dlb_fopen(fname, "r");
734     if (!f) {
735         if (complain)
736             pline("Cannot open \"%s\".", fname);
737     } else {
738         winid datawin;
739
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);
747         }
748         (void) dlb_fclose(f);
749         Gem_display_nhwindow(datawin, FALSE);
750         Gem_destroy_nhwindow(datawin);
751     }
752 }
753
754 /*ARGSUSED*/
755 /*
756  * Add a menu item to the beginning of the menu list.  This list is reversed
757  * later.
758  */
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 */
769 {
770     Gem_menu_item *G_item;
771     const char *newstr;
772     char buf[QBUFSZ];
773
774     if (str == (const char *) 0)
775         return;
776
777     if (window == WIN_ERR) /* MAR -- test existence */
778         panic(winpanicstr, window);
779
780     if (identifier->a_void)
781         Sprintf(buf, "%c - %s", ch ? ch : '?', str);
782     else
783         Sprintf(buf, "%s", str);
784     newstr = buf;
785
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);
796 }
797
798 /*
799  * End a menu in this window, window must a type NHW_MENU.
800  * We assign the keyboard accelerators as needed.
801  */
802 void
803 Gem_end_menu(window, prompt)
804 winid window;       /* menu to use */
805 const char *prompt; /* prompt to for menu */
806 {
807     if (window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU)
808         panic(winpanicstr, window);
809
810     /* Reverse the list so that items are in correct order. */
811     mar_reverse_menu();
812
813     /* Put the prompt at the beginning of the menu. */
814     mar_set_menu_title(prompt);
815
816     mar_set_accelerators();
817 }
818
819 int
820 Gem_select_menu(window, how, menu_list)
821 winid window;
822 int how;
823 menu_item **menu_list;
824 {
825     Gem_menu_item *Gmit;
826     menu_item *mi;
827     int n;
828
829     if (window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU)
830         panic(winpanicstr, window);
831
832     *menu_list = (menu_item *) 0;
833     mar_set_menu_type(how);
834     Gem_display_nhwindow(window, TRUE);
835
836     for (n = 0, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next)
837         if (Gmit->Gmi_selected)
838             n++;
839
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++;
848             }
849     }
850
851     return n;
852 }
853
854 void
855 Gem_update_inventory()
856 {
857 }
858
859 void
860 Gem_mark_synch()
861 {
862     mar_display_nhwindow(WIN_MESSAGE);
863     mar_display_nhwindow(WIN_MAP);
864     mar_display_nhwindow(WIN_STATUS);
865 }
866
867 void
868 Gem_wait_synch()
869 {
870     mar_display_nhwindow(WIN_MESSAGE);
871     mar_display_nhwindow(WIN_MAP);
872     mar_display_nhwindow(WIN_STATUS);
873 }
874
875 #ifdef CLIPPING
876 extern void mar_cliparound(void);
877 void
878 Gem_cliparound(x, y)
879 int x, y;
880 {
881     mar_curs(x - 1, y);
882     mar_cliparound();
883 }
884 #endif /* CLIPPING */
885
886 /*
887  *  Gem_print_glyph
888  *
889  *  Print the glyph to the output device.  Don't flush the output device.
890  *
891  *  Since this is only called from show_glyph(), it is assumed that the
892  *  position and glyph are always correct (checked there)!
893  */
894
895 void mar_print_gl_char(winid, xchar, xchar, int);
896
897 extern int mar_set_rogue(int);
898
899 extern void mar_add_pet_sign(winid, int, int);
900
901 void
902 Gem_print_glyph(window, x, y, glyph, bkglyph)
903 winid window;
904 xchar x, y;
905 int glyph, bkglyph;
906 {
907     /* Move the cursor. */
908     Gem_curs(window, x, y);
909
910     mar_set_rogue(Is_rogue_level(&u.uz) ? TRUE : FALSE);
911
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);
923 }
924
925 void mar_print_char(winid, xchar, xchar, char, int);
926
927 void
928 mar_print_gl_char(window, x, y, glyph)
929 winid window;
930 xchar x, y;
931 int glyph;
932 {
933     int ch;
934     int color;
935     unsigned special;
936
937     /* map glyph to character and color */
938     (void) mapglyph(glyph, &ch, &color, &special, x, y);
939
940 #ifdef TEXTCOLOR
941     /* Turn off color if rogue level. */
942     if (Is_rogue_level(&u.uz))
943         color = NO_COLOR;
944 #endif /* TEXTCOLOR */
945
946     mar_print_char(window, x, y, ch, color);
947 }
948
949 extern void mar_raw_print(const char *);
950 extern void mar_raw_print_bold(const char *);
951
952 void
953 Gem_raw_print(str)
954 const char *str;
955 {
956     if (str && *str) {
957         if (iflags.window_inited)
958             mar_raw_print(str);
959         else
960             printf("%s\n", str);
961     }
962 }
963
964 void
965 Gem_raw_print_bold(str)
966 const char *str;
967 {
968     if (str && *str) {
969         if (iflags.window_inited)
970             mar_raw_print_bold(str);
971         else
972             printf("%s\n", str);
973     }
974 }
975
976 extern void mar_update_value(void); /* wingem1.c */
977
978 int
979 Gem_nhgetch()
980 {
981     int i;
982
983     mar_update_value();
984     i = tgetch();
985     if (!i)
986         i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
987
988     return i;
989 }
990
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. */
995 int
996 Gem_get_ext_cmd()
997 {
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;
1004
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);
1021     }
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);
1029 }
1030
1031 void
1032 Gem_number_pad(state)
1033 int state;
1034 {
1035     state = state;
1036 }
1037
1038 void
1039 win_Gem_init()
1040 {
1041 }
1042
1043 #ifdef POSITIONBAR
1044 void
1045 Gem_update_positionbar(posbar)
1046 char *posbar;
1047 {
1048 }
1049 #endif
1050
1051 /** Gem_outrip **/
1052 void mar_set_text_to_rip(winid);
1053 char **rip_line = 0;
1054
1055 void
1056 Gem_outrip(w, how, when)
1057 winid w;
1058 int how;
1059 time_t when;
1060 {
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;
1071
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));
1078         }
1079     }
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);
1087
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;
1098         }
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];
1107     }
1108     /* Put year on stone */
1109     year = yyyymmdd(when) / 10000L;
1110     Sprintf(rip_line[YEAR_LINE], "%4ld", year);
1111
1112     mar_set_text_to_rip(w);
1113     for (line = 0; line < 13; line++)
1114         putstr(w, 0, "");
1115 }
1116 void
1117 mar_get_font(type, p_fname, psize)
1118 int type;
1119 char **p_fname;
1120 int *psize;
1121 {
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;
1145     }
1146 }
1147 void
1148 Gem_preference_update(pref)
1149 const char *pref;
1150 {
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;
1159     }
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;
1167     }
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;
1176     }
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;
1184     }
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;
1192     }
1193     if (stricmp(pref, "scroll_margin") == 0) {
1194         mar_set_margin(iflags.wc_scroll_margin);
1195         Gem_cliparound(u.ux, u.uy);
1196         return;
1197     }
1198     if (stricmp(pref, "ascii_map") == 0) {
1199         mar_set_tile_mode(!iflags.wc_ascii_map);
1200         doredraw();
1201         return;
1202     }
1203     if (stricmp(pref, "hilite_pet") == 0) {
1204         /* MAR -- works without doing something here. */
1205         return;
1206     }
1207     if (stricmp(pref, "align_message") == 0) {
1208         mar_set_msg_align(iflags.wc_align_message - ALIGN_BOTTOM);
1209         return;
1210     }
1211     if (stricmp(pref, "align_status") == 0) {
1212         mar_set_status_align(iflags.wc_align_status - ALIGN_BOTTOM);
1213         return;
1214     }
1215     if (stricmp(pref, "vary_msgcount") == 0) {
1216         mar_set_msg_visible(iflags.wc_vary_msgcount);
1217         return;
1218     }
1219 }
1220 /*
1221  * Allocate a copy of the given string.  If null, return a string of
1222  * zero length.
1223  *
1224  * This is an exact duplicate of copy_of() in X11/winmenu.c.
1225  */
1226 static char *
1227 copy_of(s)
1228 const char *s;
1229 {
1230     if (!s)
1231         s = nullstr;
1232     return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s);
1233 }
1234
1235 #endif /* GEM_GRAPHICS \
1236                        \
1237 /*wingem.c*/