fix #H5462 - failed F-attack gives misleading msg
authorPatR <rankin@nethack.org>
Tue, 16 May 2017 23:22:43 +0000 (16:22 -0700)
committerPatR <rankin@nethack.org>
Tue, 16 May 2017 23:22:43 +0000 (16:22 -0700)
Report was for 'F' followed by '.' reporting "cmdassist: Invalid
direction key!" and then by a direction grid (which happened to
include '.' for self).  That behavior applied for all the movement
prefix keys ('m', 'G', &c).  When 'cmdassist' was off, "F." would
yield "Unknown command 'F.'." instead.

Now you'll get "You can't fight yourself.", either instead of the
"invalid direction key" part of cmdassist feedback (followed by a
direction grid which excludes up, down, and self since they aren't
applicable for prefix keys) or of the "unknown command" result.
Likewise, "You can't run upward." or "You can't rush downward."
for "G<" and "g>", respectively.

doc/fixes36.1
src/cmd.c

index f0da1ea2d2ee5ce71715642d88df0fa00e45374a..37b7fac4d0007ada55d264b29bedec9a6c66f119 100644 (file)
@@ -380,6 +380,8 @@ levitation vs encumbrance message sequencing issues:  putting on boots of
        of encumbrance until player took another action
 removing a blindfold with 'A' took two turns, with 'R' (and 'T') only one,
        and could result in a panic if the blindfold was stolen during removal
+cmdassist help for movement prefix followed by invalid direction was strange
+       when the direction was up, down, or self disallowed for that prefix
 
 
 Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
index 048fc5bbd3ab2e042bd821550d27255b37737156..d354195bf8802c7f806c4e1a6a70d86debd5fba8 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 cmd.c   $NHDT-Date: 1494034344 2017/05/06 01:32:24 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.256 $ */
+/* NetHack 3.6 cmd.c   $NHDT-Date: 1494976933 2017/05/16 23:22:13 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.257 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -184,8 +184,8 @@ static const char *readchar_queue = "";
 static coord clicklook_cc;
 
 STATIC_DCL char *NDECL(parse);
-STATIC_DCL void FDECL(show_direction_keys, (winid, BOOLEAN_P));
-STATIC_DCL boolean FDECL(help_dir, (CHAR_P, const char *));
+STATIC_DCL void FDECL(show_direction_keys, (winid, CHAR_P, BOOLEAN_P));
+STATIC_DCL boolean FDECL(help_dir, (CHAR_P, int, const char *));
 
 STATIC_PTR int
 doprev_message(VOID_ARGS)
@@ -3073,7 +3073,11 @@ dokeylist(VOID_ARGS)
     boolean keys_used[256] = {0};
     winid datawin;
     int i;
-    const struct {
+    static const char
+        run_desc[] = "Prefix: run until something very interesting is seen",
+        forcefight_desc[] =
+                     "Prefix: force fight even if you don't see a monster";
+    static const struct {
         int nhkf;
         const char *desc;
         boolean numpad;
@@ -3081,22 +3085,18 @@ dokeylist(VOID_ARGS)
         { NHKF_ESC, "escape from the current query/action", FALSE },
         { NHKF_RUSH,
           "Prefix: rush until something interesting is seen", FALSE },
-        { NHKF_RUN,
-          "Prefix: run until something extremely interesting is seen", FALSE },
-        { NHKF_RUN2,
-          "Prefix: run until something extremely interesting is seen", TRUE },
-        { NHKF_FIGHT,
-          "Prefix: force fight even if you don't see a monster", FALSE },
-        { NHKF_FIGHT2,
-          "Prefix: force fight even if you don't see a monster", TRUE },
+        { NHKF_RUN, run_desc, FALSE },
+        { NHKF_RUN2, run_desc, TRUE },
+        { NHKF_FIGHT, forcefight_desc, FALSE },
+        { NHKF_FIGHT2, forcefight_desc, TRUE } ,
         { NHKF_NOPICKUP,
           "Prefix: move without picking up objects/fighting", FALSE },
         { NHKF_RUN_NOPICKUP,
           "Prefix: run without picking up objects/fighting", FALSE },
-        { NHKF_DOINV, "inventory (same as #inventory)", TRUE },
+        { NHKF_DOINV, "view inventory", TRUE },
         { NHKF_REQMENU, "Prefix: request a menu", FALSE },
 #ifdef REDO
-        { NHKF_DOAGAIN , "redo the previous command", FALSE },
+        { NHKF_DOAGAIN , "re-do: perform the previous command again", FALSE },
 #endif
         { 0, (const char *) 0, FALSE }
     };
@@ -3108,7 +3108,7 @@ dokeylist(VOID_ARGS)
     /* directional keys */
     putstr(datawin, 0, "");
     putstr(datawin, 0, "Directional keys:");
