Source:NetHack 3.4.3/src/cmd.c

From NetHackWiki
(Redirected from Source:Ref/contained)
Jump to navigation Jump to search

Below is the full text to src/cmd.c from NetHack 3.4.3. To link to a particular line, write Source:NetHack 3.4.3/src/cmd.c#line123, for example.

Top of file

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.    

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

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.  

doprev_message

160.  #ifdef OVL1
161.  
162.  STATIC_PTR int
163.  doprev_message()
164.  {
165.      return nh_doprev_message();
166.  }
167.  

timed_occupation

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.  

reset_occupations

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.  

set_occupation

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.  

popch

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.  

pgetchar

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.  

pushch

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.  

savech

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 */

doextcmd

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.  

doextlist

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.  

extcmd_via_menu

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.  

domonability

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.  

enter_explore_mode

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.  

wiz_wish

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.  

wiz_identify

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.  

wiz_map

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.  

wiz_genesis

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.  

wiz_where

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.  

wiz_detect

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.  

wiz_level_tele

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.  

wiz_mon_polycontrol

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.  

wiz_level_change

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.  

wiz_panic

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.  

wiz_polyself

640.  /* #polyself command - change hero's form */
641.  STATIC_PTR int
642.  wiz_polyself()
643.  {
644.          polyself(TRUE);
645.          return 0;
646.  }
647.  

wiz_show_seenv

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.  

wiz_show_vision

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.  

wiz_show_wmodes

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.  

enlght_line

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.  

enlght_combatinc

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.  

enlightenment

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. 

minimal_enlightenment

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. 

doattributes

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. 

doconduct

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. 

show_conduct

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 */

cmdlist

This array defines handlers for all of Nethack's various commands. The func_tab structure is defined in func_tab.h. It has 4 fields, the key to press, a Boolean indicating whether or not you can perform the action while buried, a pointer to the function used to handle the command, and a string that presumably would describe the command, if any of the commands bothered to set that field.

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. 

extcmdlist

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. 

debug_extcmdlist

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. 

add_debug_extended_commands

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. 

count_obj

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. 

obj_chain

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. 

mon_invent_chain

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. 

contained

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. 

mon_chain

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. 

wiz_show_stats

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. 

sanity_check

1761. void
1762. sanity_check()
1763. {
1764. 	obj_sanity_check();
1765. 	timer_sanity_check();
1766. }
1767. 

wiz_migrate_mons

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. 

rhack

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. 

xytod

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. 

dtoxy

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. 

movecmd

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. 

get_adjacent_loc

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. 

getdir

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. 

help_dir

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 */

confdir

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 */

isok

isok() takes two parameters, x and y coordinate, and returns 1 if the coordinate (x,y) is inside the map area, 0 otherwise.

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. 

click_to_cmd

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. 

parse

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 */

end_of_input

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 */

readchar

The readchar function waits for an event from the keyboard and returns the next character typed by a user. NetHack has many reasons to need to wait for your command: you might on the map, at a menu, at a "-- More --" prompt, or elsewhere. The readchar functions acts as a gate through which all of these places obtain your instruction. Most of the calls to readchar are elsewhere in cmd.c, though two are in invent.c.

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. 

The C language getchar function waits for a character on the standard input and use it. Though the tty window port could use getchar to access keyboard events, the other window ports must use different mechanisms, like X11 events or Qt signals.

Thus, the DevTeam now uses a Getchar macro (starting with an uppercase G). This macro calls a window-port-specific function to grab the key. Thus the Getchar macro takes the place of the getchar function that NetHack used when it was a tty-only game.

Given this, it seems strange that the NR_OF_EOFS code is here. On a SYSV system, NR_OF_EOFS became 20 at cmd.c#line14. This crude hack attempts to distinguish a permanent end-of-file (EOF) from a temporary interruption by re-reading the character 20 times. (The more correct way to do this would be to check the global errno variable for the EINTR error from the Unix read system call.) The strange situation is that this hack calls clearerr(stdin) even if standard input is not the source of our key events. It would be reasonable to move this code to the tty-specific implementation of the Getchar function.

Other than calling Getchar, the readchar function also needs to worry about mouse clicks from window ports that support them. It deals with them by calling the click_to_cmd function to translate the mouse click into equivalent key events. It then stores the key characters in the readchar_queue. Until this queue is empty, subsequent calls to readchar use this queue instead of requesting another event from Getchar.

dotravel

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. 

wiz_port_debug

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 */

yn_function

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*/