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. */
7 /* #define DEBUG */ /* uncomment for debugging */
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.
13 #if defined(SYSV) || defined(DGUX) || defined(HPUX)
17 #define CMD_TRAVEL (char)0x90
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
25 extern int NDECL(wiz_debug_cmd);
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); /**/
103 static int NDECL((*timed_occ_fn));
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);
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));
129 #ifdef DEBUG_MIGRATING_MONS
130 STATIC_PTR int NDECL(wiz_migrate_mons);
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);
139 STATIC_DCL int NDECL(wiz_port_debug);
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);
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 *));
151 static void NDECL(end_of_input);
155 static const char* readchar_queue="";
157 STATIC_DCL char *NDECL(parse);
158 STATIC_DCL boolean FDECL(help_dir, (CHAR_P,const char *));
165 return nh_doprev_message();
168 /* Count down by decrementing multi */
178 /* If you have moved since initially setting some occupations, they
179 * now shouldn't be able to restart.
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.
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.
188 * Currently: Take off all armor.
189 * Picking Locks / Forcing Chests.
200 /* If a time is given, use it to timeout this function, otherwise the
201 * function times out by its own means.
204 set_occupation(fn, txt, xtime)
210 occupation = timed_occupation;
221 static char NDECL(popch);
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.
230 static char pushq[BSIZE], saveq[BSIZE];
231 static NEARDATA int phead, ptail, shead, stail;
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.
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');
246 pgetchar() { /* curtesy of aeb@cwi.nl */
254 /* A ch == 0 resets the pushq */
266 /* A ch == 0 resets the saveq. Only save keystrokes when not
267 * replaying a previous command.
275 phead = ptail = shead = stail = 0;
276 else if (shead < BSIZE)
287 doextcmd() /* here after # - now read a full-word command */
291 /* keep repeating until we don't run help or quit */
294 if (idx < 0) return 0; /* quit */
296 retval = (*extcmdlist[idx].ef_funct)();
297 } while (extcmdlist[idx].ef_funct == doextlist);
303 doextlist() /* here after #? - now list all full-word commands */
305 register const struct ext_func_tab *efp;
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, "");
316 for(efp = extcmdlist; efp->ef_txt; efp++) {
317 Sprintf(buf, " %-15s - %s.", efp->ef_txt, efp->ef_desc);
318 putstr(datawin, 0, buf);
320 display_nhwindow(datawin, FALSE);
321 destroy_nhwindow(datawin);
326 #define MAX_EXT_CMD 40 /* Change if we ever have > 40 ext cmds */
328 * This is currently used only by the tty port and is
329 * controlled via runtime option 'extmenu'
332 extcmd_via_menu() /* here after # - now show pick-list of possible commands */
334 const struct ext_func_tab *efp;
335 menu_item *pick_list = (menu_item *)0;
338 const struct ext_func_tab *choices[MAX_EXT_CMD];
340 char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20];
341 int i, n, nchoices, acount;
343 int accelerator, prevaccelerator;
353 /* populate choices */
354 for(efp = extcmdlist; efp->ef_txt; efp++) {
355 if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) {
357 if ((int)strlen(efp->ef_desc) > biggest) {
358 biggest = strlen(efp->ef_desc);
359 Sprintf(fmtstr,"%%-%ds", biggest + 15);
362 if (i >= MAX_EXT_CMD - 2) {
363 impossible("Exceeded %d extended commands in doextcmd() menu",
370 choices[i] = (struct ext_func_tab *)0;
372 /* if we're down to one, we have our selection so get out of here */
374 for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++)
375 if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) {
383 win = create_nhwindow(NHW_MENU);
387 for(i = 0; choices[i]; ++i) {
388 accelerator = choices[i]->ef_txt[matchlevel];
389 if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) {
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);
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,
407 Strcat(prompt," or ");
408 Strcat(prompt, choices[i]->ef_txt);
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);
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);
423 if (matchlevel > (QBUFSZ - 2)) {
424 free((genericptr_t)pick_list);
426 impossible("Too many characters (%d) entered in extcmd_via_menu()",
431 cbuf[matchlevel++] = pick_list[0].item.a_char;
432 cbuf[matchlevel] = '\0';
433 free((genericptr_t)pick_list);
447 /* #monster command - use special monster ability while polymorphed */
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);
467 } else if (youmonst.data->msound == MS_SHRIEK) {
470 pline("Unfortunately sound does not carry well through rock.");
473 pline("Any special ability you may have is purely reflexive.");
474 else You("don't have a special ability in your normal form!");
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.");
489 clear_nhwindow(WIN_MESSAGE);
490 pline("Resuming normal game.");
498 /* ^W command - wish for something */
500 wiz_wish() /* Unlimited wishes for debug mode by Paul Polderman */
503 boolean save_verbose = flags.verbose;
505 flags.verbose = FALSE;
507 flags.verbose = save_verbose;
508 (void) encumber_msg();
510 pline("Unavailable command '^W'.");
514 /* ^I command - identify hero's inventory */
518 if (wizard) identify_pack(0);
519 else pline("Unavailable command '^I'.");
523 /* ^F command - reveal the level map and any traps on it */
529 long save_Hconf = HConfusion,
530 save_Hhallu = HHallucination;
532 HConfusion = HHallucination = 0L;
533 for (t = ftrap; t != 0; t = t->ntrap) {
538 HConfusion = save_Hconf;
539 HHallucination = save_Hhallu;
541 pline("Unavailable command '^F'.");
545 /* ^G command - generate monster(s); a count prefix will be honored */
549 if (wizard) (void) create_particular();
550 else pline("Unavailable command '^G'.");
554 /* ^O command - display dungeon layout */
558 if (wizard) (void) print_dungeon(FALSE, (schar *)0, (xchar *)0);
559 else pline("Unavailable command '^O'.");
563 /* ^E command - detect unseen (secret doors, traps, hidden monsters) */
567 if(wizard) (void) findit();
568 else pline("Unavailable command '^E'.");
572 /* ^V command - level teleport */
576 if (wizard) level_tele();
577 else pline("Unavailable command '^V'.");
581 /* #monpolycontrol command - choose new form for shapechangers, polymorphees */
583 wiz_mon_polycontrol()
585 iflags.mon_polycontrol = !iflags.mon_polycontrol;
586 pline("Monster polymorph control is %s.",
587 iflags.mon_polycontrol ? "on" : "off");
591 /* #levelchange command - adjust hero's experience level */
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);
608 if (newlevel == u.ulevel) {
609 You("are already that experienced.");
610 } else if (newlevel < u.ulevel) {
612 You("are already as inexperienced as you can get.");
615 if (newlevel < 1) newlevel = 1;
616 while (u.ulevel > newlevel)
617 losexp("#levelchange");
619 if (u.ulevel >= MAXULEV) {
620 You("are already as experienced as you can get.");
623 if (newlevel > MAXULEV) newlevel = MAXULEV;
624 while (u.ulevel < newlevel)
627 u.ulevelmax = u.ulevel;
631 /* #panic command - test program's panic handling */
635 if (yn("Do you want to call panic() and end your game?") == 'y')
636 panic("crash test.");
640 /* #polyself command - change hero's form */
653 int x, y, v, startx, stopx, curx;
656 win = create_nhwindow(NHW_TEXT);
658 * Each seenv description takes up 2 characters, so center
659 * the seenv display around the hero.
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++;
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] = '@';
671 v = levl[x][y].seenv & 0xff;
673 row[curx] = row[curx+1] = ' ';
675 Sprintf(&row[curx], "%02x", v);
678 /* remove trailing spaces */
679 for (x = curx-1; x >= 0; x--)
680 if (row[x] != ' ') break;
685 display_nhwindow(win, TRUE);
686 destroy_nhwindow(win);
690 /* #vision command */
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);
703 for (y = 0; y < ROWNO; y++) {
704 for (x = 1; x < COLNO; x++) {
705 if (x == u.ux && y == u.uy)
708 v = viz_array[y][x]; /* data access should be hidden */
712 row[x] = '0' + viz_array[y][x];
715 /* remove trailing spaces */
716 for (x = COLNO-1; x >= 1; x--)
717 if (row[x] != ' ') break;
720 putstr(win, 0, &row[1]);
722 display_nhwindow(win, TRUE);
723 destroy_nhwindow(win);
736 win = create_nhwindow(NHW_TEXT);
737 for (y = 0; y < ROWNO; y++) {
738 for (x = 0; x < COLNO; x++) {
740 if (x == u.ux && y == u.uy)
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)
746 else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ))
754 display_nhwindow(win, TRUE);
755 destroy_nhwindow(win);
762 /* -enlightenment and conduct- */
766 are[] = "are ", were[] = "were ",
767 have[] = "have ", had[] = "had ",
768 can[] = "can ", could[] = "could ";
770 have_been[] = "have been ",
771 have_never[] = "have never ", never[] = "never ";
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)
783 enlght_line(start, middle, end)
784 const char *start, *middle, *end;
788 Sprintf(buf, "%s%s%s.", start, middle, end);
789 putstr(en_win, 0, buf);
792 /* format increased damage or chance to hit */
794 enlght_combatinc(inctyp, incamt, final, outbuf)
800 const char *modif, *bonus;
807 Sprintf(numbuf, "%s%d",
808 (incamt > 0) ? "+" : "", incamt);
809 modif = (const char *) numbuf;
811 int absamt = abs(incamt);
813 if (absamt <= 3) modif = "small";
814 else if (absamt <= 6) modif = "moderate";
815 else if (absamt <= 12) modif = "large";
818 bonus = (incamt > 0) ? "bonus" : "penalty";
819 /* "bonus to hit" vs "damage bonus" */
820 if (!strcmp(inctyp, "damage")) {
821 const char *ctmp = inctyp;
825 Sprintf(outbuf, "%s %s %s", an(modif), bonus, inctyp);
831 int final; /* 0 => still in progress; 1 => over, survived; 2 => dead */
836 en_win = create_nhwindow(NHW_MENU);
837 putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:");
838 putstr(en_win, 0, "");
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"
847 you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1]);
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");
864 Sprintf(buf, " %d", u.ualign.record);
865 enl_msg("Your alignment ", "is", "was", buf);
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");
886 if (Halluc_resistance)
887 enl_msg("You resist", "", "ed", " hallucinations");
889 if (Hallucination) you_are("hallucinating");
890 if (Stunned) you_are("stunned");
891 if (Confusion) you_are("confused");
892 if (Blinded) you_are("blinded");
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");
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");
904 Sprintf(buf, "slippery %s", makeplural(body_part(FINGER)));
907 if (Fumbling) enl_msg("You fumble", "", "d", "");
913 Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
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));
921 enl_msg(buf, " has", " had", " wounded legs");
924 if (Sleeping) enl_msg("You ", "fall", "fell", " asleep");
925 if (Hunger) enl_msg("You hunger", "", "ed", " rapidly");
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" :
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");
945 /*** Appearance and behavior ***/
949 if(uleft && uleft->otyp == RIN_ADORNMENT) adorn += uleft->spe;
950 if(uright && uright->otyp == RIN_ADORNMENT) adorn += uright->spe;
952 you_are("poorly adorned");
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)
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");
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");
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
983 if (u.usteed && (final < 2 || strcmp(killer, "riding accident"))) {
984 Sprintf(buf, "riding %s", y_monnam(u.usteed));
989 Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck));
991 if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim);
994 } else if (u.ustuck) {
995 Sprintf(buf, "%s %s",
996 (Upolyd && sticks(youmonst.data)) ? "holding" : "held by",
1001 /*** Physical attributes ***/
1003 you_have(enlght_combatinc("to hit", u.uhitinc, final, buf));
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) {
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;
1017 you_are("ineffectively protected");
1019 you_are("protected");
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));
1030 if (u.umonnum == u.ulycn) Strcpy(buf, "in beast form");
1031 else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname));
1033 if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone);
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");
1043 enl_msg("Your life ", "will be", "would have been", " saved");
1044 if (u.twoweap) you_are("wielding two weapons at once");
1046 /*** Miscellany ***/
1048 ltmp = abs((int)Luck);
1049 Sprintf(buf, "%s%slucky",
1050 ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
1051 Luck < 0 ? "un" : "");
1053 if (wizard) Sprintf(eos(buf), " (%d)", Luck);
1058 else if (wizard) enl_msg("Your luck ", "is", "was", " zero");
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);
1065 enl_msg("Bad luck ", "does", "did", " not time out for you");
1067 enl_msg("Good luck ", "does", "did", " not time out for you");
1071 Sprintf(buf, " %sangry with you",
1072 u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : "");
1074 if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr);
1076 enl_msg(u_gname(), " is", " was", buf);
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.
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" : "");
1089 Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not ");
1092 if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt);
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);
1111 } else { /* game ended in character's death */
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));
1121 if (p) enl_msg(You_, "have been killed ", p, buf);
1124 display_nhwindow(en_win, TRUE);
1125 destroy_nhwindow(en_win);
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.
1135 minimal_enlightenment()
1138 menu_item *selected;
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;
1149 fmtstr = iflags.menu_tab_sep ? tabbed_fmtstr : untabbed_fmtstr;
1150 deity_fmtstr = iflags.menu_tab_sep ?
1151 tabbed_deity_fmtstr : untabbed_deity_fmtstr;
1153 buf[0] = buf2[0] = '\0';
1154 tmpwin = create_nhwindow(NHW_MENU);
1156 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Starting", FALSE);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1227 end_menu(tmpwin, "Base Attributes");
1228 n = select_menu(tmpwin, PICK_NONE, &selected);
1229 destroy_nhwindow(tmpwin);
1236 if (!minimal_enlightenment())
1238 if (wizard || discover)
1244 * (shares enlightenment's tense handling)
1260 /* Create the conduct window */
1261 en_win = create_nhwindow(NHW_MENU);
1262 putstr(en_win, 0, "Voluntary challenges:");
1263 putstr(en_win, 0, "");
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");
1273 if (!u.uconduct.gnostic)
1274 you_have_been("an atheist");
1276 if (!u.uconduct.weaphit)
1277 you_have_never("hit with a wielded weapon");
1280 Sprintf(buf, "used a wielded weapon %ld time%s",
1281 u.uconduct.weaphit, plur(u.uconduct.weaphit));
1285 if (!u.uconduct.killer)
1286 you_have_been("a pacifist");
1288 if (!u.uconduct.literate)
1289 you_have_been("illiterate");
1292 Sprintf(buf, "read items or engraved %ld time%s",
1293 u.uconduct.literate, plur(u.uconduct.literate));
1298 ngenocided = num_genocides();
1299 if (ngenocided == 0) {
1300 you_have_never("genocided any monsters");
1302 Sprintf(buf, "genocided %d type%s of monster%s",
1303 ngenocided, plur(ngenocided), plur(ngenocided));
1307 if (!u.uconduct.polypiles)
1308 you_have_never("polymorphed an object");
1311 Sprintf(buf, "polymorphed %ld item%s",
1312 u.uconduct.polypiles, plur(u.uconduct.polypiles));
1317 if (!u.uconduct.polyselfs)
1318 you_have_never("changed form");
1321 Sprintf(buf, "changed form %ld time%s",
1322 u.uconduct.polyselfs, plur(u.uconduct.polyselfs));
1327 if (!u.uconduct.wishes)
1328 you_have_X("used no wishes");
1330 Sprintf(buf, "used %ld wish%s",
1331 u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : "");
1334 if (!u.uconduct.wisharti)
1335 enl_msg(You_, "have not wished", "did not wish",
1336 " for any artifacts");
1339 /* Pop up the window and wait for a key */
1340 display_nhwindow(en_win, TRUE);
1341 destroy_nhwindow(en_win);
1349 # define M(c) (0x80 | (c))
1351 # define M(c) ((c) - 128)
1352 # endif /* NHSTDC */
1355 #define C(c) (0x1f & (c))
1358 static const struct func_tab cmdlist[] = {
1359 {C('d'), FALSE, dokick}, /* "D" is for door!...? Msg is in dokick.c */
1361 {C('e'), TRUE, wiz_detect},
1362 {C('f'), TRUE, wiz_map},
1363 {C('g'), TRUE, wiz_genesis},
1364 {C('i'), TRUE, wiz_identify},
1366 {C('l'), TRUE, doredraw}, /* if number_pad is set */
1368 {C('o'), TRUE, wiz_where},
1370 {C('p'), TRUE, doprev_message},
1371 {C('r'), TRUE, doredraw},
1372 {C('t'), TRUE, dotele},
1374 {C('v'), TRUE, wiz_level_tele},
1375 {C('w'), TRUE, wiz_wish},
1377 {C('x'), TRUE, doattributes},
1379 {C('z'), TRUE, dosuspend},
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},
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},
1447 {'>', FALSE, dodown},
1448 {'/', TRUE, dowhatis},
1449 {'&', TRUE, dowhatdoes},
1450 {'?', TRUE, dohelp},
1451 {M('?'), TRUE, doextlist},
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},
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,
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},
1494 {"ride", "ride (or stop riding) a monster", doride, FALSE},
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},
1507 * There must be a blank entry here for every entry in the table
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},
1515 {(char *)0, (char *)0, donull, TRUE},
1516 {(char *)0, (char *)0, donull, TRUE},
1517 {(char *)0, (char *)0, donull, TRUE},
1519 {(char *)0, (char *)0, donull, TRUE},
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},
1526 {(char *)0, (char *)0, donull, TRUE},
1528 {(char *)0, (char *)0, donull, TRUE},
1530 {(char *)0, (char *)0, donull, TRUE} /* sentinel */
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},
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},
1544 {"portdebug", "wizard port debug command", wiz_port_debug, TRUE},
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},
1551 {"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE},
1553 {"wmode", "show wall modes", wiz_show_wmodes, TRUE},
1554 {(char *)0, (char *)0, donull, TRUE}
1558 * Insert debug commands into the extended command list. This function
1559 * assumes that the last entry will be the help entry.
1561 * You must add entries in ext_func_tab every time you add one to the
1562 * debug_extcmdlist().
1565 add_debug_extended_commands()
1569 /* count the # of help entries */
1570 for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++)
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;
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 */
1586 static const char template[] = "%-18s %4ld %6ld";
1587 static const char count_str[] = " count bytes";
1588 static const char separator[] = "------------------ ----- ------";
1591 count_obj(chain, total_count, total_size, top, recurse)
1601 for (count = size = 0, obj = chain; obj; obj = obj->nobj) {
1604 size += sizeof(struct obj) + obj->oxlth + obj->onamelth;
1606 if (recurse && obj->cobj)
1607 count_obj(obj->cobj, total_count, total_size, TRUE, TRUE);
1609 *total_count += count;
1610 *total_size += size;
1614 obj_chain(win, src, chain, total_count, total_size)
1622 long count = 0, size = 0;
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);
1632 mon_invent_chain(win, src, chain, total_count, total_size)
1635 struct monst *chain;
1640 long count = 0, size = 0;
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);
1652 contained(win, src, total_count, total_size)
1659 long count = 0, size = 0;
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);
1672 *total_count += count; *total_size += size;
1674 Sprintf(buf, template, src, count, size);
1675 putstr(win, 0, buf);
1679 mon_chain(win, src, chain, total_count, total_size)
1682 struct monst *chain;
1690 for (count = size = 0, mon = chain; mon; mon = mon->nmon) {
1692 size += sizeof(struct monst) + mon->mxlth + mon->mnamelth;
1694 *total_count += count;
1695 *total_size += size;
1696 Sprintf(buf, template, src, count, size);
1697 putstr(win, 0, buf);
1701 * Display memory usage of all monsters and objects on the level.
1708 long total_obj_size = 0, total_obj_count = 0;
1709 long total_mon_size = 0, total_mon_count = 0;
1711 win = create_nhwindow(NHW_TEXT);
1712 putstr(win, 0, "Current memory statistics:");
1714 Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj));
1715 putstr(win, 0, buf);
1717 putstr(win, 0, count_str);
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);
1730 contained(win, "contained",
1731 &total_obj_count, &total_obj_size);
1733 putstr(win, 0, separator);
1734 Sprintf(buf, template, "Total", total_obj_count, total_obj_size);
1735 putstr(win, 0, buf);
1739 Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst));
1740 putstr(win, 0, buf);
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);
1748 putstr(win, 0, separator);
1749 Sprintf(buf, template, "Total", total_mon_count, total_mon_size);
1750 putstr(win, 0, buf);
1752 #if defined(__BORLANDC__) && !defined(_WIN32)
1753 show_borlandc_stats(win);
1756 display_nhwindow(win, FALSE);
1757 destroy_nhwindow(win);
1765 timer_sanity_check();
1768 #ifdef DEBUG_MIGRATING_MONS
1774 struct permonst *ptr;
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))
1782 while (mcount > 0) {
1783 if (Is_stronghold(&u.uz))
1784 assign_level(&tolevel, &valley_level);
1786 get_level(&tolevel, depth(&u.uz) + 1);
1788 mtmp = makemon(ptr, 0, 0, NO_MM_FLAGS);
1789 if (mtmp) migrate_to_level(mtmp, ledger_no(&tolevel),
1790 MIGR_RANDOM, (coord *)0);
1799 #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
1800 #define unmeta(c) (0x7f & (c))
1807 boolean do_walk, do_rush, prefix_seen, bad_command,
1808 firsttime = (cmd == 0);
1810 iflags.menu_requested = FALSE;
1815 if (*cmd == '\033') {
1820 if (*cmd == DOAGAIN && !in_doagain && saveq[0]) {
1823 rhack((char *)0); /* read and execute command */
1827 /* Special case of *cmd == ' ' handled better below */
1828 if(!*cmd || *cmd == (char)0377)
1830 if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' '))
1835 return; /* probably we just had an interrupt */
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.
1844 case '5': *cmd = 'g'; break;
1845 case M('5'): *cmd = 'G'; break;
1846 case M('0'): *cmd = 'I'; break;
1849 /* handle most movement commands */
1850 do_walk = do_rush = prefix_seen = FALSE;
1851 flags.travel = iflags.travel1 = 0;
1853 case 'g': if (movecmd(cmd[1])) {
1859 case '5': if (!iflags.num_pad) break; /* else FALLTHRU */
1860 case 'G': if (movecmd(lowc(cmd[1]))) {
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
1872 case 'F': if (movecmd(cmd[1])) {
1873 flags.forcefight = 1;
1878 case 'm': if (movecmd(cmd[1]) || u.dz) {
1881 if (!u.dz) do_walk = TRUE;
1882 else cmd[0] = cmd[1]; /* "m<" or "m>" */
1886 case 'M': if (movecmd(lowc(cmd[1]))) {
1893 case '0': if (!iflags.num_pad) break;
1894 (void)ddoinv(); /* a convenience borrowed from the PC */
1899 if (iflags.travelcmd) {
1908 default: if (movecmd(*cmd)) { /* ordinary movement */
1909 flags.run = 0; /* only matters here if it was 8 */
1911 } else if (movecmd(iflags.num_pad ?
1912 unmeta(*cmd) : lowc(*cmd))) {
1915 } else if (movecmd(unctrl(*cmd))) {
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;
1930 if (multi) flags.mv = TRUE;
1932 flags.forcefight = 0;
1934 } else if (do_rush) {
1936 if (!multi) multi = max(COLNO,ROWNO);
1937 u.last_str_turn = 0;
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 */
1948 /* handle all other commands */
1950 register const struct func_tab *tlist;
1951 int res, NDECL((*func));
1953 for (tlist = cmdlist; tlist->f_char; tlist++) {
1954 if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue;
1956 if (u.uburied && !tlist->can_if_buried) {
1957 You_cant("do that while you are buried!");
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 */
1973 /* if we reach here, cmd wasn't found in cmdlist[] */
1979 register char *cp = expcmd;
1981 while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) {
1982 if (*cmd >= 040 && *cmd < 0177) {
1984 } else if (*cmd & 0200) {
1987 *cp++ = *cmd++ &= ~0200;
1990 *cp++ = *cmd++ ^ 0100;
1994 if (!prefix_seen || !iflags.cmdassist ||
1995 !help_dir(0, "Invalid direction key!"))
1996 Norep("Unknown command '%s'.", expcmd);
2005 xytod(x, y) /* convert an x,y pair into a direction code */
2010 for(dd = 0; dd < 8; dd++)
2011 if(x == xdir[dd] && y == ydir[dd]) return dd;
2017 dtoxy(cc,dd) /* convert a direction code into an x,y pair */
2027 movecmd(sym) /* also sets u.dz, but returns false for <> */
2030 register const char *dp;
2031 register const char *sdp;
2032 if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
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) {
2047 * uses getdir() but unlike getdir() it specifically
2048 * produces coordinates using the direction from getdir()
2049 * and verifies that those coordinates are ok.
2051 * If the call to getdir() returns 0, Never_mind is displayed.
2052 * If the resulting coordinates are not okay, emsg is displayed.
2054 * Returns non-zero if coordinates in cc are valid.
2056 int get_adjacent_loc(prompt,emsg,x,y,cc)
2057 const char *prompt, *emsg;
2062 if (!getdir(prompt)) {
2068 if (cc && isok(new_x,new_y)) {
2072 if (emsg) pline(emsg);
2085 if(in_doagain || *readchar_queue)
2086 dirsym = readchar();
2089 dirsym = yn_function ((s && *s != '^') ? s : "In what direction?",
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!");
2103 if (!did_help) pline("What a strange direction!");
2107 if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir();
2118 static const char wiz_only_list[] = "EFGIOVW";
2119 char buf[BUFSZ], buf2[BUFSZ], *expl;
2121 win = create_nhwindow(NHW_TEXT);
2122 if (!win) return FALSE;
2124 Sprintf(buf, "cmdassist: %s", msg);
2125 putstr(win, 0, buf);
2130 ctrl = (sym - 'A') + 1;
2131 if ((expl = dowhatdoes_core(ctrl, buf2))
2132 && (!index(wiz_only_list, sym)
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);
2142 putstr(win, 0, expl);
2144 putstr(win, 0, "To use that command, you press");
2146 "the <Ctrl> key, and the <%c> key at the same time.", sym);
2147 putstr(win, 0, buf);
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");
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");
2181 putstr(win, 0, " < up");
2182 putstr(win, 0, " > down");
2183 putstr(win, 0, " . direct at yourself");
2185 putstr(win, 0, "(Suppress this message with !cmdassist in config file.)");
2186 display_nhwindow(win, FALSE);
2187 destroy_nhwindow(win);
2197 register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8);
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;
2214 static NEARDATA int last_multi;
2217 * convert a MAP window position into a movecmd
2220 click_to_cmd(x, y, mod)
2230 if (iflags.travelcmd) {
2231 if (abs(x) <= 1 && abs(y) <= 1 ) {
2232 x = sgn(x), y = sgn(y);
2236 cmd[0] = CMD_TRAVEL;
2240 if(x == 0 && y == 0) {
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');
2245 } else if(IS_THRONE(levl[u.ux][u.uy].typ)) {
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)) {
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)) {
2256 } else if(OBJ_AT(u.ux, u.uy)) {
2257 cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ',';
2260 return "."; /* just rest */
2264 /* directional commands */
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]);
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) {
2277 if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) {
2282 if (levl[u.ux+x][u.uy+y].typ <= SCORR) {
2289 /* convert without using floating point, allowing sloppy clicking */
2292 else if(y > 2*abs(x))
2294 else if(x < -2*abs(y))
2296 else if(y < -2*abs(x))
2299 x = sgn(x), y = sgn(y);
2301 if(x == 0 && y == 0) /* map click on player to "rest" command */
2307 /* move, attack, etc. */
2309 if(mod == CLICK_1) {
2310 cmd[0] = (iflags.num_pad ? ndir[dir] : sdir[dir]);
2312 cmd[0] = (iflags.num_pad ? M(ndir[dir]) :
2313 (sdir[dir] - 'a' + 'A')); /* run command */
2322 #ifdef LINT /* static char in_line[COLNO]; */
2323 char in_line[COLNO];
2325 static char in_line[COLNO];
2328 boolean prezero = FALSE;
2332 flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */
2334 if (!iflags.num_pad || (foo = readchar()) == 'n')
2337 if (foo >= '0' && foo <= '9') {
2338 multi = 10 * multi + foo - '0';
2339 if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT;
2341 clear_nhwindow(WIN_MESSAGE);
2342 Sprintf(in_line, "Count: %d", multi);
2347 if (!multi && foo == '0') prezero = TRUE;
2348 } else break; /* not a digit */
2351 if (foo == '\033') { /* esc cancels count (TH) */
2352 clear_nhwindow(WIN_MESSAGE);
2353 multi = last_multi = 0;
2355 } else if (foo == DOAGAIN || in_doagain) {
2359 savech(0); /* reset input queue */
2368 save_cm = (char *)0;
2372 if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' ||
2373 foo == 'F' || (iflags.num_pad && (foo == '5' || foo == '-'))) {
2381 clear_nhwindow(WIN_MESSAGE);
2382 if (prezero) in_line[0] = '\033';
2394 #ifndef NOSAVEONHANGUP
2395 if (!program_state.done_hup++ && program_state.something_worth_saving)
2398 exit_nhwindows((char *)0);
2400 terminate(EXIT_SUCCESS);
2411 int x = u.ux, y = u.uy, mod = 0;
2413 if ( *readchar_queue )
2414 sym = *readchar_queue++;
2417 sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod);
2425 register int cnt = NR_OF_EOFS;
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.
2432 clearerr(stdin); /* omit if clearerr is undefined */
2434 } while (--cnt && sym == EOF);
2436 # endif /* NR_OF_EOFS */
2443 readchar_queue = click_to_cmd(x, y, mod);
2444 sym = *readchar_queue++;
2452 /* Keyboard travel command */
2456 if (!iflags.travelcmd) return 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 */
2465 pline("Where do you want to travel to?");
2466 if (getpos(&cc, TRUE, "the desired destination") < 0) {
2467 /* user pressed ESC */
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;
2479 extern void NDECL(win32con_debug_keystrokes);
2480 extern void NDECL(win32con_handler_info);
2490 int num_menu_selections;
2491 struct menu_selection_struct {
2494 } menu_selections[] = {
2496 {"test win32 keystrokes", win32con_debug_keystrokes},
2497 {"show keystroke handler information", win32con_handler_info},
2499 {(char *)0, (void NDECL((*)))0} /* array terminator */
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);
2507 for (k=0; k < num_menu_selections; ++k) {
2509 add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE,
2510 menu_selections[k].menutext, MENU_UNSELECTED);
2512 end_menu(win, "Which port debugging feature?");
2513 n = select_menu(win, PICK_ONE, &pick_list);
2514 destroy_nhwindow(win);
2516 n = pick_list[0].item.a_int - 1;
2517 free((genericptr_t) pick_list);
2518 /* execute the function */
2519 (*menu_selections[n].fn)();
2522 pline("No port-specific debug capability defined.");
2525 # endif /*PORT_DEBUG*/
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.
2535 yn_function(query,resp, def)
2536 const char *query,*resp;
2540 unsigned truncspot, reduction = sizeof(" [N] ?") + 1;
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';
2551 return (*windowprocs.win_yn_function)(qbuf, resp, def);