OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / src / cmd.c
1 /*      SCCS Id: @(#)cmd.c      3.4     2003/02/06      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6 #include "func_tab.h"
7 /* #define DEBUG */     /* uncomment for debugging */
8
9 /*
10  * Some systems may have getchar() return EOF for various reasons, and
11  * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
12  */
13 #if defined(SYSV) || defined(DGUX) || defined(HPUX)
14 #define NR_OF_EOFS      20
15 #endif
16
17 #define CMD_TRAVEL (char)0x90
18
19 #ifdef DEBUG
20 /*
21  * only one "wiz_debug_cmd" routine should be available (in whatever
22  * module you are trying to debug) or things are going to get rather
23  * hard to link :-)
24  */
25 extern int NDECL(wiz_debug_cmd);
26 #endif
27
28 #ifdef DUMB     /* stuff commented out in extern.h, but needed here */
29 extern int NDECL(doapply); /**/
30 extern int NDECL(dorub); /**/
31 extern int NDECL(dojump); /**/
32 extern int NDECL(doextlist); /**/
33 extern int NDECL(dodrop); /**/
34 extern int NDECL(doddrop); /**/
35 extern int NDECL(dodown); /**/
36 extern int NDECL(doup); /**/
37 extern int NDECL(donull); /**/
38 extern int NDECL(dowipe); /**/
39 extern int NDECL(do_mname); /**/
40 extern int NDECL(ddocall); /**/
41 extern int NDECL(dotakeoff); /**/
42 extern int NDECL(doremring); /**/
43 extern int NDECL(dowear); /**/
44 extern int NDECL(doputon); /**/
45 extern int NDECL(doddoremarm); /**/
46 extern int NDECL(dokick); /**/
47 extern int NDECL(dofire); /**/
48 extern int NDECL(dothrow); /**/
49 extern int NDECL(doeat); /**/
50 extern int NDECL(done2); /**/
51 extern int NDECL(doengrave); /**/
52 extern int NDECL(dopickup); /**/
53 extern int NDECL(ddoinv); /**/
54 extern int NDECL(dotypeinv); /**/
55 extern int NDECL(dolook); /**/
56 extern int NDECL(doprgold); /**/
57 extern int NDECL(doprwep); /**/
58 extern int NDECL(doprarm); /**/
59 extern int NDECL(doprring); /**/
60 extern int NDECL(dopramulet); /**/
61 extern int NDECL(doprtool); /**/
62 extern int NDECL(dosuspend); /**/
63 extern int NDECL(doforce); /**/
64 extern int NDECL(doopen); /**/
65 extern int NDECL(doclose); /**/
66 extern int NDECL(dosh); /**/
67 extern int NDECL(dodiscovered); /**/
68 extern int NDECL(doset); /**/
69 extern int NDECL(dotogglepickup); /**/
70 extern int NDECL(dowhatis); /**/
71 extern int NDECL(doquickwhatis); /**/
72 extern int NDECL(dowhatdoes); /**/
73 extern int NDECL(dohelp); /**/
74 extern int NDECL(dohistory); /**/
75 extern int NDECL(doloot); /**/
76 extern int NDECL(dodrink); /**/
77 extern int NDECL(dodip); /**/
78 extern int NDECL(dosacrifice); /**/
79 extern int NDECL(dopray); /**/
80 extern int NDECL(doturn); /**/
81 extern int NDECL(doredraw); /**/
82 extern int NDECL(doread); /**/
83 extern int NDECL(dosave); /**/
84 extern int NDECL(dosearch); /**/
85 extern int NDECL(doidtrap); /**/
86 extern int NDECL(dopay); /**/
87 extern int NDECL(dosit); /**/
88 extern int NDECL(dotalk); /**/
89 extern int NDECL(docast); /**/
90 extern int NDECL(dovspell); /**/
91 extern int NDECL(dotele); /**/
92 extern int NDECL(dountrap); /**/
93 extern int NDECL(doversion); /**/
94 extern int NDECL(doextversion); /**/
95 extern int NDECL(doswapweapon); /**/
96 extern int NDECL(dowield); /**/
97 extern int NDECL(dowieldquiver); /**/
98 extern int NDECL(dozap); /**/
99 extern int NDECL(doorganize); /**/
100 #endif /* DUMB */
101
102 #ifdef OVL1
103 static int NDECL((*timed_occ_fn));
104 #endif /* OVL1 */
105
106 STATIC_PTR int NDECL(doprev_message);
107 STATIC_PTR int NDECL(timed_occupation);
108 STATIC_PTR int NDECL(doextcmd);
109 STATIC_PTR int NDECL(domonability);
110 STATIC_PTR int NDECL(dotravel);
111 # ifdef WIZARD
112 STATIC_PTR int NDECL(wiz_wish);
113 STATIC_PTR int NDECL(wiz_identify);
114 STATIC_PTR int NDECL(wiz_map);
115 STATIC_PTR int NDECL(wiz_genesis);
116 STATIC_PTR int NDECL(wiz_where);
117 STATIC_PTR int NDECL(wiz_detect);
118 STATIC_PTR int NDECL(wiz_panic);
119 STATIC_PTR int NDECL(wiz_polyself);
120 STATIC_PTR int NDECL(wiz_level_tele);
121 STATIC_PTR int NDECL(wiz_level_change);
122 STATIC_PTR int NDECL(wiz_show_seenv);
123 STATIC_PTR int NDECL(wiz_show_vision);
124 STATIC_PTR int NDECL(wiz_mon_polycontrol);
125 STATIC_PTR int NDECL(wiz_show_wmodes);
126 #if defined(__BORLANDC__) && !defined(_WIN32)
127 extern void FDECL(show_borlandc_stats, (winid));
128 #endif
129 #ifdef DEBUG_MIGRATING_MONS
130 STATIC_PTR int NDECL(wiz_migrate_mons);
131 #endif
132 STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P));
133 STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *));
134 STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *));
135 STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *));
136 STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *));
137 STATIC_PTR int NDECL(wiz_show_stats);
138 #  ifdef PORT_DEBUG
139 STATIC_DCL int NDECL(wiz_port_debug);
140 #  endif
141 # endif
142 STATIC_PTR int NDECL(enter_explore_mode);
143 STATIC_PTR int NDECL(doattributes);
144 STATIC_PTR int NDECL(doconduct); /**/
145 STATIC_PTR boolean NDECL(minimal_enlightenment);
146
147 #ifdef OVLB
148 STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *));
149 STATIC_DCL char *FDECL(enlght_combatinc, (const char *,int,int,char *));
150 #ifdef UNIX
151 static void NDECL(end_of_input);
152 #endif
153 #endif /* OVLB */
154
155 static const char* readchar_queue="";
156
157 STATIC_DCL char *NDECL(parse);
158 STATIC_DCL boolean FDECL(help_dir, (CHAR_P,const char *));
159
160 #ifdef OVL1
161
162 STATIC_PTR int
163 doprev_message()
164 {
165     return nh_doprev_message();
166 }
167
168 /* Count down by decrementing multi */
169 STATIC_PTR int
170 timed_occupation()
171 {
172         (*timed_occ_fn)();
173         if (multi > 0)
174                 multi--;
175         return multi > 0;
176 }
177
178 /* If you have moved since initially setting some occupations, they
179  * now shouldn't be able to restart.
180  *
181  * The basic rule is that if you are carrying it, you can continue
182  * since it is with you.  If you are acting on something at a distance,
183  * your orientation to it must have changed when you moved.
184  *
185  * The exception to this is taking off items, since they can be taken
186  * off in a number of ways in the intervening time, screwing up ordering.
187  *
188  *      Currently:      Take off all armor.
189  *                      Picking Locks / Forcing Chests.
190  *                      Setting traps.
191  */
192 void
193 reset_occupations()
194 {
195         reset_remarm();
196         reset_pick();
197         reset_trapset();
198 }
199
200 /* If a time is given, use it to timeout this function, otherwise the
201  * function times out by its own means.
202  */
203 void
204 set_occupation(fn, txt, xtime)
205 int NDECL((*fn));
206 const char *txt;
207 int xtime;
208 {
209         if (xtime) {
210                 occupation = timed_occupation;
211                 timed_occ_fn = fn;
212         } else
213                 occupation = fn;
214         occtxt = txt;
215         occtime = 0;
216         return;
217 }
218
219 #ifdef REDO
220
221 static char NDECL(popch);
222
223 /* Provide a means to redo the last command.  The flag `in_doagain' is set
224  * to true while redoing the command.  This flag is tested in commands that
225  * require additional input (like `throw' which requires a thing and a
226  * direction), and the input prompt is not shown.  Also, while in_doagain is
227  * TRUE, no keystrokes can be saved into the saveq.
228  */
229 #define BSIZE 20
230 static char pushq[BSIZE], saveq[BSIZE];
231 static NEARDATA int phead, ptail, shead, stail;
232
233 static char
234 popch() {
235         /* If occupied, return '\0', letting tgetch know a character should
236          * be read from the keyboard.  If the character read is not the
237          * ABORT character (as checked in pcmain.c), that character will be
238          * pushed back on the pushq.
239          */
240         if (occupation) return '\0';
241         if (in_doagain) return(char)((shead != stail) ? saveq[stail++] : '\0');
242         else            return(char)((phead != ptail) ? pushq[ptail++] : '\0');
243 }
244
245 char
246 pgetchar() {            /* curtesy of aeb@cwi.nl */
247         register int ch;
248
249         if(!(ch = popch()))
250                 ch = nhgetch();
251         return((char)ch);
252 }
253
254 /* A ch == 0 resets the pushq */
255 void
256 pushch(ch)
257 char ch;
258 {
259         if (!ch)
260                 phead = ptail = 0;
261         if (phead < BSIZE)
262                 pushq[phead++] = ch;
263         return;
264 }
265
266 /* A ch == 0 resets the saveq.  Only save keystrokes when not
267  * replaying a previous command.
268  */
269 void
270 savech(ch)
271 char ch;
272 {
273         if (!in_doagain) {
274                 if (!ch)
275                         phead = ptail = shead = stail = 0;
276                 else if (shead < BSIZE)
277                         saveq[shead++] = ch;
278         }
279         return;
280 }
281 #endif /* REDO */
282
283 #endif /* OVL1 */
284 #ifdef OVLB
285
286 STATIC_PTR int
287 doextcmd()      /* here after # - now read a full-word command */
288 {
289         int idx, retval;
290
291         /* keep repeating until we don't run help or quit */
292         do {
293             idx = get_ext_cmd();
294             if (idx < 0) return 0;      /* quit */
295
296             retval = (*extcmdlist[idx].ef_funct)();
297         } while (extcmdlist[idx].ef_funct == doextlist);
298
299         return retval;
300 }
301
302 int
303 doextlist()     /* here after #? - now list all full-word commands */
304 {
305         register const struct ext_func_tab *efp;
306         char     buf[BUFSZ];
307         winid datawin;
308
309         datawin = create_nhwindow(NHW_TEXT);
310         putstr(datawin, 0, "");
311         putstr(datawin, 0, "            Extended Commands List");
312         putstr(datawin, 0, "");
313         putstr(datawin, 0, "    Press '#', then type:");
314         putstr(datawin, 0, "");
315
316         for(efp = extcmdlist; efp->ef_txt; efp++) {
317                 Sprintf(buf, "    %-15s - %s.", efp->ef_txt, efp->ef_desc);
318                 putstr(datawin, 0, buf);
319         }
320         display_nhwindow(datawin, FALSE);
321         destroy_nhwindow(datawin);
322         return 0;
323 }
324
325 #ifdef TTY_GRAPHICS
326 #define MAX_EXT_CMD 40          /* Change if we ever have > 40 ext cmds */
327 /*
328  * This is currently used only by the tty port and is
329  * controlled via runtime option 'extmenu'
330  */
331 int
332 extcmd_via_menu()       /* here after # - now show pick-list of possible commands */
333 {
334     const struct ext_func_tab *efp;
335     menu_item *pick_list = (menu_item *)0;
336     winid win;
337     anything any;
338     const struct ext_func_tab *choices[MAX_EXT_CMD];
339     char buf[BUFSZ];
340     char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20];
341     int i, n, nchoices, acount;
342     int ret,  biggest;
343     int accelerator, prevaccelerator;
344     int  matchlevel = 0;
345
346     ret = 0;
347     cbuf[0] = '\0';
348     biggest = 0;
349     while (!ret) {
350             i = n = 0;
351             accelerator = 0;
352             any.a_void = 0;
353             /* populate choices */
354             for(efp = extcmdlist; efp->ef_txt; efp++) {
355                 if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) {
356                         choices[i++] = efp;
357                         if ((int)strlen(efp->ef_desc) > biggest) {
358                                 biggest = strlen(efp->ef_desc);
359                                 Sprintf(fmtstr,"%%-%ds", biggest + 15);
360                         }
361 #ifdef DEBUG
362                         if (i >= MAX_EXT_CMD - 2) {
363                             impossible("Exceeded %d extended commands in doextcmd() menu",
364                                         MAX_EXT_CMD - 2);
365                             return 0;
366                         }
367 #endif
368                 }
369             }
370             choices[i] = (struct ext_func_tab *)0;
371             nchoices = i;
372             /* if we're down to one, we have our selection so get out of here */
373             if (nchoices == 1) {
374                 for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
375                         if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) {
376                                 ret = i;
377                                 break;
378                         }
379                 break;
380             }
381
382             /* otherwise... */
383             win = create_nhwindow(NHW_MENU);
384             start_menu(win);
385             prevaccelerator = 0;
386             acount = 0;
387             for(i = 0; choices[i]; ++i) {
388                 accelerator = choices[i]->ef_txt[matchlevel];
389                 if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) {
390                     if (acount) {
391                         /* flush the extended commands for that letter already in buf */
392                         Sprintf(buf, fmtstr, prompt);
393                         any.a_char = prevaccelerator;
394                         add_menu(win, NO_GLYPH, &any, any.a_char, 0,
395                                         ATR_NONE, buf, FALSE);
396                         acount = 0;
397                     }
398                 }
399                 prevaccelerator = accelerator;
400                 if (!acount || nchoices < (ROWNO - 3)) {
401                     Sprintf(prompt, "%s [%s]", choices[i]->ef_txt,
402                                 choices[i]->ef_desc);
403                 } else if (acount == 1) {
404                     Sprintf(prompt, "%s or %s", choices[i-1]->ef_txt,
405                                 choices[i]->ef_txt);
406                 } else {
407                     Strcat(prompt," or ");
408                     Strcat(prompt, choices[i]->ef_txt);
409                 }
410                 ++acount;
411             }
412             if (acount) {
413                 /* flush buf */
414                 Sprintf(buf, fmtstr, prompt);
415                 any.a_char = prevaccelerator;
416                 add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE);
417             }
418             Sprintf(prompt, "Extended Command: %s", cbuf);
419             end_menu(win, prompt);
420             n = select_menu(win, PICK_ONE, &pick_list);
421             destroy_nhwindow(win);
422             if (n==1) {
423                 if (matchlevel > (QBUFSZ - 2)) {
424                         free((genericptr_t)pick_list);
425 #ifdef DEBUG
426                         impossible("Too many characters (%d) entered in extcmd_via_menu()",
427                                 matchlevel);
428 #endif
429                         ret = -1;
430                 } else {
431                         cbuf[matchlevel++] = pick_list[0].item.a_char;
432                         cbuf[matchlevel] = '\0';
433                         free((genericptr_t)pick_list);
434                 }
435             } else {
436                 if (matchlevel) {
437                         ret = 0;
438                         matchlevel = 0;
439                 } else
440                         ret = -1;
441             }
442     }
443     return ret;
444 }
445 #endif
446
447 /* #monster command - use special monster ability while polymorphed */
448 STATIC_PTR int
449 domonability()
450 {
451         if (can_breathe(youmonst.data)) return dobreathe();
452         else if (attacktype(youmonst.data, AT_SPIT)) return dospit();
453         else if (youmonst.data->mlet == S_NYMPH) return doremove();
454         else if (attacktype(youmonst.data, AT_GAZE)) return dogaze();
455         else if (is_were(youmonst.data)) return dosummon();
456         else if (webmaker(youmonst.data)) return dospinweb();
457         else if (is_hider(youmonst.data)) return dohide();
458         else if (is_mind_flayer(youmonst.data)) return domindblast();
459         else if (u.umonnum == PM_GREMLIN) {
460             if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
461                 if (split_mon(&youmonst, (struct monst *)0))
462                     dryup(u.ux, u.uy, TRUE);
463             } else There("is no fountain here.");
464         } else if (is_unicorn(youmonst.data)) {
465             use_unicorn_horn((struct obj *)0);
466             return 1;
467         } else if (youmonst.data->msound == MS_SHRIEK) {
468             You("shriek.");
469             if(u.uburied)
470                 pline("Unfortunately sound does not carry well through rock.");
471             else aggravate();
472         } else if (Upolyd)
473                 pline("Any special ability you may have is purely reflexive.");
474         else You("don't have a special ability in your normal form!");
475         return 0;
476 }
477
478 STATIC_PTR int
479 enter_explore_mode()
480 {
481         if(!discover && !wizard) {
482                 pline("Beware!  From explore mode there will be no return to normal game.");
483                 if (yn("Do you want to enter explore mode?") == 'y') {
484                         clear_nhwindow(WIN_MESSAGE);
485                         You("are now in non-scoring explore mode.");
486                         discover = TRUE;
487                 }
488                 else {
489                         clear_nhwindow(WIN_MESSAGE);
490                         pline("Resuming normal game.");
491                 }
492         }
493         return 0;
494 }
495
496 #ifdef WIZARD
497
498 /* ^W command - wish for something */
499 STATIC_PTR int
500 wiz_wish()      /* Unlimited wishes for debug mode by Paul Polderman */
501 {
502         if (wizard) {
503             boolean save_verbose = flags.verbose;
504
505             flags.verbose = FALSE;
506             makewish();
507             flags.verbose = save_verbose;
508             (void) encumber_msg();
509         } else
510             pline("Unavailable command '^W'.");
511         return 0;
512 }
513
514 /* ^I command - identify hero's inventory */
515 STATIC_PTR int
516 wiz_identify()
517 {
518         if (wizard)     identify_pack(0);
519         else            pline("Unavailable command '^I'.");
520         return 0;
521 }
522
523 /* ^F command - reveal the level map and any traps on it */
524 STATIC_PTR int
525 wiz_map()
526 {
527         if (wizard) {
528             struct trap *t;
529             long save_Hconf = HConfusion,
530                  save_Hhallu = HHallucination;
531
532             HConfusion = HHallucination = 0L;
533             for (t = ftrap; t != 0; t = t->ntrap) {
534                 t->tseen = 1;
535                 map_trap(t, TRUE);
536             }
537             do_mapping();
538             HConfusion = save_Hconf;
539             HHallucination = save_Hhallu;
540         } else
541             pline("Unavailable command '^F'.");
542         return 0;
543 }
544
545 /* ^G command - generate monster(s); a count prefix will be honored */
546 STATIC_PTR int
547 wiz_genesis()
548 {
549         if (wizard)     (void) create_particular();
550         else            pline("Unavailable command '^G'.");
551         return 0;
552 }
553
554 /* ^O command - display dungeon layout */
555 STATIC_PTR int
556 wiz_where()
557 {
558         if (wizard) (void) print_dungeon(FALSE, (schar *)0, (xchar *)0);
559         else        pline("Unavailable command '^O'.");
560         return 0;
561 }
562
563 /* ^E command - detect unseen (secret doors, traps, hidden monsters) */
564 STATIC_PTR int
565 wiz_detect()
566 {
567         if(wizard)  (void) findit();
568         else        pline("Unavailable command '^E'.");
569         return 0;
570 }
571
572 /* ^V command - level teleport */
573 STATIC_PTR int
574 wiz_level_tele()
575 {
576         if (wizard)     level_tele();
577         else            pline("Unavailable command '^V'.");
578         return 0;
579 }
580
581 /* #monpolycontrol command - choose new form for shapechangers, polymorphees */
582 STATIC_PTR int
583 wiz_mon_polycontrol()
584 {
585     iflags.mon_polycontrol = !iflags.mon_polycontrol;
586     pline("Monster polymorph control is %s.",
587           iflags.mon_polycontrol ? "on" : "off");
588     return 0;
589 }
590
591 /* #levelchange command - adjust hero's experience level */
592 STATIC_PTR int
593 wiz_level_change()
594 {
595     char buf[BUFSZ];
596     int newlevel;
597     int ret;
598
599     getlin("To what experience level do you want to be set?", buf);
600     (void)mungspaces(buf);
601     if (buf[0] == '\033' || buf[0] == '\0') ret = 0;
602     else ret = sscanf(buf, "%d", &newlevel);
603
604     if (ret != 1) {
605         pline(Never_mind);
606         return 0;
607     }
608     if (newlevel == u.ulevel) {
609         You("are already that experienced.");
610     } else if (newlevel < u.ulevel) {
611         if (u.ulevel == 1) {
612             You("are already as inexperienced as you can get.");
613             return 0;
614         }
615         if (newlevel < 1) newlevel = 1;
616         while (u.ulevel > newlevel)
617             losexp("#levelchange");
618     } else {
619         if (u.ulevel >= MAXULEV) {
620             You("are already as experienced as you can get.");
621             return 0;
622         }
623         if (newlevel > MAXULEV) newlevel = MAXULEV;
624         while (u.ulevel < newlevel)
625             pluslvl(FALSE);
626     }
627     u.ulevelmax = u.ulevel;
628     return 0;
629 }
630
631 /* #panic command - test program's panic handling */
632 STATIC_PTR int
633 wiz_panic()
634 {
635         if (yn("Do you want to call panic() and end your game?") == 'y')
636                 panic("crash test.");
637         return 0;
638 }
639
640 /* #polyself command - change hero's form */
641 STATIC_PTR int
642 wiz_polyself()
643 {
644         polyself(TRUE);
645         return 0;
646 }
647
648 /* #seenv command */
649 STATIC_PTR int
650 wiz_show_seenv()
651 {
652         winid win;
653         int x, y, v, startx, stopx, curx;
654         char row[COLNO+1];
655
656         win = create_nhwindow(NHW_TEXT);
657         /*
658          * Each seenv description takes up 2 characters, so center
659          * the seenv display around the hero.
660          */
661         startx = max(1, u.ux-(COLNO/4));
662         stopx = min(startx+(COLNO/2), COLNO);
663         /* can't have a line exactly 80 chars long */
664         if (stopx - startx == COLNO/2) startx++;
665
666         for (y = 0; y < ROWNO; y++) {
667             for (x = startx, curx = 0; x < stopx; x++, curx += 2) {
668                 if (x == u.ux && y == u.uy) {
669                     row[curx] = row[curx+1] = '@';
670                 } else {
671                     v = levl[x][y].seenv & 0xff;
672                     if (v == 0)
673                         row[curx] = row[curx+1] = ' ';
674                     else
675                         Sprintf(&row[curx], "%02x", v);
676                 }
677             }
678             /* remove trailing spaces */
679             for (x = curx-1; x >= 0; x--)
680                 if (row[x] != ' ') break;
681             row[x+1] = '\0';
682
683             putstr(win, 0, row);
684         }
685         display_nhwindow(win, TRUE);
686         destroy_nhwindow(win);
687         return 0;
688 }
689
690 /* #vision command */
691 STATIC_PTR int
692 wiz_show_vision()
693 {
694         winid win;
695         int x, y, v;
696         char row[COLNO+1];
697
698         win = create_nhwindow(NHW_TEXT);
699         Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit",
700                 COULD_SEE, IN_SIGHT, TEMP_LIT);
701         putstr(win, 0, row);
702         putstr(win, 0, "");
703         for (y = 0; y < ROWNO; y++) {
704             for (x = 1; x < COLNO; x++) {
705                 if (x == u.ux && y == u.uy)
706                     row[x] = '@';
707                 else {
708                     v = viz_array[y][x]; /* data access should be hidden */
709                     if (v == 0)
710                         row[x] = ' ';
711                     else
712                         row[x] = '0' + viz_array[y][x];
713                 }
714             }
715             /* remove trailing spaces */
716             for (x = COLNO-1; x >= 1; x--)
717                 if (row[x] != ' ') break;
718             row[x+1] = '\0';
719
720             putstr(win, 0, &row[1]);
721         }
722         display_nhwindow(win, TRUE);
723         destroy_nhwindow(win);
724         return 0;
725 }
726
727 /* #wmode command */
728 STATIC_PTR int
729 wiz_show_wmodes()
730 {
731         winid win;
732         int x,y;
733         char row[COLNO+1];
734         struct rm *lev;
735
736         win = create_nhwindow(NHW_TEXT);
737         for (y = 0; y < ROWNO; y++) {
738             for (x = 0; x < COLNO; x++) {
739                 lev = &levl[x][y];
740                 if (x == u.ux && y == u.uy)
741                     row[x] = '@';
742                 else if (IS_WALL(lev->typ) || lev->typ == SDOOR)
743                     row[x] = '0' + (lev->wall_info & WM_MASK);
744                 else if (lev->typ == CORR)
745                     row[x] = '#';
746                 else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ))
747                     row[x] = '.';
748                 else
749                     row[x] = 'x';
750             }
751             row[COLNO] = '\0';
752             putstr(win, 0, row);
753         }
754         display_nhwindow(win, TRUE);
755         destroy_nhwindow(win);
756         return 0;
757 }
758
759 #endif /* WIZARD */
760
761
762 /* -enlightenment and conduct- */
763 static winid en_win;
764 static const char
765         You_[] = "You ",
766         are[]  = "are ",  were[]  = "were ",
767         have[] = "have ", had[]   = "had ",
768         can[]  = "can ",  could[] = "could ";
769 static const char
770         have_been[]  = "have been ",
771         have_never[] = "have never ", never[] = "never ";
772
773 #define enl_msg(prefix,present,past,suffix) \
774                         enlght_line(prefix, final ? past : present, suffix)
775 #define you_are(attr)   enl_msg(You_,are,were,attr)
776 #define you_have(attr)  enl_msg(You_,have,had,attr)
777 #define you_can(attr)   enl_msg(You_,can,could,attr)
778 #define you_have_been(goodthing) enl_msg(You_,have_been,were,goodthing)
779 #define you_have_never(badthing) enl_msg(You_,have_never,never,badthing)
780 #define you_have_X(something)   enl_msg(You_,have,(const char *)"",something)
781
782 static void
783 enlght_line(start, middle, end)
784 const char *start, *middle, *end;
785 {
786         char buf[BUFSZ];
787
788         Sprintf(buf, "%s%s%s.", start, middle, end);
789         putstr(en_win, 0, buf);
790 }
791
792 /* format increased damage or chance to hit */
793 static char *
794 enlght_combatinc(inctyp, incamt, final, outbuf)
795 const char *inctyp;
796 int incamt, final;
797 char *outbuf;
798 {
799         char numbuf[24];
800         const char *modif, *bonus;
801
802         if (final
803 #ifdef WIZARD
804                 || wizard
805 #endif
806           ) {
807             Sprintf(numbuf, "%s%d",
808                     (incamt > 0) ? "+" : "", incamt);
809             modif = (const char *) numbuf;
810         } else {
811             int absamt = abs(incamt);
812
813             if (absamt <= 3) modif = "small";
814             else if (absamt <= 6) modif = "moderate";
815             else if (absamt <= 12) modif = "large";
816             else modif = "huge";
817         }
818         bonus = (incamt > 0) ? "bonus" : "penalty";
819         /* "bonus to hit" vs "damage bonus" */
820         if (!strcmp(inctyp, "damage")) {
821             const char *ctmp = inctyp;
822             inctyp = bonus;
823             bonus = ctmp;
824         }
825         Sprintf(outbuf, "%s %s %s", an(modif), bonus, inctyp);
826         return outbuf;
827 }
828
829 void
830 enlightenment(final)
831 int final;      /* 0 => still in progress; 1 => over, survived; 2 => dead */
832 {
833         int ltmp;
834         char buf[BUFSZ];
835
836         en_win = create_nhwindow(NHW_MENU);
837         putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:");
838         putstr(en_win, 0, "");
839
840 #ifdef ELBERETH
841         if (u.uevent.uhand_of_elbereth) {
842             static const char * const hofe_titles[3] = {
843                                 "the Hand of Elbereth",
844                                 "the Envoy of Balance",
845                                 "the Glory of Arioch"
846             };
847             you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1]);
848         }
849 #endif
850
851         /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
852         if (u.ualign.record >= 20)      you_are("piously aligned");
853         else if (u.ualign.record > 13)  you_are("devoutly aligned");
854         else if (u.ualign.record > 8)   you_are("fervently aligned");
855         else if (u.ualign.record > 3)   you_are("stridently aligned");
856         else if (u.ualign.record == 3)  you_are("aligned");
857         else if (u.ualign.record > 0)   you_are("haltingly aligned");
858         else if (u.ualign.record == 0)  you_are("nominally aligned");
859         else if (u.ualign.record >= -3) you_have("strayed");
860         else if (u.ualign.record >= -8) you_have("sinned");
861         else you_have("transgressed");
862 #ifdef WIZARD
863         if (wizard) {
864                 Sprintf(buf, " %d", u.ualign.record);
865                 enl_msg("Your alignment ", "is", "was", buf);
866         }
867 #endif
868
869         /*** Resistances to troubles ***/
870         if (Fire_resistance) you_are("fire resistant");
871         if (Cold_resistance) you_are("cold resistant");
872         if (Sleep_resistance) you_are("sleep resistant");
873         if (Disint_resistance) you_are("disintegration-resistant");
874         if (Shock_resistance) you_are("shock resistant");
875         if (Poison_resistance) you_are("poison resistant");
876         if (Drain_resistance) you_are("level-drain resistant");
877         if (Sick_resistance) you_are("immune to sickness");
878         if (Antimagic) you_are("magic-protected");
879         if (Acid_resistance) you_are("acid resistant");
880         if (Stone_resistance)
881                 you_are("petrification resistant");
882         if (Invulnerable) you_are("invulnerable");
883         if (u.uedibility) you_can("recognize detrimental food");
884
885         /*** Troubles ***/
886         if (Halluc_resistance)
887                 enl_msg("You resist", "", "ed", " hallucinations");
888         if (final) {
889                 if (Hallucination) you_are("hallucinating");
890                 if (Stunned) you_are("stunned");
891                 if (Confusion) you_are("confused");
892                 if (Blinded) you_are("blinded");
893                 if (Sick) {
894                         if (u.usick_type & SICK_VOMITABLE)
895                                 you_are("sick from food poisoning");
896                         if (u.usick_type & SICK_NONVOMITABLE)
897                                 you_are("sick from illness");
898                 }
899         }
900         if (Stoned) you_are("turning to stone");
901         if (Slimed) you_are("turning into slime");
902         if (Strangled) you_are((u.uburied) ? "buried" : "being strangled");
903         if (Glib) {
904                 Sprintf(buf, "slippery %s", makeplural(body_part(FINGER)));
905                 you_have(buf);
906         }
907         if (Fumbling) enl_msg("You fumble", "", "d", "");
908         if (Wounded_legs
909 #ifdef STEED
910             && !u.usteed
911 #endif
912                           ) {
913                 Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
914                 you_have(buf);
915         }
916 #if defined(WIZARD) && defined(STEED)
917         if (Wounded_legs && u.usteed && wizard) {
918             Strcpy(buf, x_monnam(u.usteed, ARTICLE_YOUR, (char *)0, 
919                     SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION, FALSE));
920             *buf = highc(*buf);
921             enl_msg(buf, " has", " had", " wounded legs");
922         }
923 #endif
924         if (Sleeping) enl_msg("You ", "fall", "fell", " asleep");
925         if (Hunger) enl_msg("You hunger", "", "ed", " rapidly");
926
927         /*** Vision and senses ***/
928         if (See_invisible) enl_msg(You_, "see", "saw", " invisible");
929         if (Blind_telepat) you_are("telepathic");
930         if (Warning) you_are("warned");
931         if (Warn_of_mon && flags.warntype) {
932                 Sprintf(buf, "aware of the presence of %s",
933                         (flags.warntype & M2_ORC) ? "orcs" :
934                         (flags.warntype & M2_DEMON) ? "demons" :
935                         something); 
936                 you_are(buf);
937         }
938         if (Undead_warning) you_are("warned of undead");
939         if (Searching) you_have("automatic searching");
940         if (Clairvoyant) you_are("clairvoyant");
941         if (Infravision) you_have("infravision");
942         if (Detect_monsters) you_are("sensing the presence of monsters");
943         if (u.umconf) you_are("going to confuse monsters");
944
945         /*** Appearance and behavior ***/
946         if (Adornment) {
947             int adorn = 0;
948
949             if(uleft && uleft->otyp == RIN_ADORNMENT) adorn += uleft->spe;
950             if(uright && uright->otyp == RIN_ADORNMENT) adorn += uright->spe;
951             if (adorn < 0)
952                 you_are("poorly adorned");
953             else
954                 you_are("adorned");
955         }
956         if (Invisible) you_are("invisible");
957         else if (Invis) you_are("invisible to others");
958         /* ordinarily "visible" is redundant; this is a special case for
959            the situation when invisibility would be an expected attribute */
960         else if ((HInvis || EInvis || pm_invisible(youmonst.data)) && BInvis)
961             you_are("visible");
962         if (Displaced) you_are("displaced");
963         if (Stealth) you_are("stealthy");
964         if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters");
965         if (Conflict) enl_msg("You cause", "", "d", " conflict");
966
967         /*** Transportation ***/
968         if (Jumping) you_can("jump");
969         if (Teleportation) you_can("teleport");
970         if (Teleport_control) you_have("teleport control");
971         if (Lev_at_will) you_are("levitating, at will");
972         else if (Levitation) you_are("levitating");     /* without control */
973         else if (Flying) you_can("fly");
974         if (Wwalking) you_can("walk on water");
975         if (Swimming) you_can("swim");        
976         if (Breathless) you_can("survive without air");
977         else if (Amphibious) you_can("breathe water");
978         if (Passes_walls) you_can("walk through walls");
979 #ifdef STEED
980         /* If you die while dismounting, u.usteed is still set.  Since several
981          * places in the done() sequence depend on u.usteed, just detect this
982          * special case. */
983         if (u.usteed && (final < 2 || strcmp(killer, "riding accident"))) {
984             Sprintf(buf, "riding %s", y_monnam(u.usteed));
985             you_are(buf);
986         }
987 #endif
988         if (u.uswallow) {
989             Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck));
990 #ifdef WIZARD
991             if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim);
992 #endif
993             you_are(buf);
994         } else if (u.ustuck) {
995             Sprintf(buf, "%s %s",
996                     (Upolyd && sticks(youmonst.data)) ? "holding" : "held by",
997                     a_monnam(u.ustuck));
998             you_are(buf);
999         }
1000
1001         /*** Physical attributes ***/
1002         if (u.uhitinc)
1003             you_have(enlght_combatinc("to hit", u.uhitinc, final, buf));
1004         if (u.udaminc)
1005             you_have(enlght_combatinc("damage", u.udaminc, final, buf));
1006         if (Slow_digestion) you_have("slower digestion");
1007         if (Regeneration) enl_msg("You regenerate", "", "d", "");
1008         if (u.uspellprot || Protection) {
1009             int prot = 0;
1010
1011             if(uleft && uleft->otyp == RIN_PROTECTION) prot += uleft->spe;
1012             if(uright && uright->otyp == RIN_PROTECTION) prot += uright->spe;
1013             if (HProtection & INTRINSIC) prot += u.ublessed;
1014             prot += u.uspellprot;
1015
1016             if (prot < 0)
1017                 you_are("ineffectively protected");
1018             else
1019                 you_are("protected");
1020         }
1021         if (Protection_from_shape_changers)
1022                 you_are("protected from shape changers");
1023         if (Polymorph) you_are("polymorphing");
1024         if (Polymorph_control) you_have("polymorph control");
1025         if (u.ulycn >= LOW_PM) {
1026                 Strcpy(buf, an(mons[u.ulycn].mname));
1027                 you_are(buf);
1028         }
1029         if (Upolyd) {
1030             if (u.umonnum == u.ulycn) Strcpy(buf, "in beast form");
1031             else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname));
1032 #ifdef WIZARD
1033             if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone);
1034 #endif
1035             you_are(buf);
1036         }
1037         if (Unchanging) you_can("not change from your current form");
1038         if (Fast) you_are(Very_fast ? "very fast" : "fast");
1039         if (Reflecting) you_have("reflection");
1040         if (Free_action) you_have("free action");
1041         if (Fixed_abil) you_have("fixed abilities");
1042         if (Lifesaved)
1043                 enl_msg("Your life ", "will be", "would have been", " saved");
1044         if (u.twoweap) you_are("wielding two weapons at once");
1045
1046         /*** Miscellany ***/
1047         if (Luck) {
1048             ltmp = abs((int)Luck);
1049             Sprintf(buf, "%s%slucky",
1050                     ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
1051                     Luck < 0 ? "un" : "");
1052 #ifdef WIZARD
1053             if (wizard) Sprintf(eos(buf), " (%d)", Luck);
1054 #endif
1055             you_are(buf);
1056         }
1057 #ifdef WIZARD
1058          else if (wizard) enl_msg("Your luck ", "is", "was", " zero");
1059 #endif
1060         if (u.moreluck > 0) you_have("extra luck");
1061         else if (u.moreluck < 0) you_have("reduced luck");
1062         if (carrying(LUCKSTONE) || stone_luck(TRUE)) {
1063             ltmp = stone_luck(FALSE);
1064             if (ltmp <= 0)
1065                 enl_msg("Bad luck ", "does", "did", " not time out for you");
1066             if (ltmp >= 0)
1067                 enl_msg("Good luck ", "does", "did", " not time out for you");
1068         }
1069
1070         if (u.ugangr) {
1071             Sprintf(buf, " %sangry with you",
1072                     u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : "");
1073 #ifdef WIZARD
1074             if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr);
1075 #endif
1076             enl_msg(u_gname(), " is", " was", buf);
1077         } else
1078             /*
1079              * We need to suppress this when the game is over, because death
1080              * can change the value calculated by can_pray(), potentially
1081              * resulting in a false claim that you could have prayed safely.
1082              */
1083           if (!final) {
1084 #if 0
1085             /* "can [not] safely pray" vs "could [not] have safely prayed" */
1086             Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ",
1087                     final ? "have " : "", final ? "ed" : "");
1088 #else
1089             Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not ");
1090 #endif
1091 #ifdef WIZARD
1092             if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt);
1093 #endif
1094             you_can(buf);
1095         }
1096
1097     {
1098         const char *p;
1099
1100         buf[0] = '\0';
1101         if (final < 2) {    /* still in progress, or quit/escaped/ascended */
1102             p = "survived after being killed ";
1103             switch (u.umortality) {
1104             case 0:  p = !final ? (char *)0 : "survived";  break;
1105             case 1:  Strcpy(buf, "once");  break;
1106             case 2:  Strcpy(buf, "twice");  break;
1107             case 3:  Strcpy(buf, "thrice");  break;
1108             default: Sprintf(buf, "%d times", u.umortality);
1109                      break;
1110             }
1111         } else {                /* game ended in character's death */
1112             p = "are dead";
1113             switch (u.umortality) {
1114             case 0:  impossible("dead without dying?");
1115             case 1:  break;                     /* just "are dead" */
1116             default: Sprintf(buf, " (%d%s time!)", u.umortality,
1117                              ordin(u.umortality));
1118                      break;
1119             }
1120         }
1121         if (p) enl_msg(You_, "have been killed ", p, buf);
1122     }
1123
1124         display_nhwindow(en_win, TRUE);
1125         destroy_nhwindow(en_win);
1126         return;
1127 }
1128
1129 /*
1130  * Courtesy function for non-debug, non-explorer mode players
1131  * to help refresh them about who/what they are.
1132  * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise.
1133  */
1134 STATIC_OVL boolean
1135 minimal_enlightenment()
1136 {
1137         winid tmpwin;
1138         menu_item *selected;
1139         anything any;
1140         int genidx, n;
1141         char buf[BUFSZ], buf2[BUFSZ];
1142         static const char untabbed_fmtstr[] = "%-15s: %-12s";
1143         static const char untabbed_deity_fmtstr[] = "%-17s%s";
1144         static const char tabbed_fmtstr[] = "%s:\t%-12s";
1145         static const char tabbed_deity_fmtstr[] = "%s\t%s";
1146         static const char *fmtstr;
1147         static const char *deity_fmtstr;
1148
1149         fmtstr = iflags.menu_tab_sep ? tabbed_fmtstr : untabbed_fmtstr;
1150         deity_fmtstr = iflags.menu_tab_sep ?
1151                         tabbed_deity_fmtstr : untabbed_deity_fmtstr; 
1152         any.a_void = 0;
1153         buf[0] = buf2[0] = '\0';
1154         tmpwin = create_nhwindow(NHW_MENU);
1155         start_menu(tmpwin);
1156         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Starting", FALSE);
1157
1158         /* Starting name, race, role, gender */
1159         Sprintf(buf, fmtstr, "name", plname);
1160         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1161         Sprintf(buf, fmtstr, "race", urace.noun);
1162         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1163         Sprintf(buf, fmtstr, "role",
1164                 (flags.initgend && urole.name.f) ? urole.name.f : urole.name.m);
1165         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1166         Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj);
1167         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1168
1169         /* Starting alignment */
1170         Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL]));
1171         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1172
1173         /* Current name, race, role, gender */
1174         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
1175         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Current", FALSE);
1176         Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun);
1177         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1178         if (Upolyd) {
1179             Sprintf(buf, fmtstr, "role (base)",
1180                 (u.mfemale && urole.name.f) ? urole.name.f : urole.name.m);
1181             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1182         } else {
1183             Sprintf(buf, fmtstr, "role",
1184                 (flags.female && urole.name.f) ? urole.name.f : urole.name.m);
1185             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1186         }
1187         /* don't want poly_gender() here; it forces `2' for non-humanoids */
1188         genidx = is_neuter(youmonst.data) ? 2 : flags.female;
1189         Sprintf(buf, fmtstr, "gender", genders[genidx].adj);
1190         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1191         if (Upolyd && (int)u.mfemale != genidx) {
1192             Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj);
1193             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1194         }
1195
1196         /* Current alignment */
1197         Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type));
1198         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1199
1200         /* Deity list */
1201         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
1202         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Deities", FALSE);
1203         Sprintf(buf2, deity_fmtstr, align_gname(A_CHAOTIC),
1204             (u.ualignbase[A_ORIGINAL] == u.ualign.type
1205                 && u.ualign.type == A_CHAOTIC) ? " (s,c)" :
1206             (u.ualignbase[A_ORIGINAL] == A_CHAOTIC)       ? " (s)" :
1207             (u.ualign.type   == A_CHAOTIC)       ? " (c)" : "");
1208         Sprintf(buf, fmtstr, "Chaotic", buf2);
1209         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1210
1211         Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL),
1212             (u.ualignbase[A_ORIGINAL] == u.ualign.type
1213                 && u.ualign.type == A_NEUTRAL) ? " (s,c)" :
1214             (u.ualignbase[A_ORIGINAL] == A_NEUTRAL)       ? " (s)" :
1215             (u.ualign.type   == A_NEUTRAL)       ? " (c)" : "");
1216         Sprintf(buf, fmtstr, "Neutral", buf2);
1217         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1218
1219         Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL),
1220             (u.ualignbase[A_ORIGINAL] == u.ualign.type &&
1221                 u.ualign.type == A_LAWFUL)  ? " (s,c)" :
1222             (u.ualignbase[A_ORIGINAL] == A_LAWFUL)        ? " (s)" :
1223             (u.ualign.type   == A_LAWFUL)        ? " (c)" : "");
1224         Sprintf(buf, fmtstr, "Lawful", buf2);
1225         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1226
1227         end_menu(tmpwin, "Base Attributes");
1228         n = select_menu(tmpwin, PICK_NONE, &selected);
1229         destroy_nhwindow(tmpwin);
1230         return (n != -1);
1231 }
1232
1233 STATIC_PTR int
1234 doattributes()
1235 {
1236         if (!minimal_enlightenment())
1237                 return 0;
1238         if (wizard || discover)
1239                 enlightenment(0);
1240         return 0;
1241 }
1242
1243 /* KMH, #conduct
1244  * (shares enlightenment's tense handling)
1245  */
1246 STATIC_PTR int
1247 doconduct()
1248 {
1249         show_conduct(0);
1250         return 0;
1251 }
1252
1253 void
1254 show_conduct(final)
1255 int final;
1256 {
1257         char buf[BUFSZ];
1258         int ngenocided;
1259
1260         /* Create the conduct window */
1261         en_win = create_nhwindow(NHW_MENU);
1262         putstr(en_win, 0, "Voluntary challenges:");
1263         putstr(en_win, 0, "");
1264
1265         if (!u.uconduct.food)
1266             enl_msg(You_, "have gone", "went", " without food");
1267             /* But beverages are okay */
1268         else if (!u.uconduct.unvegan)
1269             you_have_X("followed a strict vegan diet");
1270         else if (!u.uconduct.unvegetarian)
1271             you_have_been("vegetarian");
1272
1273         if (!u.uconduct.gnostic)
1274             you_have_been("an atheist");
1275
1276         if (!u.uconduct.weaphit)
1277             you_have_never("hit with a wielded weapon");
1278 #ifdef WIZARD
1279         else if (wizard) {
1280             Sprintf(buf, "used a wielded weapon %ld time%s",
1281                     u.uconduct.weaphit, plur(u.uconduct.weaphit));
1282             you_have_X(buf);
1283         }
1284 #endif
1285         if (!u.uconduct.killer)
1286             you_have_been("a pacifist");
1287
1288         if (!u.uconduct.literate)
1289             you_have_been("illiterate");
1290 #ifdef WIZARD
1291         else if (wizard) {
1292             Sprintf(buf, "read items or engraved %ld time%s",
1293                     u.uconduct.literate, plur(u.uconduct.literate));
1294             you_have_X(buf);
1295         }
1296 #endif
1297
1298         ngenocided = num_genocides();
1299         if (ngenocided == 0) {
1300             you_have_never("genocided any monsters");
1301         } else {
1302             Sprintf(buf, "genocided %d type%s of monster%s",
1303                     ngenocided, plur(ngenocided), plur(ngenocided));
1304             you_have_X(buf);
1305         }
1306
1307         if (!u.uconduct.polypiles)
1308             you_have_never("polymorphed an object");
1309 #ifdef WIZARD
1310         else if (wizard) {
1311             Sprintf(buf, "polymorphed %ld item%s",
1312                     u.uconduct.polypiles, plur(u.uconduct.polypiles));
1313             you_have_X(buf);
1314         }
1315 #endif
1316
1317         if (!u.uconduct.polyselfs)
1318             you_have_never("changed form");
1319 #ifdef WIZARD
1320         else if (wizard) {
1321             Sprintf(buf, "changed form %ld time%s",
1322                     u.uconduct.polyselfs, plur(u.uconduct.polyselfs));
1323             you_have_X(buf);
1324         }
1325 #endif
1326
1327         if (!u.uconduct.wishes)
1328             you_have_X("used no wishes");
1329         else {
1330             Sprintf(buf, "used %ld wish%s",
1331                     u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : "");
1332             you_have_X(buf);
1333
1334             if (!u.uconduct.wisharti)
1335                 enl_msg(You_, "have not wished", "did not wish",
1336                         " for any artifacts");
1337         }
1338
1339         /* Pop up the window and wait for a key */
1340         display_nhwindow(en_win, TRUE);
1341         destroy_nhwindow(en_win);
1342 }
1343
1344 #endif /* OVLB */
1345 #ifdef OVL1
1346
1347 #ifndef M
1348 # ifndef NHSTDC
1349 #  define M(c)          (0x80 | (c))
1350 # else
1351 #  define M(c)          ((c) - 128)
1352 # endif /* NHSTDC */
1353 #endif
1354 #ifndef C
1355 #define C(c)            (0x1f & (c))
1356 #endif
1357
1358 static const struct func_tab cmdlist[] = {
1359         {C('d'), FALSE, dokick}, /* "D" is for door!...?  Msg is in dokick.c */
1360 #ifdef WIZARD
1361         {C('e'), TRUE, wiz_detect},
1362         {C('f'), TRUE, wiz_map},
1363         {C('g'), TRUE, wiz_genesis},
1364         {C('i'), TRUE, wiz_identify},
1365 #endif
1366         {C('l'), TRUE, doredraw}, /* if number_pad is set */
1367 #ifdef WIZARD
1368         {C('o'), TRUE, wiz_where},
1369 #endif
1370         {C('p'), TRUE, doprev_message},
1371         {C('r'), TRUE, doredraw},
1372         {C('t'), TRUE, dotele},
1373 #ifdef WIZARD
1374         {C('v'), TRUE, wiz_level_tele},
1375         {C('w'), TRUE, wiz_wish},
1376 #endif
1377         {C('x'), TRUE, doattributes},
1378 #ifdef SUSPEND
1379         {C('z'), TRUE, dosuspend},
1380 #endif
1381         {'a', FALSE, doapply},
1382         {'A', FALSE, doddoremarm},
1383         {M('a'), TRUE, doorganize},
1384 /*      'b', 'B' : go sw */
1385         {'c', FALSE, doclose},
1386         {'C', TRUE, do_mname},
1387         {M('c'), TRUE, dotalk},
1388         {'d', FALSE, dodrop},
1389         {'D', FALSE, doddrop},
1390         {M('d'), FALSE, dodip},
1391         {'e', FALSE, doeat},
1392         {'E', FALSE, doengrave},
1393         {M('e'), TRUE, enhance_weapon_skill},
1394         {'f', FALSE, dofire},
1395 /*      'F' : fight (one time) */
1396         {M('f'), FALSE, doforce},
1397 /*      'g', 'G' : multiple go */
1398 /*      'h', 'H' : go west */
1399         {'h', TRUE, dohelp}, /* if number_pad is set */
1400         {'i', TRUE, ddoinv},
1401         {'I', TRUE, dotypeinv},         /* Robert Viduya */
1402         {M('i'), TRUE, doinvoke},
1403 /*      'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
1404         {'j', FALSE, dojump}, /* if number_pad is on */
1405         {M('j'), FALSE, dojump},
1406         {'k', FALSE, dokick}, /* if number_pad is on */
1407         {'l', FALSE, doloot}, /* if number_pad is on */
1408         {M('l'), FALSE, doloot},
1409 /*      'n' prefixes a count if number_pad is on */
1410         {M('m'), TRUE, domonability},
1411         {'N', TRUE, ddocall}, /* if number_pad is on */
1412         {M('n'), TRUE, ddocall},
1413         {M('N'), TRUE, ddocall},
1414         {'o', FALSE, doopen},
1415         {'O', TRUE, doset},
1416         {M('o'), FALSE, dosacrifice},
1417         {'p', FALSE, dopay},
1418         {'P', FALSE, doputon},
1419         {M('p'), TRUE, dopray},
1420         {'q', FALSE, dodrink},
1421         {'Q', FALSE, dowieldquiver},
1422         {M('q'), TRUE, done2},
1423         {'r', FALSE, doread},
1424         {'R', FALSE, doremring},
1425         {M('r'), FALSE, dorub},
1426         {'s', TRUE, dosearch, "searching"},
1427         {'S', TRUE, dosave},
1428         {M('s'), FALSE, dosit},
1429         {'t', FALSE, dothrow},
1430         {'T', FALSE, dotakeoff},
1431         {M('t'), TRUE, doturn},
1432 /*      'u', 'U' : go ne */
1433         {'u', FALSE, dountrap}, /* if number_pad is on */
1434         {M('u'), FALSE, dountrap},
1435         {'v', TRUE, doversion},
1436         {'V', TRUE, dohistory},
1437         {M('v'), TRUE, doextversion},
1438         {'w', FALSE, dowield},
1439         {'W', FALSE, dowear},
1440         {M('w'), FALSE, dowipe},
1441         {'x', FALSE, doswapweapon},
1442         {'X', TRUE, enter_explore_mode},
1443 /*      'y', 'Y' : go nw */
1444         {'z', FALSE, dozap},
1445         {'Z', TRUE, docast},
1446         {'<', FALSE, doup},
1447         {'>', FALSE, dodown},
1448         {'/', TRUE, dowhatis},
1449         {'&', TRUE, dowhatdoes},
1450         {'?', TRUE, dohelp},
1451         {M('?'), TRUE, doextlist},
1452 #ifdef SHELL
1453         {'!', TRUE, dosh},
1454 #endif
1455         {'.', TRUE, donull, "waiting"},
1456         {' ', TRUE, donull, "waiting"},
1457         {',', FALSE, dopickup},
1458         {':', TRUE, dolook},
1459         {';', TRUE, doquickwhatis},
1460         {'^', TRUE, doidtrap},
1461         {'\\', TRUE, dodiscovered},             /* Robert Viduya */
1462         {'@', TRUE, dotogglepickup},
1463         {M('2'), FALSE, dotwoweapon},
1464         {WEAPON_SYM,  TRUE, doprwep},
1465         {ARMOR_SYM,  TRUE, doprarm},
1466         {RING_SYM,  TRUE, doprring},
1467         {AMULET_SYM, TRUE, dopramulet},
1468         {TOOL_SYM, TRUE, doprtool},
1469         {'*', TRUE, doprinuse}, /* inventory of all equipment in use */
1470         {GOLD_SYM, TRUE, doprgold},
1471         {SPBOOK_SYM, TRUE, dovspell},                   /* Mike Stephenson */
1472         {'#', TRUE, doextcmd},
1473         {'_', TRUE, dotravel},
1474         {0,0,0,0}
1475 };
1476
1477 struct ext_func_tab extcmdlist[] = {
1478         {"adjust", "adjust inventory letters", doorganize, TRUE},
1479         {"chat", "talk to someone", dotalk, TRUE},      /* converse? */
1480         {"conduct", "list which challenges you have adhered to", doconduct, TRUE},
1481         {"dip", "dip an object into something", dodip, FALSE},
1482         {"enhance", "advance or check weapons skills", enhance_weapon_skill,
1483                                                         TRUE},
1484         {"force", "force a lock", doforce, FALSE},
1485         {"invoke", "invoke an object's powers", doinvoke, TRUE},
1486         {"jump", "jump to a location", dojump, FALSE},
1487         {"loot", "loot a box on the floor", doloot, FALSE},
1488         {"monster", "use a monster's special ability", domonability, TRUE},
1489         {"name", "name an item or type of object", ddocall, TRUE},
1490         {"offer", "offer a sacrifice to the gods", dosacrifice, FALSE},
1491         {"pray", "pray to the gods for help", dopray, TRUE},
1492         {"quit", "exit without saving current game", done2, TRUE},
1493 #ifdef STEED
1494         {"ride", "ride (or stop riding) a monster", doride, FALSE},
1495 #endif
1496         {"rub", "rub a lamp or a stone", dorub, FALSE},
1497         {"sit", "sit down", dosit, FALSE},
1498         {"turn", "turn undead", doturn, TRUE},
1499         {"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE},
1500         {"untrap", "untrap something", dountrap, FALSE},
1501         {"version", "list compile time options for this version of NetHack",
1502                 doextversion, TRUE},
1503         {"wipe", "wipe off your face", dowipe, FALSE},
1504         {"?", "get this list of extended commands", doextlist, TRUE},
1505 #if defined(WIZARD)
1506         /*
1507          * There must be a blank entry here for every entry in the table
1508          * below.
1509          */
1510         {(char *)0, (char *)0, donull, TRUE},
1511         {(char *)0, (char *)0, donull, TRUE},
1512 #ifdef DEBUG_MIGRATING_MONS
1513         {(char *)0, (char *)0, donull, TRUE},
1514 #endif
1515         {(char *)0, (char *)0, donull, TRUE},
1516         {(char *)0, (char *)0, donull, TRUE},
1517         {(char *)0, (char *)0, donull, TRUE},
1518 #ifdef PORT_DEBUG
1519         {(char *)0, (char *)0, donull, TRUE},
1520 #endif
1521         {(char *)0, (char *)0, donull, TRUE},
1522         {(char *)0, (char *)0, donull, TRUE},
1523         {(char *)0, (char *)0, donull, TRUE},
1524         {(char *)0, (char *)0, donull, TRUE},
1525 #ifdef DEBUG
1526         {(char *)0, (char *)0, donull, TRUE},
1527 #endif
1528         {(char *)0, (char *)0, donull, TRUE},
1529 #endif
1530         {(char *)0, (char *)0, donull, TRUE}    /* sentinel */
1531 };
1532
1533 #if defined(WIZARD)
1534 static const struct ext_func_tab debug_extcmdlist[] = {
1535         {"levelchange", "change experience level", wiz_level_change, TRUE},
1536         {"lightsources", "show mobile light sources", wiz_light_sources, TRUE},
1537 #ifdef DEBUG_MIGRATING_MONS
1538         {"migratemons", "migrate n random monsters", wiz_migrate_mons, TRUE},
1539 #endif
1540         {"monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol, TRUE},
1541         {"panic", "test panic routine (fatal to game)", wiz_panic, TRUE},
1542         {"polyself", "polymorph self", wiz_polyself, TRUE},
1543 #ifdef PORT_DEBUG
1544         {"portdebug", "wizard port debug command", wiz_port_debug, TRUE},
1545 #endif
1546         {"seenv", "show seen vectors", wiz_show_seenv, TRUE},
1547         {"stats", "show memory statistics", wiz_show_stats, TRUE},
1548         {"timeout", "look at timeout queue", wiz_timeout_queue, TRUE},
1549         {"vision", "show vision array", wiz_show_vision, TRUE},
1550 #ifdef DEBUG
1551         {"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE},
1552 #endif
1553         {"wmode", "show wall modes", wiz_show_wmodes, TRUE},
1554         {(char *)0, (char *)0, donull, TRUE}
1555 };
1556
1557 /*
1558  * Insert debug commands into the extended command list.  This function
1559  * assumes that the last entry will be the help entry.
1560  *
1561  * You must add entries in ext_func_tab every time you add one to the
1562  * debug_extcmdlist().
1563  */
1564 void
1565 add_debug_extended_commands()
1566 {
1567         int i, j, k, n;
1568
1569         /* count the # of help entries */
1570         for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++)
1571             ;
1572
1573         for (i = 0; debug_extcmdlist[i].ef_txt; i++) {
1574             for (j = 0; j < n; j++)
1575                 if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break;
1576
1577             /* insert i'th debug entry into extcmdlist[j], pushing down  */
1578             for (k = n; k >= j; --k)
1579                 extcmdlist[k+1] = extcmdlist[k];
1580             extcmdlist[j] = debug_extcmdlist[i];
1581             n++;        /* now an extra entry */
1582         }
1583 }
1584
1585
1586 static const char template[] = "%-18s %4ld  %6ld";
1587 static const char count_str[] = "                   count  bytes";
1588 static const char separator[] = "------------------ -----  ------";
1589
1590 STATIC_OVL void
1591 count_obj(chain, total_count, total_size, top, recurse)
1592         struct obj *chain;
1593         long *total_count;
1594         long *total_size;
1595         boolean top;
1596         boolean recurse;
1597 {
1598         long count, size;
1599         struct obj *obj;
1600
1601         for (count = size = 0, obj = chain; obj; obj = obj->nobj) {
1602             if (top) {
1603                 count++;
1604                 size += sizeof(struct obj) + obj->oxlth + obj->onamelth;
1605             }
1606             if (recurse && obj->cobj)
1607                 count_obj(obj->cobj, total_count, total_size, TRUE, TRUE);
1608         }
1609         *total_count += count;
1610         *total_size += size;
1611 }
1612
1613 STATIC_OVL void
1614 obj_chain(win, src, chain, total_count, total_size)
1615         winid win;
1616         const char *src;
1617         struct obj *chain;
1618         long *total_count;
1619         long *total_size;
1620 {
1621         char buf[BUFSZ];
1622         long count = 0, size = 0;
1623
1624         count_obj(chain, &count, &size, TRUE, FALSE);
1625         *total_count += count;
1626         *total_size += size;
1627         Sprintf(buf, template, src, count, size);
1628         putstr(win, 0, buf);
1629 }
1630
1631 STATIC_OVL void
1632 mon_invent_chain(win, src, chain, total_count, total_size)
1633         winid win;
1634         const char *src;
1635         struct monst *chain;
1636         long *total_count;
1637         long *total_size;
1638 {
1639         char buf[BUFSZ];
1640         long count = 0, size = 0;
1641         struct monst *mon;
1642
1643         for (mon = chain; mon; mon = mon->nmon)
1644             count_obj(mon->minvent, &count, &size, TRUE, FALSE);
1645         *total_count += count;
1646         *total_size += size;
1647         Sprintf(buf, template, src, count, size);
1648         putstr(win, 0, buf);
1649 }
1650
1651 STATIC_OVL void
1652 contained(win, src, total_count, total_size)
1653         winid win;
1654         const char *src;
1655         long *total_count;
1656         long *total_size;
1657 {
1658         char buf[BUFSZ];
1659         long count = 0, size = 0;
1660         struct monst *mon;
1661
1662         count_obj(invent, &count, &size, FALSE, TRUE);
1663         count_obj(fobj, &count, &size, FALSE, TRUE);
1664         count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE);
1665         count_obj(migrating_objs, &count, &size, FALSE, TRUE);
1666         /* DEADMONSTER check not required in this loop since they have no inventory */
1667         for (mon = fmon; mon; mon = mon->nmon)
1668             count_obj(mon->minvent, &count, &size, FALSE, TRUE);
1669         for (mon = migrating_mons; mon; mon = mon->nmon)
1670             count_obj(mon->minvent, &count, &size, FALSE, TRUE);
1671
1672         *total_count += count; *total_size += size;
1673
1674         Sprintf(buf, template, src, count, size);
1675         putstr(win, 0, buf);
1676 }
1677
1678 STATIC_OVL void
1679 mon_chain(win, src, chain, total_count, total_size)
1680         winid win;
1681         const char *src;
1682         struct monst *chain;
1683         long *total_count;
1684         long *total_size;
1685 {
1686         char buf[BUFSZ];
1687         long count, size;
1688         struct monst *mon;
1689
1690         for (count = size = 0, mon = chain; mon; mon = mon->nmon) {
1691             count++;
1692             size += sizeof(struct monst) + mon->mxlth + mon->mnamelth;
1693         }
1694         *total_count += count;
1695         *total_size += size;
1696         Sprintf(buf, template, src, count, size);
1697         putstr(win, 0, buf);
1698 }
1699
1700 /*
1701  * Display memory usage of all monsters and objects on the level.
1702  */
1703 static int
1704 wiz_show_stats()
1705 {
1706         char buf[BUFSZ];
1707         winid win;
1708         long total_obj_size = 0, total_obj_count = 0;
1709         long total_mon_size = 0, total_mon_count = 0;
1710
1711         win = create_nhwindow(NHW_TEXT);
1712         putstr(win, 0, "Current memory statistics:");
1713         putstr(win, 0, "");
1714         Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj));
1715         putstr(win, 0, buf);
1716         putstr(win, 0, "");
1717         putstr(win, 0, count_str);
1718
1719         obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size);
1720         obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size);
1721         obj_chain(win, "buried", level.buriedobjlist,
1722                                 &total_obj_count, &total_obj_size);
1723         obj_chain(win, "migrating obj", migrating_objs,
1724                                 &total_obj_count, &total_obj_size);
1725         mon_invent_chain(win, "minvent", fmon,
1726                                 &total_obj_count,&total_obj_size);
1727         mon_invent_chain(win, "migrating minvent", migrating_mons,
1728                                 &total_obj_count, &total_obj_size);
1729
1730         contained(win, "contained",
1731                                 &total_obj_count, &total_obj_size);
1732
1733         putstr(win, 0, separator);
1734         Sprintf(buf, template, "Total", total_obj_count, total_obj_size);
1735         putstr(win, 0, buf);
1736
1737         putstr(win, 0, "");
1738         putstr(win, 0, "");
1739         Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst));
1740         putstr(win, 0, buf);
1741         putstr(win, 0, "");
1742
1743         mon_chain(win, "fmon", fmon,
1744                                 &total_mon_count, &total_mon_size);
1745         mon_chain(win, "migrating", migrating_mons,
1746                                 &total_mon_count, &total_mon_size);
1747
1748         putstr(win, 0, separator);
1749         Sprintf(buf, template, "Total", total_mon_count, total_mon_size);
1750         putstr(win, 0, buf);
1751
1752 #if defined(__BORLANDC__) && !defined(_WIN32)
1753         show_borlandc_stats(win);
1754 #endif
1755
1756         display_nhwindow(win, FALSE);
1757         destroy_nhwindow(win);
1758         return 0;
1759 }
1760
1761 void
1762 sanity_check()
1763 {
1764         obj_sanity_check();
1765         timer_sanity_check();
1766 }
1767
1768 #ifdef DEBUG_MIGRATING_MONS
1769 static int
1770 wiz_migrate_mons()
1771 {
1772         int mcount = 0;
1773         char inbuf[BUFSZ];
1774         struct permonst *ptr;
1775         struct monst *mtmp;
1776         d_level tolevel;
1777         getlin("How many random monsters to migrate? [0]", inbuf);
1778         if (*inbuf == '\033') return 0;
1779         mcount = atoi(inbuf);
1780         if (mcount < 0 || mcount > (COLNO * ROWNO) || Is_botlevel(&u.uz))
1781                 return 0;
1782         while (mcount > 0) {
1783                 if (Is_stronghold(&u.uz))
1784                     assign_level(&tolevel, &valley_level);
1785                 else
1786                     get_level(&tolevel, depth(&u.uz) + 1);
1787                 ptr = rndmonst();
1788                 mtmp = makemon(ptr, 0, 0, NO_MM_FLAGS);
1789                 if (mtmp) migrate_to_level(mtmp, ledger_no(&tolevel),
1790                                 MIGR_RANDOM, (coord *)0);
1791                 mcount--;
1792         }
1793         return 0;
1794 }
1795 #endif
1796
1797 #endif /* WIZARD */
1798
1799 #define unctrl(c)       ((c) <= C('z') ? (0x60 | (c)) : (c))
1800 #define unmeta(c)       (0x7f & (c))
1801
1802
1803 void
1804 rhack(cmd)
1805 register char *cmd;
1806 {
1807         boolean do_walk, do_rush, prefix_seen, bad_command,
1808                 firsttime = (cmd == 0);
1809
1810         iflags.menu_requested = FALSE;
1811         if (firsttime) {
1812                 flags.nopick = 0;
1813                 cmd = parse();
1814         }
1815         if (*cmd == '\033') {
1816                 flags.move = FALSE;
1817                 return;
1818         }
1819 #ifdef REDO
1820         if (*cmd == DOAGAIN && !in_doagain && saveq[0]) {
1821                 in_doagain = TRUE;
1822                 stail = 0;
1823                 rhack((char *)0);       /* read and execute command */
1824                 in_doagain = FALSE;
1825                 return;
1826         }
1827         /* Special case of *cmd == ' ' handled better below */
1828         if(!*cmd || *cmd == (char)0377)
1829 #else
1830         if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' '))
1831 #endif
1832         {
1833                 nhbell();
1834                 flags.move = FALSE;
1835                 return;         /* probably we just had an interrupt */
1836         }
1837         if (iflags.num_pad && iflags.num_pad_mode == 1) {
1838                 /* This handles very old inconsistent DOS/Windows behaviour
1839                  * in a new way: earlier, the keyboard handler mapped these,
1840                  * which caused counts to be strange when entered from the
1841                  * number pad. Now do not map them until here. 
1842                  */
1843                 switch (*cmd) {
1844                     case '5':       *cmd = 'g'; break;
1845                     case M('5'):    *cmd = 'G'; break;
1846                     case M('0'):    *cmd = 'I'; break;
1847                 }
1848         }
1849         /* handle most movement commands */
1850         do_walk = do_rush = prefix_seen = FALSE;
1851         flags.travel = iflags.travel1 = 0;
1852         switch (*cmd) {
1853          case 'g':  if (movecmd(cmd[1])) {
1854                         flags.run = 2;
1855                         do_rush = TRUE;
1856                     } else
1857                         prefix_seen = TRUE;
1858                     break;
1859          case '5':  if (!iflags.num_pad) break; /* else FALLTHRU */
1860          case 'G':  if (movecmd(lowc(cmd[1]))) {
1861                         flags.run = 3;
1862                         do_rush = TRUE;
1863                     } else
1864                         prefix_seen = TRUE;
1865                     break;
1866          case '-':  if (!iflags.num_pad) break; /* else FALLTHRU */
1867         /* Effects of movement commands and invisible monsters:
1868          * m: always move onto space (even if 'I' remembered)
1869          * F: always attack space (even if 'I' not remembered)
1870          * normal movement: attack if 'I', move otherwise
1871          */
1872          case 'F':  if (movecmd(cmd[1])) {
1873                         flags.forcefight = 1;
1874                         do_walk = TRUE;
1875                     } else
1876                         prefix_seen = TRUE;
1877                     break;
1878          case 'm':  if (movecmd(cmd[1]) || u.dz) {
1879                         flags.run = 0;
1880                         flags.nopick = 1;
1881                         if (!u.dz) do_walk = TRUE;
1882                         else cmd[0] = cmd[1];   /* "m<" or "m>" */
1883                     } else
1884                         prefix_seen = TRUE;
1885                     break;
1886          case 'M':  if (movecmd(lowc(cmd[1]))) {
1887                         flags.run = 1;
1888                         flags.nopick = 1;
1889                         do_rush = TRUE;
1890                     } else
1891                         prefix_seen = TRUE;
1892                     break;
1893          case '0':  if (!iflags.num_pad) break;
1894                     (void)ddoinv(); /* a convenience borrowed from the PC */
1895                     flags.move = FALSE;
1896                     multi = 0;
1897                     return;
1898          case CMD_TRAVEL:
1899                     if (iflags.travelcmd) {
1900                             flags.travel = 1;
1901                             iflags.travel1 = 1;
1902                             flags.run = 8;
1903                             flags.nopick = 1;
1904                             do_rush = TRUE;
1905                             break;
1906                     }
1907                     /*FALLTHRU*/
1908          default:   if (movecmd(*cmd)) {        /* ordinary movement */
1909                         flags.run = 0;  /* only matters here if it was 8 */
1910                         do_walk = TRUE;
1911                     } else if (movecmd(iflags.num_pad ?
1912                                        unmeta(*cmd) : lowc(*cmd))) {
1913                         flags.run = 1;
1914                         do_rush = TRUE;
1915                     } else if (movecmd(unctrl(*cmd))) {
1916                         flags.run = 3;
1917                         do_rush = TRUE;
1918                     }
1919                     break;
1920         }
1921
1922         /* some special prefix handling */
1923         /* overload 'm' prefix for ',' to mean "request a menu" */
1924         if (prefix_seen && cmd[1] == ',') {
1925                 iflags.menu_requested = TRUE;
1926                 ++cmd;
1927         }
1928
1929         if (do_walk) {
1930             if (multi) flags.mv = TRUE;
1931             domove();
1932             flags.forcefight = 0;
1933             return;
1934         } else if (do_rush) {
1935             if (firsttime) {
1936                 if (!multi) multi = max(COLNO,ROWNO);
1937                 u.last_str_turn = 0;
1938             }
1939             flags.mv = TRUE;
1940             domove();
1941             return;
1942         } else if (prefix_seen && cmd[1] == '\033') {   /* <prefix><escape> */
1943             /* don't report "unknown command" for change of heart... */
1944             bad_command = FALSE;
1945         } else if (*cmd == ' ' && !flags.rest_on_space) {
1946             bad_command = TRUE;         /* skip cmdlist[] loop */
1947
1948         /* handle all other commands */
1949         } else {
1950             register const struct func_tab *tlist;
1951             int res, NDECL((*func));
1952
1953             for (tlist = cmdlist; tlist->f_char; tlist++) {
1954                 if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue;
1955
1956                 if (u.uburied && !tlist->can_if_buried) {
1957                     You_cant("do that while you are buried!");
1958                     res = 0;
1959                 } else {
1960                     /* we discard 'const' because some compilers seem to have
1961                        trouble with the pointer passed to set_occupation() */
1962                     func = ((struct func_tab *)tlist)->f_funct;
1963                     if (tlist->f_text && !occupation && multi)
1964                         set_occupation(func, tlist->f_text, multi);
1965                     res = (*func)();            /* perform the command */
1966                 }
1967                 if (!res) {
1968                     flags.move = FALSE;
1969                     multi = 0;
1970                 }
1971                 return;
1972             }
1973             /* if we reach here, cmd wasn't found in cmdlist[] */
1974             bad_command = TRUE;
1975         }
1976
1977         if (bad_command) {
1978             char expcmd[10];
1979             register char *cp = expcmd;
1980
1981             while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) {
1982                 if (*cmd >= 040 && *cmd < 0177) {
1983                     *cp++ = *cmd++;
1984                 } else if (*cmd & 0200) {
1985                     *cp++ = 'M';
1986                     *cp++ = '-';
1987                     *cp++ = *cmd++ &= ~0200;
1988                 } else {
1989                     *cp++ = '^';
1990                     *cp++ = *cmd++ ^ 0100;
1991                 }
1992             }
1993             *cp = '\0';
1994             if (!prefix_seen || !iflags.cmdassist ||
1995                 !help_dir(0, "Invalid direction key!"))
1996                 Norep("Unknown command '%s'.", expcmd);
1997         }
1998         /* didn't move */
1999         flags.move = FALSE;
2000         multi = 0;
2001         return;
2002 }
2003
2004 int
2005 xytod(x, y)     /* convert an x,y pair into a direction code */
2006 schar x, y;
2007 {
2008         register int dd;
2009
2010         for(dd = 0; dd < 8; dd++)
2011             if(x == xdir[dd] && y == ydir[dd]) return dd;
2012
2013         return -1;
2014 }
2015
2016 void
2017 dtoxy(cc,dd)    /* convert a direction code into an x,y pair */
2018 coord *cc;
2019 register int dd;
2020 {
2021         cc->x = xdir[dd];
2022         cc->y = ydir[dd];
2023         return;
2024 }
2025
2026 int
2027 movecmd(sym)    /* also sets u.dz, but returns false for <> */
2028 char sym;
2029 {
2030         register const char *dp;
2031         register const char *sdp;
2032         if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
2033
2034         u.dz = 0;
2035         if(!(dp = index(sdp, sym))) return 0;
2036         u.dx = xdir[dp-sdp];
2037         u.dy = ydir[dp-sdp];
2038         u.dz = zdir[dp-sdp];
2039         if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) {
2040                 u.dx = u.dy = 0;
2041                 return 0;
2042         }
2043         return !u.dz;
2044 }
2045
2046 /*
2047  * uses getdir() but unlike getdir() it specifically
2048  * produces coordinates using the direction from getdir()
2049  * and verifies that those coordinates are ok.
2050  *
2051  * If the call to getdir() returns 0, Never_mind is displayed.
2052  * If the resulting coordinates are not okay, emsg is displayed.
2053  *
2054  * Returns non-zero if coordinates in cc are valid.
2055  */
2056 int get_adjacent_loc(prompt,emsg,x,y,cc)
2057 const char *prompt, *emsg;
2058 xchar x,y;
2059 coord *cc;
2060 {
2061         xchar new_x, new_y;
2062         if (!getdir(prompt)) {
2063                 pline(Never_mind);
2064                 return 0;
2065         }
2066         new_x = x + u.dx;
2067         new_y = y + u.dy;
2068         if (cc && isok(new_x,new_y)) {
2069                 cc->x = new_x;
2070                 cc->y = new_y;
2071         } else {
2072                 if (emsg) pline(emsg);
2073                 return 0;
2074         }
2075         return 1;
2076 }
2077
2078 int
2079 getdir(s)
2080 const char *s;
2081 {
2082         char dirsym;
2083
2084 #ifdef REDO
2085         if(in_doagain || *readchar_queue)
2086             dirsym = readchar();
2087         else
2088 #endif
2089             dirsym = yn_function ((s && *s != '^') ? s : "In what direction?",
2090                                         (char *)0, '\0');
2091 #ifdef REDO
2092         savech(dirsym);
2093 #endif
2094         if(dirsym == '.' || dirsym == 's')
2095                 u.dx = u.dy = u.dz = 0;
2096         else if(!movecmd(dirsym) && !u.dz) {
2097                 boolean did_help = FALSE;
2098                 if(!index(quitchars, dirsym)) {
2099                     if (iflags.cmdassist) {
2100                         did_help = help_dir((s && *s == '^') ? dirsym : 0,
2101                                             "Invalid direction key!");
2102                     }
2103                     if (!did_help) pline("What a strange direction!");
2104                 }
2105                 return 0;
2106         }
2107         if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
2108         return 1;
2109 }
2110
2111 STATIC_OVL boolean
2112 help_dir(sym, msg)
2113 char sym;
2114 const char *msg;
2115 {
2116         char ctrl;
2117         winid win;
2118         static const char wiz_only_list[] = "EFGIOVW";
2119         char buf[BUFSZ], buf2[BUFSZ], *expl;
2120
2121         win = create_nhwindow(NHW_TEXT);
2122         if (!win) return FALSE;
2123         if (msg) {
2124                 Sprintf(buf, "cmdassist: %s", msg);
2125                 putstr(win, 0, buf);
2126                 putstr(win, 0, "");
2127         }
2128         if (letter(sym)) { 
2129             sym = highc(sym);
2130             ctrl = (sym - 'A') + 1;
2131             if ((expl = dowhatdoes_core(ctrl, buf2))
2132                 && (!index(wiz_only_list, sym)
2133 #ifdef WIZARD
2134                     || wizard
2135 #endif
2136                              )) {
2137                 Sprintf(buf, "Are you trying to use ^%c%s?", sym,
2138                         index(wiz_only_list, sym) ? "" :
2139                         " as specified in the Guidebook");
2140                 putstr(win, 0, buf);
2141                 putstr(win, 0, "");
2142                 putstr(win, 0, expl);
2143                 putstr(win, 0, "");
2144                 putstr(win, 0, "To use that command, you press");
2145                 Sprintf(buf,
2146                         "the <Ctrl> key, and the <%c> key at the same time.", sym);
2147                 putstr(win, 0, buf);
2148                 putstr(win, 0, "");
2149             }
2150         }
2151         if (iflags.num_pad && u.umonnum == PM_GRID_BUG) {
2152             putstr(win, 0, "Valid direction keys in your current form (with number_pad on) are:");
2153             putstr(win, 0, "             8   ");
2154             putstr(win, 0, "             |   ");
2155             putstr(win, 0, "          4- . -6");
2156             putstr(win, 0, "             |   ");
2157             putstr(win, 0, "             2   ");
2158         } else if (u.umonnum == PM_GRID_BUG) {
2159             putstr(win, 0, "Valid direction keys in your current form are:");
2160             putstr(win, 0, "             k   ");
2161             putstr(win, 0, "             |   ");
2162             putstr(win, 0, "          h- . -l");
2163             putstr(win, 0, "             |   ");
2164             putstr(win, 0, "             j   ");
2165         } else if (iflags.num_pad) {
2166             putstr(win, 0, "Valid direction keys (with number_pad on) are:");
2167             putstr(win, 0, "          7  8  9");
2168             putstr(win, 0, "           \\ | / ");
2169             putstr(win, 0, "          4- . -6");
2170             putstr(win, 0, "           / | \\ ");
2171             putstr(win, 0, "          1  2  3");
2172         } else {
2173             putstr(win, 0, "Valid direction keys are:");
2174             putstr(win, 0, "          y  k  u");
2175             putstr(win, 0, "           \\ | / ");
2176             putstr(win, 0, "          h- . -l");
2177             putstr(win, 0, "           / | \\ ");
2178             putstr(win, 0, "          b  j  n");
2179         };
2180         putstr(win, 0, "");
2181         putstr(win, 0, "          <  up");
2182         putstr(win, 0, "          >  down");
2183         putstr(win, 0, "          .  direct at yourself");
2184         putstr(win, 0, "");
2185         putstr(win, 0, "(Suppress this message with !cmdassist in config file.)");
2186         display_nhwindow(win, FALSE);
2187         destroy_nhwindow(win);
2188         return TRUE;
2189 }
2190
2191 #endif /* OVL1 */
2192 #ifdef OVLB
2193
2194 void
2195 confdir()
2196 {
2197         register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8);
2198         u.dx = xdir[x];
2199         u.dy = ydir[x];
2200         return;
2201 }
2202
2203 #endif /* OVLB */
2204 #ifdef OVL0
2205
2206 int
2207 isok(x,y)
2208 register int x, y;
2209 {
2210         /* x corresponds to curx, so x==1 is the first column. Ach. %% */
2211         return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1;
2212 }
2213
2214 static NEARDATA int last_multi;
2215
2216 /*
2217  * convert a MAP window position into a movecmd
2218  */
2219 const char *
2220 click_to_cmd(x, y, mod)
2221     int x, y, mod;
2222 {
2223     int dir;
2224     static char cmd[4];
2225     cmd[1]=0;
2226
2227     x -= u.ux;
2228     y -= u.uy;
2229
2230     if (iflags.travelcmd) {
2231         if (abs(x) <= 1 && abs(y) <= 1 ) {
2232             x = sgn(x), y = sgn(y);
2233         } else {
2234             u.tx = u.ux+x;
2235             u.ty = u.uy+y;
2236             cmd[0] = CMD_TRAVEL;
2237             return cmd;
2238         }
2239
2240         if(x == 0 && y == 0) {
2241             /* here */
2242             if(IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) {
2243                 cmd[0]=mod == CLICK_1 ? 'q' : M('d');
2244                 return cmd;
2245             } else if(IS_THRONE(levl[u.ux][u.uy].typ)) {
2246                 cmd[0]=M('s');
2247                 return cmd;
2248             } else if((u.ux == xupstair && u.uy == yupstair)
2249                       || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up)
2250                       || (u.ux == xupladder && u.uy == yupladder)) {
2251                 return "<";
2252             } else if((u.ux == xdnstair && u.uy == ydnstair)
2253                       || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)
2254                       || (u.ux == xdnladder && u.uy == ydnladder)) {
2255                 return ">";
2256             } else if(OBJ_AT(u.ux, u.uy)) {
2257                 cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ',';
2258                 return cmd;
2259             } else {
2260                 return "."; /* just rest */
2261             }
2262         }
2263
2264         /* directional commands */
2265
2266         dir = xytod(x, y);
2267
2268         if (!m_at(u.ux+x, u.uy+y) && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) {
2269             cmd[1] = (iflags.num_pad ? ndir[dir] : sdir[dir]);
2270             cmd[2] = 0;
2271             if (IS_DOOR(levl[u.ux+x][u.uy+y].typ)) {
2272                 /* slight assistance to the player: choose kick/open for them */
2273                 if (levl[u.ux+x][u.uy+y].doormask & D_LOCKED) {
2274                     cmd[0] = C('d');
2275                     return cmd;
2276                 }
2277                 if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) {
2278                     cmd[0] = 'o';
2279                     return cmd;
2280                 }
2281             }
2282             if (levl[u.ux+x][u.uy+y].typ <= SCORR) {
2283                 cmd[0] = 's';
2284                 cmd[1] = 0;
2285                 return cmd;
2286             }
2287         }
2288     } else {
2289         /* convert without using floating point, allowing sloppy clicking */
2290         if(x > 2*abs(y))
2291             x = 1, y = 0;
2292         else if(y > 2*abs(x))
2293             x = 0, y = 1;
2294         else if(x < -2*abs(y))
2295             x = -1, y = 0;
2296         else if(y < -2*abs(x))
2297             x = 0, y = -1;
2298         else
2299             x = sgn(x), y = sgn(y);
2300
2301         if(x == 0 && y == 0)    /* map click on player to "rest" command */
2302             return ".";
2303
2304         dir = xytod(x, y);
2305     }
2306
2307     /* move, attack, etc. */
2308     cmd[1] = 0;
2309     if(mod == CLICK_1) {
2310         cmd[0] = (iflags.num_pad ? ndir[dir] : sdir[dir]);
2311     } else {
2312         cmd[0] = (iflags.num_pad ? M(ndir[dir]) :
2313                 (sdir[dir] - 'a' + 'A')); /* run command */
2314     }
2315
2316     return cmd;
2317 }
2318
2319 STATIC_OVL char *
2320 parse()
2321 {
2322 #ifdef LINT     /* static char in_line[COLNO]; */
2323         char in_line[COLNO];
2324 #else
2325         static char in_line[COLNO];
2326 #endif
2327         register int foo;
2328         boolean prezero = FALSE;
2329
2330         multi = 0;
2331         flags.move = 1;
2332         flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
2333
2334         if (!iflags.num_pad || (foo = readchar()) == 'n')
2335             for (;;) {
2336                 foo = readchar();
2337                 if (foo >= '0' && foo <= '9') {
2338                     multi = 10 * multi + foo - '0';
2339                     if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT;
2340                     if (multi > 9) {
2341                         clear_nhwindow(WIN_MESSAGE);
2342                         Sprintf(in_line, "Count: %d", multi);
2343                         pline(in_line);
2344                         mark_synch();
2345                     }
2346                     last_multi = multi;
2347                     if (!multi && foo == '0') prezero = TRUE;
2348                 } else break;   /* not a digit */
2349             }
2350
2351         if (foo == '\033') {   /* esc cancels count (TH) */
2352             clear_nhwindow(WIN_MESSAGE);
2353             multi = last_multi = 0;
2354 # ifdef REDO
2355         } else if (foo == DOAGAIN || in_doagain) {
2356             multi = last_multi;
2357         } else {
2358             last_multi = multi;
2359             savech(0);  /* reset input queue */
2360             savech((char)foo);
2361 # endif
2362         }
2363
2364         if (multi) {
2365             multi--;
2366             save_cm = in_line;
2367         } else {
2368             save_cm = (char *)0;
2369         }
2370         in_line[0] = foo;
2371         in_line[1] = '\0';
2372         if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' ||
2373             foo == 'F' || (iflags.num_pad && (foo == '5' || foo == '-'))) {
2374             foo = readchar();
2375 #ifdef REDO
2376             savech((char)foo);
2377 #endif
2378             in_line[1] = foo;
2379             in_line[2] = 0;
2380         }
2381         clear_nhwindow(WIN_MESSAGE);
2382         if (prezero) in_line[0] = '\033';
2383         return(in_line);
2384 }
2385
2386 #endif /* OVL0 */
2387 #ifdef OVLB
2388
2389 #ifdef UNIX
2390 static
2391 void
2392 end_of_input()
2393 {
2394 #ifndef NOSAVEONHANGUP
2395         if (!program_state.done_hup++ && program_state.something_worth_saving)
2396             (void) dosave0();
2397 #endif
2398         exit_nhwindows((char *)0);
2399         clearlocks();
2400         terminate(EXIT_SUCCESS);
2401 }
2402 #endif
2403
2404 #endif /* OVLB */
2405 #ifdef OVL0
2406
2407 char
2408 readchar()
2409 {
2410         register int sym;
2411         int x = u.ux, y = u.uy, mod = 0;
2412
2413         if ( *readchar_queue )
2414             sym = *readchar_queue++;
2415         else
2416 #ifdef REDO
2417             sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod);
2418 #else
2419             sym = Getchar();
2420 #endif
2421
2422 #ifdef UNIX
2423 # ifdef NR_OF_EOFS
2424         if (sym == EOF) {
2425             register int cnt = NR_OF_EOFS;
2426           /*
2427            * Some SYSV systems seem to return EOFs for various reasons
2428            * (?like when one hits break or for interrupted systemcalls?),
2429            * and we must see several before we quit.
2430            */
2431             do {
2432                 clearerr(stdin);        /* omit if clearerr is undefined */
2433                 sym = Getchar();
2434             } while (--cnt && sym == EOF);
2435         }
2436 # endif /* NR_OF_EOFS */
2437         if (sym == EOF)
2438             end_of_input();
2439 #endif /* UNIX */
2440
2441         if(sym == 0) {
2442             /* click event */
2443             readchar_queue = click_to_cmd(x, y, mod);
2444             sym = *readchar_queue++;
2445         }
2446         return((char) sym);
2447 }
2448
2449 STATIC_PTR int
2450 dotravel()
2451 {
2452         /* Keyboard travel command */
2453         static char cmd[2];
2454         coord cc;
2455
2456         if (!iflags.travelcmd) return 0;
2457         cmd[1]=0;
2458         cc.x = iflags.travelcc.x;
2459         cc.y = iflags.travelcc.y;
2460         if (cc.x == -1 && cc.y == -1) {
2461             /* No cached destination, start attempt from current position */
2462             cc.x = u.ux;
2463             cc.y = u.uy;
2464         }
2465         pline("Where do you want to travel to?");
2466         if (getpos(&cc, TRUE, "the desired destination") < 0) {
2467                 /* user pressed ESC */
2468                 return 0;
2469         }
2470         iflags.travelcc.x = u.tx = cc.x;
2471         iflags.travelcc.y = u.ty = cc.y;
2472         cmd[0] = CMD_TRAVEL;
2473         readchar_queue = cmd;
2474         return 0;
2475 }
2476
2477 #ifdef PORT_DEBUG
2478 # ifdef WIN32CON
2479 extern void NDECL(win32con_debug_keystrokes);
2480 extern void NDECL(win32con_handler_info);
2481 # endif
2482
2483 int
2484 wiz_port_debug()
2485 {
2486         int n, k;
2487         winid win;
2488         anything any;
2489         int item = 'a';
2490         int num_menu_selections;
2491         struct menu_selection_struct {
2492                 char *menutext;
2493                 void NDECL((*fn));
2494         } menu_selections[] = {
2495 #ifdef WIN32CON
2496                 {"test win32 keystrokes", win32con_debug_keystrokes},
2497                 {"show keystroke handler information", win32con_handler_info},
2498 #endif
2499                 {(char *)0, (void NDECL((*)))0}         /* array terminator */
2500         };
2501
2502         num_menu_selections = SIZE(menu_selections) - 1;
2503         if (num_menu_selections > 0) {
2504                 menu_item *pick_list;
2505                 win = create_nhwindow(NHW_MENU);
2506                 start_menu(win);
2507                 for (k=0; k < num_menu_selections; ++k) {
2508                         any.a_int = k+1;
2509                         add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE,
2510                                 menu_selections[k].menutext, MENU_UNSELECTED);
2511                 }
2512                 end_menu(win, "Which port debugging feature?");
2513                 n = select_menu(win, PICK_ONE, &pick_list);
2514                 destroy_nhwindow(win);
2515                 if (n > 0) {
2516                         n = pick_list[0].item.a_int - 1;
2517                         free((genericptr_t) pick_list);
2518                         /* execute the function */
2519                         (*menu_selections[n].fn)();
2520                 }
2521         } else
2522                 pline("No port-specific debug capability defined.");
2523         return 0;
2524 }
2525 # endif /*PORT_DEBUG*/
2526
2527 #endif /* OVL0 */
2528 #ifdef OVLB
2529 /*
2530  *   Parameter validator for generic yes/no function to prevent
2531  *   the core from sending too long a prompt string to the
2532  *   window port causing a buffer overflow there.
2533  */
2534 char
2535 yn_function(query,resp, def)
2536 const char *query,*resp;
2537 char def;
2538 {
2539         char qbuf[QBUFSZ];
2540         unsigned truncspot, reduction = sizeof(" [N]  ?") + 1;
2541
2542         if (resp) reduction += strlen(resp) + sizeof(" () ");
2543         if (strlen(query) < (QBUFSZ - reduction))
2544                 return (*windowprocs.win_yn_function)(query, resp, def);
2545         paniclog("Query truncated: ", query);
2546         reduction += sizeof("...");
2547         truncspot = QBUFSZ - reduction;
2548         (void) strncpy(qbuf, query, (int)truncspot);
2549         qbuf[truncspot] = '\0';
2550         Strcat(qbuf,"...");
2551         return (*windowprocs.win_yn_function)(qbuf, resp, def);
2552 }
2553 #endif
2554
2555 /*cmd.c*/