-^ Show the type of a trap
-^[ Cancel command (same as ESCape key)
-^A Redo the previous command
-^C Quit the game
-^D Kick something (usually a door, chest, or box)
-^E Search a room (available in debug mode only)
-^F Map the level (available in debug mode only)
-^G Create a monster (available in debug mode only)
-^I Identify all items (available in debug mode only)
-^O Show dungeon overview (normal play) or special levels (debug mode)
-^P Toggle through previously displayed game messages
-^R Redraw screen
-^T Teleport around level
-^V Teleport between levels (available in debug mode only)
-^W Wish (available in debug mode only)
-^X Show your attributes (shows more in debug or explore mode)
-^Z Suspend game (only if defined)
-a Apply (use) a tool
-A Remove all armor
-b Go southwest 1 space
-B Go southwest until you are on top of something
-^B Go southwest until you are near something
-c Close a door
-C Call (name) a monster, an individual object, or a type of object
-d Drop an item
-D Drop specific item types
-e Eat something
-E Engrave writing on the floor
-f Fire ammunition from quiver
-F Followed by direction, fight a monster (even if you don't sense it)
-g Followed by direction, move until you are near something
-G Followed by direction, same as control-direction
-h Go west 1 space (if number_pad is on, display help message)
-H Go west until you are on top of something
-^H Go west until you are near something
-i Show your inventory
-I Inventory specific item types
-j Go south 1 space (or if number_pad is on, jump to another location)
-J Go south until you are on top of something
-^J Go south until you are near something
-k Go north 1 space (or if number_pad is on, kick something)
-K Go north until you are on top of something
-^K Go north until you are near something
-l Go east 1 space (or if number_pad is on, loot a box on the floor)
-L Go east until you are on top of something
-^L Go east until you are near something
-m Followed by direction, move without picking anything up or fighting
-M Followed by direction, move a distance without picking anything up
-n Go southeast 1 space
-N Go southeast until you are on something (if number_pad is on, name)
-^N Go southeast until you are near something
-o Open a door
-O Show option settings, possibly change them
-p Pay your shopping bill
-P Put on an accessory (ring, amulet, etc)
-q Quaff (drink) something (potion, water, etc)
-Q Select ammunition for quiver
-r Read a scroll or spellbook
-R Remove an accessory (ring, amulet, etc)
-s Search for traps and secret doors
-S Save the game
-t Throw something
-T Take off one piece of armor
-u Go northeast 1 space (or if number_pad is on, untrap something)
-U Go northeast until you are on top of something
-^U Go northeast until you are near something
-v Show version
-V Show long version and game history
-w Wield (put in use) a weapon
-W Wear a piece of armor
-x Swap wielded and secondary weapons
-X Toggle two-weapon combat
-y Go northwest 1 space
-Y Go northwest until you are on top of something
-^Y Go northwest until you are near something
-z Zap a wand
-Z Zap (cast) a spell
-< Go up a staircase
-> Go down a staircase
-/ Show what type of thing a symbol corresponds to
-? Give a help message
-& Tell what a command does
-! Do a shell escape (only if defined)
-\ Show what object types have been discovered
-` Show discovered types for one class of objects
-_ Travel via a shortest-path algorithm to a point on the map
-. Rest one move while doing nothing
- Rest one move while doing nothing (if rest_on_space option is on)
-: Look at what is on the floor
-; Show what type of thing a map symbol on the level corresponds to
-, Pick up things at the current location
-@ Toggle the pickup option on/off
-) Show the weapon currently wielded
-[ Show the armor currently worn
-= Show the ring(s) currently worn
-" Show the amulet currently worn
-( Show the tools currently in use
-* Show all equipment in use (combination of the ),[,=,",( commands)
-$ Count your gold
-+ List known spells
-# Perform an extended command
-M-? Display extended command help (if the platform allows this)
-M-2 Toggle two-weapon combat (unless number_pad is enabled)
-M-a Adjust inventory letters
-M-A Annotate: supply a name for the current dungeon level
-M-c Talk to someone
-M-C Conduct: list voluntary challenges you have maintained
-M-d Dip an object into something
-M-e Advance or check weapons skills
-M-f Force a lock
-M-i Invoke an object's special powers
-M-j Jump to another location
-M-l Loot a box on the floor
-M-m Use a monster's special ability
-M-n Name a monster, an individual object, or a type of object
-M-o Offer a sacrifice to the gods
-M-O Overview: show a summary of the explored dungeon
-M-p Pray to the gods for help
-M-q Quit
-M-r Rub a lamp
-M-R Ride: mount or dismount a saddled steed
-M-s Sit down
-M-t Turn undead
-M-T Tip: empty a container
-M-u Untrap something (trap, door, or chest)
-M-v Print compile time options for this version of NetHack
-M-w Wipe off your face
+&# cmdhelp
+& Tell what command a keystroke invokes
+^ Show the type of an adjacent trap
+^[ Cancel command (same as ESCape key)
+&? debug
+^E Search for nearby traps, secret doors, and unseen monsters
+^F Map level; reveals traps and secret corridors but not secret doors
+^G Create a monster by name or class
+^I View inventory with all items identified
+^O List special level locations
+^V Teleport between levels
+^W Wish for something
+&: #!debug
+^E unavailable debugging command
+^F unavailable debugging command
+^G unavailable debugging command
+^I unavailable debugging command
+^O Shortcut for '#overview': list interesting levels you have visited
+^V unavailable debugging command
+^W unavailable debugging command
+&. #?debug
+&? number_pad=0,-1
+b Go southwest 1 space
+B Go southwest until you are on top of something
+h Go west 1 space
+H Go west until you are on top of something
+j Go south 1 space
+J Go south until you are on top of something
+k Go north 1 space
+K Go north until you are on top of something
+l Go east 1 space
+L Go east until you are on top of something
+n Go southeast 1 space
+N Go southeast until you are on something
+u Go northeast 1 space
+U Go northeast until you are on top of something
+&# y,Y handled below
+&: #number_pad=1,2,3,4
+h Help: synonym for '?'
+j Jump: shortcut for '#jump'
+k Kick: synonym for '^D'
+l Loot: shortcut for '#loot'
+n Start a count; continue with digit(s)
+N Name: shortcut for '#name'
+u Untrap: shortcut for '#untrap'
+&. #0,-1 vs 1,2,3,4
+a Apply (use) a tool or break a wand
+A Remove all armor and/or all accessories and/or unwield weapons
+^A Redo the previous command
+^B Go southwest until you are near something
+c Close a door
+C Call (name) a monster, an individual object, or a type of object
+^C Interrupt: quit the game
+d Drop an item
+D Drop specific item types
+^D Kick something (usually a door, chest, or box)
+e Eat something
+E Engrave writing on the floor
+f Fire ammunition from quiver
+F Followed by direction, fight a monster (even if you don't sense it)
+g Followed by direction, move until you are near something
+G Followed by direction, same as control-direction
+^H Go west until you are near something
+i Show your inventory
+I Inventory specific item types
+^J Go south until you are near something
+^K Go north until you are near something
+^L Go east until you are near something
+m Followed by direction, move without picking anything up or fighting
+M Followed by direction, move a distance without picking anything up
+^N Go southeast until you are near something
+o Open a door
+O Show option settings, possibly change them
+p Pay your shopping bill
+P Put on an accessory (ring, amulet, etc; will work for armor too)
+^P Toggle through previously displayed game messages
+q Quaff (drink) something (potion, water, etc)
+Q Select ammunition for quiver (use '#quit' to quit)
+r Read a scroll or spellbook
+R Remove an accessory (ring, amulet, etc; will work for armor too)
+^R Redraw screen
+s Search all immediately adjacent locations for traps and secret doors
+S Save the game (and exit; there is no "save and keep going")
+t Throw something (choose an item, then a direction--not a target)
+T Take off one piece of armor (will work for accessories too)
+^T Teleport around level
+^U Go northeast until you are near something
+v Show version ('#version' shows more information)
+V Show history of game's development
+w Wield a weapon (for dual weapons: 'w' secondary, 'x', 'w' primary, 'X')
+W Wear a piece of armor (will work for accessories too)
+x Swap wielded and secondary weapons
+X Toggle two-weapon combat
+^X Show your attributes (shows more in debug or explore mode)
+&? number_pad=0,1,2,3,4
+&? number_pad=0
+y Go northwest 1 space
+Y Go northwest until you are on top of something
+&.
+^Y Go northwest until you are near something
+z Zap a wand
+Z Zap (cast) a spell
+&? suspend
+^Z Suspend game; 'fg' (foreground) to resume
+&:
+^Z unavailable command: suspend
+&.
+&: number_pad=-1
+y Zap a wand
+Y Zap (cast) a spell
+&? suspend
+^Y Suspend game; 'fg' (foreground) to resume
+&:
+^Y unavailable command: suspend
+&.
+z Go northwest 1 space
+Z Go northwest until you are on top of something
+^Z Go northwest until you are near something
+&. #0,1..4 vs -1
+< Go up a staircase
+> Go down a staircase
+/ Show what type of thing a symbol corresponds to
+? Give a help message
+&? shell
+! Do a shell escape; 'exit' shell to come back
+&:
+! unavailable command: shell
+&.
+\ Show what object types have been discovered
+` Show discovered types for one class of objects
+_ Travel via a shortest-path algorithm to a point on the map
+. Rest one move while doing nothing
+&? rest_on_space
+ Rest one move while doing nothing
+&.
+: Look at what is on the floor
+; Show what type of thing a map symbol on the level corresponds to
+, Pick up things at the current location
+@ Toggle the pickup option on/off
+) Show the weapon(s) currently wielded or readied
+[ Show the armor currently worn
+= Show the ring(s) currently worn
+" Show the amulet currently worn
+( Show the tools currently in use
+* Show all equipment in use (combination of the ),[,=,",( commands)
+$ Count your gold
++ List known spells
+# Perform an extended command (use '#?' to list choices)
+&# number_pad:
+&# -1 = numpad off, swap y with z (including Y with Z, ^Y with ^Z, M-y &c)
+&# 0 = numpad off (default)
+&# 1 = numpad on, normal keypad layout, '5'->'g'
+&# 2 = numpad on, normal keypad layout, '5'->'G'
+&# 3 = numpad on, phone keypad layout, '5'->'g'
+&# 4 = numpad on, phone keypad layout, '5'->'G'
+&? number_pad = 1,2,3,4
+0 Show inventory
+4 Move west
+6 Move east
+&: #-1,0
+0 Continue a count
+4 Start or continue a count
+6 Start or continue a count
+&. #1,2,3,4 vs -1,0
+&? number_pad=1,2
+7 Move northwest
+8 Move north
+9 Move northeast
+1 Move southwest
+2 Move south
+3 Move southeast
+&: number_pad=3,4
+1 Move northwest
+2 Move north
+3 Move northeast
+7 Move southwest
+8 Move south
+9 Move southeast
+&: #-1,0
+1 Start or continue a count
+2 Start or continue a count
+3 Start or continue a count
+7 Start or continue a count
+8 Start or continue a count
+9 Start or continue a count
+&. #1,2 vs 3,4 vs -1,0
+&? number_pad=1,3
+5 'g' movement prefix
+&: number_pad=2,4
+5 'G' movement prefix
+&: #-1,0
+5 Start or continue a count
+M-2 Toggle two-weapon combat
+&. #1,3 vs 2,4 vs -1,0
+M-? Display extended command help (if the platform allows this)
+M-a Adjust inventory letters
+M-A Annotate: supply a name for the current dungeon level
+M-c Chat: talk to an adjacent creature
+M-C Conduct: list voluntary challenges you have maintained
+M-d Dip an object into something
+M-e Enhance: check weapons skills, advance them if eligible
+M-f Force a lock
+M-i Invoke an object's special powers
+M-j Jump to a nearby location
+M-l Loot a box on the floor
+M-m When polymorphed, use a monster's special ability
+M-n Name a monster, an individual object, or a type of object
+M-N Name a monster, an individual object, or a type of object
+M-o Offer a sacrifice to the gods
+M-O Overview: show a summary of the explored dungeon
+M-p Pray to the gods for help
+M-q Quit (exit without saving)
+M-r Rub a lamp or a touchstone
+M-R Ride: mount or dismount a saddled steed
+M-s Sit down
+M-t Turn undead
+M-T Tip: empty a container
+M-u Untrap something (trap, door, or chest)
+M-v Print compile time options for this version of NetHack
+M-w Wipe off your face
STATIC_DCL void FDECL(checkfile, (char *, struct permonst *,
BOOLEAN_P, BOOLEAN_P));
STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
+STATIC_DCL void NDECL(whatdoes_help);
+STATIC_DCL boolean FDECL(whatdoes_cond, (char *, boolean *, int *, int));
STATIC_DCL boolean FDECL(help_menu, (int *));
STATIC_DCL void NDECL(docontact);
#ifdef PORT_HELP
}
STATIC_DCL void
-dowhatdoes_help()
+whatdoes_help()
{
dlb *fp;
char *p, buf[BUFSZ];
destroy_nhwindow(tmpwin);
}
+#define WD_STACKLIMIT 5
+
+STATIC_OVL boolean
+whatdoes_cond(buf, stack, depth, lnum)
+char *buf;
+boolean *stack;
+int *depth, lnum;
+{
+ const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
+ boolean newcond, neg;
+ char *p, *q, act = buf[1];
+ int np = 0;
+
+ buf += 2;
+ mungspaces(buf);
+ if (act == '#' || *buf == '#') {
+ *buf = '\0';
+ neg = FALSE; /* lint suppression */
+ p = q = (char *) 0;
+ } else {
+ if ((neg = (*buf == '!')) != 0)
+ if (*++buf == ' ')
+ ++buf;
+ p = index(buf, '='), q = index(buf, ':');
+ if (!p || (q && q < p))
+ p = q;
+ if (p) { /* we have a value specified */
+ /* handle a space before or after (or both) '=' (or ':') */
+ if (p > buf && p[-1] == ' ')
+ p[-1] = '\0'; /* end of keyword in buf[] */
+ *p++ = '\0'; /* terminate keyword, advance to start of value */
+ if (*p == ' ')
+ p++;
+ }
+ }
+ newcond = TRUE;
+ if (*buf && (act == '?' || act == ':')) {
+ if (!strcmpi(buf, "number_pad")) {
+ if (!p) {
+ newcond = iflags.num_pad;
+ } else {
+ /* convert internal encoding (separate yes/no and 0..3)
+ back to user-visible one (-1..4) */
+ np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
+ : (-1 * iflags.num_pad_mode); /* -1..0 */
+ newcond = FALSE;
+ for (; p; p = q) {
+ q = index(p, ',');
+ if (q)
+ *q++ = '\0';
+ if (atoi(p) == np) {
+ newcond = TRUE;
+ break;
+ }
+ }
+ }
+ } else if (!strcmpi(buf, "rest_on_space")) {
+ newcond = flags.rest_on_space;
+ } else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
+ newcond = flags.debug; /* == wizard */
+ } else if (!strcmpi(buf, "shell")) {
+#ifdef SHELL
+ /* should we also check sysopt.shellers? */
+ newcond = TRUE;
+#else
+ newcond = FALSE;
+#endif
+ } else if (!strcmpi(buf, "suspend")) {
+#ifdef SUSPEND
+ /* sysopt.shellers is also used for dosuspend()... */
+ newcond = TRUE;
+#else
+ newcond = FALSE;
+#endif
+ } else {
+ impossible(
+ "cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
+ act, lnum, buf);
+ neg = FALSE;
+ }
+ /* this works for number_pad too: &? !number_pad:-1,0
+ would be true for 1..4 after negation */
+ if (neg)
+ newcond = !newcond;
+ }
+ switch (act) {
+ default:
+ case '#': /* comment */
+ break;
+ case '.': /* endif */
+ if (--*depth < 0) {
+ impossible(badstackfmt, '.', lnum);
+ *depth = 0;
+ }
+ break;
+ case ':': /* else or elif */
+ if (*depth == 0) {
+ impossible(badstackfmt, ':', lnum);
+ *depth = 1; /* so that stack[*depth - 1] is a valid access */
+ }
+ if (stack[*depth] || !stack[*depth - 1])
+ stack[*depth] = FALSE;
+ else if (newcond)
+ stack[*depth] = TRUE;
+ break;
+ case '?': /* if */
+ if (++*depth >= WD_STACKLIMIT) {
+ impossible(badstackfmt, '?', lnum);
+ *depth = WD_STACKLIMIT - 1;
+ }
+ stack[*depth] = newcond && stack[*depth - 1];
+ break;
+ }
+ return stack[*depth];
+}
+
char *
dowhatdoes_core(q, cbuf)
char q;
char *cbuf;
{
dlb *fp;
- char bufr[BUFSZ];
- register char *buf = &bufr[6], ctrl, meta;
+ char buf[BUFSZ];
+ boolean cond, stack[WD_STACKLIMIT];
+ int ctrl, meta, depth = 0, lnum = 0;
fp = dlb_fopen(CMDHELPFILE, "r");
if (!fp) {
return 0;
}
- ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
- meta = ((0x80 & q) ? (0x7f & q) : 0);
- while (dlb_fgets(buf, BUFSZ - 6, fp)) {
- if ((ctrl && *buf == '^' && *(buf + 1) == ctrl)
- || (meta && *buf == 'M' && *(buf + 1) == '-'
- && *(buf + 2) == meta) || *buf == q) {
+ meta = (0x80 & (uchar) q) != 0;
+ if (meta)
+ q &= 0x7f;
+ ctrl = (0x1f & (uchar) q) == (uchar) q;
+ if (ctrl)
+ q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
+ else if (q == 0x7f)
+ ctrl = 1, q = '?';
+
+ cond = stack[0] = TRUE, stack[1] = FALSE;
+ while (dlb_fgets(buf, sizeof buf, fp)) {
+ ++lnum;
+ if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
+ cond = whatdoes_cond(buf, stack, &depth, lnum);
+ continue;
+ }
+ if (!cond)
+ continue;
+ if (meta ? (buf[0] == 'M' && buf[1] == '-'
+ && (ctrl ? buf[2] == '^' && highc(buf[3]) == q
+ : buf[2] == q))
+ : (ctrl ? buf[0] == '^' && highc(buf[1]) == q
+ : buf[0] == q)) {
(void) strip_newline(buf);
- if (ctrl && buf[2] == '\t') {
- buf = bufr + 1;
- (void) strncpy(buf, "^? ", 8);
- buf[1] = ctrl;
- } else if (meta && buf[3] == '\t') {
- buf = bufr + 2;
+ if (index(buf, '\t'))
+ (void) tabexpand(buf);
+ if (meta && ctrl && buf[4] == ' ') {
+ (void) strncpy(buf, "M-^? ", 8);
+ buf[3] = q;
+ } else if (meta && buf[3] == ' ') {
(void) strncpy(buf, "M-? ", 8);
- buf[2] = meta;
- } else if (buf[1] == '\t') {
- buf = bufr;
+ buf[2] = q;
+ } else if (ctrl && buf[2] == ' ') {
+ (void) strncpy(buf, "^? ", 8);
+ buf[1] = q;
+ } else if (buf[1] == ' ') {
+ (void) strncpy(buf, "? ", 8);
buf[0] = q;
- (void) strncpy(buf + 1, " ", 7);
}
(void) dlb_fclose(fp);
Strcpy(cbuf, buf);
}
}
(void) dlb_fclose(fp);
+ if (depth != 0)
+ impossible("cmdhelp: mismatched &? &: &. conditionals.");
return (char *) 0;
}
if (q == '\033' && iflags.altmeta) {
/* in an ideal world, we would know whether another keystroke
was already pending, but this is not an ideal world...
- if user types ESC, we'll essentially hang until another
+ if user typed ESC, we'll essentially hang until another
character is typed */
- q = yn_function("", (char *) 0, '\0');
+ q = yn_function("]", (char *) 0, '\0');
if (q != '\033')
q = (char) ((uchar) q | 0200);
}
reslt = dowhatdoes_core(q, bufr);
if (reslt) {
if (q == '&' || q == '?')
- dowhatdoes_help();
+ whatdoes_help();
pline("%s", reslt);
} else {
pline("No such command '%s', char code %d (0%03o or 0x%02x).",
return 0;
}
-void
+STATIC_OVL void
docontact()
{
winid cwin = create_nhwindow(NHW_TEXT);