1    | /*	SCCS Id: @(#)cmd.c	3.3	2000/05/05	*/
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   | #ifdef DEBUG
18   | /*
19   |  * only one "wiz_debug_cmd" routine should be available (in whatever
20   |  * module you are trying to debug) or things are going to get rather
21   |  * hard to link :-)
22   |  */
23   | extern void NDECL(wiz_debug_cmd);
24   | #endif
25   | 
26   | #ifdef DUMB	/* stuff commented out in extern.h, but needed here */
27   | extern int NDECL(doapply); /**/
28   | extern int NDECL(dorub); /**/
29   | extern int NDECL(dojump); /**/
30   | extern int NDECL(doextlist); /**/
31   | extern int NDECL(dodrop); /**/
32   | extern int NDECL(doddrop); /**/
33   | extern int NDECL(dodown); /**/
34   | extern int NDECL(doup); /**/
35   | extern int NDECL(donull); /**/
36   | extern int NDECL(dowipe); /**/
37   | extern int NDECL(do_mname); /**/
38   | extern int NDECL(ddocall); /**/
39   | extern int NDECL(dotakeoff); /**/
40   | extern int NDECL(doremring); /**/
41   | extern int NDECL(dowear); /**/
42   | extern int NDECL(doputon); /**/
43   | extern int NDECL(doddoremarm); /**/
44   | extern int NDECL(dokick); /**/
45   | extern int NDECL(dofire); /**/
46   | extern int NDECL(dothrow); /**/
47   | extern int NDECL(doeat); /**/
48   | extern int NDECL(done2); /**/
49   | extern int NDECL(doengrave); /**/
50   | extern int NDECL(dopickup); /**/
51   | extern int NDECL(ddoinv); /**/
52   | extern int NDECL(dotypeinv); /**/
53   | extern int NDECL(dolook); /**/
54   | extern int NDECL(doprgold); /**/
55   | extern int NDECL(doprwep); /**/
56   | extern int NDECL(doprarm); /**/
57   | extern int NDECL(doprring); /**/
58   | extern int NDECL(dopramulet); /**/
59   | extern int NDECL(doprtool); /**/
60   | extern int NDECL(dosuspend); /**/
61   | extern int NDECL(doforce); /**/
62   | extern int NDECL(doopen); /**/
63   | extern int NDECL(doclose); /**/
64   | extern int NDECL(dosh); /**/
65   | extern int NDECL(dodiscovered); /**/
66   | extern int NDECL(doset); /**/
67   | extern int NDECL(dotogglepickup); /**/
68   | extern int NDECL(dowhatis); /**/
69   | extern int NDECL(doquickwhatis); /**/
70   | extern int NDECL(dowhatdoes); /**/
71   | extern int NDECL(dohelp); /**/
72   | extern int NDECL(dohistory); /**/
73   | extern int NDECL(doloot); /**/
74   | extern int NDECL(dodrink); /**/
75   | extern int NDECL(dodip); /**/
76   | extern int NDECL(dosacrifice); /**/
77   | extern int NDECL(dopray); /**/
78   | extern int NDECL(doturn); /**/
79   | extern int NDECL(doredraw); /**/
80   | extern int NDECL(doread); /**/
81   | extern int NDECL(dosave); /**/
82   | extern int NDECL(dosearch); /**/
83   | extern int NDECL(doidtrap); /**/
84   | extern int NDECL(dopay); /**/
85   | extern int NDECL(dosit); /**/
86   | extern int NDECL(dotalk); /**/
87   | extern int NDECL(docast); /**/
88   | extern int NDECL(dovspell); /**/
89   | extern int NDECL(dotele); /**/
90   | extern int NDECL(dountrap); /**/
91   | extern int NDECL(doversion); /**/
92   | extern int NDECL(doextversion); /**/
93   | extern int NDECL(doswapweapon); /**/
94   | extern int NDECL(dowield); /**/
95   | extern int NDECL(dowieldquiver); /**/
96   | extern int NDECL(dozap); /**/
97   | extern int NDECL(doorganize); /**/
98   | #endif /* DUMB */
99   | 
100  | #ifdef OVL1
101  | static int NDECL((*timed_occ_fn));
102  | #endif /* OVL1 */
103  | 
104  | STATIC_PTR int NDECL(doprev_message);
105  | STATIC_PTR int NDECL(timed_occupation);
106  | STATIC_PTR int NDECL(doextcmd);
107  | STATIC_PTR int NDECL(domonability);
108  | # ifdef WIZARD
109  | STATIC_PTR int NDECL(wiz_wish);
110  | STATIC_PTR int NDECL(wiz_identify);
111  | STATIC_PTR int NDECL(wiz_map);
112  | STATIC_PTR int NDECL(wiz_genesis);
113  | STATIC_PTR int NDECL(wiz_where);
114  | STATIC_PTR int NDECL(wiz_detect);
115  | STATIC_PTR int NDECL(wiz_level_tele);
116  | STATIC_PTR int NDECL(wiz_show_seenv);
117  | STATIC_PTR int NDECL(wiz_show_vision);
118  | STATIC_PTR int NDECL(wiz_show_wmodes);
119  | #ifdef __BORLANDC__
120  | extern void FDECL(show_borlandc_stats, (winid));
121  | #endif
122  | STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P));
123  | STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *));
124  | STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *));
125  | STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *));
126  | STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *));
127  | STATIC_PTR int NDECL(wiz_show_stats);
128  | # endif
129  | STATIC_PTR int NDECL(enter_explore_mode);
130  | STATIC_PTR int NDECL(doattributes);
131  | STATIC_PTR int NDECL(doconduct); /**/
132  | STATIC_PTR void NDECL(minimal_enlightenment);
133  | 
134  | #ifdef OVLB
135  | STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *));
136  | #ifdef UNIX
137  | static void NDECL(end_of_input);
138  | #endif
139  | #endif /* OVLB */
140  | 
141  | STATIC_DCL char *NDECL(parse);
142  | 
143  | #ifdef OVL1
144  | 
145  | STATIC_PTR int
146  | doprev_message()
147  | {
148  |     return nh_doprev_message();
149  | }
150  | 
151  | /* Count down by decrementing multi */
152  | STATIC_PTR int
153  | timed_occupation()
154  | {
155  | 	(*timed_occ_fn)();
156  | 	if (multi > 0)
157  | 		multi--;
158  | 	return multi > 0;
159  | }
160  | 
161  | /* If you have moved since initially setting some occupations, they
162  |  * now shouldn't be able to restart.
163  |  *
164  |  * The basic rule is that if you are carrying it, you can continue
165  |  * since it is with you.  If you are acting on something at a distance,
166  |  * your orientation to it must have changed when you moved.
167  |  *
168  |  * The exception to this is taking off items, since they can be taken
169  |  * off in a number of ways in the intervening time, screwing up ordering.
170  |  *
171  |  *	Currently:	Take off all armor.
172  |  *			Picking Locks / Forcing Chests.
173  |  *			Setting traps.
174  |  */
175  | void
176  | reset_occupations()
177  | {
178  | 	reset_remarm();
179  | 	reset_pick();
180  | 	reset_trapset();
181  | }
182  | 
183  | /* If a time is given, use it to timeout this function, otherwise the
184  |  * function times out by its own means.
185  |  */
186  | void
187  | set_occupation(fn, txt, xtime)
188  | int NDECL((*fn));
189  | const char *txt;
190  | int xtime;
191  | {
192  | 	if (xtime) {
193  | 		occupation = timed_occupation;
194  | 		timed_occ_fn = fn;
195  | 	} else
196  | 		occupation = fn;
197  | 	occtxt = txt;
198  | 	occtime = 0;
199  | 	return;
200  | }
201  | 
202  | #ifdef REDO
203  | 
204  | static char NDECL(popch);
205  | 
206  | /* Provide a means to redo the last command.  The flag `in_doagain' is set
207  |  * to true while redoing the command.  This flag is tested in commands that
208  |  * require additional input (like `throw' which requires a thing and a
209  |  * direction), and the input prompt is not shown.  Also, while in_doagain is
210  |  * TRUE, no keystrokes can be saved into the saveq.
211  |  */
212  | #define BSIZE 20
213  | static char pushq[BSIZE], saveq[BSIZE];
214  | static NEARDATA int phead, ptail, shead, stail;
215  | 
216  | static char
217  | popch() {
218  | 	/* If occupied, return '\0', letting tgetch know a character should
219  | 	 * be read from the keyboard.  If the character read is not the
220  | 	 * ABORT character (as checked in pcmain.c), that character will be
221  | 	 * pushed back on the pushq.
222  | 	 */
223  | 	if (occupation) return '\0';
224  | 	if (in_doagain) return(char)((shead != stail) ? saveq[stail++] : '\0');
225  | 	else		return(char)((phead != ptail) ? pushq[ptail++] : '\0');
226  | }
227  | 
228  | char
229  | pgetchar() {		/* curtesy of aeb@cwi.nl */
230  | 	register int ch;
231  | 
232  | 	if(!(ch = popch()))
233  | 		ch = nhgetch();
234  | 	return((char)ch);
235  | }
236  | 
237  | /* A ch == 0 resets the pushq */
238  | void
239  | pushch(ch)
240  | char ch;
241  | {
242  | 	if (!ch)
243  | 		phead = ptail = 0;
244  | 	if (phead < BSIZE)
245  | 		pushq[phead++] = ch;
246  | 	return;
247  | }
248  | 
249  | /* A ch == 0 resets the saveq.	Only save keystrokes when not
250  |  * replaying a previous command.
251  |  */
252  | void
253  | savech(ch)
254  | char ch;
255  | {
256  | 	if (!in_doagain) {
257  | 		if (!ch)
258  | 			phead = ptail = shead = stail = 0;
259  | 		else if (shead < BSIZE)
260  | 			saveq[shead++] = ch;
261  | 	}
262  | 	return;
263  | }
264  | #endif /* REDO */
265  | 
266  | #endif /* OVL1 */
267  | #ifdef OVLB
268  | 
269  | STATIC_PTR int
270  | doextcmd()	/* here after # - now read a full-word command */
271  | {
272  | 	int idx, retval;
273  | 
274  | 	/* keep repeating until we don't run help or quit */
275  | 	do {
276  | 	    idx = get_ext_cmd();
277  | 	    if (idx < 0) return 0;	/* quit */
278  | 
279  | 	    retval = (*extcmdlist[idx].ef_funct)();
280  | 	} while (extcmdlist[idx].ef_funct == doextlist);
281  | 
282  | 	return retval;
283  | }
284  | 
285  | int
286  | doextlist()	/* here after #? - now list all full-word commands */
287  | {
288  | 	register const struct ext_func_tab *efp;
289  | 	char	 buf[BUFSZ];
290  | 	winid datawin;
291  | 
292  | 	datawin = create_nhwindow(NHW_TEXT);
293  | 	putstr(datawin, 0, "");
294  | 	putstr(datawin, 0, "            Extended Commands List");
295  | 	putstr(datawin, 0, "");
296  | 	putstr(datawin, 0, "    Press '#', then type:");
297  | 	putstr(datawin, 0, "");
298  | 
299  | 	for(efp = extcmdlist; efp->ef_txt; efp++) {
300  | 		Sprintf(buf, "    %-14s  - %s.", efp->ef_txt, efp->ef_desc);
301  | 		putstr(datawin, 0, buf);
302  | 	}
303  | 	display_nhwindow(datawin, FALSE);
304  | 	destroy_nhwindow(datawin);
305  | 	return 0;
306  | }
307  | 
308  | #ifdef TTY_GRAPHICS
309  | #define MAX_EXT_CMD 40		/* Change if we ever have > 40 ext cmds */
310  | /*
311  |  * This is currently used only by the tty port and is
312  |  * controlled via runtime option 'extmenu'
313  |  */
314  | int
315  | extcmd_via_menu()	/* here after # - now show pick-list of possible commands */
316  | {
317  |     const struct ext_func_tab *efp;
318  |     menu_item *pick_list = (menu_item *)0;
319  |     winid win;
320  |     anything any;
321  |     const struct ext_func_tab *choices[MAX_EXT_CMD];
322  |     char buf[BUFSZ];
323  |     char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20];
324  |     int i, n, nchoices, acount;
325  |     int ret,  biggest;
326  |     int accelerator, prevaccelerator;
327  |     int  matchlevel = 0;
328  | 
329  |     ret = 0;
330  |     cbuf[0] = '\0';
331  |     biggest = 0;
332  |     while (!ret) {
333  | 	    i = n = 0;
334  | 	    accelerator = 0;
335  | 	    any.a_void = 0;
336  | 	    /* populate choices */
337  | 	    for(efp = extcmdlist; efp->ef_txt; efp++) {
338  | 		if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) {
339  | 			choices[i++] = efp;
340  | 			if ((int)strlen(efp->ef_desc) > biggest) {
341  | 				biggest = strlen(efp->ef_desc);
342  | 				Sprintf(fmtstr,"%%-%ds", biggest + 15);
343  | 			}
344  | #ifdef DEBUG
345  | 			if (i >= MAX_EXT_CMD - 2) {
346  | 			    impossible("Exceeded %d extended commands in doextcmd() menu",
347  | 					MAX_EXT_CMD - 2);
348  | 			    return 0;
349  | 			}
350  | #endif
351  | 		}
352  | 	    }
353  | 	    choices[i] = (struct ext_func_tab *)0;
354  | 	    nchoices = i;
355  | 	    /* if we're down to one, we have our selection so get out of here */
356  | 	    if (nchoices == 1) {
357  | 		for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
358  | 			if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) {
359  | 				ret = i;
360  | 				break;
361  | 			}
362  | 		break;
363  | 	    }
364  | 
365  | 	    /* otherwise... */
366  | 	    win = create_nhwindow(NHW_MENU);
367  | 	    start_menu(win);
368  | 	    prevaccelerator = 0;
369  | 	    acount = 0;
370  | 	    for(i = 0; choices[i]; ++i) {
371  | 		accelerator = choices[i]->ef_txt[matchlevel];
372  | 		if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) {
373  | 		    if (acount) {
374  |  			/* flush the extended commands for that letter already in buf */
375  | 			Sprintf(buf, fmtstr, prompt);
376  | 			any.a_char = prevaccelerator;
377  | 			add_menu(win, NO_GLYPH, &any, any.a_char, 0,
378  | 					ATR_NONE, buf, FALSE);
379  | 			acount = 0;
380  | 		    }
381  | 		}
382  | 		prevaccelerator = accelerator;
383  | 		if (!acount || nchoices < (ROWNO - 3)) {
384  | 		    Sprintf(prompt, "%s [%s]", choices[i]->ef_txt,
385  | 				choices[i]->ef_desc);
386  | 		} else if (acount == 1) {
387  | 		    Sprintf(prompt, "%s or %s", choices[i-1]->ef_txt,
388  | 				choices[i]->ef_txt);
389  | 		} else {
390  | 		    Strcat(prompt," or ");
391  | 		    Strcat(prompt, choices[i]->ef_txt);
392  | 		}
393  | 		++acount;
394  | 	    }
395  | 	    if (acount) {
396  | 		/* flush buf */
397  | 		Sprintf(buf, fmtstr, prompt);
398  | 		any.a_char = prevaccelerator;
399  | 		add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE);
400  | 	    }
401  | 	    Sprintf(prompt, "Extended Command: %s", cbuf);
402  | 	    end_menu(win, prompt);
403  | 	    n = select_menu(win, PICK_ONE, &pick_list);
404  | 	    destroy_nhwindow(win);
405  | 	    if (n==1) {
406  | 		if (matchlevel > (QBUFSZ - 2)) {
407  | 			free((genericptr_t)pick_list);
408  | #ifdef DEBUG
409  | 			impossible("Too many characters (%d) entered in extcmd_via_menu()",
410  | 				matchlevel);
411  | #endif
412  | 			ret = -1;
413  | 		} else {
414  | 			cbuf[matchlevel++] = pick_list[0].item.a_char;
415  | 			cbuf[matchlevel] = '\0';
416  | 			free((genericptr_t)pick_list);
417  | 		}
418  | 	    } else {
419  | 		if (matchlevel) {
420  | 			ret = 0;
421  | 			matchlevel = 0;
422  | 		} else
423  | 			ret = -1;
424  | 	    }
425  |     }
426  |     return ret;
427  | }
428  | #endif
429  | 
430  | STATIC_PTR int
431  | domonability()
432  | {
433  | 	if (can_breathe(youmonst.data)) return dobreathe();
434  | 	else if (attacktype(youmonst.data, AT_SPIT)) return dospit();
435  | 	else if (youmonst.data->mlet == S_NYMPH) return doremove();
436  | 	else if (youmonst.data->mlet == S_UMBER) return doconfuse();
437  | 	else if (is_were(youmonst.data)) return dosummon();
438  | 	else if (webmaker(youmonst.data)) return dospinweb();
439  | 	else if (is_hider(youmonst.data)) return dohide();
440  | 	else if (is_mind_flayer(youmonst.data)) return domindblast();
441  | 	else if (u.umonnum == PM_GREMLIN) {
442  | 	    if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
443  | 		if (split_mon(&youmonst, (struct monst *)0))
444  | 		    dryup(u.ux, u.uy, TRUE);
445  | 	    } else There("is no fountain here.");
446  | 	} else if (is_unicorn(youmonst.data)) {
447  | 	    use_unicorn_horn((struct obj *)0);
448  | 	    return 1;
449  | 	} else if (youmonst.data->msound == MS_SHRIEK) {
450  | 	    You("shriek.");
451  | 	    if(u.uburied)
452  | 		pline("Unfortunately sound does not carry well through rock.");
453  | 	    else aggravate();
454  | 	} else if (Upolyd)
455  | 		pline("Any special ability you may have is purely reflexive.");
456  | 	else You("don't have a special ability in your normal form!");
457  | 	return 0;
458  | }
459  | 
460  | STATIC_PTR int
461  | enter_explore_mode()
462  | {
463  | 	if(!discover && !wizard) {
464  | 		pline("Beware!  From explore mode there will be no return to normal game.");
465  | 		if (yn("Do you want to enter explore mode?") == 'y') {
466  | 			clear_nhwindow(WIN_MESSAGE);
467  | 			You("are now in non-scoring explore mode.");
468  | 			discover = TRUE;
469  | 		}
470  | 		else {
471  | 			clear_nhwindow(WIN_MESSAGE);
472  | 			pline("Resuming normal game.");
473  | 		}
474  | 	}
475  | 	return 0;
476  | }
477  | 
478  | #ifdef WIZARD
479  | STATIC_PTR int
480  | wiz_wish()	/* Unlimited wishes for debug mode by Paul Polderman */
481  | {
482  | 	if (wizard) {
483  | 	    boolean save_verbose = flags.verbose;
484  | 
485  | 	    flags.verbose = FALSE;
486  | 	    makewish();
487  | 	    flags.verbose = save_verbose;
488  | 	    (void) encumber_msg();
489  | 	} else
490  | 	    pline("Unavailable command '^W'.");
491  | 	return 0;
492  | }
493  | 
494  | STATIC_PTR int
495  | wiz_identify()
496  | {
497  | 	if (wizard)	identify_pack(0);
498  | 	else		pline("Unavailable command '^I'.");
499  | 	return 0;
500  | }
501  | 
502  | /* reveal the level map and any traps on it */
503  | STATIC_PTR int
504  | wiz_map()
505  | {
506  | 	if (wizard) {
507  | 	    struct trap *t;
508  | 
509  | 	    for (t = ftrap; t != 0; t = t->ntrap) {
510  | 		t->tseen = 1;
511  | 		map_trap(t, TRUE);
512  | 	    }
513  | 	    do_mapping();
514  | 	} else
515  | 	    pline("Unavailable command '^F'.");
516  | 	return 0;
517  | }
518  | 
519  | STATIC_PTR int
520  | wiz_genesis()
521  | {
522  | 	if (wizard)	(void) create_particular();
523  | 	else		pline("Unavailable command '^G'.");
524  | 	return 0;
525  | }
526  | 
527  | STATIC_PTR int
528  | wiz_where()
529  | {
530  | 	if (wizard) print_dungeon();
531  | 	else	    pline("Unavailable command '^O'.");
532  | 	return 0;
533  | }
534  | 
535  | STATIC_PTR int
536  | wiz_detect()
537  | {
538  | 	if(wizard)  (void) findit();
539  | 	else	    pline("Unavailable command '^E'.");
540  | 	return 0;
541  | }
542  | 
543  | STATIC_PTR int
544  | wiz_level_tele()
545  | {
546  | 	if (wizard)	level_tele();
547  | 	else		pline("Unavailable command '^V'.");
548  | 	return 0;
549  | }
550  | 
551  | STATIC_PTR int
552  | wiz_show_seenv()
553  | {
554  | 	winid win;
555  | 	int x, y, v, startx, stopx, curx;
556  | 	char row[COLNO+1];
557  | 
558  | 	win = create_nhwindow(NHW_TEXT);
559  | 	/*
560  | 	 * Each seenv description takes up 2 characters, so center
561  | 	 * the seenv display around the hero.
562  | 	 */
563  | 	startx = max(1, u.ux-(COLNO/4));
564  | 	stopx = min(startx+(COLNO/2), COLNO);
565  | 	/* can't have a line exactly 80 chars long */
566  | 	if (stopx - startx == COLNO/2) startx++;
567  | 
568  | 	for (y = 0; y < ROWNO; y++) {
569  | 	    for (x = startx, curx = 0; x < stopx; x++, curx += 2) {
570  | 		if (x == u.ux && y == u.uy) {
571  | 		    row[curx] = row[curx+1] = '@';
572  | 		} else {
573  | 		    v = levl[x][y].seenv & 0xff;
574  | 		    if (v == 0)
575  | 			row[curx] = row[curx+1] = ' ';
576  | 		    else
577  | 			Sprintf(&row[curx], "%02x", v);
578  | 		}
579  | 	    }
580  | 	    /* remove trailing spaces */
581  | 	    for (x = curx-1; x >= 0; x--)
582  | 		if (row[x] != ' ') break;
583  | 	    row[x+1] = '\0';
584  | 
585  | 	    putstr(win, 0, row);
586  | 	}
587  | 	display_nhwindow(win, TRUE);
588  | 	destroy_nhwindow(win);
589  | 	return 0;
590  | }
591  | 
592  | STATIC_PTR int
593  | wiz_show_vision()
594  | {
595  | 	winid win;
596  | 	int x, y, v;
597  | 	char row[COLNO+1];
598  | 
599  | 	win = create_nhwindow(NHW_TEXT);
600  | 	Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit",
601  | 		COULD_SEE, IN_SIGHT, TEMP_LIT);
602  | 	putstr(win, 0, row);
603  | 	putstr(win, 0, "");
604  | 	for (y = 0; y < ROWNO; y++) {
605  | 	    for (x = 1; x < COLNO; x++) {
606  | 		if (x == u.ux && y == u.uy)
607  | 		    row[x] = '@';
608  | 		else {
609  | 		    v = viz_array[y][x]; /* data access should be hidden */
610  | 		    if (v == 0)
611  | 			row[x] = ' ';
612  | 		    else
613  | 			row[x] = '0' + viz_array[y][x];
614  | 		}
615  | 	    }
616  | 	    /* remove trailing spaces */
617  | 	    for (x = COLNO-1; x >= 1; x--)
618  | 		if (row[x] != ' ') break;
619  | 	    row[x+1] = '\0';
620  | 
621  | 	    putstr(win, 0, &row[1]);
622  | 	}
623  | 	display_nhwindow(win, TRUE);
624  | 	destroy_nhwindow(win);
625  | 	return 0;
626  | }
627  | 
628  | STATIC_PTR int
629  | wiz_show_wmodes()
630  | {
631  | 	winid win;
632  | 	int x,y;
633  | 	char row[COLNO+1];
634  | 	struct rm *lev;
635  | 
636  | 	win = create_nhwindow(NHW_TEXT);
637  | 	for (y = 0; y < ROWNO; y++) {
638  | 	    for (x = 0; x < COLNO; x++) {
639  | 		lev = &levl[x][y];
640  | 		if (x == u.ux && y == u.uy)
641  | 		    row[x] = '@';
642  | 		if (IS_WALL(lev->typ) || lev->typ == SDOOR)
643  | 		    row[x] = '0' + (lev->wall_info & WM_MASK);
644  | 		else if (lev->typ == CORR)
645  | 		    row[x] = '#';
646  | 		else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ))
647  | 		    row[x] = '.';
648  | 		else
649  | 		    row[x] = 'x';
650  | 	    }
651  | 	    row[COLNO] = '\0';
652  | 	    putstr(win, 0, row);
653  | 	}
654  | 	display_nhwindow(win, TRUE);
655  | 	destroy_nhwindow(win);
656  | 	return 0;
657  | }
658  | 
659  | #endif /* WIZARD */
660  | 
661  | 
662  | /* -enlightenment and conduct- */
663  | static winid en_win;
664  | static const char
665  | 	*You_ = "You ",
666  | 	*are  = "are ",  *were  = "were ",
667  | 	*have = "have ", *had   = "had ",
668  | 	*can  = "can ",  *could = "could ";
669  | static const char
670  | 	*have_been  = "have been ",
671  | 	*have_never = "have never ", *never = "never ";
672  | 
673  | #define enl_msg(prefix,present,past,suffix) \
674  | 			enlght_line(prefix, final ? past : present, suffix)
675  | #define you_are(attr)	enl_msg(You_,are,were,attr)
676  | #define you_have(attr)	enl_msg(You_,have,had,attr)
677  | #define you_can(attr)	enl_msg(You_,can,could,attr)
678  | #define you_have_been(goodthing) enl_msg(You_,have_been,were,goodthing)
679  | #define you_have_never(badthing) enl_msg(You_,have_never,never,badthing)
680  | #define you_have_X(something)	enl_msg(You_,have,(const char *)"",something)
681  | 
682  | static void
683  | enlght_line(start, middle, end)
684  | const char *start, *middle, *end;
685  | {
686  | 	char buf[BUFSZ];
687  | 
688  | 	Sprintf(buf, "%s%s%s.", start, middle, end);
689  | 	putstr(en_win, 0, buf);
690  | }
691  | 
692  | void
693  | enlightenment(final)
694  | int final;	/* 0 => still in progress; 1 => over, survived; 2 => dead */
695  | {
696  | 	int ltmp;
697  | 	char buf[BUFSZ];
698  | 
699  | 	en_win = create_nhwindow(NHW_MENU);
700  | 	putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:");
701  | 	putstr(en_win, 0, "");
702  | 
703  | #ifdef ELBERETH
704  | 	if (u.uevent.uhand_of_elbereth) {
705  | 	    static const char *hofe_titles[3] = {
706  | 				"the Hand of Elbereth",
707  | 				"the Envoy of Balance",
708  | 				"the Glory of Arioch"
709  | 	    };
710  | 	    you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1]);
711  | 	}
712  | #endif
713  | 
714  | 	/* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
715  | 	if (u.ualign.record >= 20)	you_are("piously aligned");
716  | 	else if (u.ualign.record > 13)	you_are("devoutly aligned");
717  | 	else if (u.ualign.record > 8)	you_are("fervently aligned");
718  | 	else if (u.ualign.record > 3)	you_are("stridently aligned");
719  | 	else if (u.ualign.record == 3)	you_are("aligned");
720  | 	else if (u.ualign.record > 0)	you_are("haltingly aligned");
721  | 	else if (u.ualign.record == 0)	you_are("nominally aligned");
722  | 	else if (u.ualign.record >= -3)	you_have("strayed");
723  | 	else if (u.ualign.record >= -8)	you_have("sinned");
724  | 	else you_have("transgressed");
725  | #ifdef WIZARD
726  | 	if (wizard) {
727  | 		Sprintf(buf, " %d", u.ualign.record);
728  | 		enl_msg("Your alignment ", "is", "was", buf);
729  | 	}
730  | #endif
731  | 
732  | 	/*** Resistances to troubles ***/
733  | 	if (Fire_resistance) you_are("fire resistant");
734  | 	if (Cold_resistance) you_are("cold resistant");
735  | 	if (Sleep_resistance) you_are("sleep resistant");
736  | 	if (Disint_resistance) you_are("disintegration-resistant");
737  | 	if (Shock_resistance) you_are("shock resistant");
738  | 	if (Poison_resistance) you_are("poison resistant");
739  | 	if (Drain_resistance) you_are("level-drain resistant");
740  | 	if (Sick_resistance) you_are("immune to sickness");
741  | 	if (Antimagic) you_are("magic-protected");
742  | 	if (Acid_resistance) you_are("acid resistant");
743  | 	if (Stone_resistance)
744  | 		you_are("petrification resistant");
745  | 	if (Invulnerable) you_are("invulnerable");
746  | 
747  | 	/*** Troubles ***/
748  | 	if (Halluc_resistance)
749  | 		enl_msg("You resist", "", "ed", " hallucinations");
750  | 	if (final) {
751  | 		if (Hallucination) you_are("hallucinating");
752  | 		if (Stunned) you_are("stunned");
753  | 		if (Confusion) you_are("confused");
754  | 		if (Blinded) you_are("blinded");
755  | 		if (Sick) {
756  | 			if (u.usick_type & SICK_VOMITABLE)
757  | 				you_are("sick from food poisoning");
758  | 			if (u.usick_type & SICK_NONVOMITABLE)
759  | 				you_are("sick from illness");
760  | 		}
761  | 	}
762  | 	if (Stoned) you_are("turning to stone");
763  | 	if (Slimed) you_are("turning into slime");
764  | 	if (Strangled) you_are((u.uburied) ? "buried" : "being strangled");
765  | 	if (Glib) {
766  | 		Sprintf(buf, "slippery %s", makeplural(body_part(FINGER)));
767  | 		you_have(buf);
768  | 	}
769  | 	if (Fumbling) enl_msg("You fumble", "", "d", "");
770  | 	if (Wounded_legs) {
771  | 		Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
772  | 		you_have(buf);
773  | 	}
774  | 	if (Sleeping) enl_msg("You ", "fall", "fell", " asleep");
775  | 	if (Hunger) enl_msg("You hunger", "", "ed", " rapidly");
776  | 
777  | 	/*** Vision and senses ***/
778  | 	if (See_invisible) enl_msg(You_, "see", "saw", " invisible");
779  | 	if (Blind_telepat) you_are("telepathic");
780  | 	if (Warning) you_are("warned");
781  | 	if (Warn_of_mon && flags.warntype) {
782  | 		Sprintf(buf, "aware of the presence of %s",
783  | 			(flags.warntype & M2_ORC) ? "orcs" :
784  | 			(flags.warntype & M2_DEMON) ? "demons" :
785  | 			something); 
786  | 		you_are(buf);
787  | 	}
788  | 	if (Undead_warning) you_are("warned of undead");
789  | 	if (Searching) you_have("automatic searching");
790  | 	if (Clairvoyant) you_are("clairvoyant");
791  | 	if (Infravision) you_have("infravision");
792  | 	if (Detect_monsters) you_are("sensing the presence of monsters");
793  | 
794  | 	/*** Appearance and behavior ***/
795  | 	if (Adornment) you_are("adorned");
796  | 	if (Invisible) you_are("invisible");
797  | 	else if (Invis) you_are("invisible to others");
798  | 	/* ordinarily "visible" is redundant; this is a special case for
799  | 	   the situation when invisibility would be an expected attribute */
800  | 	else if ((HInvis || EInvis || pm_invisible(youmonst.data)) && BInvis)
801  | 	    you_are("visible");
802  | 	if (Displaced) you_are("displaced");
803  | 	if (Stealth) you_are("stealthy");
804  | 	if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters");
805  | 	if (Conflict) enl_msg("You cause", "", "d", " conflict");
806  | 
807  | 	/*** Transportation ***/
808  | 	if (Jumping) you_can("jump");
809  | 	if (Teleportation) you_can("teleport");
810  | 	if (Teleport_control) you_have("teleport control");
811  | 	if (Lev_at_will) you_are("levitating, at will");
812  | 	else if (Levitation) you_are("levitating");	/* without control */
813  | 	else if (Flying) you_can("fly");
814  | 	if (Wwalking) you_can("walk on water");
815  | 	if (Swimming) you_can("swim");        
816  | 	if (Breathless) you_can("survive without air");
817  | 	else if (Amphibious) you_can("breathe water");
818  | 	if (Passes_walls) you_can("walk through walls");
819  | #ifdef STEED
820  | 	if (u.usteed) {
821  | 	    Sprintf(buf, "riding %s", y_monnam(u.usteed));
822  | 	    you_are(buf);
823  | 	}
824  | #endif
825  | 	if (u.uswallow) {
826  | 	    Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck));
827  | #ifdef WIZARD
828  | 	    if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim);
829  | #endif
830  | 	    you_are(buf);
831  | 	} else if (u.ustuck) {
832  | 	    Sprintf(buf, "%s %s",
833  | 		    (Upolyd && sticks(youmonst.data)) ? "holding" : "held by",
834  | 		    a_monnam(u.ustuck));
835  | 	    you_are(buf);
836  | 	}
837  | 
838  | 	/*** Physical attributes ***/
839  | 	if (Slow_digestion) you_have("slower digestion");
840  | 	if (Regeneration) enl_msg("You regenerate", "", "d", "");
841  | 	if (u.uspellprot || Protection) you_are("protected");
842  | 	if (Protection_from_shape_changers)
843  | 		you_are("protected from shape changers");
844  | 	if (Polymorph) you_are("polymorphing");
845  | 	if (Polymorph_control) you_have("polymorph control");
846  | 	if (u.ulycn >= LOW_PM) {
847  | 		Strcpy(buf, an(mons[u.ulycn].mname));
848  | 		you_are(buf);
849  | 	}
850  | 	if (Upolyd) {
851  | 	    if (u.ulycn >= LOW_PM) Strcpy(buf, "in beast form");
852  | 	    else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname));
853  | #ifdef WIZARD
854  | 	    if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone);
855  | #endif
856  | 	    you_are(buf);
857  | 	}
858  | 	if (Unchanging) you_can("not change from your current form");
859  | 	if (Fast) you_are(Very_fast ? "very fast" : "fast");
860  | 	if (Reflecting) you_have("reflection");
861  | 	if (Free_action) you_have("free action");
862  | 	if (Fixed_abil) you_have("fixed abilities");
863  | 	if (Lifesaved)
864  | 		enl_msg("Your life ", "will be", "would have been", " saved");
865  | 	if (u.twoweap) you_are("wielding two weapons at once");
866  | 
867  | 	/*** Miscellany ***/
868  | 	if (Luck) {
869  | 	    ltmp = abs((int)Luck);
870  | 	    Sprintf(buf, "%s%slucky",
871  | 		    ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
872  | 		    Luck < 0 ? "un" : "");
873  | #ifdef WIZARD
874  | 	    if (wizard) Sprintf(eos(buf), " (%d)", Luck);
875  | #endif
876  | 	    you_are(buf);
877  | 	}
878  | #ifdef WIZARD
879  | 	 else if (wizard) enl_msg("Your luck ", "is", "was", " zero");
880  | #endif
881  | 	if (u.moreluck > 0) you_have("extra luck");
882  | 	else if (u.moreluck < 0) you_have("reduced luck");
883  | 	if (carrying(LUCKSTONE) || stone_luck(TRUE)) {
884  | 	    ltmp = stone_luck(FALSE);
885  | 	    if (ltmp <= 0)
886  | 		enl_msg("Bad luck ", "does", "did", " not time out for you");
887  | 	    if (ltmp >= 0)
888  | 		enl_msg("Good luck ", "does", "did", " not time out for you");
889  | 	}
890  | 
891  | 	if (u.ugangr) {
892  | 	    Sprintf(buf, " %sangry with you",
893  | 		    u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : "");
894  | #ifdef WIZARD
895  | 	    if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr);
896  | #endif
897  | 	    enl_msg(u_gname(), " is", " was", buf);
898  | 	} else
899  | 	    /*
900  | 	     * We need to suppress this when the game is over, because death
901  | 	     * can change the value calculated by can_pray(), potentially
902  | 	     * resulting in a false claim that you could have prayed safely.
903  | 	     */
904  | 	  if (!final) {
905  | #if 0
906  | 	    /* "can [not] safely pray" vs "could [not] have safely prayed" */
907  | 	    Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ",
908  | 		    final ? "have " : "", final ? "ed" : "");
909  | #else
910  | 	    Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not ");
911  | #endif
912  | #ifdef WIZARD
913  | 	    if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt);
914  | #endif
915  | 	    you_can(buf);
916  | 	}
917  | 
918  |     {
919  | 	const char *p;
920  | 
921  | 	buf[0] = '\0';
922  | 	if (final < 2) {    /* still in progress, or quit/escaped/ascended */
923  | 	    p = "survived after being killed ";
924  | 	    switch (u.umortality) {
925  | 	    case 0:  p = !final ? (char *)0 : "survived";  break;
926  | 	    case 1:  Strcpy(buf, "once");  break;
927  | 	    case 2:  Strcpy(buf, "twice");  break;
928  | 	    case 3:  Strcpy(buf, "thrice");  break;
929  | 	    default: Sprintf(buf, "%d times", u.umortality);
930  | 		     break;
931  | 	    }
932  | 	} else {		/* game ended in character's death */
933  | 	    p = "are dead";
934  | 	    switch (u.umortality) {
935  | 	    case 0:  impossible("dead without dying?");
936  | 	    case 1:  break;			/* just "are dead" */
937  | 	    default: Sprintf(buf, " (%d%s time!)", u.umortality,
938  | 			     ordin(u.umortality));
939  | 		     break;
940  | 	    }
941  | 	}
942  | 	if (p) enl_msg(You_, "have been killed ", p, buf);
943  |     }
944  | 
945  | 	display_nhwindow(en_win, TRUE);
946  | 	destroy_nhwindow(en_win);
947  | 	return;
948  | }
949  | 
950  | /*
951  |  * Courtesy function for non-debug, non-explorer mode players
952  |  * to help refresh them about who/what they are.
953  |  */
954  | STATIC_OVL void
955  | minimal_enlightenment()
956  | {
957  | 	winid tmpwin;
958  | 	menu_item *selected;
959  | 	anything any;
960  | 	char buf[BUFSZ], buf2[BUFSZ];
961  | 	static char fmtstr[] = "%-15s: %-12s";
962  | 
963  | 	any.a_void = 0;
964  | 	buf[0] = buf2[0] = '\0';
965  | 	tmpwin = create_nhwindow(NHW_MENU);
966  | 	start_menu(tmpwin);
967  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Starting", FALSE);
968  | 
969  | 	/* Starting name, race, role, gender */
970  | 	Sprintf(buf, fmtstr, "name", plname);
971  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
972  | 	Sprintf(buf, fmtstr, "race", urace.noun);
973  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
974  | 	Sprintf(buf, fmtstr, "role",
975  | 		(flags.initgend && urole.name.f) ? urole.name.f : urole.name.m);
976  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
977  | 	Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj);
978  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
979  | 
980  | 	/* Starting alignment */
981  | 	Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL]));
982  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
983  | 
984  | 	/* Current name, race, role, gender */
985  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
986  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Current", FALSE);
987  | 	Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun);
988  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
989  | 	if (!Upolyd) {
990  | 	    Sprintf(buf, fmtstr, "role",
991  | 		(flags.female && urole.name.f) ? urole.name.f : urole.name.m);
992  | 	    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
993  | 	}
994  | 	Sprintf(buf, fmtstr, "gender", genders[poly_gender()].adj);
995  | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
996  | 
997  | 	if (Upolyd) {
998  | 	    Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj);
999  | 	    add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1000 | 	}
1001 | 
1002 | 	/* Current alignment */
1003 | 	Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type));
1004 | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1005 | 
1006 | 	/* Deity list */
1007 | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE);
1008 | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, "Deities", FALSE);
1009 | 	Sprintf(buf2, "%-17s%s", align_gname(A_CHAOTIC),
1010 | 	    (u.ualignbase[A_ORIGINAL] == u.ualign.type
1011 | 		&& u.ualign.type == A_CHAOTIC) ? " (s,c)" :
1012 | 	    (u.ualignbase[A_ORIGINAL] == A_CHAOTIC)       ? " (s)" :
1013 | 	    (u.ualign.type   == A_CHAOTIC)       ? " (c)" : "");
1014 |     	Sprintf(buf, fmtstr, "chaotic deity", buf2);
1015 | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1016 | 
1017 | 	Sprintf(buf2, "%-17s%s", align_gname(A_NEUTRAL),
1018 | 	    (u.ualignbase[A_ORIGINAL] == u.ualign.type
1019 | 		&& u.ualign.type == A_NEUTRAL) ? " (s,c)" :
1020 | 	    (u.ualignbase[A_ORIGINAL] == A_NEUTRAL)       ? " (s)" :
1021 | 	    (u.ualign.type   == A_NEUTRAL)       ? " (c)" : "");
1022 |     	Sprintf(buf, fmtstr, "neutral deity", buf2);
1023 | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1024 | 
1025 | 	Sprintf(buf2, "%-17s%s", align_gname(A_LAWFUL),
1026 | 	    (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_LAWFUL)  ? " (s,c)" :
1027 | 	    (u.ualignbase[A_ORIGINAL] == A_LAWFUL)        ? " (s)" :
1028 | 	    (u.ualign.type   == A_LAWFUL)        ? " (c)" : "");
1029 |     	Sprintf(buf, fmtstr, "lawful  deity", buf2);
1030 | 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
1031 | 
1032 | 	end_menu(tmpwin, "Base Attributes");
1033 | 	(void) select_menu(tmpwin, PICK_NONE, &selected);
1034 | 	destroy_nhwindow(tmpwin);
1035 | }
1036 | 
1037 | STATIC_PTR int
1038 | doattributes()
1039 | {
1040 | 	minimal_enlightenment();
1041 | 	if (wizard || discover)
1042 | 		enlightenment(0);
1043 | 	return 0;
1044 | }
1045 | 
1046 | /* KMH, #conduct
1047 |  * (shares enlightenment's tense handling)
1048 |  */
1049 | STATIC_PTR int
1050 | doconduct()
1051 | {
1052 | 	show_conduct(0);
1053 | 	return 0;
1054 | }
1055 | 
1056 | void
1057 | show_conduct(final)
1058 | int final;
1059 | {
1060 | 	char buf[BUFSZ];
1061 | 	int ngenocided;
1062 | 
1063 | 	/* Create the conduct window */
1064 | 	en_win = create_nhwindow(NHW_MENU);
1065 | 	putstr(en_win, 0, "Voluntary challenges:");
1066 | 	putstr(en_win, 0, "");
1067 | 
1068 | 	if (!u.uconduct.food)
1069 | 	    enl_msg(You_, "have gone", "went", " without food");
1070 | 	    /* But beverages are okay */
1071 | 	else if (!u.uconduct.unvegan)
1072 | 	    you_have_X("followed a strict vegan diet");
1073 | 	else if (!u.uconduct.unvegetarian)
1074 | 	    you_have_been("vegetarian");
1075 | 
1076 | 	if (!u.uconduct.gnostic)
1077 | 	    you_have_been("an atheist");
1078 | 
1079 | 	if (!u.uconduct.weaphit)
1080 | 	    you_have_never("hit with a wielded weapon");
1081 | #ifdef WIZARD
1082 | 	else if (wizard) {
1083 | 	    Sprintf(buf, "used a wielded weapon %ld time%s",
1084 | 		    u.uconduct.weaphit, plur(u.uconduct.weaphit));
1085 | 	    you_have_X(buf);
1086 | 	}
1087 | #endif
1088 | 	if (!u.uconduct.killer)
1089 | 	    you_have_been("a pacifist");
1090 | 
1091 | 	if (!u.uconduct.literate)
1092 | 	    you_have_been("illiterate");
1093 | #ifdef WIZARD
1094 | 	else if (wizard) {
1095 | 	    Sprintf(buf, "read items or engraved %ld time%s",
1096 | 		    u.uconduct.literate, plur(u.uconduct.literate));
1097 | 	    you_have_X(buf);
1098 | 	}
1099 | #endif
1100 | 
1101 | 	ngenocided = num_genocides();
1102 | 	if (ngenocided == 0) {
1103 | 	    you_have_never("genocided any monsters");
1104 | 	} else {
1105 | 	    Sprintf(buf, "genocided %d type%s of monster%s",
1106 | 		    ngenocided, plur(ngenocided), plur(ngenocided));
1107 | 	    you_have_X(buf);
1108 | 	}
1109 | 
1110 | 	if (!u.uconduct.polypiles)
1111 | 	    you_have_never("polymorphed an object");
1112 | #ifdef WIZARD
1113 | 	else if (wizard) {
1114 | 	    Sprintf(buf, "polymorphed %ld item%s",
1115 | 		    u.uconduct.polypiles, plur(u.uconduct.polypiles));
1116 | 	    you_have_X(buf);
1117 | 	}
1118 | #endif
1119 | 
1120 | 	if (!u.uconduct.polyselfs)
1121 | 	    you_have_never("changed form");
1122 | #ifdef WIZARD
1123 | 	else if (wizard) {
1124 | 	    Sprintf(buf, "changed form %ld time%s",
1125 | 		    u.uconduct.polyselfs, plur(u.uconduct.polyselfs));
1126 | 	    you_have_X(buf);
1127 | 	}
1128 | #endif
1129 | 
1130 | 	if (!u.uconduct.wishes)
1131 | 	    you_have_X("used no wishes");
1132 | 	else {
1133 | 	    Sprintf(buf, "used %ld wish%s",
1134 | 		    u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : "");
1135 | 	    you_have_X(buf);
1136 | 
1137 | 	    if (!u.uconduct.wisharti)
1138 | 		enl_msg(You_, "have not wished", "did not wish",
1139 | 			" for any artifacts");
1140 | 	}
1141 | 
1142 | 	/* Pop up the window and wait for a key */
1143 | 	display_nhwindow(en_win, TRUE);
1144 | 	destroy_nhwindow(en_win);
1145 | }
1146 | 
1147 | #endif /* OVLB */
1148 | #ifdef OVL1
1149 | 
1150 | #ifndef M
1151 | # ifndef NHSTDC
1152 | #  define M(c)		(0x80 | (c))
1153 | # else
1154 | #  define M(c)		((c) - 128)
1155 | # endif /* NHSTDC */
1156 | #endif
1157 | #ifndef C
1158 | #define C(c)		(0x1f & (c))
1159 | #endif
1160 | 
1161 | static const struct func_tab cmdlist[] = {
1162 | 	{C('d'), FALSE, dokick}, /* "D" is for door!...?  Msg is in dokick.c */
1163 | #ifdef WIZARD
1164 | 	{C('e'), TRUE, wiz_detect},
1165 | 	{C('f'), TRUE, wiz_map},
1166 | 	{C('g'), TRUE, wiz_genesis},
1167 | 	{C('i'), TRUE, wiz_identify},
1168 | #endif
1169 | 	{C('l'), TRUE, doredraw}, /* if number_pad is set */
1170 | #ifdef WIZARD
1171 | 	{C('o'), TRUE, wiz_where},
1172 | #endif
1173 | 	{C('p'), TRUE, doprev_message},
1174 | 	{C('r'), TRUE, doredraw},
1175 | 	{C('t'), TRUE, dotele},
1176 | #ifdef WIZARD
1177 | 	{C('v'), TRUE, wiz_level_tele},
1178 | 	{C('w'), TRUE, wiz_wish},
1179 | #endif
1180 | 	{C('x'), TRUE, doattributes},
1181 | #ifdef SUSPEND
1182 | 	{C('z'), TRUE, dosuspend},
1183 | #endif
1184 | 	{'a', FALSE, doapply},
1185 | 	{'A', FALSE, doddoremarm},
1186 | 	{M('a'), TRUE, doorganize},
1187 | /*	'b', 'B' : go sw */
1188 | 	{'c', FALSE, doclose},
1189 | 	{'C', TRUE, do_mname},
1190 | 	{M('c'), TRUE, dotalk},
1191 | 	{'d', FALSE, dodrop},
1192 | 	{'D', FALSE, doddrop},
1193 | 	{M('d'), FALSE, dodip},
1194 | 	{'e', FALSE, doeat},
1195 | 	{'E', FALSE, doengrave},
1196 | 	{M('e'), TRUE, enhance_weapon_skill},
1197 | 	{'f', FALSE, dofire},
1198 | /*	'F' : fight (one time) */
1199 | 	{M('f'), FALSE, doforce},
1200 | /*	'g', 'G' : multiple go */
1201 | /*	'h', 'H' : go west */
1202 | 	{'h', TRUE, dohelp}, /* if number_pad is set */
1203 | 	{'i', TRUE, ddoinv},
1204 | 	{'I', TRUE, dotypeinv},		/* Robert Viduya */
1205 | 	{M('i'), TRUE, doinvoke},
1206 | /*	'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */
1207 | 	{'j', FALSE, dojump}, /* if number_pad is on */
1208 | 	{M('j'), FALSE, dojump},
1209 | 	{'k', FALSE, dokick}, /* if number_pad is on */
1210 | 	{'l', FALSE, doloot}, /* if number_pad is on */
1211 | 	{M('l'), FALSE, doloot},
1212 | /*	'n' prefixes a count if number_pad is on */
1213 | 	{M('m'), TRUE, domonability},
1214 | 	{'N', TRUE, ddocall}, /* if number_pad is on */
1215 | 	{M('n'), TRUE, ddocall},
1216 | 	{M('N'), TRUE, ddocall},
1217 | 	{'o', FALSE, doopen},
1218 | 	{'O', TRUE, doset},
1219 | 	{M('o'), FALSE, dosacrifice},
1220 | 	{'p', FALSE, dopay},
1221 | 	{'P', FALSE, doputon},
1222 | 	{M('p'), TRUE, dopray},
1223 | 	{'q', FALSE, dodrink},
1224 | 	{'Q', FALSE, dowieldquiver},
1225 | 	{M('q'), TRUE, done2},
1226 | 	{'r', FALSE, doread},
1227 | 	{'R', FALSE, doremring},
1228 | 	{M('r'), FALSE, dorub},
1229 | 	{'s', TRUE, dosearch, "searching"},
1230 | 	{'S', TRUE, dosave},
1231 | 	{M('s'), FALSE, dosit},
1232 | 	{'t', FALSE, dothrow},
1233 | 	{'T', FALSE, dotakeoff},
1234 | 	{M('t'), TRUE, doturn},
1235 | /*	'u', 'U' : go ne */
1236 | 	{'u', FALSE, dountrap}, /* if number_pad is on */
1237 | 	{M('u'), FALSE, dountrap},
1238 | 	{'v', TRUE, doversion},
1239 | 	{'V', TRUE, dohistory},
1240 | 	{M('v'), TRUE, doextversion},
1241 | 	{'w', FALSE, dowield},
1242 | 	{'W', FALSE, dowear},
1243 | 	{M('w'), FALSE, dowipe},
1244 | 	{'x', FALSE, doswapweapon},
1245 | 	{'X', TRUE, enter_explore_mode},
1246 | /*	'y', 'Y' : go nw */
1247 | 	{'z', FALSE, dozap},
1248 | 	{'Z', TRUE, docast},
1249 | 	{'<', FALSE, doup},
1250 | 	{'>', FALSE, dodown},
1251 | 	{'/', TRUE, dowhatis},
1252 | 	{'&', TRUE, dowhatdoes},
1253 | 	{'?', TRUE, dohelp},
1254 | 	{M('?'), TRUE, doextlist},
1255 | #ifdef SHELL
1256 | 	{'!', TRUE, dosh},
1257 | #endif
1258 | 	{'.', TRUE, donull, "waiting"},
1259 | 	{' ', TRUE, donull, "waiting"},
1260 | 	{',', FALSE, dopickup},
1261 | 	{':', TRUE, dolook},
1262 | 	{';', TRUE, doquickwhatis},
1263 | 	{'^', TRUE, doidtrap},
1264 | 	{'\\', TRUE, dodiscovered},		/* Robert Viduya */
1265 | 	{'@', TRUE, dotogglepickup},
1266 | 	{M('2'), FALSE, dotwoweapon},
1267 | 	{WEAPON_SYM,  TRUE, doprwep},
1268 | 	{ARMOR_SYM,  TRUE, doprarm},
1269 | 	{RING_SYM,  TRUE, doprring},
1270 | 	{AMULET_SYM, TRUE, dopramulet},
1271 | 	{TOOL_SYM, TRUE, doprtool},
1272 | 	{'*', TRUE, doprinuse},	/* inventory of all equipment in use */
1273 | 	{GOLD_SYM, TRUE, doprgold},
1274 | 	{SPBOOK_SYM, TRUE, dovspell},			/* Mike Stephenson */
1275 | 	{'#', TRUE, doextcmd},
1276 | 	{0,0,0,0}
1277 | };
1278 | 
1279 | struct ext_func_tab extcmdlist[] = {
1280 | 	{"adjust", "adjust inventory letters", doorganize, TRUE},
1281 | 	{"chat", "talk to someone", dotalk, TRUE},	/* converse? */
1282 | 	{"conduct", "list which challenges you have adhered to", doconduct, TRUE},
1283 | 	{"dip", "dip an object into something", dodip, FALSE},
1284 | 	{"enhance", "advance or check weapons skills", enhance_weapon_skill,
1285 | 							TRUE},
1286 | 	{"force", "force a lock", doforce, FALSE},
1287 | 	{"invoke", "invoke an object's powers", doinvoke, TRUE},
1288 | 	{"jump", "jump to a location", dojump, FALSE},
1289 | 	{"loot", "loot a box on the floor", doloot, FALSE},
1290 | 	{"monster", "use a monster's special ability", domonability, TRUE},
1291 | 	{"name", "name an item or type of object", ddocall, TRUE},
1292 | 	{"offer", "offer a sacrifice to the gods", dosacrifice, FALSE},
1293 | 	{"pray", "pray to the gods for help", dopray, TRUE},
1294 | 	{"quit", "exit without saving current game", done2, TRUE},
1295 | #ifdef STEED
1296 | 	{"ride", "ride (or stop riding) a monster", doride, FALSE},
1297 | #endif
1298 | 	{"rub", "rub a lamp", dorub, FALSE},
1299 | 	{"sit", "sit down", dosit, FALSE},
1300 | 	{"turn", "turn undead", doturn, TRUE},
1301 | 	{"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE},
1302 | 	{"untrap", "untrap something", dountrap, FALSE},
1303 | 	{"version", "list compile time options for this version of NetHack",
1304 | 		doextversion, TRUE},
1305 | 	{"wipe", "wipe off your face", dowipe, FALSE},
1306 | 	{"?", "get this list of extended commands", doextlist, TRUE},
1307 | #if defined(WIZARD)
1308 | 	/*
1309 | 	 * There must be a blank entry here for every entry in the table
1310 | 	 * below.
1311 | 	 */
1312 | 	{(char *)0, (char *)0, donull, TRUE},
1313 | 	{(char *)0, (char *)0, donull, TRUE},
1314 | 	{(char *)0, (char *)0, donull, TRUE},
1315 | 	{(char *)0, (char *)0, donull, TRUE},
1316 | 	{(char *)0, (char *)0, donull, TRUE},
1317 | #ifdef DEBUG
1318 | 	{(char *)0, (char *)0, donull, TRUE},
1319 | #endif
1320 | 	{(char *)0, (char *)0, donull, TRUE},
1321 | #endif
1322 | 	{(char *)0, (char *)0, donull, TRUE}	/* sentinel */
1323 | };
1324 | 
1325 | #if defined(WIZARD)
1326 | static const struct ext_func_tab debug_extcmdlist[] = {
1327 | 	{"light sources", "show mobile light sources", wiz_light_sources, TRUE},
1328 | 	{"seenv", "show seen vectors", wiz_show_seenv, TRUE},
1329 | 	{"stats", "show memory statistics", wiz_show_stats, TRUE},
1330 | 	{"timeout", "look at timeout queue", wiz_timeout_queue, TRUE},
1331 | 	{"vision", "show vision array", wiz_show_vision, TRUE},
1332 | #ifdef DEBUG
1333 | 	{"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE},
1334 | #endif
1335 | 	{"wmode", "show wall modes", wiz_show_wmodes, TRUE},
1336 | 	{(char *)0, (char *)0, donull, TRUE}
1337 | };
1338 | 
1339 | /*
1340 |  * Insert debug commands into the extended command list.  This function
1341 |  * assumes that the last entry will be the help entry.
1342 |  *
1343 |  * You must add entries in ext_func_tab every time you add one to the
1344 |  * debug_extcmdlist().
1345 |  */
1346 | void
1347 | add_debug_extended_commands()
1348 | {
1349 | 	int i, j, k, n;
1350 | 
1351 | 	/* count the # of help entries */
1352 | 	for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++)
1353 | 	    ;
1354 | 
1355 | 	for (i = 0; debug_extcmdlist[i].ef_txt; i++) {
1356 | 	    for (j = 0; j < n; j++)
1357 | 		if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break;
1358 | 
1359 | 	    /* insert i'th debug entry into extcmdlist[j], pushing down  */
1360 | 	    for (k = n; k >= j; --k)
1361 | 		extcmdlist[k+1] = extcmdlist[k];
1362 | 	    extcmdlist[j] = debug_extcmdlist[i];
1363 | 	    n++;	/* now an extra entry */
1364 | 	}
1365 | }
1366 | 
1367 | 
1368 | static const char *template = "%-18s %4ld  %6ld";
1369 | static const char *count_str = "                   count  bytes";
1370 | static const char *separator = "------------------ -----  ------";
1371 | 
1372 | STATIC_OVL void
1373 | count_obj(chain, total_count, total_size, top, recurse)
1374 | 	struct obj *chain;
1375 | 	long *total_count;
1376 | 	long *total_size;
1377 | 	boolean top;
1378 | 	boolean recurse;
1379 | {
1380 | 	long count, size;
1381 | 	struct obj *obj;
1382 | 
1383 | 	for (count = size = 0, obj = chain; obj; obj = obj->nobj) {
1384 | 	    if (top) {
1385 | 		count++;
1386 | 		size += sizeof(struct obj) + obj->oxlth + obj->onamelth;
1387 | 	    }
1388 | 	    if (recurse && obj->cobj)
1389 | 		count_obj(obj->cobj, total_count, total_size, TRUE, TRUE);
1390 | 	}
1391 | 	*total_count += count;
1392 | 	*total_size += size;
1393 | }
1394 | 
1395 | STATIC_OVL void
1396 | obj_chain(win, src, chain, total_count, total_size)
1397 | 	winid win;
1398 | 	const char *src;
1399 | 	struct obj *chain;
1400 | 	long *total_count;
1401 | 	long *total_size;
1402 | {
1403 | 	char buf[BUFSZ];
1404 | 	long count = 0, size = 0;
1405 | 
1406 | 	count_obj(chain, &count, &size, TRUE, FALSE);
1407 | 	*total_count += count;
1408 | 	*total_size += size;
1409 | 	Sprintf(buf, template, src, count, size);
1410 | 	putstr(win, 0, buf);
1411 | }
1412 | 
1413 | STATIC_OVL void
1414 | mon_invent_chain(win, src, chain, total_count, total_size)
1415 | 	winid win;
1416 | 	const char *src;
1417 | 	struct monst *chain;
1418 | 	long *total_count;
1419 | 	long *total_size;
1420 | {
1421 | 	char buf[BUFSZ];
1422 | 	long count = 0, size = 0;
1423 | 	struct monst *mon;
1424 | 
1425 | 	for (mon = chain; mon; mon = mon->nmon)
1426 | 	    count_obj(mon->minvent, &count, &size, TRUE, FALSE);
1427 | 	*total_count += count;
1428 | 	*total_size += size;
1429 | 	Sprintf(buf, template, src, count, size);
1430 | 	putstr(win, 0, buf);
1431 | }
1432 | 
1433 | STATIC_OVL void
1434 | contained(win, src, total_count, total_size)
1435 | 	winid win;
1436 | 	const char *src;
1437 | 	long *total_count;
1438 | 	long *total_size;
1439 | {
1440 | 	char buf[BUFSZ];
1441 | 	long count = 0, size = 0;
1442 | 	struct monst *mon;
1443 | 
1444 | 	count_obj(invent, &count, &size, FALSE, TRUE);
1445 | 	count_obj(fobj, &count, &size, FALSE, TRUE);
1446 | 	count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE);
1447 | 	count_obj(migrating_objs, &count, &size, FALSE, TRUE);
1448 | 	/* DEADMONSTER check not required in this loop since they have no inventory */
1449 | 	for (mon = fmon; mon; mon = mon->nmon)
1450 | 	    count_obj(mon->minvent, &count, &size, FALSE, TRUE);
1451 | 	for (mon = migrating_mons; mon; mon = mon->nmon)
1452 | 	    count_obj(mon->minvent, &count, &size, FALSE, TRUE);
1453 | 
1454 | 	*total_count += count; *total_size += size;
1455 | 
1456 | 	Sprintf(buf, template, src, count, size);
1457 | 	putstr(win, 0, buf);
1458 | }
1459 | 
1460 | STATIC_OVL void
1461 | mon_chain(win, src, chain, total_count, total_size)
1462 | 	winid win;
1463 | 	const char *src;
1464 | 	struct monst *chain;
1465 | 	long *total_count;
1466 | 	long *total_size;
1467 | {
1468 | 	char buf[BUFSZ];
1469 | 	long count, size;
1470 | 	struct monst *mon;
1471 | 
1472 | 	for (count = size = 0, mon = chain; mon; mon = mon->nmon) {
1473 | 	    count++;
1474 | 	    size += sizeof(struct monst) + mon->mxlth + mon->mnamelth;
1475 | 	}
1476 | 	*total_count += count;
1477 | 	*total_size += size;
1478 | 	Sprintf(buf, template, src, count, size);
1479 | 	putstr(win, 0, buf);
1480 | }
1481 | 
1482 | /*
1483 |  * Display memory usage of all monsters and objects on the level.
1484 |  */
1485 | static int
1486 | wiz_show_stats()
1487 | {
1488 | 	char buf[BUFSZ];
1489 | 	winid win;
1490 | 	long total_obj_size = 0, total_obj_count = 0;
1491 | 	long total_mon_size = 0, total_mon_count = 0;
1492 | 
1493 | 	win = create_nhwindow(NHW_TEXT);
1494 | 	putstr(win, 0, "Current memory statistics:");
1495 | 	putstr(win, 0, "");
1496 | 	Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj));
1497 | 	putstr(win, 0, buf);
1498 | 	putstr(win, 0, "");
1499 | 	putstr(win, 0, count_str);
1500 | 
1501 | 	obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size);
1502 | 	obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size);
1503 | 	obj_chain(win, "buried", level.buriedobjlist,
1504 | 				&total_obj_count, &total_obj_size);
1505 | 	obj_chain(win, "migrating obj", migrating_objs,
1506 | 				&total_obj_count, &total_obj_size);
1507 | 	mon_invent_chain(win, "minvent", fmon,
1508 | 				&total_obj_count,&total_obj_size);
1509 | 	mon_invent_chain(win, "migrating minvent", migrating_mons,
1510 | 				&total_obj_count, &total_obj_size);
1511 | 
1512 | 	contained(win, "contained",
1513 | 				&total_obj_count, &total_obj_size);
1514 | 
1515 | 	putstr(win, 0, separator);
1516 | 	Sprintf(buf, template, "Total", total_obj_count, total_obj_size);
1517 | 	putstr(win, 0, buf);
1518 | 
1519 | 	putstr(win, 0, "");
1520 | 	putstr(win, 0, "");
1521 | 	Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst));
1522 | 	putstr(win, 0, buf);
1523 | 	putstr(win, 0, "");
1524 | 
1525 | 	mon_chain(win, "fmon", fmon,
1526 | 				&total_mon_count, &total_mon_size);
1527 | 	mon_chain(win, "migrating", migrating_mons,
1528 | 				&total_mon_count, &total_mon_size);
1529 | 
1530 | 	putstr(win, 0, separator);
1531 | 	Sprintf(buf, template, "Total", total_mon_count, total_mon_size);
1532 | 	putstr(win, 0, buf);
1533 | 
1534 | #ifdef __BORLANDC__
1535 | 	show_borlandc_stats(win);
1536 | #endif
1537 | 
1538 | 	display_nhwindow(win, FALSE);
1539 | 	destroy_nhwindow(win);
1540 | 	return 0;
1541 | }
1542 | 
1543 | void
1544 | sanity_check()
1545 | {
1546 | 	obj_sanity_check();
1547 | 	timer_sanity_check();
1548 | }
1549 | 
1550 | #endif /* WIZARD */
1551 | 
1552 | #define unctrl(c)	((c) <= C('z') ? (0x60 | (c)) : (c))
1553 | #define unmeta(c)	(0x7f & (c))
1554 | 
1555 | 
1556 | void
1557 | rhack(cmd)
1558 | register char *cmd;
1559 | {
1560 | 	boolean do_walk, do_rush, prefix_seen, bad_command,
1561 | 		firsttime = (cmd == 0);
1562 | 
1563 | 	if (firsttime) {
1564 | 		flags.nopick = 0;
1565 | 		cmd = parse();
1566 | 	}
1567 | 	if (*cmd == '\033') {
1568 | 		flags.move = FALSE;
1569 | 		return;
1570 | 	}
1571 | #ifdef REDO
1572 | 	if (*cmd == DOAGAIN && !in_doagain && saveq[0]) {
1573 | 		in_doagain = TRUE;
1574 | 		stail = 0;
1575 | 		rhack((char *)0);	/* read and execute command */
1576 | 		in_doagain = FALSE;
1577 | 		return;
1578 | 	}
1579 | 	/* Special case of *cmd == ' ' handled better below */
1580 | 	if(!*cmd || *cmd == (char)0377)
1581 | #else
1582 | 	if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' '))
1583 | #endif
1584 | 	{
1585 | 		nhbell();
1586 | 		flags.move = FALSE;
1587 | 		return;		/* probably we just had an interrupt */
1588 | 	}
1589 | 
1590 | 	/* handle most movement commands */
1591 | 	do_walk = do_rush = prefix_seen = FALSE;
1592 | 	switch (*cmd) {
1593 | 	 case 'g':  if (movecmd(cmd[1])) {
1594 | 			flags.run = 2;
1595 | 			do_rush = TRUE;
1596 | 		    } else
1597 | 			prefix_seen = TRUE;
1598 | 		    break;
1599 | 	 case '5':  if (!iflags.num_pad) break;	/* else FALLTHRU */
1600 | 	 case 'G':  if (movecmd(lowc(cmd[1]))) {
1601 | 			flags.run = 3;
1602 | 			do_rush = TRUE;
1603 | 		    } else
1604 | 			prefix_seen = TRUE;
1605 | 		    break;
1606 | 	 case '-':  if (!iflags.num_pad) break;	/* else FALLTHRU */
1607 | 	/* Effects of movement commands and invisible monsters:
1608 | 	 * m: always move onto space (even if 'I' remembered)
1609 | 	 * F: always attack space (even if 'I' not remembered)
1610 | 	 * normal movement: attack if 'I', move otherwise
1611 | 	 */
1612 | 	 case 'F':  if (movecmd(cmd[1])) {
1613 | 			flags.forcefight = 1;
1614 | 			do_walk = TRUE;
1615 | 		    } else
1616 | 			prefix_seen = TRUE;
1617 | 		    break;
1618 | 	 case 'm':  if (movecmd(cmd[1]) || u.dz) {
1619 | 			flags.run = 0;
1620 | 			flags.nopick = 1;
1621 | 			if (!u.dz) do_walk = TRUE;
1622 | 			else cmd[0] = cmd[1];	/* "m<" or "m>" */
1623 | 		    } else
1624 | 			prefix_seen = TRUE;
1625 | 		    break;
1626 | 	 case 'M':  if (movecmd(lowc(cmd[1]))) {
1627 | 			flags.run = 1;
1628 | 			flags.nopick = 1;
1629 | 			do_rush = TRUE;
1630 | 		    } else
1631 | 			prefix_seen = TRUE;
1632 | 		    break;
1633 | 	 case '0':  if (!iflags.num_pad) break;
1634 | 		    (void)ddoinv(); /* a convenience borrowed from the PC */
1635 | 		    flags.move = FALSE;
1636 | 		    multi = 0;
1637 | 		    return;
1638 | 	 default:   if (movecmd(*cmd)) {	/* ordinary movement */
1639 | 			do_walk = TRUE;
1640 | 		    } else if (movecmd(iflags.num_pad ?
1641 | 				       unmeta(*cmd) : lowc(*cmd))) {
1642 | 			flags.run = 1;
1643 | 			do_rush = TRUE;
1644 | 		    } else if (movecmd(unctrl(*cmd))) {
1645 | 			flags.run = 3;
1646 | 			do_rush = TRUE;
1647 | 		    }
1648 | 		    break;
1649 | 	}
1650 | 	if (do_walk) {
1651 | 	    if (multi) flags.mv = TRUE;
1652 | 	    domove();
1653 | 	    flags.forcefight = 0;
1654 | 	    return;
1655 | 	} else if (do_rush) {
1656 | 	    if (firsttime) {
1657 | 		if (!multi) multi = max(COLNO,ROWNO);
1658 | 		u.last_str_turn = 0;
1659 | 	    }
1660 | 	    flags.mv = TRUE;
1661 | 	    domove();
1662 | 	    return;
1663 | 	} else if (prefix_seen && cmd[1] == '\033') {	/* <prefix><escape> */
1664 | 	    /* don't report "unknown command" for change of heart... */
1665 | 	    bad_command = FALSE;
1666 | 	} else if (*cmd == ' ' && !flags.rest_on_space) {
1667 | 	    bad_command = TRUE;		/* skip cmdlist[] loop */
1668 | 
1669 | 	/* handle all other commands */
1670 | 	} else {
1671 | 	    register const struct func_tab *tlist;
1672 | 	    int res, NDECL((*func));
1673 | 
1674 | 	    for (tlist = cmdlist; tlist->f_char; tlist++) {
1675 | 		if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue;
1676 | 
1677 | 		if (u.uburied && !tlist->can_if_buried) {
1678 | 		    You_cant("do that while you are buried!");
1679 | 		    res = 0;
1680 | 		} else {
1681 | 		    /* we discard 'const' because some compilers seem to have
1682 | 		       trouble with the pointer passed to set_occupation() */
1683 | 		    func = ((struct func_tab *)tlist)->f_funct;
1684 | 		    if (tlist->f_text && !occupation && multi)
1685 | 			set_occupation(func, tlist->f_text, multi);
1686 | 		    res = (*func)();		/* perform the command */
1687 | 		}
1688 | 		if (!res) {
1689 | 		    flags.move = FALSE;
1690 | 		    multi = 0;
1691 | 		}
1692 | 		return;
1693 | 	    }
1694 | 	    /* if we reach here, cmd wasn't found in cmdlist[] */
1695 | 	    bad_command = TRUE;
1696 | 	}
1697 | 
1698 | 	if (bad_command) {
1699 | 	    char expcmd[10];
1700 | 	    register char *cp = expcmd;
1701 | 
1702 | 	    while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) {
1703 | 		if (*cmd >= 040 && *cmd < 0177) {
1704 | 		    *cp++ = *cmd++;
1705 | 		} else if (*cmd & 0200) {
1706 | 		    *cp++ = 'M';
1707 | 		    *cp++ = '-';
1708 | 		    *cp++ = *cmd++ &= ~0200;
1709 | 		} else {
1710 | 		    *cp++ = '^';
1711 | 		    *cp++ = *cmd++ ^ 0100;
1712 | 		}
1713 | 	    }
1714 | 	    *cp = '\0';
1715 | 	    Norep("Unknown command '%s'.", expcmd);
1716 | 	}
1717 | 	/* didn't move */
1718 | 	flags.move = FALSE;
1719 | 	multi = 0;
1720 | 	return;
1721 | }
1722 | 
1723 | int
1724 | xytod(x, y)	/* convert an x,y pair into a direction code */
1725 | schar x, y;
1726 | {
1727 | 	register int dd;
1728 | 
1729 | 	for(dd = 0; dd < 8; dd++)
1730 | 	    if(x == xdir[dd] && y == ydir[dd]) return dd;
1731 | 
1732 | 	return -1;
1733 | }
1734 | 
1735 | void
1736 | dtoxy(cc,dd)	/* convert a direction code into an x,y pair */
1737 | coord *cc;
1738 | register int dd;
1739 | {
1740 | 	cc->x = xdir[dd];
1741 | 	cc->y = ydir[dd];
1742 | 	return;
1743 | }
1744 | 
1745 | int
1746 | movecmd(sym)	/* also sets u.dz, but returns false for <> */
1747 | char sym;
1748 | {
1749 | 	register const char *dp;
1750 | 	register const char *sdp;
1751 | 	if(iflags.num_pad) sdp = ndir; else sdp = sdir;	/* DICE workaround */
1752 | 
1753 | 	u.dz = 0;
1754 | 	if(!(dp = index(sdp, sym))) return 0;
1755 | 	u.dx = xdir[dp-sdp];
1756 | 	u.dy = ydir[dp-sdp];
1757 | 	u.dz = zdir[dp-sdp];
1758 | 	if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) {
1759 | 		u.dx = u.dy = 0;
1760 | 		return 0;
1761 | 	}
1762 | 	return !u.dz;
1763 | }
1764 | 
1765 | int
1766 | getdir(s)
1767 | const char *s;
1768 | {
1769 | 	char dirsym;
1770 | 
1771 | #ifdef REDO	
1772 | 	if(in_doagain)
1773 | 	    dirsym = readchar();
1774 | 	else
1775 | #endif
1776 | 	    dirsym = yn_function (s ? s : "In what direction?",
1777 | 					(char *)0, '\0');
1778 | #ifdef REDO
1779 | 	savech(dirsym);
1780 | #endif
1781 | 	if(dirsym == '.' || dirsym == 's')
1782 | 		u.dx = u.dy = u.dz = 0;
1783 | 	else if(!movecmd(dirsym) && !u.dz) {
1784 | 		if(!index(quitchars, dirsym))
1785 | 			pline("What a strange direction!");
1786 | 		return 0;
1787 | 	}
1788 | 	if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
1789 | 	return 1;
1790 | }
1791 | 
1792 | #endif /* OVL1 */
1793 | #ifdef OVLB
1794 | 
1795 | void
1796 | confdir()
1797 | {
1798 | 	register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8);
1799 | 	u.dx = xdir[x];
1800 | 	u.dy = ydir[x];
1801 | 	return;
1802 | }
1803 | 
1804 | #endif /* OVLB */
1805 | #ifdef OVL0
1806 | 
1807 | int
1808 | isok(x,y)
1809 | register int x, y;
1810 | {
1811 | 	/* x corresponds to curx, so x==1 is the first column. Ach. %% */
1812 | 	return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1;
1813 | }
1814 | 
1815 | static NEARDATA int last_multi;
1816 | 
1817 | /*
1818 |  * convert a MAP window position into a movecmd
1819 |  */
1820 | int
1821 | click_to_cmd(x, y, mod)
1822 |     int x, y, mod;
1823 | {
1824 |     x -= u.ux;
1825 |     y -= u.uy;
1826 |     /* convert without using floating point, allowing sloppy clicking */
1827 |     if(x > 2*abs(y))
1828 | 	x = 1, y = 0;
1829 |     else if(y > 2*abs(x))
1830 | 	x = 0, y = 1;
1831 |     else if(x < -2*abs(y))
1832 | 	x = -1, y = 0;
1833 |     else if(y < -2*abs(x))
1834 | 	x = 0, y = -1;
1835 |     else
1836 | 	x = sgn(x), y = sgn(y);
1837 | 
1838 |     if(x == 0 && y == 0)	/* map click on player to "rest" command */
1839 | 	return '.';
1840 | 
1841 |     x = xytod(x, y);
1842 |     if(mod == CLICK_1) {
1843 | 	return (iflags.num_pad ? ndir[x] : sdir[x]);
1844 |     } else {
1845 | 	return (iflags.num_pad ? M(ndir[x]) :
1846 | 		(sdir[x] - 'a' + 'A')); /* run command */
1847 |     }
1848 | }
1849 | 
1850 | STATIC_OVL char *
1851 | parse()
1852 | {
1853 | #ifdef LINT	/* static char in_line[COLNO]; */
1854 | 	char in_line[COLNO];
1855 | #else
1856 | 	static char in_line[COLNO];
1857 | #endif
1858 | 	register int foo;
1859 | 	boolean prezero = FALSE;
1860 | 
1861 | 	multi = 0;
1862 | 	flags.move = 1;
1863 | 	flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
1864 | 
1865 | 	if (!iflags.num_pad || (foo = readchar()) == 'n')
1866 | 	    for (;;) {
1867 | 		foo = readchar();
1868 | 		if (foo >= '0' && foo <= '9') {
1869 | 		    multi = 10 * multi + foo - '0';
1870 | 		    if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT;
1871 | 		    if (multi > 9) {
1872 | 			clear_nhwindow(WIN_MESSAGE);
1873 | 			Sprintf(in_line, "Count: %d", multi);
1874 | 			pline(in_line);
1875 | 			mark_synch();
1876 | 		    }
1877 | 		    last_multi = multi;
1878 | 		    if (!multi && foo == '0') prezero = TRUE;
1879 | 		} else break;	/* not a digit */
1880 | 	    }
1881 | 
1882 | 	if (foo == '\033') {   /* esc cancels count (TH) */
1883 | 	    clear_nhwindow(WIN_MESSAGE);
1884 | 	    multi = last_multi = 0;
1885 | # ifdef REDO
1886 | 	} else if (foo == DOAGAIN || in_doagain) {
1887 | 	    multi = last_multi;
1888 | 	} else {
1889 | 	    last_multi = multi;
1890 | 	    savech(0);	/* reset input queue */
1891 | 	    savech((char)foo);
1892 | # endif
1893 | 	}
1894 | 
1895 | 	if (multi) {
1896 | 	    multi--;
1897 | 	    save_cm = in_line;
1898 | 	} else {
1899 | 	    save_cm = (char *)0;
1900 | 	}
1901 | 	in_line[0] = foo;
1902 | 	in_line[1] = '\0';
1903 | 	if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' ||
1904 | 	    foo == 'F' || (iflags.num_pad && (foo == '5' || foo == '-'))) {
1905 | 	    foo = readchar();
1906 | #ifdef REDO
1907 | 	    savech((char)foo);
1908 | #endif
1909 | 	    in_line[1] = foo;
1910 | 	    in_line[2] = 0;
1911 | 	}
1912 | 	clear_nhwindow(WIN_MESSAGE);
1913 | 	if (prezero) in_line[0] = '\033';
1914 | 	return(in_line);
1915 | }
1916 | 
1917 | #endif /* OVL0 */
1918 | #ifdef OVLB
1919 | 
1920 | #ifdef UNIX
1921 | static
1922 | void
1923 | end_of_input()
1924 | {
1925 | 	exit_nhwindows("End of input?");
1926 | #ifndef NOSAVEONHANGUP
1927 | 	if (!program_state.done_hup++)
1928 | 	    (void) dosave0();
1929 | #endif
1930 | 	clearlocks();
1931 | 	terminate(EXIT_SUCCESS);
1932 | }
1933 | #endif
1934 | 
1935 | #endif /* OVLB */
1936 | #ifdef OVL0
1937 | 
1938 | char
1939 | readchar()
1940 | {
1941 | 	register int sym;
1942 | 	int x = u.ux, y = u.uy, mod = 0;
1943 | 
1944 | #ifdef REDO
1945 | 	sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod);
1946 | #else
1947 | 	sym = Getchar();
1948 | #endif
1949 | 
1950 | #ifdef UNIX
1951 | # ifdef NR_OF_EOFS
1952 | 	if (sym == EOF) {
1953 | 	    register int cnt = NR_OF_EOFS;
1954 | 	  /*
1955 | 	   * Some SYSV systems seem to return EOFs for various reasons
1956 | 	   * (?like when one hits break or for interrupted systemcalls?),
1957 | 	   * and we must see several before we quit.
1958 | 	   */
1959 | 	    do {
1960 | 		clearerr(stdin);	/* omit if clearerr is undefined */
1961 | 		sym = Getchar();
1962 | 	    } while (--cnt && sym == EOF);
1963 | 	}
1964 | # endif /* NR_OF_EOFS */
1965 | 	if (sym == EOF)
1966 | 	    end_of_input();
1967 | #endif /* UNIX */
1968 | 
1969 | 	if(sym == 0) /* click event */
1970 | 	    sym = click_to_cmd(x, y, mod);
1971 | 	return((char) sym);
1972 | }
1973 | #endif /* OVL0 */
1974 | 
1975 | /*cmd.c*/