-    show_direction_keys(datawin, FALSE);
+    show_direction_keys(datawin, '.', FALSE); /* '.'==self in direction grid */
 
     keys_used[(uchar) Cmd.move_NW] = keys_used[(uchar) Cmd.move_N]
         = keys_used[(uchar) Cmd.move_NE] = keys_used[(uchar) Cmd.move_W]
@@ -3942,11 +3942,12 @@ int NDECL((*cmd_func));
 }
 
 int
-ch2spkeys(c, start,end)
+ch2spkeys(c, start, end)
 char c;
 int start,end;
 {
     int i;
+
     for (i = start; i <= end; i++)
         if (Cmd.spkeys[i] == c)
             return i;
@@ -3957,6 +3958,7 @@ void
 rhack(cmd)
 register char *cmd;
 {
+    int spkey;
     boolean do_walk, do_rush, prefix_seen, bad_command,
         firsttime = (cmd == 0);
 
@@ -3990,7 +3992,9 @@ register char *cmd;
     /* handle most movement commands */
     do_walk = do_rush = prefix_seen = FALSE;
     context.travel = context.travel1 = 0;
-    switch (ch2spkeys(*cmd, NHKF_RUN,NHKF_CLICKLOOK)) {
+    spkey = ch2spkeys(*cmd, NHKF_RUN, NHKF_CLICKLOOK);
+
+    switch (spkey) {
     case NHKF_RUSH:
         if (movecmd(cmd[1])) {
             context.run = 2;
@@ -4161,14 +4165,13 @@ register char *cmd;
 
     if (bad_command) {
         char expcmd[20]; /* we expect 'cmd' to point to 1 or 2 chars */
-        register char c;
+        char c, c1 = cmd[1];
 
         expcmd[0] = '\0';
         while ((c = *cmd++) != '\0')
             Strcat(expcmd, visctrl(c)); /* add 1..4 chars plus terminator */
 
-        if (!prefix_seen || !iflags.cmdassist
-            || !help_dir(0, "Invalid direction key!"))
+        if (!prefix_seen || !help_dir(c1, spkey, "Invalid direction key!"))
             Norep("Unknown command '%s'.", expcmd);
     }
     /* didn't move */
@@ -4319,7 +4322,8 @@ retry:
         if (!index(quitchars, dirsym)) {
             help_requested = (dirsym == Cmd.spkeys[NHKF_GETDIR_HELP]);
             if (help_requested || iflags.cmdassist) {
-                did_help = help_dir((s && *s == '^') ? dirsym : 0,
+                did_help = help_dir((s && *s == '^') ? dirsym : '\0',
+                                    NHKF_ESC,
                                     help_requested ? (const char *) 0
                                                   : "Invalid direction key!");
                 if (help_requested)
@@ -4339,61 +4343,141 @@ retry:
 }
 
 STATIC_OVL void
-show_direction_keys(win, nodiag)
-winid win;
+show_direction_keys(win, centerchar, nodiag)
+winid win; /* should specify a window which is using a fixed-width font... */
+char centerchar; /* '.' or '@' or ' ' */
 boolean nodiag;
 {
     char buf[BUFSZ];
 
+    if (!centerchar)
+        centerchar = ' ';
+
     if (nodiag) {
         Sprintf(buf, "             %c   ", Cmd.move_N);
         putstr(win, 0, buf);
         putstr(win, 0, "             |   ");
-        Sprintf(buf, "          %c- . -%c", Cmd.move_W, Cmd.move_E);
+        Sprintf(buf, "          %c- %c -%c",
+                Cmd.move_W, centerchar, Cmd.move_E);
         putstr(win, 0, buf);
         putstr(win, 0, "             |   ");
         Sprintf(buf, "             %c   ", Cmd.move_S);
         putstr(win, 0, buf);
     } else {
-        Sprintf(buf, "          %c  %c  %c", Cmd.move_NW, Cmd.move_N,
-                Cmd.move_NE);
+        Sprintf(buf, "          %c  %c  %c",
+                Cmd.move_NW, Cmd.move_N, Cmd.move_NE);
         putstr(win, 0, buf);
         putstr(win, 0, "           \\ | / ");
-        Sprintf(buf, "          %c- . -%c", Cmd.move_W, Cmd.move_E);
+        Sprintf(buf, "          %c- %c -%c",
+                Cmd.move_W, centerchar, Cmd.move_E);
         putstr(win, 0, buf);
         putstr(win, 0, "           / | \\ ");
-        Sprintf(buf, "          %c  %c  %c", Cmd.move_SW, Cmd.move_S,
-                Cmd.move_SE);
+        Sprintf(buf, "          %c  %c  %c",
+                Cmd.move_SW, Cmd.move_S, Cmd.move_SE);
         putstr(win, 0, buf);
     };
 }
 
+/* explain choices if player has asked for getdir() help or has given
+   an invalid direction after a prefix key ('F', 'g', 'm', &c), which
+   might be bogus but could be up, down, or self when not applicable */
 STATIC_OVL boolean
-help_dir(sym, msg)
+help_dir(sym, spkey, msg)
 char sym;
+int spkey; /* NHKF_ code for prefix key, if one was used, or for ESC */
 const char *msg;
 {
     static const char wiz_only_list[] = "EFGIVW";
     char ctrl;
     winid win;
     char buf[BUFSZ], buf2[BUFSZ], *explain;
+    const char *dothat, *how;
+    boolean prefixhandling, viawindow;
+
+    /* NHKF_ESC indicates that player asked for help at getdir prompt */
+    viawindow = (spkey == NHKF_ESC || iflags.cmdassist);
+    prefixhandling = (spkey != NHKF_ESC);
+    /*
+     * Handling for prefix keys that don't want special directions.
+     * Delivered via pline if 'cmdassist' is off, or instead of the
+     * general message if it's on.
+     */
+    dothat = "do that";
+    how = " at"; /* for "<action> at yourself"; not used for up/down */
+    switch (spkey) {
+    case NHKF_NOPICKUP:
+        dothat = "move";
+        break;
+    case NHKF_RUSH:
+        dothat = "rush";
+        break;
+    case NHKF_RUN2:
+        if (!Cmd.num_pad)
+            break; /* else FALLTHRU */
+    case NHKF_RUN:
+    case NHKF_RUN_NOPICKUP:
+        dothat = "run";
+        break;
+    case NHKF_FIGHT2:
+        if (!Cmd.num_pad)
+            break; /* else FALLTHRU */
+    case NHKF_FIGHT:
+        dothat = "fight";
+        how = ""; /* avoid "fight at yourself" */
+        break;
+    default:
+        prefixhandling = FALSE;
+        break;
+    }
+
+    buf[0] = '\0';
+    /* for movement prefix followed by '.' or (numpad && 's') to mean 'self';
+       note: '-' for hands (inventory form of 'self') is not handled here */
+    if (prefixhandling
+        && (sym == Cmd.spkeys[NHKF_GETDIR_SELF]
+            || (Cmd.num_pad && sym == Cmd.spkeys[NHKF_GETDIR_SELF2]))) {
+        Sprintf(buf, "You can't %s%s yourself.", dothat, how);
+    /* for movement prefix followed by up or down */
+    } else if (prefixhandling && (sym == '<' || sym == '>')) {
+        Sprintf(buf, "You can't %s %s.", dothat,
+                /* was "upwards" and "downwards", but they're considered
+                   to be variants of canonical "upward" and "downward" */
+                (sym == '<') ? "upward" : "downward");
+    }
+
+    /* if 'cmdassist', display via pline() and we're done (note: asking
+       for help at getdir() prompt forces cmdassist for this operation) */
+    if (!viawindow) {
+        if (*buf) {
+            pline("%s", buf);
+            return TRUE;
+        }
+        /* when 'cmdassist' is off and caller doesn't insist, do nothing */
+        return FALSE;
+    }
 
     win = create_nhwindow(NHW_TEXT);
     if (!win)
         return FALSE;
-    if (msg) {
+
+    if (*buf) {
+        /* show bad-prefix message instead of general invalid-direction one */
+        putstr(win, 0, buf);
+        putstr(win, 0, "");
+    } else if (msg) {
         Sprintf(buf, "cmdassist: %s", msg);
         putstr(win, 0, buf);
         putstr(win, 0, "");
     }
-    if (letter(sym) || sym == '[') { /* 'dat/cmdhelp' shows ESC as ^[ */
+
+    if (!prefixhandling && (letter(sym) || sym == '[')) {
+        /* '[': old 'cmdhelp' showed ESC as ^[ */
         sym = highc(sym); /* @A-Z[ (note: letter() accepts '@') */
         ctrl = (sym - 'A') + 1; /* 0-27 (note: 28-31 aren't applicable) */
         if ((explain = dowhatdoes_core(ctrl, buf2)) != 0
             && (!index(wiz_only_list, sym) || wizard)) {
             Sprintf(buf, "Are you trying to use ^%c%s?", sym,
-                    index(wiz_only_list, sym)
-                        ? ""
+                    index(wiz_only_list, sym) ? ""
                         : " as specified in the Guidebook");
             putstr(win, 0, buf);
             putstr(win, 0, "");
@@ -4407,17 +4491,29 @@ const char *msg;
         }
     }
 
-    Sprintf(buf, "Valid direction keys %sare:",
-            NODIAG(u.umonnum) ? "in your current form " : "");
+    Sprintf(buf, "Valid direction keys%s%s%s are:",
+            prefixhandling ? " to " : "", prefixhandling ? dothat : "",
+            NODIAG(u.umonnum) ? " in your current form" : "");
     putstr(win, 0, buf);
-    show_direction_keys(win, NODIAG(u.umonnum));
+    show_direction_keys(win, !prefixhandling ? '.' : ' ', NODIAG(u.umonnum));
+
+    if (!prefixhandling || spkey == NHKF_NOPICKUP) {
+        /* NOPICKUP: unlike the other prefix keys, 'm' allows up/down for
+           stair traversal; we won't get here when "m<" or "m>" has been
+           given but we include up and down for 'm'+invalid_direction;
+           self is excluded as a viable direction for every prefix */
+        putstr(win, 0, "");
+        putstr(win, 0, "          <  up");
+        putstr(win, 0, "          >  down");
+        if (!prefixhandling) {
+            int selfi = Cmd.num_pad ? NHKF_GETDIR_SELF2 : NHKF_GETDIR_SELF;
+
+            Sprintf(buf,   "       %4s  direct at yourself",
+                    visctrl(Cmd.spkeys[selfi]));
+            putstr(win, 0, buf);
+        }
+    }
 
-    putstr(win, 0, "");
-    putstr(win, 0, "          <  up");
-    putstr(win, 0, "          >  down");
-    Sprintf(buf,   "       %4s  direct at yourself",
-            visctrl(Cmd.spkeys[NHKF_GETDIR_SELF]));
-    putstr(win, 0, buf);
     if (msg) {
         /* non-null msg means that this wasn't an explicit user request */
         putstr(win, 0, "");