1 /* Copyright (c) Shawn Betts, Ryan Yeske, 2001 */
2 /* NetHack may be freely redistributed. See license for details. */
3
4 /*
5 * "Main" file for the lisp/emacs window-port. This contains most of
6 * the interface routines. Please see doc/window.doc for an
7 * description of the window interface.
8 */
9
10 #ifdef MSDOS /* from compiler */
11 #define SHORT_FILENAMES
12 #endif
13
14 #include "hack.h"
15 #include "winlisp.h"
16 #include "func_tab.h"
17
18 #include "dlb.h"
19 #ifdef SHORT_FILENAMES
20 #include "patchlev.h"
21 #else
22 #include "patchlevel.h"
23 #endif
24
25 #define CMD_KEY 0
26 #define CMD_EXT 1
27 #define CMD_LISP 2 /* These are commands specific to the lisp port */
28
29 /* from tile.c */
30 extern short glyph2tile[];
31 extern int total_tiles_used;
32
33 typedef struct
34 {
35 anything identifier;
36 char accelerator;
37 } lisp_menu_item_t;
38
39 /* An iterator for assigning accelerator keys. */
40 static char lisp_current_accelerator;
41
42 /* Helper structures to map menu id's to nethack anything's */
43 static lisp_menu_item_t lisp_menu_item_list[1000];
44 static int lisp_menu_list_size = 1000;
45 static int lisp_menu_list_num;
46
47 extern char *enc_stat[];
48 const char *hunger_stat[] = {
49 "Satiated",
50 "",
51 "Hungry",
52 "Weak",
53 "Fainting",
54 "Fainted",
55 "Starved"
56 };
57
58 typedef struct
59 {
60 char *name;
61 int type;
62 int cmd; /* The command (a keystroke) */
63 }cmd_index_t;
64
65 #ifndef C
66 #define C(c) (0x1f & (c))
67 #endif
68
69 /* Taken from cmd.c */
70 cmd_index_t cmd_index[] = { {"gowest", CMD_KEY, 'h'},
71 {"gowestontop", CMD_KEY, 'H'},
72 {"gowestnear", CMD_KEY, C('h')},
73
74 {"gosouth", CMD_KEY, 'j'},
75 {"gosouthontop", CMD_KEY, 'J'},
76 {"gosouthnear", CMD_KEY, C('j')},
77
78 {"gonorth", CMD_KEY, 'k'},
79 {"gonorthontop", CMD_KEY, 'K'},
80 {"gonorthnear", CMD_KEY, C('k')},
81
82 {"goeast", CMD_KEY, 'l'},
83 {"goeastontop", CMD_KEY, 'L'},
84 {"goeastnear", CMD_KEY, C('l')},
85
86 {"gonorthwest", CMD_KEY, 'y'},
87 {"gonorthwestontop", CMD_KEY, 'Y'},
88 {"gonorthwestnear", CMD_KEY, C('y')},
89
90 {"gonortheast", CMD_KEY, 'u'},
91 {"gonortheastontop", CMD_KEY, 'U'},
92 {"gonortheastnear", CMD_KEY, C('u')},
93
94 {"gosouthwest", CMD_KEY, 'b'},
95 {"gosouthwestontop", CMD_KEY, 'B'},
96 {"gosouthwestnear", CMD_KEY, C('b')},
97
98 {"gosoutheast", CMD_KEY, 'n'},
99 {"gosoutheastontop", CMD_KEY, 'N'},
100 {"gosoutheastnear", CMD_KEY, C('n')},
101
102 {"travel", CMD_KEY, '_'},
103
104 {"idtrap", CMD_KEY, '^'},
105 {"apply", CMD_KEY, 'a'},
106 {"remarm", CMD_KEY, 'A'},
107 {"close", CMD_KEY, 'c'},
108 {"drop", CMD_KEY, 'd'},
109
110 {"ddrop", CMD_KEY, 'D'},
111 {"eat", CMD_KEY, 'e'},
112 {"engrave", CMD_KEY, 'E'},
113 {"fire", CMD_KEY, 'f'},
114 {"inv", CMD_KEY, 'i'},
115
116 {"typeinv", CMD_KEY, 'I'},
117 {"open", CMD_KEY, 'o'},
118 {"set", CMD_KEY, 'O'},
119 {"pay", CMD_KEY, 'p'},
120 {"puton", CMD_KEY, 'P'},
121
122 {"drink", CMD_KEY, 'q'},
123 {"wieldquiver", CMD_KEY, 'Q'},
124 {"read", CMD_KEY, 'r'},
125 {"remring", CMD_KEY, 'R'},
126 {"search", CMD_KEY, 's'},
127
128 {"save", CMD_KEY, 'S'},
129 {"throw", CMD_KEY, 't'},
130 {"takeoff", CMD_KEY, 'T'},
131 {"simpleversion", CMD_KEY, 'v'},
132 {"history", CMD_KEY, 'V'},
133
134 {"wield", CMD_KEY, 'w'},
135 {"wear", CMD_KEY, 'W'},
136 {"swapweapon", CMD_KEY, 'x'},
137 {"enter_explore_mode", CMD_KEY, 'X'},
138 {"zap", CMD_KEY, 'z'},
139
140 {"cast", CMD_KEY, 'Z'},
141 {"up", CMD_KEY, '<'},
142 {"down", CMD_KEY, '>'},
143 {"whatis", CMD_KEY, '/'},
144 {"help", CMD_KEY, '?'},
145
146 {"whatdoes", CMD_KEY, '&'},
147 {"sh", CMD_KEY, '!'},
148 {"discovered", CMD_KEY, '\\'},
149 {"null", CMD_KEY, '.'},
150 {"look", CMD_KEY, ':'},
151
152 {"quickwhatis", CMD_KEY, ';'},
153 {"pickup", CMD_KEY, ','},
154 {"togglepickup", CMD_KEY, '@'},
155 {"prinuse", CMD_KEY, '*'},
156 {"countgold", CMD_KEY, '$'},
157
158 {"kick", CMD_KEY, C('d')},
159 {"listspells", CMD_KEY, '+'},
160 {"redraw", CMD_KEY, C('r')},
161 {"teleport", CMD_KEY, C('t')},
162 {"callmon", CMD_KEY, 'C'},
163 {"fight", CMD_KEY, 'F'},
164 {"movenear", CMD_KEY, 'g'},
165 {"move", CMD_KEY, 'G'},
166 {"movenopickuporfight", CMD_KEY, 'm'},
167 {"movenopickup", CMD_KEY, 'M'},
168 {"showweapon", CMD_KEY, ')'},
169 {"showarmor", CMD_KEY, '['},
170 {"showrings", CMD_KEY, '='},
171 {"showamulet", CMD_KEY, '"'},
172 {"showtool", CMD_KEY, '('},
173 {"attributes", CMD_KEY, C('x')},
174 #ifdef REDO
175 {"again", CMD_KEY, DOAGAIN},
176 #endif /* REDO */
177
178 /* wizard commands */
179 {"wiz_detect", CMD_KEY, C('e')},
180 {"wiz_map", CMD_KEY, C('f')},
181 {"wiz_genesis", CMD_KEY, C('g')},
182 {"wiz_identify", CMD_KEY, C('i')},
183 {"wiz_where", CMD_KEY, C('o')},
184 {"wiz_level_tele", CMD_KEY, C('v')},
185 {"wiz_wish", CMD_KEY, C('w')},
186
187 /* wizard extended commands */
188 #ifdef WIZARD
189 {"light sources", CMD_EXT, 0},
190 {"seenv", CMD_EXT, 0},
191 {"stats", CMD_EXT, 0},
192 {"timeout", CMD_EXT, 0},
193 {"vision", CMD_EXT, 0},
194 #ifdef DEBUG
195 {"wizdebug", CMD_EXT, 0},
196 #endif /* DEBUG */
197 {"wmode", CMD_EXT, 0},
198 #endif /* WIZARD */
199 {"pray", CMD_EXT, 0},
200 {"adjust", CMD_EXT, 0},
201 {"chat", CMD_EXT, 0},
202 {"conduct", CMD_EXT, 0},
203 {"dip", CMD_EXT, 0},
204
205 {"enhance", CMD_EXT, 0},
206 {"force", CMD_EXT, 0},
207 {"invoke", CMD_EXT, 0},
208 {"jump", CMD_EXT, 0},
209 {"loot", CMD_EXT, 0},
210
211 {"monster", CMD_EXT, 0},
212 {"name", CMD_EXT, 0},
213 {"offer", CMD_EXT, 0},
214 {"quit", CMD_EXT, 0},
215 {"ride", CMD_EXT, 0},
216
217 {"rub", CMD_EXT, 0},
218 {"sit", CMD_EXT, 0},
219 {"turn", CMD_EXT, 0},
220 {"twoweapon", CMD_EXT, 0},
221 {"untrap", CMD_EXT, 0},
222
223 {"version", CMD_EXT, 0},
224 {"wipe", CMD_EXT, 0},
225
226 /* Lisp port specific commands */
227 {"options", CMD_LISP, 0},
228
229 {0, CMD_KEY, '\0'} };
230
231 /* This variable is set when the user has selected an extended command. */
232 static int extended_cmd_id;
233
234 /* Interface definition, for windows.c */
235 struct window_procs lisp_procs = {
236 "lisp",
237 WC_COLOR|WC_HILITE_PET,
238 0L,
239 lisp_init_nhwindows,
240 lisp_player_selection,
241 lisp_askname,
242 lisp_get_nh_event,
243 lisp_exit_nhwindows,
244 lisp_suspend_nhwindows,
245 lisp_resume_nhwindows,
246 lisp_create_nhwindow,
247 lisp_clear_nhwindow,
248 lisp_display_nhwindow,
249 lisp_destroy_nhwindow,
250 lisp_curs,
251 lisp_putstr,
252 lisp_display_file,
253 lisp_start_menu,
254 lisp_add_menu,
255 lisp_end_menu,
256 lisp_select_menu,
257 genl_message_menu,
258 lisp_update_inventory,
259 lisp_mark_synch,
260 lisp_wait_synch,
261 #ifdef CLIPPING
262 lisp_cliparound,
263 #endif
264 #ifdef POSITIONBAR
265 lisp_update_positionbar,
266 #endif
267 lisp_print_glyph,
268 lisp_raw_print,
269 lisp_raw_print_bold,
270 lisp_nhgetch,
271 lisp_nh_poskey,
272 lisp_nhbell,
273 lisp_doprev_message,
274 lisp_yn_function,
275 lisp_getlin,
276 lisp_get_ext_cmd,
277 lisp_number_pad,
278 lisp_delay_output,
279 #ifdef CHANGE_COLOR /* the Mac uses a palette device */
280 donull,
281 donull,
282 #endif
283 /* other defs that really should go away (they're tty specific) */
284 lisp_start_screen,
285 lisp_end_screen,
286 lisp_outrip,
287 genl_preference_update,
288 };
289
290 /* macros for printing lisp output */
291 #define lisp_cmd(s,body) \
292 do \
293 { \
294 printf("(nhapi-%s ",s); \
295 body; \
296 printf(")\n"); \
297 } \
298 while (0)
299 /* #define lisp_cmd0(s) printf ("(nhapi-%s)\n", s) */
300 #define lisp_list(body) \
301 do \
302 { \
303 printf("("); \
304 body; \
305 printf(") "); \
306 } \
307 while (0)
308
309 #define lisp_open printf("(")
310 #define lisp_close printf(") ")
311 #define lisp_quote printf("'")
312 #define lisp_dot printf(". ")
313 #define lisp_t printf("t ")
314 #define lisp_nil printf("nil ")
315 #define lisp_literal(x) \
316 do \
317 { \
318 lisp_quote; \
319 printf ("%s ", x); \
320 } \
321 while (0)
322 #define lisp_cons(x,y) \
323 do \
324 { \
325 lisp_open; \
326 x; \
327 lisp_dot; \
328 y; \
329 lisp_close; \
330 } \
331 while (0)
332 #define lisp_int(i) printf("%d ",i)
333 #define lisp_long(i) printf("%ld", i)
334 #define lisp_coord(c) printf("'(%d,%d) ",c.x,c.y)
335 #define lisp_boolean(i) printf("%s ",i?"t":"nil")
336 #define lisp_string(s) \
337 do \
338 { \
339 int nhi; \
340 printf ("\""); \
341 if (s) \
342 for (nhi=0;nhi<strlen(s);nhi++) \
343 { \
344 if (s[nhi] == 34 \
345 || s[nhi] == 92) putchar('\\'); \
346 putchar(s[nhi]); \
347 } \
348 printf("\" "); \
349 } \
350 while (0)
351
352 static const char*
attr_to_string(attr)353 attr_to_string(attr)
354 int attr;
355 {
356 switch (attr)
357 {
358 case ATR_NONE:
359 return "atr-none";
360 case ATR_ULINE:
361 return "atr-uline";
362 case ATR_BOLD:
363 return "atr-bold";
364 case ATR_BLINK:
365 return "atr-blink";
366 case ATR_INVERSE:
367 return "atr-inverse";
368 default:
369 /* Should never happen. */
370 impossible ("Invalid attribute code.");
371 exit (EXIT_FAILURE);
372 break;
373 }
374 }
375
376 static const char*
special_glyph_to_string(special)377 special_glyph_to_string(special)
378 unsigned special;
379 {
380 switch (special)
381 {
382 case MG_CORPSE:
383 return "corpse";
384 case MG_INVIS:
385 return "invis";
386 case MG_DETECT:
387 return "detect";
388 case MG_PET:
389 return "pet";
390 case MG_RIDDEN:
391 return "ridden";
392 }
393
394 /* If it's a combination, just return special. */
395 if (special)
396 return "special";
397 else
398 return "none";
399 }
400
401 static const char*
wintype_to_string(type)402 wintype_to_string(type)
403 int type;
404 {
405 switch (type)
406 {
407 case NHW_MAP:
408 return "nhw-map";
409 case NHW_MESSAGE:
410 return "nhw-message";
411 case NHW_STATUS:
412 return "nhw-status";
413 case NHW_MENU:
414 return "nhw-menu";
415 case NHW_TEXT:
416 return "nhw-text";
417 default:
418 fprintf (stderr, "Invalid window code\n");
419 exit (EXIT_FAILURE);
420 break;
421 }
422 }
423
424 static const char*
how_to_string(how)425 how_to_string (how)
426 int how;
427 {
428 switch (how)
429 {
430 case PICK_NONE:
431 return "pick-none";
432 case PICK_ONE:
433 return "pick-one";
434 case PICK_ANY:
435 return "pick-any";
436 default:
437 impossible ("Invalid how value %d", how);
438 }
439 return NULL;
440 }
441
442 static int
read_int(prompt,i)443 read_int (prompt, i)
444 const char* prompt;
445 int *i;
446 {
447 char line[BUFSZ];
448 int rv;
449 printf ("%s> ", prompt);
450 fflush(stdout);
451 fgets (line, BUFSZ, stdin);
452 rv = sscanf (line, "%d", i);
453 if (rv != 1) *i = -1;
454 return rv;
455 }
456
457 static int
read_string(prompt,str)458 read_string (prompt, str)
459 const char* prompt;
460 char **str;
461 {
462 char* rv;
463 int len;
464 int size;
465 char tmp[BUFSZ];
466
467 len = 0;
468 size = BUFSZ * 2;
469 *str = malloc (size);
470 (*str)[0] = '\0';
471
472 printf ("%s> ", prompt);
473 fflush(stdout);
474 do
475 {
476 /* Read the string */
477 rv = fgets (tmp, BUFSZ, stdin);
478 if (rv == NULL)
479 break;
480
481 len += strlen (tmp);
482 if (len >= size - 1)
483 {
484 size *= 2;
485 *str = realloc (*str, size);
486 if (*str == NULL)
487 panic ("Memory allocation failure; cannot get %u bytes", size);
488 }
489 strcat (*str, tmp);
490 } while (tmp[strlen (tmp) - 1] != '\n');
491
492 /* Did we read a string or error out? */
493 if (rv == NULL)
494 {
495 free (*str);
496 return -1;
497 }
498 else
499 {
500 /* chop the newline */
501 (*str) [strlen (*str) - 1] = '\0';
502 return 0;
503 }
504 }
505
506
507 static int
read_command(prompt,cmd,count)508 read_command (prompt, cmd, count)
509 const char *prompt;
510 char *cmd;
511 char *count;
512 {
513 char *buf;
514 int rv;
515 cmd[0] = '\0';
516 *count = 0;
517 if (read_string (prompt, &buf) == -1)
518 return -1;
519 rv = sscanf (buf, "%s %s", cmd, count);
520 free (buf);
521 if (rv != 2) *count = 0;
522 return rv;
523 }
524
525 void
bail(mesg)526 bail(mesg)
527 const char *mesg;
528 {
529 clearlocks ();
530 lisp_exit_nhwindows (mesg);
531 terminate (EXIT_SUCCESS);
532 /*NOTREACHED*/
533 }
534
535 void
win_lisp_init()536 win_lisp_init ()
537 {
538 /* Code to be executed on startup. */
539 }
540
541 void
lisp_player_selection()542 lisp_player_selection ()
543 {
544 int i, k, n;
545 char pick4u = 'n', thisch, lastch = 0;
546 char pbuf[QBUFSZ], plbuf[QBUFSZ];
547 winid win;
548 anything any;
549 menu_item *selected = 0;
550
551 /* prevent an unnecessary prompt */
552 rigid_role_checks();
553
554 /* Should we randomly pick for the player? */
555 if (!flags.randomall &&
556 (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE ||
557 flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
558
559 pick4u = lisp_yn_function ("Shall I pick a character for you? [ynq] ", "ynq", 'y');
560
561 if (pick4u != 'y' && pick4u != 'n')
562 {
563 give_up: /* Quit */
564 if (selected) free((genericptr_t) selected);
565 bail((char *)0);
566 /*NOTREACHED*/
567 return;
568 }
569
570 }
571
572 (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
573 flags.initrole, flags.initrace, flags.initgend, flags.initalign);
574
575 /* Select a role, if necessary */
576 /* we'll try to be compatible with pre-selected race/gender/alignment,
577 * but may not succeed */
578 if (flags.initrole < 0) {
579 char rolenamebuf[QBUFSZ];
580 /* Process the choice */
581 if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) {
582 /* Pick a random role */
583 flags.initrole = pick_role(flags.initrace, flags.initgend,
584 flags.initalign, PICK_RANDOM);
585 if (flags.initrole < 0) {
586 /* lisp_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
587 flags.initrole = randrole();
588 }
589 } else {
590 /* Prompt for a role */
591 win = create_nhwindow(NHW_MENU);
592 start_menu(win);
593 any.a_void = 0; /* zero out all bits */
594 for (i = 0; roles[i].name.m; i++) {
595 if (ok_role(i, flags.initrace, flags.initgend,
596 flags.initalign)) {
597 any.a_int = i+1; /* must be non-zero */
598 thisch = lowc(roles[i].name.m[0]);
599 if (thisch == lastch) thisch = highc(thisch);
600 if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) {
601 if (flags.initgend == 1 && roles[i].name.f)
602 Strcpy(rolenamebuf, roles[i].name.f);
603 else
604 Strcpy(rolenamebuf, roles[i].name.m);
605 } else {
606 if (roles[i].name.f) {
607 Strcpy(rolenamebuf, roles[i].name.m);
608 Strcat(rolenamebuf, "/");
609 Strcat(rolenamebuf, roles[i].name.f);
610 } else
611 Strcpy(rolenamebuf, roles[i].name.m);
612 }
613 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any, thisch,
614 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED);
615 lastch = thisch;
616 }
617 }
618 any.a_int = pick_role(flags.initrace, flags.initgend,
619 flags.initalign, PICK_RANDOM)+1;
620 if (any.a_int == 0) /* must be non-zero */
621 any.a_int = randrole()+1;
622 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any , '*', 0, ATR_NONE,
623 "Random", MENU_UNSELECTED);
624 any.a_int = i+1; /* must be non-zero */
625 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any , 'q', 0, ATR_NONE,
626 "Quit", MENU_UNSELECTED);
627 Sprintf(pbuf, "Pick a role for your %s", plbuf);
628 end_menu(win, pbuf);
629 n = select_menu(win, PICK_ONE, &selected);
630 destroy_nhwindow(win);
631
632 /* Process the choice */
633 if (n != 1 || selected[0].item.a_int == any.a_int)
634 goto give_up; /* Selected quit */
635
636 flags.initrole = selected[0].item.a_int - 1;
637 free((genericptr_t) selected), selected = 0;
638 }
639 (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
640 flags.initrole, flags.initrace, flags.initgend, flags.initalign);
641 }
642
643 /* Select a race, if necessary */
644 /* force compatibility with role, try for compatibility with
645 * pre-selected gender/alignment */
646 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
647 /* pre-selected race not valid */
648 if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) {
649 flags.initrace = pick_race(flags.initrole, flags.initgend,
650 flags.initalign, PICK_RANDOM);
651 if (flags.initrace < 0) {
652 /* lisp_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
653 flags.initrace = randrace(flags.initrole);
654 }
655 } else { /* pick4u == 'n' */
656 /* Count the number of valid races */
657 n = 0; /* number valid */
658 k = 0; /* valid race */
659 for (i = 0; races[i].noun; i++) {
660 if (ok_race(flags.initrole, i, flags.initgend,
661 flags.initalign)) {
662 n++;
663 k = i;
664 }
665 }
666 if (n == 0) {
667 for (i = 0; races[i].noun; i++) {
668 if (validrace(flags.initrole, i)) {
669 n++;
670 k = i;
671 }
672 }
673 }
674
675 /* Permit the user to pick, if there is more than one */
676 if (n > 1) {
677 win = create_nhwindow(NHW_MENU);
678 start_menu(win);
679 any.a_void = 0; /* zero out all bits */
680 for (i = 0; races[i].noun; i++)
681 if (ok_race(flags.initrole, i, flags.initgend,
682 flags.initalign)) {
683 any.a_int = i+1; /* must be non-zero */
684 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any, races[i].noun[0],
685 0, ATR_NONE, races[i].noun, MENU_UNSELECTED);
686 }
687 any.a_int = pick_race(flags.initrole, flags.initgend,
688 flags.initalign, PICK_RANDOM)+1;
689 if (any.a_int == 0) /* must be non-zero */
690 any.a_int = randrace(flags.initrole)+1;
691 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any , '*', 0, ATR_NONE,
692 "Random", MENU_UNSELECTED);
693 any.a_int = i+1; /* must be non-zero */
694 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any , 'q', 0, ATR_NONE,
695 "Quit", MENU_UNSELECTED);
696 Sprintf(pbuf, "Pick the race of your %s", plbuf);
697 end_menu(win, pbuf);
698 n = select_menu(win, PICK_ONE, &selected);
699 destroy_nhwindow(win);
700 if (n != 1 || selected[0].item.a_int == any.a_int)
701 goto give_up; /* Selected quit */
702
703 k = selected[0].item.a_int - 1;
704 free((genericptr_t) selected), selected = 0;
705 }
706 flags.initrace = k;
707 }
708 (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
709 flags.initrole, flags.initrace, flags.initgend, flags.initalign);
710 }
711
712 /* Select a gender, if necessary */
713 /* force compatibility with role/race, try for compatibility with
714 * pre-selected alignment */
715 if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace,
716 flags.initgend)) {
717 /* pre-selected gender not valid */
718 if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) {
719 flags.initgend = pick_gend(flags.initrole, flags.initrace,
720 flags.initalign, PICK_RANDOM);
721 if (flags.initgend < 0) {
722 /* lisp_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
723 flags.initgend = randgend(flags.initrole, flags.initrace);
724 }
725 } else { /* pick4u == 'n' */
726 /* Count the number of valid genders */
727 n = 0; /* number valid */
728 k = 0; /* valid gender */
729 for (i = 0; i < ROLE_GENDERS; i++) {
730 if (ok_gend(flags.initrole, flags.initrace, i,
731 flags.initalign)) {
732 n++;
733 k = i;
734 }
735 }
736 if (n == 0) {
737 for (i = 0; i < ROLE_GENDERS; i++) {
738 if (validgend(flags.initrole, flags.initrace, i)) {
739 n++;
740 k = i;
741 }
742 }
743 }
744
745 /* Permit the user to pick, if there is more than one */
746 if (n > 1) {
747 win = create_nhwindow(NHW_MENU);
748 start_menu(win);
749 any.a_void = 0; /* zero out all bits */
750 for (i = 0; i < ROLE_GENDERS; i++)
751 if (ok_gend(flags.initrole, flags.initrace, i,
752 flags.initalign)) {
753 any.a_int = i+1;
754 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any, genders[i].adj[0],
755 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED);
756 }
757 any.a_int = pick_gend(flags.initrole, flags.initrace,
758 flags.initalign, PICK_RANDOM)+1;
759 if (any.a_int == 0) /* must be non-zero */
760 any.a_int = randgend(flags.initrole, flags.initrace)+1;
761 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any , '*', 0, ATR_NONE,
762 "Random", MENU_UNSELECTED);
763 any.a_int = i+1; /* must be non-zero */
764 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any , 'q', 0, ATR_NONE,
765 "Quit", MENU_UNSELECTED);
766 Sprintf(pbuf, "Pick the gender of your %s", plbuf);
767 end_menu(win, pbuf);
768 n = select_menu(win, PICK_ONE, &selected);
769 destroy_nhwindow(win);
770 if (n != 1 || selected[0].item.a_int == any.a_int)
771 goto give_up; /* Selected quit */
772
773 k = selected[0].item.a_int - 1;
774 free((genericptr_t) selected), selected = 0;
775 }
776 flags.initgend = k;
777 }
778 (void) root_plselection_prompt(plbuf, QBUFSZ - 1,
779 flags.initrole, flags.initrace, flags.initgend, flags.initalign);
780 }
781
782 /* Select an alignment, if necessary */
783 /* force compatibility with role/race/gender */
784 if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace,
785 flags.initalign)) {
786 /* pre-selected alignment not valid */
787 if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) {
788 flags.initalign = pick_align(flags.initrole, flags.initrace,
789 flags.initgend, PICK_RANDOM);
790 if (flags.initalign < 0) {
791 /* lisp_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
792 flags.initalign = randalign(flags.initrole, flags.initrace);
793 }
794 } else { /* pick4u == 'n' */
795 /* Count the number of valid alignments */
796 n = 0; /* number valid */
797 k = 0; /* valid alignment */
798 for (i = 0; i < ROLE_ALIGNS; i++) {
799 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
800 i)) {
801 n++;
802 k = i;
803 }
804 }
805 if (n == 0) {
806 for (i = 0; i < ROLE_ALIGNS; i++) {
807 if (validalign(flags.initrole, flags.initrace, i)) {
808 n++;
809 k = i;
810 }
811 }
812 }
813
814 /* Permit the user to pick, if there is more than one */
815 if (n > 1) {
816 win = create_nhwindow(NHW_MENU);
817 start_menu(win);
818 any.a_void = 0; /* zero out all bits */
819 for (i = 0; i < ROLE_ALIGNS; i++)
820 if (ok_align(flags.initrole, flags.initrace,
821 flags.initgend, i)) {
822 any.a_int = i+1;
823 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any, aligns[i].adj[0],
824 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
825 }
826 any.a_int = pick_align(flags.initrole, flags.initrace,
827 flags.initgend, PICK_RANDOM)+1;
828 if (any.a_int == 0) /* must be non-zero */
829 any.a_int = randalign(flags.initrole, flags.initrace)+1;
830 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any , '*', 0, ATR_NONE,
831 "Random", MENU_UNSELECTED);
832 any.a_int = i+1; /* must be non-zero */
833 add_menu(win, NO_GLYPH, MENU_DEFCNT, &any , 'q', 0, ATR_NONE,
834 "Quit", MENU_UNSELECTED);
835 Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
836 end_menu(win, pbuf);
837 n = select_menu(win, PICK_ONE, &selected);
838 destroy_nhwindow(win);
839 if (n != 1 || selected[0].item.a_int == any.a_int)
840 goto give_up; /* Selected quit */
841
842 k = selected[0].item.a_int - 1;
843 free((genericptr_t) selected), selected = 0;
844 }
845 flags.initalign = k;
846 }
847 }
848 /* Success! */
849 /* lisp_display_nhwindow(BASE_WINDOW, FALSE); */
850 }
851
852 /* Reads from standard in, the player's name. */
853 void
lisp_askname()854 lisp_askname ()
855 {
856 char *line;
857 lisp_cmd ("askname",);
858 read_string ("string", &line);
859 strncpy (plname, line, PL_NSIZ);
860 plname[PL_NSIZ-1] = '\0';
861 free (line);
862 }
863
864 /* This is a noop for tty and X, so should it be a noop for us too? */
865 void
lisp_get_nh_event()866 lisp_get_nh_event ()
867 {
868 /* lisp_cmd ("get-event",); */
869 }
870
871 /* Global Functions */
872 void
lisp_raw_print(str)873 lisp_raw_print(str)
874 const char *str;
875 {
876 lisp_cmd ("raw-print", lisp_string (str));
877 }
878
879 void
lisp_raw_print_bold(str)880 lisp_raw_print_bold(str)
881 const char *str;
882 {
883 lisp_cmd ("raw-print-bold", lisp_string (str));
884 }
885
886 void
lisp_curs(window,x,y)887 lisp_curs(window, x, y)
888 winid window;
889 int x, y;
890 {
891 if (window == WIN_MAP)
892 lisp_cmd ("curs",
893 lisp_int (x);
894 lisp_int (y));
895 else if (window == WIN_STATUS)
896 {
897 /* do nothing */
898 }
899 else
900 lisp_cmd ("error", lisp_string("lisp_curs bad window"); lisp_int (window));
901 }
902
903 /* Send the options to the lisp process */
904 static void
get_options()905 get_options()
906 {
907 lisp_cmd ("options",
908 lisp_boolean(iflags.cbreak); /* in cbreak mode, rogue format */
909 lisp_boolean(iflags.DECgraphics); /* use DEC VT-xxx extended character set */
910 lisp_boolean(iflags.echo); /* 1 to echo characters */
911 lisp_boolean(iflags.IBMgraphics); /* use IBM extended character set */
912 lisp_int(iflags.msg_history); /* hint: # of top lines to save */
913 lisp_boolean(iflags.num_pad); /* use numbers for movement commands */
914 lisp_boolean(iflags.news); /* print news */
915 lisp_boolean(iflags.window_inited); /* true if init_nhwindows() completed */
916 lisp_boolean(iflags.vision_inited); /* true if vision is ready */
917 lisp_boolean(iflags.menu_tab_sep); /* Use tabs to separate option menu fields */
918 lisp_boolean(iflags.menu_requested); /* Flag for overloaded use of 'm' prefix
919 * on some non-move commands */
920 lisp_int(iflags.num_pad_mode);
921 lisp_int(iflags.purge_monsters); /* # of dead monsters still on fmon list */
922 /* lisp_int(*iflags.opt_booldup); /\* for duplication of boolean opts in config file *\/ */
923 /* lisp_int(*iflags.opt_compdup); /\* for duplication of compound opts in config file *\/ */
924 lisp_int(iflags.bouldersym); /* symbol for boulder display */
925 lisp_coord(iflags.travelcc); /* coordinates for travel_cache */
926 #ifdef WIZARD
927 lisp_boolean(iflags.sanity_check); /* run sanity checks */
928 lisp_boolean(iflags.mon_polycontrol); /* debug: control monster polymorphs */
929 #endif
930 );
931 }
932
933 static void
generate_status_line()934 generate_status_line ()
935 {
936 /* Ripped from botl.c */
937 int hp, hpmax;
938
939 hp = Upolyd ? u.mh : u.uhp;
940 hpmax = Upolyd ? u.mhmax : u.uhpmax;
941 if(hp < 0) hp = 0;
942
943 printf ("(nhapi-update-status ");
944 lisp_quote;
945 printf ("(");
946 lisp_list (lisp_string ("name");
947 lisp_string (plname););
948 if (Upolyd)
949 {
950 lisp_list (lisp_string ("rank");
951 lisp_nil);
952 lisp_list (lisp_string ("monster");
953 lisp_string (mons[u.umonnum].mname));
954 }
955 else
956 {
957 lisp_list (lisp_string ("rank");
958 lisp_string (rank_of(u.ulevel, Role_switch, flags.female)););;
959 lisp_list (lisp_string ("monster");
960 lisp_nil);
961 }
962
963 lisp_list (lisp_string ("St");
964 lisp_int (ACURR(A_STR)););
965 lisp_list (lisp_string ("Dx");
966 lisp_int (ACURR(A_DEX)););
967 lisp_list (lisp_string ("Co");
968 lisp_int (ACURR(A_CON)););
969 lisp_list (lisp_string ("In");
970 lisp_int (ACURR(A_INT)););
971 lisp_list (lisp_string ("Wi");
972 lisp_int (ACURR(A_WIS)););
973 lisp_list (lisp_string ("Ch");
974 lisp_int (ACURR(A_CHA)););
975 lisp_list (lisp_string ("Align");
976 if (u.ualign.type == A_CHAOTIC)
977 lisp_string ("Chaotic");
978 else if (u.ualign.type == A_NEUTRAL)
979 lisp_string ("Neutral");
980 else
981 lisp_string ("Lawful"););
982
983 #ifdef SCORE_ON_BOTL
984 lisp_list (lisp_string ("Score");
985 lisp_int (botl_score()););
986 #endif
987
988 if (In_endgame(&u.uz))
989 {
990 lisp_list (lisp_string ("Dungeon");
991 if (Is_astralevel(&u.uz))
992 lisp_string ("Astral Plane");
993 else
994 lisp_string ("End Game"););
995 }
996 else
997 {
998 lisp_list (lisp_string ("Dungeon");
999 lisp_string (dungeons[u.uz.dnum].dname););
1000 }
1001
1002 lisp_list (lisp_string ("Dlvl");
1003 lisp_int (depth(&u.uz)););
1004
1005 lisp_list (lisp_string ("$");
1006 lisp_long (u.ugold););
1007 lisp_list (lisp_string ("HP");
1008 lisp_int (hp););
1009 lisp_list (lisp_string ("HPmax");
1010 lisp_int (hpmax););
1011 lisp_list (lisp_string ("PW");
1012 lisp_int (u.uen););
1013 lisp_list (lisp_string ("PWmax");
1014 lisp_int (u.uenmax););
1015 lisp_list (lisp_string ("AC");
1016 lisp_int (u.uac););
1017
1018 if (Upolyd)
1019 {
1020 lisp_list (lisp_string ("HD");
1021 lisp_int (mons[u.umonnum].mlevel););
1022 }
1023 else
1024 {
1025 lisp_list (lisp_string ("HD");
1026 lisp_nil);
1027 }
1028
1029 lisp_list (lisp_string ("Level");
1030 lisp_int (u.ulevel););
1031 #ifdef EXP_ON_BOTL
1032 lisp_list (lisp_string ("XP");
1033 lisp_long (u.uexp););
1034 #endif
1035 lisp_list (lisp_string ("T");
1036 lisp_long (moves););
1037
1038 if (Confusion)
1039 lisp_list (lisp_string ("confusion"); lisp_string ("Conf"));
1040 else
1041 lisp_list (lisp_string ("confusion"); lisp_nil);
1042
1043 if (u.uhs != 1)
1044 lisp_list (lisp_string ("hunger"); lisp_string (hunger_stat[u.uhs]));
1045 else
1046 lisp_list (lisp_string ("hunger"); lisp_nil);
1047
1048 if (Sick)
1049 {
1050 if (u.usick_type & SICK_VOMITABLE)
1051 lisp_list (lisp_string ("sick"); lisp_string ("FoodPois"));
1052 if (u.usick_type & SICK_NONVOMITABLE)
1053 lisp_list (lisp_string ("sick"); lisp_string ("Ill"));
1054 }
1055 else
1056 lisp_list (lisp_string ("sick"); lisp_nil);
1057
1058 if (Blind)
1059 lisp_list (lisp_string ("blind"); lisp_string ("Blind"));
1060 else
1061 lisp_list (lisp_string ("blind"); lisp_nil);
1062
1063 if (Stunned)
1064 lisp_list (lisp_string ("stunned"); lisp_string ("Stun"));
1065 else
1066 lisp_list (lisp_string ("stunned"); lisp_nil);
1067
1068 if (Hallucination)
1069 lisp_list (lisp_string ("hallucination"); lisp_string ("Hallu"));
1070 else
1071 lisp_list (lisp_string ("hallucination"); lisp_nil);
1072
1073 if (Slimed)
1074 lisp_list (lisp_string ("slimed"); lisp_string ("Slime"));
1075 else
1076 lisp_list (lisp_string ("slimed"); lisp_nil);
1077
1078 if (near_capacity() > UNENCUMBERED)
1079 lisp_list (lisp_string ("encumbrance");
1080 lisp_string (enc_stat[near_capacity()]));
1081 else
1082 lisp_list (lisp_string ("encumbrance"); lisp_nil);
1083
1084 printf (" ))\n");
1085 }
1086
1087 void
lisp_putstr(window,attr,str)1088 lisp_putstr(window, attr, str)
1089 winid window;
1090 int attr;
1091 const char *str;
1092 {
1093 static char statline1[BUFSZ] = "";
1094 if (window == WIN_STATUS)
1095 {
1096 if (statline1[0]=='\0')
1097 Strcpy (statline1, str);
1098 else
1099 {
1100 generate_status_line ();
1101 statline1[0]='\0';
1102 }
1103 }
1104 else if (window == WIN_MESSAGE)
1105 lisp_cmd ("message",
1106 lisp_literal (attr_to_string (attr));
1107 lisp_string (str));
1108 else
1109 lisp_cmd ("menu-putstr",
1110 lisp_int (window);
1111 lisp_literal (attr_to_string (attr));
1112 lisp_string (str));
1113 }
1114
1115 void
lisp_start_menu(window)1116 lisp_start_menu(window)
1117 winid window;
1118 {
1119 lisp_menu_list_num = 0;
1120 lisp_current_accelerator = 'a';
1121 lisp_cmd ("start-menu", lisp_int (window));
1122 }
1123
1124 void
lisp_add_menu(window,glyph,cnt,identifier,ch,gch,attr,str,preselected)1125 lisp_add_menu(window, glyph, cnt, identifier, ch, gch, attr, str, preselected)
1126 winid window; /* window to use, must be of type NHW_MENU */
1127 int glyph; /* glyph to display with item (unused) */
1128 int cnt; /* max number of times this item can be selected */
1129 const anything *identifier; /* what to return if selected */
1130 char ch; /* keyboard accelerator (0 = pick our own) */
1131 char gch; /* group accelerator (0 = no group) */
1132 int attr; /* attribute for string (like tty_putstr()) */
1133 const char *str; /* menu string */
1134 boolean preselected; /* item is marked as selected */
1135 {
1136 if (identifier->a_void)
1137 {
1138 lisp_menu_item_list[lisp_menu_list_num].identifier = *identifier;
1139 if (ch == 0)
1140 {
1141 ch = lisp_menu_item_list[lisp_menu_list_num].accelerator = lisp_current_accelerator;
1142 if (lisp_current_accelerator == 'z')
1143 lisp_current_accelerator = 'A';
1144 else
1145 lisp_current_accelerator++;
1146 }
1147 else
1148 lisp_menu_item_list[lisp_menu_list_num].accelerator = ch;
1149
1150 lisp_menu_list_num++;
1151 }
1152 else
1153 ch = -1;
1154
1155 lisp_cmd ("add-menu",
1156 lisp_int (window);
1157 lisp_int (glyph);
1158 lisp_int (glyph2tile[glyph]);
1159 lisp_int (ch);
1160 lisp_int (gch);
1161 lisp_literal (attr_to_string (attr));
1162 lisp_string (str);
1163 preselected ? lisp_t : lisp_nil;
1164 /* The max count feature is already implemented in
1165 nethack-el, so we can avoid emitting `cnt'. */
1166 /* lisp_int (cnt); */
1167 );
1168 }
1169
1170 void
lisp_end_menu(window,prompt)1171 lisp_end_menu(window, prompt)
1172 winid window; /* menu to use */
1173 const char *prompt; /* prompt to for menu */
1174 {
1175 lisp_cmd ("end-menu",
1176 lisp_int (window);
1177 lisp_string (prompt));
1178 }
1179
1180 static int
lisp_get_menu_identifier(ch,identifier)1181 lisp_get_menu_identifier(ch, identifier)
1182 char ch;
1183 anything *identifier;
1184 {
1185 int i;
1186
1187 for(i=0; i < lisp_menu_list_num; i++)
1188 {
1189 if( lisp_menu_item_list[i].accelerator == ch )
1190 {
1191 *identifier = lisp_menu_item_list[i].identifier;
1192 return 1;
1193 }
1194 }
1195
1196 return 0;
1197 }
1198
1199 int
lisp_select_menu(window,how,menu_list)1200 lisp_select_menu(window, how, menu_list)
1201 winid window;
1202 int how;
1203 menu_item **menu_list;
1204 {
1205 const char *delim = "() \n";
1206 char *list;
1207 char *token;
1208 int size = 0;
1209
1210 lisp_cmd ("select-menu",
1211 lisp_int (window);
1212 lisp_literal (how_to_string (how)));
1213
1214 read_string ("menu", &list);
1215
1216 /* lisp_prompt ("menu"); */
1217 /* fgets (list, LINESIZ, stdin); */
1218
1219 /* The client should submit a structure like this:
1220
1221 ((ch count) (ch count) (ch count) ...)
1222
1223 where ch is the accelerator for the menu item and count is the
1224 number of them to select.
1225
1226 We strtok it so we just get id count id count id count. */
1227
1228 token = strtok (list, delim);
1229
1230 /* Start with some memory so realloc doesn't fail. */
1231 *menu_list = malloc (sizeof (menu_item));
1232 if (*menu_list == NULL)
1233 {
1234 panic ("Memory allocation failure; cannot get %u bytes",
1235 sizeof (menu_item));
1236 }
1237 size = 0;
1238
1239 while (token != NULL)
1240 {
1241 /* Make more room in the array for the new item */
1242 size++;
1243 if ((*menu_list = realloc (*menu_list, size * sizeof (menu_item))) == NULL)
1244 {
1245 panic ("Memory allocation failure; cannot get %u bytes",
1246 size * sizeof (menu_item));
1247 }
1248
1249 /* assign the item ID */
1250 lisp_get_menu_identifier (atoi (token), &(*menu_list)[size-1].item );
1251
1252 /* Read the item count */
1253 token = strtok (NULL, delim);
1254 (*menu_list)[size-1].count = atoi (token);
1255
1256 /* read the next item ID */
1257 token = strtok (NULL, delim);
1258 }
1259
1260 free (list);
1261
1262 return size;
1263 }
1264
1265 /* This is a tty-specific hack. Do we need it? */
1266 char
lisp_message_menu(let,how,mesg)1267 lisp_message_menu(let, how, mesg)
1268 char let;
1269 int how;
1270 const char *mesg;
1271 {
1272 lisp_cmd ("message-menu",
1273 lisp_int (let);
1274 lisp_literal (how_to_string (how));
1275 lisp_string (mesg));
1276 return '\0';
1277 }
1278
1279 static int
lisp_get_cmd(str)1280 lisp_get_cmd(str)
1281 const char *str;
1282 {
1283 int i;
1284
1285 for (i=0; cmd_index[i].name != (char *)0; i++)
1286 {
1287 if (!strcmp (str, cmd_index[i].name))
1288 return i;
1289 }
1290
1291 return -1;
1292 }
1293
1294 static int
lisp_get_ext_cmd_id(str)1295 lisp_get_ext_cmd_id (str)
1296 const char *str;
1297 {
1298 int i;
1299
1300 for (i=0; extcmdlist[i].ef_txt != (char *)0; i++) {
1301 if (!strcmp (str, extcmdlist[i].ef_txt)) return i;
1302 }
1303
1304 return -1;
1305 }
1306
1307 /* static int */
1308 /* num_digits(n) */
1309 /* int n; */
1310 /* { */
1311 /* int i; */
1312 /* int ret = 1; */
1313
1314 /* for (i=10;n / i; i *= 10) */
1315 /* { */
1316 /* ret++; */
1317 /* } */
1318
1319 /* return ret; */
1320 /* } */
1321
1322 /* static */
1323 /* int */
1324 /* power_of_ten (n) */
1325 /* int n; */
1326 /* { */
1327 /* int i; */
1328 /* int power = 1; */
1329
1330 /* for (i=0; i<n; i++) */
1331 /* { */
1332 /* power *= 10; */
1333 /* } */
1334
1335 /* return power; */
1336 /* } */
1337
1338 int
lisp_nhgetch()1339 lisp_nhgetch()
1340 {
1341 /* multi is not 0 if this */
1342 static char count_buf[BUFSIZ] = "";
1343 static char *count_pos = count_buf;
1344 static int count_cmd = -1;
1345 int cmd;
1346
1347 if (*count_pos)
1348 {
1349 char *tmp = count_pos;
1350 count_pos++;
1351 return *tmp;
1352 }
1353
1354 if (count_cmd >= 0)
1355 {
1356 cmd = count_cmd;
1357 count_cmd = -1;
1358 }
1359 else
1360 {
1361 char cmdstr[BUFSZ];
1362 int nh_cmd = 0;
1363
1364 while (!nh_cmd)
1365 {
1366 read_command ("command", cmdstr, count_buf);
1367
1368 count_pos = count_buf;
1369 cmd = lisp_get_cmd (cmdstr);
1370 if (cmd == -1)
1371 {
1372 printf ("(nhapi-message 'atr-none \"undefined-command %s\")\n", cmdstr);
1373 }
1374 else if (cmd_index[cmd].type == CMD_LISP)
1375 {
1376 /* We have to handle Lisp commands in this inner loop, because
1377 they don't interact with the nethack layer. */
1378 /* FIXME: Maybe this should go in an array? */
1379 if (!strcmp(cmd_index[cmd].name, "options"))
1380 {
1381 get_options();
1382 }
1383 } else {
1384 /* We have a nh command. */
1385 nh_cmd = 1;
1386 }
1387 }
1388
1389 if (atoi (count_pos) > 1)
1390 {
1391 char* tmp = count_pos;
1392 count_pos++;
1393 count_cmd = cmd;
1394 return *tmp;
1395 }
1396 else
1397 {
1398 /* Since the count is 1, zero out the string. */
1399 *count_pos = 0;
1400 }
1401 }
1402
1403 if (cmd_index[cmd].type == CMD_KEY)
1404 {
1405 return cmd_index[cmd].cmd;
1406 }
1407 else if (cmd_index[cmd].type == CMD_EXT)
1408 {
1409 if ((extended_cmd_id = lisp_get_ext_cmd_id (cmd_index[cmd].name)) == -1)
1410 {
1411 /* Can never happen. */
1412 printf ("%s:%d: Bad extended command name\n", __FILE__, __LINE__);
1413 }
1414 return '#';
1415 }
1416 else
1417 {
1418 impossible ("Impossible command type: %d", cmd_index[cmd].type);
1419 }
1420 return NULL;
1421 }
1422
1423 int
lisp_nh_poskey(x,y,mod)1424 lisp_nh_poskey(x, y, mod)
1425 int *x, *y, *mod;
1426 {
1427 /* char scratch[256]; */
1428
1429 /* printf ("(nethack-api-poskey)\n"); */
1430
1431 /* scanf ("( %d %d '%255s )", x, y, scratch); */
1432 /* if (!strcmp (scratch, "click-1")) *mod = CLICK_1; */
1433 /* else *mod = CLICK_2; */
1434
1435 /* return 0; */
1436
1437 return lisp_nhgetch();
1438 }
1439
1440 static boolean inven_win_created = FALSE;
1441
1442 /* These globals are used to keep track of window IDs. */
1443 static winid *winid_list = NULL;
1444 static int winid_list_len = 0;
1445 static int winid_list_max = 0;
1446
1447 /* returns index into winid_list that can be used. */
1448 static int
find_empty_cell()1449 find_empty_cell ()
1450 {
1451 int i;
1452
1453 /* Check for a vacant spot in the list. */
1454 for (i=0; i<winid_list_len; i++)
1455 {
1456 if (winid_list[i] == -1) return i;
1457 }
1458
1459 /* no vacant ones, so grow the array. */
1460 if (winid_list_len >= winid_list_max)
1461 {
1462 winid_list_max *= 2;
1463 winid_list = realloc (winid_list, sizeof (int) * winid_list_max);
1464 if (winid_list == NULL)
1465 bail ("Out of memory\n");
1466 }
1467 winid_list_len++;
1468
1469 return winid_list_len-1;
1470 }
1471
1472 static int
winid_is_taken(winid n)1473 winid_is_taken (winid n)
1474 {
1475 int i;
1476
1477 for (i=0; i<winid_list_len; i++)
1478 if (winid_list[i] == n) return 1;
1479
1480 return 0;
1481 }
1482
1483 static int
add_winid(winid n)1484 add_winid (winid n)
1485 {
1486 if (winid_is_taken (n)) return 0; /* failed. */
1487
1488 winid_list[find_empty_cell()] = n;
1489 return 1; /* success! */
1490 }
1491
1492 static winid
get_unique_winid()1493 get_unique_winid ()
1494 {
1495 winid i;
1496
1497 /* look for a unique number, and add it to the list of taken
1498 numbers. */
1499 i = 0;
1500 while (!add_winid (i)) i++;
1501
1502 return i;
1503 }
1504
1505 /* When a window is destroyed, it gives back its window number with
1506 this function. */
1507 static void
return_winid(winid n)1508 return_winid (winid n)
1509 {
1510 int i;
1511
1512 for (i=0; i<winid_list_len; i++)
1513 {
1514 if (winid_list[i] == n)
1515 {
1516 winid_list[i] = -1;
1517 return;
1518 }
1519 }
1520 }
1521
1522 static void
init_winid_list()1523 init_winid_list ()
1524 {
1525 winid_list_max = 10;
1526 winid_list_len = 0;
1527
1528 winid_list = malloc (winid_list_max * sizeof (int));
1529 }
1530
1531 /* Prints a create_nhwindow function and expects from stdin the id of
1532 this new window as a number. */
1533 winid
lisp_create_nhwindow(type)1534 lisp_create_nhwindow(type)
1535 int type;
1536 {
1537 winid id = get_unique_winid();
1538
1539 switch (type)
1540 {
1541 case NHW_MESSAGE:
1542 lisp_cmd ("create-message-window",);
1543 break;
1544 case NHW_MAP:
1545 lisp_cmd ("create-map-window",);
1546 break;
1547 case NHW_STATUS:
1548 lisp_cmd ("create-status-window",);
1549 break;
1550 case NHW_TEXT:
1551 lisp_cmd ("create-text-window", lisp_int (id));
1552 break;
1553 case NHW_MENU:
1554 if (!inven_win_created)
1555 {
1556 lisp_cmd ("create-inventory-window", lisp_int (id));
1557 inven_win_created = TRUE;
1558 }
1559 else
1560 lisp_cmd ("create-menu-window", lisp_int (id));
1561 break;
1562 default:
1563 impossible ("Unknown window type: %d", type);
1564 };
1565
1566 return id;
1567 }
1568
1569 void
lisp_clear_nhwindow(window)1570 lisp_clear_nhwindow(window)
1571 winid window;
1572 {
1573 if (window == WIN_MESSAGE)
1574 lisp_cmd ("clear-message",);
1575 else if (window == WIN_MAP)
1576 lisp_cmd ("clear-map",);
1577 else
1578 /* are other window types ever cleared? */
1579 lisp_cmd ("error", lisp_string("clearing unknown winid"));
1580 }
1581
1582 void
lisp_display_nhwindow(window,blocking)1583 lisp_display_nhwindow(window, blocking)
1584 winid window;
1585 boolean blocking;
1586 {
1587 /* don't send display messages for anything but menus */
1588 char *dummy;
1589 if (window != WIN_MESSAGE && window != WIN_STATUS && window != WIN_MAP)
1590 {
1591 lisp_cmd ("display-menu", lisp_int (window));
1592 read_string ("dummy", &dummy);
1593 free (dummy);
1594 }
1595 else if (blocking)
1596 {
1597 if (window == WIN_MESSAGE)
1598 {
1599 /* blocking on the message window happens only at the end of
1600 the game */
1601 lisp_cmd ("end",);
1602 }
1603 else
1604 {
1605 lisp_cmd ("block",);
1606 read_string ("dummy", &dummy);
1607 free (dummy);
1608 }
1609 }
1610 else if (window == WIN_STATUS)
1611 {
1612 /* initial window setup hack here :) */
1613 lisp_cmd ("restore-window-configuration",);
1614 }
1615 }
1616
1617 void
lisp_destroy_nhwindow(window)1618 lisp_destroy_nhwindow(window)
1619 winid window;
1620 {
1621 if ((window != WIN_STATUS)
1622 && (window != WIN_MESSAGE)
1623 && (window != WIN_MAP))
1624 {
1625 lisp_cmd ("destroy-menu", lisp_int (window));
1626 return_winid (window);
1627 }
1628 }
1629
1630 void
lisp_update_inventory()1631 lisp_update_inventory()
1632 {
1633 lisp_cmd ("update-inventory",);
1634 }
1635
1636 int
lisp_doprev_message()1637 lisp_doprev_message()
1638 {
1639 lisp_cmd ("doprev-message",);
1640 return 0;
1641 }
1642
1643 void
lisp_nhbell()1644 lisp_nhbell()
1645 {
1646 lisp_cmd ("nhbell",);
1647 }
1648
1649 /* Can be an empty call says window.doc. */
1650 void
lisp_mark_synch()1651 lisp_mark_synch()
1652 {
1653 /* lisp_cmd ("mark-sync",); */
1654 }
1655
1656 void
lisp_wait_synch()1657 lisp_wait_synch()
1658 {
1659 lisp_cmd ("wait-synch",);
1660 }
1661
1662 /* Since nethack will never be suspended, we need not worry about this
1663 function. */
1664 void
lisp_resume_nhwindows()1665 lisp_resume_nhwindows()
1666 {
1667 return;
1668 }
1669
1670 /* Since nethack will never be suspended, we need not worry about this
1671 function. */
1672 void
lisp_suspend_nhwindows(str)1673 lisp_suspend_nhwindows(str)
1674 const char *str;
1675 {
1676 return;
1677 }
1678
1679 /* All keys are defined in emacs, so number_pad makes no sense. */
1680 void
lisp_number_pad(state)1681 lisp_number_pad(state)
1682 int state;
1683 {
1684 return;
1685 }
1686
1687 void
lisp_init_nhwindows(argcp,argv)1688 lisp_init_nhwindows(argcp,argv)
1689 int* argcp;
1690 char** argv;
1691 {
1692 int i;
1693
1694 /* Print each command-line option, constructing a list of strings */
1695 lisp_cmd ("init-nhwindows",
1696 for (i=0; i<*argcp; i++)
1697 lisp_string (argv[i]));
1698
1699 /* FIXME: doesn't remove the arguments parsed, as specified in the
1700 api doc. */
1701
1702 /* Setup certain flags lisp clients need */
1703 iflags.num_pad = FALSE;
1704 #ifdef EXP_ON_BOTL /* we are going to lose if Nethack is
1705 compiled without this option -rcy */
1706 flags.showexp = TRUE;
1707 #endif
1708 flags.time = TRUE;
1709
1710 /* inform nethack that the windows have been initialized. */
1711 iflags.window_inited = TRUE;
1712
1713 init_winid_list();
1714 }
1715
1716 void
lisp_exit_nhwindows(str)1717 lisp_exit_nhwindows (str)
1718 const char *str;
1719 {
1720 lisp_cmd ("exit-nhwindows ", lisp_string (str));
1721 }
1722
1723 void
lisp_delay_output()1724 lisp_delay_output()
1725 {
1726 char *dummy;
1727 lisp_cmd ("delay-output",);
1728 read_string ("dummy", &dummy);
1729 free (dummy);
1730 }
1731
1732 void
lisp_getlin(question,input)1733 lisp_getlin(question, input)
1734 const char *question;
1735 char *input;
1736 {
1737 char *tmp;
1738 lisp_cmd ("getlin", lisp_string (question));
1739 read_string ("string", &tmp);
1740 /* FIXME: potential buffer overflow. */
1741 strcpy (input, tmp);
1742 }
1743
1744 int
lisp_get_ext_cmd()1745 lisp_get_ext_cmd()
1746 {
1747 /* int cmd; */
1748 /* int i; */
1749
1750 /* printf ("(nethack-api-get-ext-cmd '("); */
1751
1752 /* for (i=0; extcmdlist[i].ef_txt != (char *)0; i++) { */
1753 /* printf ("(\"%s\" . %d)", extcmdlist[i].ef_txt, i); */
1754 /* } */
1755 /* printf ("))\n"); */
1756
1757 /* scanf ("%d", &cmd); */
1758
1759 /* This is set when the user chooses an extended command. */
1760 return extended_cmd_id;
1761 }
1762
1763 void
1764 #ifdef FILE_AREAS
lisp_display_file(farea,fname,complain)1765 lisp_display_file(farea, fname, complain)
1766 const char *farea;
1767 #else
1768 lisp_display_file(fname, complain)
1769 #endif
1770 const char *fname;
1771 boolean complain;
1772 {
1773 lisp_cmd ("display-file",
1774 lisp_string (fname);
1775 complain ? lisp_t : lisp_nil);;
1776 }
1777
1778 char
lisp_yn_function(ques,choices,def)1779 lisp_yn_function(ques, choices, def)
1780 const char *ques;
1781 const char *choices;
1782 char def;
1783 {
1784 int answer;
1785
1786 /* Some questions have special functions. */
1787 if (!strncmp (ques, "In what direction", 17)
1788 || !strncmp (ques, "Talk to whom? (in what direction)", 33))
1789 {
1790 char *dir;
1791 lisp_cmd ("ask-direction",
1792 lisp_string (ques));
1793 read_string ("direction", &dir);
1794 if (!strcmp (dir, "n"))
1795 answer = 'k';
1796 else if (!strcmp (dir, "s"))
1797 answer = 'j';
1798 else if (!strcmp (dir, "e"))
1799 answer = 'l';
1800 else if (!strcmp (dir, "w"))
1801 answer = 'h';
1802 else if (!strcmp (dir, "ne"))
1803 answer = 'u';
1804 else if (!strcmp (dir, "nw"))
1805 answer = 'y';
1806 else if (!strcmp (dir, "se"))
1807 answer = 'n';
1808 else if (!strcmp (dir, "sw"))
1809 answer = 'b';
1810 else if (!strcmp (dir, "up"))
1811 answer = '<';
1812 else if (!strcmp (dir, "down"))
1813 answer = '>';
1814 else if (!strcmp (dir, "self"))
1815 answer = '.';
1816 else
1817 {
1818 if (def == '\0')
1819 answer = 0x20; /* space */
1820 else
1821 answer = def;
1822 }
1823
1824 free (dir);
1825 }
1826 else
1827 {
1828 lisp_cmd ("yn-function",
1829 lisp_string (ques);
1830 lisp_string (choices);
1831 lisp_int (def));
1832 read_int ("number", &answer);
1833 }
1834
1835 return (char)answer;
1836 }
1837
1838 #ifdef POSITIONBAR
1839 void
lisp_update_positionbar(features)1840 lisp_update_positionbar(features)
1841 char *features;
1842 {
1843 lisp_cmd ("update-positionbar", lisp_string (features));
1844 }
1845 #endif
1846
1847 #define zap_color(n) zapcolors[n]
1848 #define cmap_color(n) defsyms[n].color
1849 #define obj_color(n) objects[n].oc_color
1850 #define mon_color(n) mons[n].mcolor
1851 #define invis_color(n) NO_COLOR
1852 #define pet_color(n) mons[n].mcolor
1853 #define warn_color(n) def_warnsyms[n].color
1854
1855 void
lisp_print_glyph(window,x,y,glyph)1856 lisp_print_glyph(window, x, y, glyph)
1857 winid window;
1858 xchar x, y;
1859 int glyph;
1860 {
1861 glyph_t ch;
1862 int color;
1863 unsigned special;
1864
1865 /* map glyph to character and color */
1866 mapglyph(glyph, &ch, &color, &special, x, y);
1867
1868 /* If the user doesn't want to highlight the pet, then we erase
1869 the PET bit from special. In the lisp code the special argument
1870 will be 'pet if the glyph is a pet and will be printed in the
1871 color of the pet highlight face. But we don't want this if the
1872 user hasn't turned on hilite_pet. */
1873 if (!iflags.hilite_pet)
1874 {
1875 special &= ~MG_PET;
1876 }
1877
1878 if (window == WIN_MAP)
1879 {
1880 /* The last parameter, special, is optional. It is only
1881 present when the tile is special in some way. FIXME: This
1882 duplicate code is a bit gross. */
1883 if (special)
1884 {
1885 lisp_cmd ("print-glyph",
1886 lisp_int (x);
1887 lisp_int (y);
1888 lisp_int (color);
1889 lisp_int (glyph);
1890 lisp_int (glyph2tile[glyph]);
1891 lisp_int (ch);
1892 lisp_literal (special_glyph_to_string (special)););
1893 }
1894 else
1895 {
1896 lisp_cmd ("print-glyph",
1897 lisp_int (x);
1898 lisp_int (y);
1899 lisp_int (color);
1900 lisp_int (glyph);
1901 lisp_int (glyph2tile[glyph]);
1902 lisp_int (ch););
1903 }
1904 }
1905 else
1906 lisp_cmd ("error",
1907 lisp_string ("lisp_print_glyph bad window");
1908 lisp_int (window));
1909 }
1910
1911 #ifdef CLIPPING
1912 void
lisp_cliparound(x,y)1913 lisp_cliparound(x, y)
1914 int x;
1915 int y;
1916 {
1917 /* as far as I can tell, the x and y values here are exactly the
1918 ones given by the next lisp_curs call, so its redundant
1919 information -rcy */
1920
1921 /* lisp_cmd ("cliparound", lisp_int (x); lisp_int (y)); */
1922 }
1923 #endif
1924
lisp_start_screen()1925 void lisp_start_screen() { return; } /* called from setftty() in unixtty.c */
lisp_end_screen()1926 void lisp_end_screen() {return; } /* called from settty() in unixtty.c */
1927
1928 static void
get_death_text(buf)1929 get_death_text (buf)
1930 char buf[BUFSZ];
1931 {
1932
1933 }
1934
1935 void
lisp_outrip(window,how)1936 lisp_outrip(window, how)
1937 winid window;
1938 int how;
1939 {
1940 lisp_cmd ("outrip",
1941 lisp_int (window);
1942 lisp_string (plname);
1943 lisp_long (u.ugold);
1944 lisp_string ("Died while trying to finish nethack-el."));
1945 }
1946