OSDN Git Service

fix #45401
[jnethack/source.git] / src / cmd.c
index afc6220..f8dc36a 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -1,17 +1,36 @@
-/* NetHack 3.6 cmd.c   $NHDT-Date: 1523306904 2018/04/09 20:48:24 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.281 $ */
+/* NetHack 3.6 cmd.c   $NHDT-Date: 1575245052 2019/12/02 00:04:12 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.350 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2013. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 /* JNetHack Copyright */
 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016            */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2022            */
 /* JNetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
 #include "lev.h"
 #include "func_tab.h"
 
+/* Macros for meta and ctrl modifiers:
+ *   M and C return the meta/ctrl code for the given character;
+ *     e.g., (C('c') is ctrl-c
+ */
+#ifndef M
+#ifndef NHSTDC
+#define M(c) (0x80 | (c))
+#else
+#define M(c) ((c) - 128)
+#endif /* NHSTDC */
+#endif
+
+#ifndef C
+#define C(c) (0x1f & (c))
+#endif
+
+#define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
+#define unmeta(c) (0x7f & (c))
+
 #ifdef ALTMETA
 STATIC_VAR boolean alt_esc = FALSE;
 #endif
@@ -36,7 +55,6 @@ extern const char *enc_stat[]; /* encumbrance status from botl.c */
 
 #ifdef DEBUG
 extern int NDECL(wiz_debug_cmd_bury);
-extern int NDECL(wiz_debug_cmd_traveldisplay);
 #endif
 
 #ifdef DUMB /* stuff commented out in extern.h, but needed here */
@@ -105,7 +123,7 @@ extern int NDECL(dosit);              /**/
 extern int NDECL(dotalk);             /**/
 extern int NDECL(docast);             /**/
 extern int NDECL(dovspell);           /**/
-extern int NDECL(dotele);             /**/
+extern int NDECL(dotelecmd);          /**/
 extern int NDECL(dountrap);           /**/
 extern int NDECL(doversion);          /**/
 extern int NDECL(doextversion);       /**/
@@ -116,10 +134,10 @@ extern int NDECL(dozap);              /**/
 extern int NDECL(doorganize);         /**/
 #endif /* DUMB */
 
-static int NDECL(dosuspend_core); /**/
-
 static int NDECL((*timed_occ_fn));
 
+STATIC_PTR int NDECL(dosuspend_core);
+STATIC_PTR int NDECL(dosh_core);
 STATIC_PTR int NDECL(doherecmdmenu);
 STATIC_PTR int NDECL(dotherecmdmenu);
 STATIC_PTR int NDECL(doprev_message);
@@ -142,8 +160,6 @@ STATIC_PTR int NDECL(wiz_level_change);
 STATIC_PTR int NDECL(wiz_show_seenv);
 STATIC_PTR int NDECL(wiz_show_vision);
 STATIC_PTR int NDECL(wiz_smell);
-STATIC_PTR int NDECL(wiz_intrinsic);
-STATIC_PTR int NDECL(wiz_mon_polycontrol);
 STATIC_PTR int NDECL(wiz_show_wmodes);
 STATIC_DCL void NDECL(wiz_map_levltyp);
 STATIC_DCL void NDECL(wiz_levltyp_legend);
@@ -167,12 +183,10 @@ STATIC_DCL void FDECL(contained_stats, (winid, const char *, long *, long *));
 STATIC_DCL void FDECL(misc_stats, (winid, long *, long *));
 STATIC_PTR int NDECL(wiz_show_stats);
 STATIC_DCL boolean FDECL(accept_menu_prefix, (int NDECL((*))));
-#ifdef PORT_DEBUG
-STATIC_DCL int NDECL(wiz_port_debug);
-#endif
 STATIC_PTR int NDECL(wiz_rumor_check);
 STATIC_PTR int NDECL(doattributes);
 
+STATIC_DCL void FDECL(enlght_out, (const char *));
 STATIC_DCL void FDECL(enlght_line, (const char *, const char *, const char *,
                                     const char *));
 STATIC_DCL char *FDECL(enlght_combatinc, (const char *, int, int, char *));
@@ -181,14 +195,12 @@ STATIC_DCL boolean NDECL(walking_on_water);
 STATIC_DCL boolean FDECL(cause_known, (int));
 STATIC_DCL char *FDECL(attrval, (int, int, char *));
 STATIC_DCL void FDECL(background_enlightenment, (int, int));
+STATIC_DCL void FDECL(basics_enlightenment, (int, int));
 STATIC_DCL void FDECL(characteristics_enlightenment, (int, int));
 STATIC_DCL void FDECL(one_characteristic, (int, int, int));
 STATIC_DCL void FDECL(status_enlightenment, (int, int));
 STATIC_DCL void FDECL(attributes_enlightenment, (int, int));
 
-static const char *readchar_queue = "";
-static coord clicklook_cc;
-
 STATIC_DCL void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)),
                                              const char *));
 STATIC_DCL char FDECL(here_cmd_menu, (BOOLEAN_P));
@@ -197,6 +209,19 @@ STATIC_DCL char *NDECL(parse);
 STATIC_DCL void FDECL(show_direction_keys, (winid, CHAR_P, BOOLEAN_P));
 STATIC_DCL boolean FDECL(help_dir, (CHAR_P, int, const char *));
 
+static const char *readchar_queue = "";
+static coord clicklook_cc;
+/* for rejecting attempts to use wizard mode commands */
+/*JP
+static const char unavailcmd[] = "Unavailable command '%s'.";
+*/
+static const char unavailcmd[] = "'%s'\83R\83}\83\93\83h\82Í\8eg\82¦\82È\82¢\81D";
+/* for rejecting #if !SHELL, !SUSPEND */
+/*JP
+static const char cmdnotavail[] = "'%s' command not available.";
+*/
+static const char cmdnotavail[] = "'%s'\83R\83}\83\93\83h\82Í\97\98\97p\82Å\82«\82Ü\82¹\82ñ\81D";
+
 STATIC_PTR int
 doprev_message(VOID_ARGS)
 {
@@ -287,6 +312,8 @@ pgetchar() /* courtesy of aeb@cwi.nl */
 {
     register int ch;
 
+    if (iflags.debug_fuzzer)
+        return randomkey();
     if (!(ch = popch()))
         ch = nhgetch();
     return (char) ch;
@@ -335,11 +362,14 @@ doextcmd(VOID_ARGS)
 
         func = extcmdlist[idx].ef_funct;
         if (!wizard && (extcmdlist[idx].flags & WIZMODECMD)) {
+/*JP
             You("can't do that.");
+*/
+            pline("\82»\82ê\82Í\82Å\82«\82Ü\82¹\82ñ\81D");
             return 0;
         }
         if (iflags.menu_requested && !accept_menu_prefix(func)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("'%s' prefix has no effect for the %s command.",
                   visctrl(Cmd.spkeys[NHKF_REQMENU]),
                   extcmdlist[idx].ef_txt);
@@ -356,51 +386,219 @@ doextcmd(VOID_ARGS)
     return retval;
 }
 
-/* here after #? - now list all full-word commands */
+/* here after #? - now list all full-word commands and provid
+   some navigation capability through the long list */
 int
 doextlist(VOID_ARGS)
 {
     register const struct ext_func_tab *efp;
-    char buf[BUFSZ];
-    winid datawin;
-    char ch = cmd_from_func(doextcmd);
+    char buf[BUFSZ], searchbuf[BUFSZ], promptbuf[QBUFSZ];
+    winid menuwin;
+    anything any;
+    menu_item *selected;
+    int n, pass;
+    int menumode = 0, menushown[2], onelist = 0;
+    boolean redisplay = TRUE, search = FALSE;
+#if 0 /*JP:T*/
+    static const char *headings[] = { "Extended commands",
+                                      "Debugging Extended Commands" };
+#else
+    static const char *headings[] = { "\8ag\92£\83R\83}\83\93\83h",
+                                      "\83f\83o\83b\83O\8ag\92£\83R\83}\83\93\83h" };
+#endif
 
-    datawin = create_nhwindow(NHW_TEXT);
-    putstr(datawin, 0, "");
-/*JP
-    putstr(datawin, 0, "            Extended Commands List");
-*/
-    putstr(datawin, 0, "            \8ag\92£\83R\83}\83\93\83h\88ê\97\97");
-    putstr(datawin, 0, "");
-    if (ch) {
-#if 0 /*JP*/
-        Sprintf(buf, "    Press '%s', then type:",
-                visctrl(ch));
+    searchbuf[0] = '\0';
+    menuwin = create_nhwindow(NHW_MENU);
+
+    while (redisplay) {
+        redisplay = FALSE;
+        any = zeroany;
+        start_menu(menuwin);
+#if 0 /*JP:T*/
+        add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                 "Extended Commands List", MENU_UNSELECTED);
 #else
-        Sprintf(buf, "    '%s'\82ð\89\9f\82µ\82½\82 \82Æ\83^\83C\83v\82¹\82æ:",
-                visctrl(ch));
+        add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                 "\8ag\92£\83R\83}\83\93\83h\88ê\97\97", MENU_UNSELECTED);
 #endif
-        putstr(datawin, 0, buf);
-        putstr(datawin, 0, "");
-    }
+        add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                 "", MENU_UNSELECTED);
 
-    for (efp = extcmdlist; efp->ef_txt; efp++) {
-        if (!wizard && (efp->flags & WIZMODECMD))
-            continue;
-        Sprintf(buf, "   %-15s %c %s.",
-                efp->ef_txt,
-                (efp->flags & AUTOCOMPLETE) ? '*' : ' ',
-                efp->ef_desc);
-        putstr(datawin, 0, buf);
+#if 0 /*JP:T*/
+        Strcpy(buf, menumode ? "Show" : "Hide");
+        Strcat(buf, " commands that don't autocomplete");
+        if (!menumode)
+            Strcat(buf, " (those not marked with [A])");
+#else
+        Strcpy(buf, "\8e©\93®\95â\8a®\82³\82ê\82È\82¢\83R\83}\83\93\83h\82ð");
+        Strcat(buf, menumode ? "\95\\8e¦\82·\82é" : "\95\\8e¦\82µ\82È\82¢ (\82±\82ê\82ç\82Í[A]\83}\81[\83N\82ª\82Â\82©\82È\82¢)");
+#endif
+        any.a_int = 1;
+        add_menu(menuwin, NO_GLYPH, &any, 'a', 0, ATR_NONE, buf,
+                 MENU_UNSELECTED);
+
+        if (!*searchbuf) {
+            any.a_int = 2;
+            /* was 's', but then using ':' handling within the interface
+               would only examine the two or three meta entries, not the
+               actual list of extended commands shown via separator lines;
+               having ':' as an explicit selector overrides the default
+               menu behavior for it; we retain 's' as a group accelerator */
+#if 0 /*JP:T*/
+            add_menu(menuwin, NO_GLYPH, &any, ':', 's', ATR_NONE,
+                     "Search extended commands", MENU_UNSELECTED);
+#else
+            add_menu(menuwin, NO_GLYPH, &any, ':', 's', ATR_NONE,
+                     "\8ag\92£\83R\83}\83\93\83h\82ð\8c\9f\8dõ\82·\82é", MENU_UNSELECTED);
+#endif
+        } else {
+#if 0 /*JP:T*/
+            Strcpy(buf, "Show all, clear search");
+#else
+            Strcpy(buf, "\91S\82Ä\95\\8e¦; \8c\9f\8dõ\82ð\83N\83\8a\83A");
+#endif
+            if (strlen(buf) + strlen(searchbuf) + strlen(" (\"\")") < QBUFSZ)
+                Sprintf(eos(buf), " (\"%s\")", searchbuf);
+            any.a_int = 3;
+            /* specifying ':' as a group accelerator here is mostly a
+               statement of intent (we'd like to accept it as a synonym but
+               also want to hide it from general menu use) because it won't
+               work for interfaces which support ':' to search; use as a
+               general menu command takes precedence over group accelerator */
+            add_menu(menuwin, NO_GLYPH, &any, 's', ':', ATR_NONE,
+                     buf, MENU_UNSELECTED);
+        }
+        if (wizard) {
+            any.a_int = 4;
+#if 0 /*JP:T*/
+            add_menu(menuwin, NO_GLYPH, &any, 'z', 0, ATR_NONE,
+                     onelist ? "Show debugging commands in separate section"
+                     : "Show all alphabetically, including debugging commands",
+                     MENU_UNSELECTED);
+#else
+            add_menu(menuwin, NO_GLYPH, &any, 'z', 0, ATR_NONE,
+                     onelist ? "\83f\83o\83b\83O\83R\83}\83\93\83h\82Í\95Ê\82Ì\90ß\82É\95\\8e¦\82·\82é"
+                     : "\83f\83o\83b\83O\83R\83}\83\93\83h\82ð\8aÜ\82Þ\91S\82Ä\82Ì\83R\83}\83\93\83h\82ð\83A\83\8b\83t\83@\83x\83b\83g\8f\87\82É\95\\8e¦\82·\82é",
+                     MENU_UNSELECTED);
+#endif
+        }
+        any = zeroany;
+        add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                 "", MENU_UNSELECTED);
+        menushown[0] = menushown[1] = 0;
+        n = 0;
+        for (pass = 0; pass <= 1; ++pass) {
+            /* skip second pass if not in wizard mode or wizard mode
+               commands are being integrated into a single list */
+            if (pass == 1 && (onelist || !wizard))
+                break;
+            for (efp = extcmdlist; efp->ef_txt; efp++) {
+                int wizc;
+
+                if ((efp->flags & CMD_NOT_AVAILABLE) != 0)
+                    continue;
+                /* if hiding non-autocomplete commands, skip such */
+                if (menumode == 1 && (efp->flags & AUTOCOMPLETE) == 0)
+                    continue;
+                /* if searching, skip this command if it doesn't match */
+                if (*searchbuf
+                    /* first try case-insensitive substring match */
+                    && !strstri(efp->ef_txt, searchbuf)
+                    && !strstri(efp->ef_desc, searchbuf)
+                    /* wildcard support; most interfaces use case-insensitve
+                       pmatch rather than regexp for menu searching */
+                    && !pmatchi(searchbuf, efp->ef_txt)
+                    && !pmatchi(searchbuf, efp->ef_desc))
+                    continue;
+                /* skip wizard mode commands if not in wizard mode;
+                   when showing two sections, skip wizard mode commands
+                   in pass==0 and skip other commands in pass==1 */
+                wizc = (efp->flags & WIZMODECMD) != 0;
+                if (wizc && !wizard)
+                    continue;
+                if (!onelist && pass != wizc)
+                    continue;
+
+                /* We're about to show an item, have we shown the menu yet?
+                   Doing menu in inner loop like this on demand avoids a
+                   heading with no subordinate entries on the search
+                   results menu. */
+                if (!menushown[pass]) {
+                    Strcpy(buf, headings[pass]);
+                    add_menu(menuwin, NO_GLYPH, &any, 0, 0,
+                             iflags.menu_headings, buf, MENU_UNSELECTED);
+                    menushown[pass] = 1;
+                }
+                Sprintf(buf, " %-14s %-3s %s",
+                        efp->ef_txt,
+                        (efp->flags & AUTOCOMPLETE) ? "[A]" : " ",
+                        efp->ef_desc);
+                add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                         buf, MENU_UNSELECTED);
+                ++n;
+            }
+            if (n)
+                add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                         "", MENU_UNSELECTED);
+        }
+        if (*searchbuf && !n)
+#if 0 /*JP:T*/
+            add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                     "no matches", MENU_UNSELECTED);
+#else
+            add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                     "\88ê\92v\82È\82µ", MENU_UNSELECTED);
+#endif
+
+        end_menu(menuwin, (char *) 0);
+        n = select_menu(menuwin, PICK_ONE, &selected);
+        if (n > 0) {
+            switch (selected[0].item.a_int) {
+            case 1: /* 'a': toggle show/hide non-autocomplete */
+                menumode = 1 - menumode;  /* toggle 0 -> 1, 1 -> 0 */
+                redisplay = TRUE;
+                break;
+            case 2: /* ':' when not searching yet: enable search */
+                search = TRUE;
+                break;
+            case 3: /* 's' when already searching: disable search */
+                search = FALSE;
+                searchbuf[0] = '\0';
+                redisplay = TRUE;
+                break;
+            case 4: /* 'z': toggle showing wizard mode commands separately */
+                search = FALSE;
+                searchbuf[0] = '\0';
+                onelist = 1 - onelist;  /* toggle 0 -> 1, 1 -> 0 */
+                redisplay = TRUE;
+                break;
+            }
+            free((genericptr_t) selected);
+        } else {
+            search = FALSE;
+            searchbuf[0] = '\0';
+        }
+        if (search) {
+#if 0 /*JP:T*/
+            Strcpy(promptbuf, "Extended command list search phrase");
+            Strcat(promptbuf, "?");
+#else
+            Strcpy(promptbuf, "\8ag\92£\83R\83}\83\93\83h\82Ì\8c\9f\8dõ\95\8e\9a\97ñ\82Í?");
+#endif
+            getlin(promptbuf, searchbuf);
+            (void) mungspaces(searchbuf);
+            if (searchbuf[0] == '\033')
+                searchbuf[0] = '\0';
+            if (*searchbuf)
+                redisplay = TRUE;
+            search = FALSE;
+        }
     }
-    putstr(datawin, 0, "");
-    putstr(datawin, 0, "    Commands marked with a * will be autocompleted.");
-    display_nhwindow(datawin, FALSE);
-    destroy_nhwindow(datawin);
+    destroy_nhwindow(menuwin);
     return 0;
 }
 
-#ifdef TTY_GRAPHICS
+#if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS)
 #define MAX_EXT_CMD 200 /* Change if we ever have more ext cmds */
 
 /*
@@ -437,7 +635,8 @@ extcmd_via_menu()
         any = zeroany;
         /* populate choices */
         for (efp = extcmdlist; efp->ef_txt; efp++) {
-            if (!(efp->flags & AUTOCOMPLETE)
+            if ((efp->flags & CMD_NOT_AVAILABLE)
+                || !(efp->flags & AUTOCOMPLETE)
                 || (!wizard && (efp->flags & WIZMODECMD)))
                 continue;
             if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) {
@@ -445,11 +644,11 @@ extcmd_via_menu()
                 if ((len = (int) strlen(efp->ef_desc)) > biggest)
                     biggest = len;
                 if (++i > MAX_EXT_CMD) {
-#if defined(BETA)
+#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
                     impossible(
       "Exceeded %d extended commands in doextcmd() menu; 'extmenu' disabled.",
                                MAX_EXT_CMD);
-#endif /* BETA */
+#endif /* NH_DEVEL_STATUS != NH_STATUS_RELEASED */
                     iflags.extmenu = 0;
                     return -1;
                 }
@@ -539,7 +738,7 @@ extcmd_via_menu()
         if (n == 1) {
             if (matchlevel > (QBUFSZ - 2)) {
                 free((genericptr_t) pick_list);
-#if defined(BETA)
+#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
                 impossible("Too many chars (%d) entered in extcmd_via_menu()",
                            matchlevel);
 #endif
@@ -685,11 +884,7 @@ wiz_wish(VOID_ARGS) /* Unlimited wishes for debug mode by Paul Polderman */
         flags.verbose = save_verbose;
         (void) encumber_msg();
     } else
-/*JP
-        pline("Unavailable command '%s'.",
-*/
-        pline("'%s'\83R\83}\83\93\83h\82Í\8eg\82¦\82È\82¢\81D",
-              visctrl((int) cmd_from_func(wiz_wish)));
+        pline(unavailcmd, visctrl((int) cmd_from_func(wiz_wish)));
     return 0;
 }
 
@@ -699,47 +894,104 @@ wiz_identify(VOID_ARGS)
 {
     if (wizard) {
         iflags.override_ID = (int) cmd_from_func(wiz_identify);
-        if (display_inventory((char *) 0, TRUE) == -1)
-            identify_pack(0, FALSE);
+        /* command remapping might leave #wizidentify as the only way
+           to invoke us, in which case cmd_from_func() will yield NUL;
+           it won't matter to display_inventory()/display_pickinv()
+           if ^I invokes some other command--what matters is that
+           display_pickinv() and xname() see override_ID as nonzero */
+        if (!iflags.override_ID)
+            iflags.override_ID = C('I');
+        (void) display_inventory((char *) 0, FALSE);
         iflags.override_ID = 0;
     } else
-/*JP
-        pline("Unavailable command '%s'.",
-*/
-        pline("'%s'\83R\83}\83\93\83h\82Í\8eg\82¦\82È\82¢\81D",
-              visctrl((int) cmd_from_func(wiz_identify)));
+        pline(unavailcmd, visctrl((int) cmd_from_func(wiz_identify)));
     return 0;
 }
 
+/* #wizmakemap - discard current dungeon level and replace with a new one */
 STATIC_PTR int
 wiz_makemap(VOID_ARGS)
 {
-    /* FIXME: doesn't handle riding */
     if (wizard) {
         struct monst *mtmp;
+        boolean was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz);
 
         rm_mapseen(ledger_no(&u.uz));
-        for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
+        for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
+            if (mtmp->isgd) { /* vault is going away; get rid of guard */
+                mtmp->isgd = 0;
+                mongone(mtmp);
+            }
+            if (DEADMONSTER(mtmp))
+                continue;
             if (mtmp->isshk)
                 setpaid(mtmp);
+            /* TODO?
+             *  Reduce 'born' tally for each monster about to be discarded
+             *  by savelev(), otherwise replacing heavily populated levels
+             *  tends to make their inhabitants become extinct.
+             */
+        }
         if (Punished) {
             ballrelease(FALSE);
             unplacebc();
         }
-        check_special_room(TRUE);
-        dmonsfree();
+        /* reset lock picking unless it's for a carried container */
+        maybe_reset_pick((struct obj *) 0);
+        /* reset interrupted digging if it was taking place on this level */
+        if (on_level(&context.digging.level, &u.uz))
+            (void) memset((genericptr_t) &context.digging, 0,
+                          sizeof (struct dig_info));
+        /* reset cached targets */
+        iflags.travelcc.x = iflags.travelcc.y = 0; /* travel destination */
+        context.polearm.hitmon = (struct monst *) 0; /* polearm target */
+        /* escape from trap */
+        reset_utrap(FALSE);
+        check_special_room(TRUE); /* room exit */
+        u.ustuck = (struct monst *) 0;
+        u.uswallow = 0;
+        u.uinwater = 0;
+        u.uundetected = 0; /* not hidden, even if means are available */
+        dmonsfree(); /* purge dead monsters from 'fmon' */
+        /* keep steed and other adjacent pets after releasing them
+           from traps, stopping eating, &c as if hero were ascending */
+        keepdogs(TRUE); /* (pets-only; normally we'd be using 'FALSE' here) */
+
+        /* discard current level; "saving" is used to release dynamic data */
         savelev(-1, ledger_no(&u.uz), FREE_SAVE);
+        /* create a new level; various things like bestowing a guardian
+           angel on Astral or setting off alarm on Ft.Ludios are handled
+           by goto_level(do.c) so won't occur for replacement levels */
         mklev();
+
         vision_reset();
         vision_full_recalc = 1;
         cls();
-        (void) safe_teleds(TRUE);
+        /* was using safe_teleds() but that doesn't honor arrival region
+           on levels which have such; we don't force stairs, just area */
+        u_on_rndspot((u.uhave.amulet ? 1 : 0) /* 'going up' flag */
+                     | (was_in_W_tower ? 2 : 0));
+        losedogs();
+        kill_genocided_monsters();
+        /* u_on_rndspot() might pick a spot that has a monster, or losedogs()
+           might pick the hero's spot (only if there isn't already a monster
+           there), so we might have to move hero or the co-located monster */
+        if ((mtmp = m_at(u.ux, u.uy)) != 0)
+            u_collide_m(mtmp);
+        initrack();
         if (Punished) {
             unplacebc();
             placebc();
         }
         docrt();
         flush_screen(1);
+        deliver_splev_message(); /* level entry */
+        check_special_room(FALSE); /* room entry */
+#ifdef INSURANCE
+        save_currentstate();
+#endif
+    } else {
+        pline(unavailcmd, "#wizmakemap");
     }
     return 0;
 }
@@ -761,11 +1013,7 @@ wiz_map(VOID_ARGS)
         HConfusion = save_Hconf;
         HHallucination = save_Hhallu;
     } else
-/*JP
-        pline("Unavailable command '%s'.",
-*/
-        pline("'%s'\83R\83}\83\93\83h\82Í\8eg\82¦\82È\82¢\81D",
-              visctrl((int) cmd_from_func(wiz_map)));
+        pline(unavailcmd, visctrl((int) cmd_from_func(wiz_map)));
     return 0;
 }
 
@@ -776,11 +1024,7 @@ wiz_genesis(VOID_ARGS)
     if (wizard)
         (void) create_particular();
     else
-/*JP
-        pline("Unavailable command '%s'.",
-*/
-        pline("'%s'\83R\83}\83\93\83h\82Í\8eg\82¦\82È\82¢\81D",
-              visctrl((int) cmd_from_func(wiz_genesis)));
+        pline(unavailcmd, visctrl((int) cmd_from_func(wiz_genesis)));
     return 0;
 }
 
@@ -791,11 +1035,7 @@ wiz_where(VOID_ARGS)
     if (wizard)
         (void) print_dungeon(FALSE, (schar *) 0, (xchar *) 0);
     else
-/*JP
-        pline("Unavailable command '%s'.",
-*/
-        pline("'%s'\83R\83}\83\93\83h\82Í\8eg\82¦\82È\82¢\81D",
-              visctrl((int) cmd_from_func(wiz_where)));
+        pline(unavailcmd, visctrl((int) cmd_from_func(wiz_where)));
     return 0;
 }
 
@@ -806,11 +1046,7 @@ wiz_detect(VOID_ARGS)
     if (wizard)
         (void) findit();
     else
-/*JP
-        pline("Unavailable command '%s'.",
-*/
-        pline("'%s'\83R\83}\83\93\83h\82Í\8eg\82¦\82È\82¢\81D",
-              visctrl((int) cmd_from_func(wiz_detect)));
+        pline(unavailcmd, visctrl((int) cmd_from_func(wiz_detect)));
     return 0;
 }
 
@@ -821,26 +1057,7 @@ wiz_level_tele(VOID_ARGS)
     if (wizard)
         level_tele();
     else
-/*JP
-        pline("Unavailable command '%s'.",
-*/
-        pline("'%s'\83R\83}\83\93\83h\82Í\8eg\82¦\82È\82¢\81D",
-              visctrl((int) cmd_from_func(wiz_level_tele)));
-    return 0;
-}
-
-/* #monpolycontrol command - choose new form for shapechangers, polymorphees */
-STATIC_PTR int
-wiz_mon_polycontrol(VOID_ARGS)
-{
-    iflags.mon_polycontrol = !iflags.mon_polycontrol;
-#if 0 /*JP*/
-    pline("Monster polymorph control is %s.",
-          iflags.mon_polycontrol ? "on" : "off");
-#else
-    pline("\89ö\95¨\82Ì\95Ï\89»\90§\8cä: %s",
-          iflags.mon_polycontrol ? "\83I\83\93" : "\83I\83t");
-#endif
+        pline(unavailcmd, visctrl((int) cmd_from_func(wiz_level_tele)));
     return 0;
 }
 
@@ -849,7 +1066,7 @@ STATIC_PTR int
 wiz_level_change(VOID_ARGS)
 {
     char buf[BUFSZ] = DUMMY;
-    int newlevel;
+    int newlevel = 0;
     int ret;
 
 /*JP
@@ -907,10 +1124,18 @@ wiz_level_change(VOID_ARGS)
 STATIC_PTR int
 wiz_panic(VOID_ARGS)
 {
-/*JP
-    if (yn("Do you want to call panic() and end your game?") == 'y')
-*/
-    if (yn("panic()\8aÖ\90\94\82ð\8cÄ\82Ñ\8fo\82µ\82Ä\83Q\81[\83\80\82ð\8fI\97¹\82³\82¹\82Ü\82·\82©\81H") == 'y')
+    if (iflags.debug_fuzzer) {
+        u.uhp = u.uhpmax = 1000;
+        u.uen = u.uenmax = 1000;
+        return 0;
+    }
+#if 0 /*JP:T*/
+    if (paranoid_query(ParanoidQuit,
+                       "Do you want to call panic() and end your game?"))
+#else
+    if (paranoid_query(ParanoidQuit,
+                       "panic()\8aÖ\90\94\82ð\8cÄ\82Ñ\8fo\82µ\82Ä\83Q\81[\83\80\82ð\8fI\97¹\82³\82¹\82Ü\82·\82©\81H"))
+#endif
         panic("Crash test.");
     return 0;
 }
@@ -1013,7 +1238,7 @@ wiz_show_wmodes(VOID_ARGS)
     int x, y;
     char row[COLNO + 1];
     struct rm *lev;
-    boolean istty = !strcmp(windowprocs.name, "tty");
+    boolean istty = WINDOWPORT("tty");
 
     win = create_nhwindow(NHW_TEXT);
     if (istty)
@@ -1384,10 +1609,28 @@ wiz_intrinsic(VOID_ARGS)
                 make_vomiting(newtimeout, FALSE);
                 pline1(buf);
                 break;
+            case WARN_OF_MON:
+                if (!Warn_of_mon) {
+                    context.warntype.speciesidx = PM_GRID_BUG;
+                    context.warntype.species
+                                         = &mons[context.warntype.speciesidx];
+                }
+                goto def_feedback;
+            case GLIB:
+                /* slippery fingers applies to gloves if worn at the time
+                   so persistent inventory might need updating */
+                make_glib((int) newtimeout);
+                goto def_feedback;
+            case LEVITATION:
+            case FLYING:
+                float_vs_flight();
+                /*FALLTHRU*/
             default:
+ def_feedback:
                 pline("Timeout for %s %s %d.", propertynames[i].prop_name,
                       oldtimeout ? "increased by" : "set to", amt);
-                incr_itimeout(&u.uprops[p].intrinsic, amt);
+                if (p != GLIB)
+                    incr_itimeout(&u.uprops[p].intrinsic, amt);
                 break;
             }
             context.botl = 1; /* probably not necessary... */
@@ -1396,8 +1639,7 @@ wiz_intrinsic(VOID_ARGS)
             free((genericptr_t) pick_list);
         doredraw();
     } else
-        pline("Unavailable command '%s'.",
-              visctrl((int) cmd_from_func(wiz_intrinsic)));
+        pline(unavailcmd, visctrl((int) cmd_from_func(wiz_intrinsic)));
     return 0;
 }
 
@@ -1434,20 +1676,32 @@ doterrain(VOID_ARGS)
     any = zeroany;
     any.a_int = 1;
     add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE,
+/*JP
              "known map without monsters, objects, and traps",
+*/
+             "\89ö\95¨\81C\95¨\81Cã©\82È\82µ\82Ì\92n\90}",
              MENU_SELECTED);
     any.a_int = 2;
     add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE,
+/*JP
              "known map without monsters and objects",
+*/
+             "\89ö\95¨\81C\95¨\82È\82µ\82Ì\92n\90}",
              MENU_UNSELECTED);
     any.a_int = 3;
     add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE,
+/*JP
              "known map without monsters",
+*/
+             "\89ö\95¨\82È\82µ\82Ì\92n\90}",
              MENU_UNSELECTED);
     if (discover || wizard) {
         any.a_int = 4;
         add_menu(men, NO_GLYPH, &any, 0, 0, ATR_NONE,
+/*JP
                  "full map without monsters, objects, and traps",
+*/
+                 "\89ö\95¨\81C\95¨\81Cã©\82È\82µ\82Ì\8a®\91S\82È\92n\90}",
                  MENU_UNSELECTED);
         if (wizard) {
             any.a_int = 5;
@@ -1460,7 +1714,10 @@ doterrain(VOID_ARGS)
                      MENU_UNSELECTED);
         }
     }
+/*JP
     end_menu(men, "View which?");
+*/
+    end_menu(men, "\82Ç\82ê\82ð\8c©\82é\81H");
 
     n = select_menu(men, PICK_ONE, &sel);
     destroy_nhwindow(men);
@@ -1503,6 +1760,7 @@ doterrain(VOID_ARGS)
 
 /* -enlightenment and conduct- */
 static winid en_win = WIN_ERR;
+static boolean en_via_menu = FALSE;
 #if 0 /*JP*/
 static const char You_[] = "You ", are[] = "are ", were[] = "were ",
                   have[] = "have ", had[] = "had ", can[] = "can ",
@@ -1552,6 +1810,19 @@ static const char have_been[] = "have been ", have_never[] = "have never ",
 #endif
 
 static void
+enlght_out(buf)
+const char *buf;
+{
+    if (en_via_menu) {
+        anything any;
+
+        any = zeroany;
+        add_menu(en_win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
+    } else
+        putstr(en_win, 0, buf);
+}
+
+static void
 enlght_line(start, middle, end, ps)
 const char *start, *middle, *end, *ps;
 {
@@ -1561,7 +1832,7 @@ const char *start, *middle, *end, *ps;
     Sprintf(buf, " %s%s%s%s.", start, middle, end, ps);
 */
     Sprintf(buf, "%s%s%s%s\81D", start, middle, end, ps);
-    putstr(en_win, 0, buf);
+    enlght_out(buf);
 }
 
 /* format increased chance to hit or damage or defense (Protection) */
@@ -1572,14 +1843,20 @@ int incamt, final;
 char *outbuf;
 {
     const char *modif, *bonus;
+#if 0 /*JP*/
     boolean invrt;
+#endif
     int absamt;
 
     absamt = abs(incamt);
     /* Protection amount is typically larger than damage or to-hit;
        reduce magnitude by a third in order to stretch modifier ranges
        (small:1..5, moderate:6..10, large:11..19, huge:20+) */
+#if 0 /*JP:T*/
     if (!strcmp(inctyp, "defense"))
+#else
+    if (!strcmp(inctyp, "\96h\8cä"))
+#endif
         absamt = (absamt * 2) / 3;
 
     if (absamt <= 3)
@@ -1611,7 +1888,9 @@ char *outbuf;
 */
     bonus = (incamt > 0) ? "\83{\81[\83i\83X" : "\83y\83i\83\8b\83e\83B";
     /* "bonus <foo>" (to hit) vs "<bar> bonus" (damage, defense) */
+#if 0 /*JP*/
     invrt = strcmp(inctyp, "to hit") ? TRUE : FALSE;
+#endif
 
 #if 0 /*JP*/
     Sprintf(outbuf, "%s %s %s", modif, invrt ? inctyp : bonus,
@@ -1636,18 +1915,33 @@ int final;
 
     switch (category) {
     case HALF_PHDAM:
+/*JP
         category_name = "physical";
+*/
+        category_name = "\95¨\97\9d";
         break;
     case HALF_SPDAM:
+/*JP
         category_name = "spell";
+*/
+        category_name = "\8eô\95¶";
         break;
     default:
+/*JP
         category_name = "unknown";
+*/
+        category_name = "\95s\96¾";
         break;
     }
+#if 0 /*JP:T*/
     Sprintf(buf, " %s %s damage", (final || wizard) ? "half" : "reduced",
             category_name);
     enl_msg(You_, "take", "took", buf, from_what(category));
+#else
+    Sprintf(buf, " %s\83_\83\81\81[\83W\82ð%s", (final || wizard) ? "\94¼\8c¸" : "\8c¸\8f­",
+            category_name);
+    enl_msg(You_, "\82µ\82Ä\82¢\82é", "\82µ\82Ä\82¢\82½", buf, from_what(category));
+#endif
 }
 
 /* is hero actively using water walking capability on water (or lava)? */
@@ -1704,11 +1998,16 @@ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */
 {
     char buf[BUFSZ], tmpbuf[BUFSZ];
 
+    en_win = create_nhwindow(NHW_MENU);
+    en_via_menu = !final;
+    if (en_via_menu)
+        start_menu(en_win);
+
     Strcpy(tmpbuf, plname);
     *tmpbuf = highc(*tmpbuf); /* same adjustment as bottom line */
     /* as in background_enlightenment, when poly'd we need to use the saved
        gender in u.mfemale rather than the current you-as-monster gender */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     Sprintf(buf, "%s the %s's attributes:", tmpbuf,
             ((Upolyd ? u.mfemale : flags.female) && urole.name.f)
                 ? urole.name.f
@@ -1721,13 +2020,14 @@ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */
              tmpbuf);
 #endif
 
-    en_win = create_nhwindow(NHW_MENU);
     /* title */
-    putstr(en_win, 0, buf); /* "Conan the Archeologist's attributes:" */
+    enlght_out(buf); /* "Conan the Archeologist's attributes:" */
     /* background and characteristics; ^X or end-of-game disclosure */
     if (mode & BASICENLIGHTENMENT) {
-        /* role, race, alignment, deities */
+        /* role, race, alignment, deities, dungeon level, time, experience */
         background_enlightenment(mode, final);
+        /* hit points, energy points, armor class, gold */
+        basics_enlightenment(mode, final);
         /* strength, dexterity, &c */
         characteristics_enlightenment(mode, final);
     }
@@ -1743,7 +2043,17 @@ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */
         /* intrinsics and other traditional enlightenment feedback */
         attributes_enlightenment(mode, final);
     }
-    display_nhwindow(en_win, TRUE);
+
+    if (!en_via_menu) {
+        display_nhwindow(en_win, TRUE);
+    } else {
+        menu_item *selected = 0;
+
+        end_menu(en_win, (char *) 0);
+        if (select_menu(en_win, PICK_NONE, &selected) > 0)
+            free((genericptr_t) selected);
+        en_via_menu = FALSE;
+    }
     destroy_nhwindow(en_win);
     en_win = WIN_ERR;
 }
@@ -1765,11 +2075,11 @@ int final;
     role_titl = (innategend && urole.name.f) ? urole.name.f : urole.name.m;
     rank_titl = rank_of(u.ulevel, Role_switch, innategend);
 
-    putstr(en_win, 0, ""); /* separator after title */
+    enlght_out(""); /* separator after title */
 /*JP
-    putstr(en_win, 0, "Background:");
+    enlght_out("Background:");
 */
-    putstr(en_win, 0, "\94w\8ci\8fî\95ñ:");
+    enlght_out("\94w\8ci\8fî\95ñ:");
 
     /* if polymorphed, report current shape before underlying role;
        will be repeated as first status: "you are transformed" and also
@@ -1787,7 +2097,7 @@ int final;
             Sprintf(tmpbuf, "%s ", genders[flags.female ? 1 : 0].adj);
 */
             Sprintf(tmpbuf, "%s\82Ì", genders[flags.female ? 1 : 0].adj);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, "%sin %s%s form", !final ? "currently " : "", tmpbuf,
                 uasmon->mname);
 #else
@@ -1811,14 +2121,14 @@ int final;
         Sprintf(tmpbuf, "%s", genders[innategend].adj);
     buf[0] = '\0';
     if (Upolyd)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Strcpy(buf, "actually "); /* "You are actually a ..." */
 #else
         Strcpy(buf, "\8eÀ\8dÛ\82É\82Í"); /* "\82 \82È\82½\82Í\8eÀ\8dÛ\82É\82Í..." */
 #endif
     if (!strcmpi(rank_titl, role_titl)) {
         /* omit role when rank title matches it */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(eos(buf), "%s, level %d %s%s", an(rank_titl), u.ulevel,
                 tmpbuf, urace.noun);
 #else
@@ -1826,7 +2136,7 @@ int final;
                 tmpbuf, urace.adj, role_titl);
 #endif
     } else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(eos(buf), "%s, a level %d %s%s %s", an(rank_titl), u.ulevel,
                 tmpbuf, urace.adj, role_titl);
 #else
@@ -1834,10 +2144,7 @@ int final;
                 tmpbuf, urace.adj, role_titl, rank_titl);
 #endif
     }
-/*JP
-        you_are(buf, "");
-*/
-        you_are_ing(buf, "");
+    you_are(buf, "");
 
     /* report alignment (bypass you_are() in order to omit ending period);
        adverb is used to distinguish between temporary change (helm of opp.
@@ -1876,7 +2183,7 @@ int final;
                      : "",
             u_gname(), !final ? iru : ita);
 #endif
-    putstr(en_win, 0, buf);
+    enlght_out(buf);
     /* show the rest of this game's pantheon (finishes previous sentence)
        [appending "also Moloch" at the end would allow for straightforward
        trailing "and" on all three aligned entries but looks too verbose] */
@@ -1886,7 +2193,7 @@ int final;
     Strcpy(buf, "\82 \82È\82½\82Í");
 #endif
     if (u.ualign.type != A_LAWFUL)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(eos(buf), " %s (%s) and", align_gname(A_LAWFUL),
                 align_str(A_LAWFUL));
 #else
@@ -1894,7 +2201,7 @@ int final;
                 align_str(A_LAWFUL));
 #endif
     if (u.ualign.type != A_NEUTRAL)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(eos(buf), " %s (%s)%s", align_gname(A_NEUTRAL),
                 align_str(A_NEUTRAL),
                 (u.ualign.type != A_CHAOTIC) ? " and" : "");
@@ -1903,8 +2210,8 @@ int final;
                 align_str(A_NEUTRAL),
                 (u.ualign.type != A_CHAOTIC) ? "\82¨\82æ\82Ñ" : "");
 #endif
-#if 0 /*JP*/
     if (u.ualign.type != A_CHAOTIC)
+#if 0 /*JP:T*/
         Sprintf(eos(buf), " %s (%s)", align_gname(A_CHAOTIC),
                 align_str(A_CHAOTIC));
 #else
@@ -1917,7 +2224,7 @@ int final;
 #else
     Sprintf(eos(buf), "\82Æ\91Î\97§\82µ\82Ä%s\81D", !final ? iru : ita);
 #endif
-    putstr(en_win, 0, buf);
+    enlght_out(buf);
 
     /* show original alignment,gender,race,role if any have been changed;
        giving separate message for temporary alignment change bypasses need
@@ -1932,14 +2239,15 @@ int final;
         Sprintf(buf, "actually %s", align_str(u.ualignbase[A_CURRENT]));
 */
         Sprintf(buf, "\8eÀ\8dÛ\82É\82Í%s", align_str(u.ualignbase[A_CURRENT]));
-/*JP
+#if 0 /*JP*/
         you_are(buf, "");
-*/
+#else
         enl_msg(buf, "\82Ä\82¢\82é", "\82Ä\82¢\82½", "", "");
+#endif
         difalgn &= ~1; /* suppress helm from "started out <foo>" message */
     }
     if (difgend || difalgn) { /* sex change or perm align change or both */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, " You started out %s%s%s.",
                 difgend ? genders[flags.initgend].adj : "",
                 (difgend && difalgn) ? " and " : "",
@@ -1950,76 +2258,373 @@ int final;
                 (difgend && difalgn) ? "\82©\82Â" : "",
                 difalgn ? align_str(u.ualignbase[A_ORIGINAL]) : "");
 #endif
-        putstr(en_win, 0, buf);
+        enlght_out(buf);
     }
+
+    /* As of 3.6.2: dungeon level, so that ^X really has all status info as
+       claimed by the comment below; this reveals more information than
+       the basic status display, but that's one of the purposes of ^X;
+       similar information is revealed by #overview; the "You died in
+       <location>" given by really_done() is more rudimentary than this */
+    *buf = *tmpbuf = '\0';
+    if (In_endgame(&u.uz)) {
+        int egdepth = observable_depth(&u.uz);
+
+        (void) endgamelevelname(tmpbuf, egdepth);
+#if 0 /*JP*/
+        Sprintf(buf, "in the endgame, on the %s%s",
+                !strncmp(tmpbuf, "Plane", 5) ? "Elemental " : "", tmpbuf);
+#else
+        Sprintf(buf, "\8dÅ\8fI\8e\8e\97û\82Ì%s", tmpbuf);
+#endif
+    } else if (Is_knox(&u.uz)) {
+        /* this gives away the fact that the knox branch is only 1 level */
+/*JP
+        Sprintf(buf, "on the %s level", dungeons[u.uz.dnum].dname);
+*/
+        Sprintf(buf, "%s", dungeons[u.uz.dnum].dname);
+        /* TODO? maybe phrase it differently when actually inside the fort,
+           if we're able to determine that (not trivial) */
+    } else {
+        char dgnbuf[QBUFSZ];
+
+        Strcpy(dgnbuf, dungeons[u.uz.dnum].dname);
+#if 0 /*JP*/
+        if (!strncmpi(dgnbuf, "The ", 4))
+            *dgnbuf = lowc(*dgnbuf);
+#endif
+#if 0 /*JP*/
+        Sprintf(tmpbuf, "level %d",
+                In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
+#else
+        if (In_quest(&u.uz)) {
+            Sprintf(tmpbuf, "\91æ%d\8aK\91w", dunlev(&u.uz));
+        } else {
+            Sprintf(tmpbuf, "\92n\89º%d\8aK", depth(&u.uz));
+        }
+#endif
+        /* TODO? maybe extend this bit to include various other automatic
+           annotations from the dungeon overview code */
+        if (Is_rogue_level(&u.uz))
+/*JP
+            Strcat(tmpbuf, ", a primitive area");
+*/
+            Strcat(tmpbuf, ", \92P\8f\83\82È\90¢\8aE");
+        else if (Is_bigroom(&u.uz) && !Blind)
+/*JP
+            Strcat(tmpbuf, ", a very big room");
+*/
+            Strcat(tmpbuf, ", \82Æ\82Ä\82à\91å\82«\82È\95\94\89®");
+#if 0 /*JP*/
+        Sprintf(buf, "in %s, on %s", dgnbuf, tmpbuf);
+#else
+        Sprintf(buf, "%s\82Ì%s", dgnbuf, tmpbuf);
+#endif
+    }
+    you_are(buf, "");
+
+    /* this is shown even if the 'time' option is off */
+    if (moves == 1L) {
+#if 0 /*JP*/
+        you_have("just started your adventure", "");
+#else
+        enlght_line(You_, "", "\96`\8c¯\82ð\8aJ\8en\82µ\82½\82Æ\82±\82ë\82¾", "");
+#endif
+    } else {
+        /* 'turns' grates on the nerves in this context... */
+/*JP
+        Sprintf(buf, "the dungeon %ld turn%s ago", moves, plur(moves));
+*/
+        Sprintf(buf, "%ld\83^\81[\83\93\91O\82É\96À\8b{\82É\93ü\82Á\82½", moves);
+        /* same phrasing for current and final: "entered" is unconditional */
+#if 0 /*JP*/
+        enlght_line(You_, "entered ", buf, "");
+#else
+        enlght_line(You_, "", buf, "");
+#endif
+    }
+
+    /* for gameover, these have been obtained in really_done() so that they
+       won't vary if user leaves a disclosure prompt or --More-- unanswered
+       long enough for the dynamic value to change between then and now */
+    if (final ? iflags.at_midnight : midnight()) {
+#if 0 /*JP:T*/
+        enl_msg("It ", "is ", "was ", "the midnight hour", "");
+#else
+        enl_msg("\8e\9e\8aÔ\91Ñ\82Í\90[\96é", "\82¾", "\82¾\82Á\82½", "", "");
+#endif
+    } else if (final ? iflags.at_night : night()) {
+#if 0 /*JP:T*/
+        enl_msg("It ", "is ", "was ", "nighttime", "");
+#else
+        enl_msg("\8e\9e\8aÔ\91Ñ\82Í\96é", "\82¾", "\82¾\82Á\82½", "", "");
+#endif
+    }
+    /* other environmental factors */
+    if (flags.moonphase == FULL_MOON || flags.moonphase == NEW_MOON) {
+        /* [This had "tonight" but has been changed to "in effect".
+           There is a similar issue to Friday the 13th--it's the value
+           at the start of the current session but that session might
+           have dragged on for an arbitrary amount of time.  We want to
+           report the values that currently affect play--or affected
+           play when game ended--rather than actual outside situation.] */
+#if 0 /*JP:T*/
+        Sprintf(buf, "a %s moon in effect%s",
+                (flags.moonphase == FULL_MOON) ? "full"
+                : (flags.moonphase == NEW_MOON) ? "new"
+                  /* showing these would probably just lead to confusion
+                     since they have no effect on game play... */
+                  : (flags.moonphase < FULL_MOON) ? "first quarter"
+                    : "last quarter",
+                /* we don't have access to 'how' here--aside from survived
+                   vs died--so settle for general platitude */
+                final ? " when your adventure ended" : "");
+        enl_msg("There ", "is ", "was ", buf, "");
+#else
+        Sprintf(buf, "%s%s\8c\8e",
+                /* we don't have access to 'how' here--aside from survived
+                   vs died--so settle for general platitude */
+                final ? "\96`\8c¯\82ð\8fI\82¦\82½\82Æ\82«\81C" : "",
+                (flags.moonphase == FULL_MOON) ? "\96\9e"
+                : (flags.moonphase == NEW_MOON) ? "\90V"
+                  /* showing these would probably just lead to confusion
+                     since they have no effect on game play... */
+                  : (flags.moonphase < FULL_MOON) ? "\8fã\8c·\82Ì"
+                    : "\89º\8c·\82Ì");
+        enl_msg("", "\82¾", "\82¾\82Á\82½", buf, "");
+#endif
+    }
+    if (flags.friday13) {
+        /* let player know that friday13 penalty is/was in effect;
+           we don't say "it is/was Friday the 13th" because that was at
+           the start of the session and it might be past midnight (or
+           days later if the game has been paused without save/restore),
+           so phrase this similar to the start up message */
+#if 0 /*JP:T*/
+        Sprintf(buf, " Bad things %s on Friday the 13th.",
+                !final ? "can happen"
+                : (final == ENL_GAMEOVERALIVE) ? "could have happened"
+                  /* there's no may to tell whether -1 Luck made a
+                     difference but hero has died... */
+                  : "happened");
+#else
+        Sprintf(buf, "\82P\82R\93ú\82Ì\8bà\97j\93ú\82É\82Í\82æ\82­\82È\82¢\82±\82Æ\82ª%s\81D",
+                !final ? "\82 \82é"
+                : (final == ENL_GAMEOVERALIVE) ? "\82 \82Á\82½\82©\82à\82µ\82ê\82È\82¢"
+                  /* there's no may to tell whether -1 Luck made a
+                     difference but hero has died... */
+                  : "\82 \82Á\82½");
+#endif
+        enlght_out(buf);
+    }
+
+    if (!Upolyd) {
+        int ulvl = (int) u.ulevel;
+        /* [flags.showexp currently does not matter; should it?] */
+
+        /* experience level is already shown above */
+#if 0 /*JP*/
+        Sprintf(buf, "%-1ld experience point%s", u.uexp, plur(u.uexp));
+#else
+        Sprintf(buf, "\8co\8c±\92l%-1ld\83|\83C\83\93\83g", u.uexp);
+#endif
+        /* TODO?
+         *  Remove wizard-mode restriction since patient players can
+         *  determine the numbers needed without resorting to spoilers
+         *  (even before this started being disclosed for 'final';
+         *  just enable 'showexp' and look at normal status lines
+         *  after drinking gain level potions or eating wraith corpses
+         *  or being level-drained by vampires).
+         */
+        if (ulvl < 30 && (final || wizard)) {
+            long nxtlvl = newuexp(ulvl), delta = nxtlvl - u.uexp;
+
+#if 0 /*JP*/
+            Sprintf(eos(buf), ", %ld %s%sneeded %s level %d",
+                    delta, (u.uexp > 0) ? "more " : "",
+                    /* present tense=="needed", past tense=="were needed" */
+                    !final ? "" : (delta == 1L) ? "was " : "were ",
+                    /* "for": grammatically iffy but less likely to wrap */
+                    (ulvl < 18) ? "to attain" : "for", (ulvl + 1));
+#else
+            Sprintf(eos(buf), "(\83\8c\83x\83\8b%d\82Ü\82Å%ld\83|\83C\83\93\83g)",
+                    (ulvl + 1), delta);
+#endif
+        }
+        you_have(buf, "");
+    }
+#ifdef SCORE_ON_BOTL
+    if (flags.showscore) {
+        /* describes what's shown on status line, which is an approximation;
+           only show it here if player has the 'showscore' option enabled */
+#if 0 /*JP*/
+        Sprintf(buf, "%ld%s", botl_score(),
+                !final ? "" : " before end-of-game adjustments");
+        enl_msg("Your score ", "is ", "was ", buf, "");
+#else
+        Sprintf(buf, "%s%ld", botl_score(),
+                !final ? "" : "\83Q\81[\83\80\8fI\97¹\8e\9e\82Ì\92²\90®\91O\82Í");
+        enl_msg("\82 \82È\82½\82Ì\83X\83R\83A\82Í", "\82Å\82 \82é", "\82Å\82 \82Á\82½", buf, "");
+#endif
+    }
+#endif
 }
 
-/* characteristics: expanded version of bottom line strength, dexterity, &c;
-   [3.6.1: now includes all status info (except things already shown in the
-   'background' section), primarily so that blind players can suppress the
-   status line(s) altogether and use ^X feedback on demand to view HP, &c] */
+/* hit points, energy points, armor class -- essential information which
+   doesn't fit very well in other categories */
+/*ARGSUSED*/
 STATIC_OVL void
-characteristics_enlightenment(mode, final)
-int mode;
+basics_enlightenment(mode, final)
+int mode UNUSED;
 int final;
 {
+#if 0 /*JP*//*unused*/
+    static char Power[] = "energy points (spell power)";
+#endif
     char buf[BUFSZ];
-    int hp = Upolyd ? u.mh : u.uhp;
-    int hpmax = Upolyd ? u.mhmax : u.uhpmax;
+    int pw = u.uen, hp = (Upolyd ? u.mh : u.uhp),
+        pwmax = u.uenmax, hpmax = (Upolyd ? u.mhmax : u.uhpmax);
 
-    putstr(en_win, 0, ""); /* separator after background */
-    putstr(en_win, 0,
+    enlght_out(""); /* separator after background */
 /*JP
-           final ? "Final Characteristics:" : "Current Characteristics:");
+    enlght_out("Basics:");
 */
-           final ? "\8dÅ\8fI\91®\90«\81F" : "\8c»\8dÝ\82Ì\91®\90«\81F");
+    enlght_out("\8aî\96{:");
 
     if (hp < 0)
         hp = 0;
-    Sprintf(buf, "%d hit points (max:%d)", hp, hpmax);
+    /* "1 out of 1" rather than "all" if max is only 1; should never happen */
+#if 0 /*JP*/
+    if (hp == hpmax && hpmax > 1)
+        Sprintf(buf, "all %d hit points", hpmax);
+    else
+        Sprintf(buf, "%d out of %d hit point%s", hp, hpmax, plur(hpmax));
+#else
+    Sprintf(buf, "%d\83q\83b\83g\83|\83C\83\93\83g(\8dÅ\91å:%d)", hp, hpmax);
+#endif
     you_have(buf, "");
 
-    Sprintf(buf, "%d magic power (max:%d)", u.uen, u.uenmax);
+    /* low max energy is feasible, so handle couple of extra special cases */
+#if 0 /*JP*/
+    if (pwmax == 0 || (pw == pwmax && pwmax == 2)) /* both: "all 2" is silly */
+        Sprintf(buf, "%s %s", !pwmax ? "no" : "both", Power);
+    else if (pw == pwmax && pwmax > 2)
+        Sprintf(buf, "all %d %s", pwmax, Power);
+    else
+        Sprintf(buf, "%d out of %d %s", pw, pwmax, Power);
+#else
+    Sprintf(buf, "%d\96\82\97Í\83|\83C\83\93\83g(\8dÅ\91å:%d)", pw, pwmax);
+#endif
     you_have(buf, "");
 
-    Sprintf(buf, "%d", u.uac);
-    enl_msg("Your armor class ", "is ", "was ", buf, "");
-
     if (Upolyd) {
         switch (mons[u.umonnum].mlevel) {
         case 0:
             /* status line currently being explained shows "HD:0" */
+/*JP
             Strcpy(buf, "0 hit dice (actually 1/2)");
+*/
+            Strcpy(buf, "HD0(\8eÀ\8dÛ\82É\82Í1/2)");
             break;
         case 1:
+/*JP
             Strcpy(buf, "1 hit die");
+*/
+            Strcpy(buf, "HD1");
             break;
         default:
+/*JP
             Sprintf(buf, "%d hit dice", mons[u.umonnum].mlevel);
+*/
+            Sprintf(buf, "HD%d", mons[u.umonnum].mlevel);
             break;
         }
-    } else {
-        /* flags.showexp does not matter */
-        /* experience level is already shown in the Background section */
-        Sprintf(buf, "%-1ld experience point%s",
-                u.uexp, plur(u.uexp));
+        you_have(buf, "");
     }
-    you_have(buf, "");
 
-    /* this is shown even if the 'time' option is off */
-    Sprintf(buf, "the dungeon %ld turn%s ago", moves, plur(moves));
-    /* same phrasing at end of game:  "entered" is unconditional */
-    enlght_line(You_, "entered ", buf, "");
+    Sprintf(buf, "%d", u.uac);
+/*JP
+    enl_msg("Your armor class ", "is ", "was ", buf, "");
+*/
+    enl_msg("\82 \82È\82½\82Ì\96h\8cä\92l\82Í", "\82Å\82 \82é", "\82Å\82 \82Á\82½", buf, "");
 
-#ifdef SCORE_ON_BOTL
-    if (flags.showscore) {
-        /* describes what's shown on status line, which is an approximation;
-           only show it here if player has the 'showscore' option enabled */
-        Sprintf(buf, "%ld%s", botl_score(),
-                !final ? "" : " before end-of-game adjustments");
-        enl_msg("Your score ", "is ", "was ", buf, "");
+    /* gold; similar to doprgold(#seegold) but without shop billing info;
+       same amount as shown on status line which ignores container contents */
+    {
+/*JP
+        static const char Your_wallet[] = "Your wallet ";
+*/
+        static const char Your_wallet[] = "\82 \82È\82½\82Ì\8dà\95z";
+        long umoney = money_cnt(invent);
+
+        if (!umoney) {
+/*JP
+            enl_msg(Your_wallet, "is ", "was ", "empty", "");
+*/
+            enl_msg(Your_wallet, "\82Å\82 \82é", "\82¾\82Á\82½", "\82Í\8bó", "");
+        } else {
+#if 0 /*JP:T*/
+            Sprintf(buf, "%ld %s", umoney, currency(umoney));
+            enl_msg(Your_wallet, "contains ", "contained ", buf, "");
+#else
+            Sprintf(buf, "\82É\82Í%ld%s", umoney, currency(umoney));
+            enl_msg(Your_wallet, "\93ü\82Á\82Ä\82¢\82é", "\93ü\82Á\82Ä\82¢\82½", buf, "");
+#endif
+        }
     }
+
+    if (flags.pickup) {
+        char ocl[MAXOCLASSES + 1];
+
+#if 0 /*JP*//*\8cã\82É\89ñ\82·*/
+        Strcpy(buf, "on");
 #endif
+        oc_to_str(flags.pickup_types, ocl);
+#if 0 /*JP*/
+        Sprintf(eos(buf), " for %s%s%s",
+                *ocl ? "'" : "", *ocl ? ocl : "all types", *ocl ? "'" : "");
+#else
+        Sprintf(buf, "%s%s%s",
+                *ocl ? "'" : "", *ocl ? ocl : "\91S\82Ä\82Ì\8eí\97Þ", *ocl ? "'" : "");
+#endif
+        if (flags.pickup_thrown && *ocl) /* *ocl: don't show if 'all types' */
+/*JP
+            Strcat(buf, " plus thrown");
+*/
+            Strcat(buf, "\82É\89Á\82¦\82Ä\93\8a\82°\82é\82à\82Ì");
+        if (apelist)
+/*JP
+            Strcat(buf, ", with exceptions");
+*/
+            Strcat(buf, "(\97á\8aO\82 \82è)");
+#if 1 /*JP*/
+        Strcat(buf, "\82É\91Î\82µ\82Ä\83I\83\93");
+#endif
+    } else
+/*JP
+        Strcpy(buf, "off");
+*/
+        Strcpy(buf, "\83I\83t");
+/*JP
+    enl_msg("Autopickup ", "is ", "was ", buf, "");
+*/
+    enl_msg("\8e©\93®\8fE\82¢\90Ý\92è\82Í", "\82Å\82 \82é", "\82Å\82 \82Á\82½", buf, "");
+}
+
+/* characteristics: expanded version of bottom line strength, dexterity, &c */
+STATIC_OVL void
+characteristics_enlightenment(mode, final)
+int mode;
+int final;
+{
+    char buf[BUFSZ];
+
+    enlght_out("");
+/*JP
+    Sprintf(buf, "%s Characteristics:", !final ? "Current" : "Final");
+*/
+    Sprintf(buf, "%s\93Á\90«\81F", !final ? "\8c»\8dÝ\82Ì" : "\8dÅ\8fI");
+    enlght_out(buf);
 
     /* bottom line order */
     one_characteristic(mode, final, A_STR); /* strength */
@@ -2109,7 +2714,7 @@ int mode, final, attrindx;
 */
         paren_pfx = final ? " (" : " (\8c»\8dÝ; ";
         if (acurrent != abase) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             Sprintf(eos(valubuf), "%sbase:%s", paren_pfx,
                     attrval(attrindx, abase, valstring));
 #else
@@ -2119,7 +2724,7 @@ int mode, final, attrindx;
             paren_pfx = ", ";
         }
         if (abase != apeak) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             Sprintf(eos(valubuf), "%speak:%s", paren_pfx,
                     attrval(attrindx, apeak, valstring));
 #else
@@ -2129,7 +2734,7 @@ int mode, final, attrindx;
             paren_pfx = ", ";
         }
         if (interesting_alimit) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             Sprintf(eos(valubuf), "%s%slimit:%s", paren_pfx,
                     /* more verbose if exceeding 'limit' due to magic bonus */
                     (acurrent > alimit) ? "innate " : "",
@@ -2158,7 +2763,7 @@ int mode;
 int final;
 {
     boolean magic = (mode & MAGICENLIGHTENMENT) ? TRUE : FALSE;
-    int cap;
+    int cap, wtype;
     char buf[BUFSZ], youtoo[BUFSZ];
     boolean Riding = (u.usteed
                       /* if hero dies while dismounting, u.usteed will still
@@ -2179,11 +2784,11 @@ int final;
      * Status (many are abbreviated on bottom line; others are or
      *     should be discernible to the hero hence to the player)
     \*/
-    putstr(en_win, 0, ""); /* separator after title or characteristics */
+    enlght_out(""); /* separator after title or characteristics */
 /*JP
-    putstr(en_win, 0, final ? "Final Status:" : "Current Status:");
+    enlght_out(final ? "Final Status:" : "Current Status:");
 */
-    putstr(en_win, 0, final ? "\8dÅ\8fI\8fó\91Ô:" : "\8c»\8dÝ\82Ì\8fó\91Ô:");
+    enlght_out(final ? "\8dÅ\8fI\8fó\91Ô:" : "\8c»\8dÝ\82Ì\8fó\91Ô:");
 
     Strcpy(youtoo, You_);
     /* not a traditional status but inherently obvious to player; more
@@ -2202,7 +2807,7 @@ int final;
     /* not a trouble, but we want to display riding status before maybe
        reporting steed as trapped or hero stuck to cursed saddle */
     if (Riding) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, "riding %s", steedname);
         you_are(buf, "");
 #else
@@ -2258,20 +2863,34 @@ int final;
         you_are_ing(buf, from_what(WWALKING));
 #endif
     }
-    if (Upolyd && (u.uundetected || youmonst.m_ap_type != M_AP_NOTHING))
+    if (Upolyd && (u.uundetected || U_AP_TYPE != M_AP_NOTHING))
         youhiding(TRUE, final);
 
     /* internal troubles, mostly in the order that prayer ranks them */
-    if (Stoned)
+    if (Stoned) {
+        if (final && (Stoned & I_SPECIAL))
 /*JP
-        you_are("turning to stone", "");
+            enlght_out(" You turned into stone.");
 */
-        enl_msg("\82 \82È\82½\82Í", "\82È\82è\82Â\82Â\82 \82é", "\82È\82Á\82½", "\90Î\82É", "");
-    if (Slimed)
+            enlght_out(" \82 \82È\82½\82Í\90Î\82É\82È\82Á\82½\81D");
+        else
+/*JP
+            you_are("turning to stone", "");
+*/
+            enl_msg("\82 \82È\82½\82Í", "\82È\82è\82Â\82Â\82 \82é", "\82È\82Á\82½", "\90Î\82É", "");
+    }
+    if (Slimed) {
+        if (final && (Slimed & I_SPECIAL))
 /*JP
-        you_are("turning into slime", "");
+            enlght_out(" You turned into slime.");
 */
-        enl_msg("\82 \82È\82½\82Í", "\82È\82è\82Â\82Â\82 \82é", "\82È\82Á\82½", "\83X\83\89\83C\83\80\82É", "");
+            enlght_out(" \82 \82È\82½\82Í\83X\83\89\83C\83\80\82É\82È\82Á\82½\81D");
+        else
+/*JP
+            you_are("turning into slime", "");
+*/
+            enl_msg("\82 \82È\82½\82Í", "\82È\82è\82Â\82Â\82 \82é", "\82È\82Á\82½", "\83X\83\89\83C\83\80\82É", "");
+    }
     if (Strangled) {
         if (u.uburied) {
 /*JP
@@ -2279,30 +2898,55 @@ int final;
 */
             you_are_ing("\92\82\91§\82µ\82Ä", "");
         } else {
+            if (final && (Strangled & I_SPECIAL)) {
 /*JP
-            Strcpy(buf, "being strangled");
+                enlght_out(" You died from strangulation.");
 */
-            Strcpy(buf, "\8eñ\82ð\8di\82ß\82ç\82ê\82Ä");
-            if (wizard)
-                Sprintf(eos(buf), " (%ld)", (Strangled & TIMEOUT));
+                enlght_out(" \82 \82È\82½\82Í\92\82\91§\8e\80\82µ\82½\81D");
+            } else {
+/*JP
+                Strcpy(buf, "being strangled");
+*/
+                Strcpy(buf, "\8eñ\82ð\8di\82ß\82ç\82ê\82Ä");
+                if (wizard)
+                    Sprintf(eos(buf), " (%ld)", (Strangled & TIMEOUT));
 /*JP
-            you_are(buf, from_what(STRANGLED));
+                you_are(buf, from_what(STRANGLED));
 */
-            enl_msg("\82 \82È\82½\82Í", "\82¢\82é", "\82¢\82½", buf, from_what(STRANGLED));
+                enl_msg("\82 \82È\82½\82Í", "\82¢\82é", "\82¢\82½", buf, from_what(STRANGLED));
+            }
         }
     }
     if (Sick) {
-        /* prayer lumps these together; botl puts Ill before FoodPois */
-        if (u.usick_type & SICK_NONVOMITABLE)
+        /* the two types of sickness are lumped together; hero can be
+           afflicted by both but there is only one timeout; botl status
+           puts TermIll before FoodPois and death due to timeout reports
+           terminal illness if both are in effect, so do the same here */
+        if (final && (Sick & I_SPECIAL)) {
+#if 0 /*JP:T*/
+            Sprintf(buf, " %sdied from %s.", You_, /* has trailing space */
+                    (u.usick_type & SICK_NONVOMITABLE)
+                    ? "terminal illness" : "food poisoning");
+#else
+            Sprintf(buf, " %s%s\82Å\8e\80\82ñ\82¾\81D", You_, /* has trailing space */
+                    (u.usick_type & SICK_NONVOMITABLE)
+                    ? "\95a\8bC" : "\90H\92\86\93Å");
+#endif
+            enlght_out(buf);
+        } else {
+            /* unlike death due to sickness, report the two cases separately
+               because it is possible to cure one without curing the other */
+            if (u.usick_type & SICK_NONVOMITABLE)
 /*JP
-            you_are("terminally sick from illness", "");
+                you_are("terminally sick from illness", "");
 */
-            enl_msg("\82 \82È\82½\82Í\95a\8bC\82Å\92v\96½\93I\82É\8bC\95ª\82ª\88«", "\82¢", "\82©\82Á\82½", "", "");
-        if (u.usick_type & SICK_VOMITABLE)
+                enl_msg("\82 \82È\82½\82Í\95a\8bC\82Å\92v\96½\93I\82É\8bC\95ª\82ª\88«", "\82¢", "\82©\82Á\82½", "", "");
+            if (u.usick_type & SICK_VOMITABLE)
 /*JP
-            you_are("terminally sick from food poisoning", "");
+                you_are("terminally sick from food poisoning", "");
 */
-            enl_msg("\82 \82È\82½\82Í\90H\92\86\93Å\82Å\92v\96½\93I\82É\8bC\95ª\82ª\88«", "\82¢", "\82©\82Á\82½", "", "");
+                enl_msg("\82 \82È\82½\82Í\90H\92\86\93Å\82Å\92v\96½\93I\82É\8bC\95ª\82ª\88«", "\82¢", "\82©\82Á\82½", "", "");
+        }
     }
     if (Vomiting)
 /*JP
@@ -2327,7 +2971,7 @@ int final;
     if (Blind) {
         /* from_what() (currently wizard-mode only) checks !haseyes()
            before u.uroleplay.blind, so we should too */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, "%s blind",
                 !haseyes(youmonst.data) ? "innately"
                 : u.uroleplay.blind ? "permanently"
@@ -2437,9 +3081,15 @@ int final;
         struct obj *saddle = which_armor(u.usteed, W_SADDLE);
 
         if (saddle && saddle->cursed) {
+#if 0 /*JP*/
             Sprintf(buf, "stuck to %s %s", s_suffix(steedname),
                     simpleonames(saddle));
             you_are(buf, "");
+#else
+            Sprintf(buf, "%s\82Ì%s\82É\82Â\82©\82Ü\82Á\82Ä", steedname,
+                    simpleonames(saddle));
+            you_are_ing(buf, "");
+#endif
         }
     }
     if (Wounded_legs) {
@@ -2467,10 +3117,14 @@ int final;
     }
     if (Glib) {
 #if 0 /*JP*/
-        Sprintf(buf, "slippery %s", makeplural(body_part(FINGER)));
+        Sprintf(buf, "slippery %s", fingers_or_gloves(TRUE));
+        if (wizard)
+            Sprintf(eos(buf), " (%ld)", (Glib & TIMEOUT));
         you_have(buf, "");
 #else
         Sprintf(buf, "%s\82ª\82Ê\82é\82Ê\82é\82µ\82Ä", body_part(FINGER));
+        if (wizard)
+            Sprintf(eos(buf), " (%ld)", (Glib & TIMEOUT));
         enl_msg(buf, iru, ita, "", "");
 #endif
     }
@@ -2557,6 +3211,7 @@ int final;
 */
         you_are("\89×\95¨\82Í\8e×\96\82\82É\82È\82ç\82È\82¢\8fó\91Ô", "");
     }
+
     /* report being weaponless; distinguish whether gloves are worn */
     if (!uwep) {
 #if 0 /*JP*/
@@ -2570,7 +3225,8 @@ int final;
 #else
         enl_msg(You_, "\82¢", "\82©\82Á\82½", "\95\90\8aí\82ð\91\95\94õ\82µ\82Ä\82¢\82È", "");
 #endif
-    /* two-weaponing implies a weapon (not other odd stuff) in each hand */
+    /* two-weaponing implies hands (can't be polymorphed) and
+       a weapon or wep-tool (not other odd stuff) in each hand */
     } else if (u.twoweap) {
 /*JP
         you_are("wielding two weapons at once", "");
@@ -2595,16 +3251,55 @@ int final;
         enl_msg(You_, "\82¢\82é", "\82¢\82½", buf, "");
 #endif
     }
+    /*
+     * Skill with current weapon.  Might help players who've never
+     * noticed #enhance or decided that it was pointless.
+     *
+     * TODO?  Maybe merge wielding line and skill line into one sentence.
+     */
+    if ((wtype = uwep_skill_type()) != P_NONE) {
+        char sklvlbuf[20];
+        int sklvl = P_SKILL(wtype);
+        boolean hav = (sklvl != P_UNSKILLED && sklvl != P_SKILLED);
+
+        if (sklvl == P_ISRESTRICTED)
+/*JP
+            Strcpy(sklvlbuf, "no");
+*/
+            Strcpy(sklvlbuf, "\90§\8cÀ");
+        else
+            (void) lcase(skill_level_name(wtype, sklvlbuf));
+        /* "you have no/basic/expert/master/grand-master skill with <skill>"
+           or "you are unskilled/skilled in <skill>" */
+#if 0 /*JP:T*/
+        Sprintf(buf, "%s %s %s", sklvlbuf,
+                hav ? "skill with" : "in", skill_name(wtype));
+#else
+        Sprintf(buf, "%s\82Ì%s\83X\83L\83\8b", skill_name(wtype), sklvlbuf);
+#endif
+        if (can_advance(wtype, FALSE))
+#if 0 /*JP:T*/
+            Sprintf(eos(buf), " and %s that",
+                    !final ? "can enhance" : "could have enhanced");
+#else
+            Sprintf(eos(buf), "(\8d\82\82ß\82é\82±\82Æ\82ª\82Å\82«%s)",
+                    !final ? "\82é" : "\82½");
+#endif
+        if (hav)
+            you_have(buf, "");
+        else
+            you_are(buf, "");
+    }
     /* report 'nudity' */
-    if (!uarm && !uarmu && !uarmc && !uarmg && !uarmf && !uarmh) {
+    if (!uarm && !uarmu && !uarmc && !uarms && !uarmg && !uarmf && !uarmh) {
         if (u.uroleplay.nudist)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             enl_msg(You_, "do", "did", " not wear any armor", "");
 #else
             enl_msg(You_, "\82¢", "\82©\82Á\82½", "\89½\82Ì\8aZ\82à\91\95\94õ\82µ\82È", "");
 #endif
         else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             you_are("not wearing any armor", "");
 #else
             enl_msg(You_, "\82¢", "\82©\82Á\82½", "\89½\82Ì\8aZ\82à\91\95\94õ\82µ\82Ä\82¢\82È", "");
@@ -2613,27 +3308,29 @@ int final;
 }
 
 /* attributes: intrinsics and the like, other non-obvious capabilities */
-void
+STATIC_OVL void
 attributes_enlightenment(unused_mode, final)
 int unused_mode UNUSED;
 int final;
 {
+#if 0 /*JP*/
     static NEARDATA const char if_surroundings_permitted[] =
         " if surroundings permitted";
+#endif
     int ltmp, armpro;
     char buf[BUFSZ];
 
     /*\
      *  Attributes
     \*/
-    putstr(en_win, 0, "");
+    enlght_out("");
 /*JP
-    putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:");
+    enlght_out(final ? "Final Attributes:" : "Current Attributes:");
 */
-    putstr(en_win, 0, final ? "\8dÅ\8fI\91®\90«:" : "\8c»\8dÝ\82Ì\91®\90«:");
+    enlght_out(final ? "\8dÅ\8fI\91®\90«:" : "\8c»\8dÝ\82Ì\91®\90«:");
 
     if (u.uevent.uhand_of_elbereth) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         static const char *const hofe_titles[3] = { "the Hand of Elbereth",
                                                     "the Envoy of Balance",
                                                     "the Glory of Arioch" };
@@ -2655,7 +3352,7 @@ int final;
         you_have(buf, "");
 
     if (wizard) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, " %d", u.ualign.record);
         enl_msg("Your alignment ", "is", "was", buf, "");
 #else
@@ -2726,7 +3423,7 @@ int final;
 */
         you_have("\90Î\89»\82Ö\82Ì\91Ï\90«", from_what(STONE_RES));
     if (Halluc_resistance)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         enl_msg(You_, "resist", "resisted", " hallucinations",
                 from_what(HALLUC_RES));
 #else
@@ -2740,7 +3437,11 @@ int final;
 
     /*** Vision and senses ***/
     if (!Blind && (Blinded || !haseyes(youmonst.data)))
+#if 0 /*JP*/
         you_can("see", from_what(-BLINDED)); /* Eyes of the Overworld */
+#else /*\81u\92´\90¢\8aE\82Ì\96Ú\82É\82æ\82Á\82Ä\8c©\82é\82±\82Æ\82ª\82Å\82«\82é\81v*/
+        you_can("\8c©\82é\82±\82Æ\82ª", from_what(-BLINDED)); /* Eyes of the Overworld */
+#endif
     if (See_invisible) {
         if (!Blind)
 /*JP
@@ -2748,7 +3449,7 @@ int final;
 */
             enl_msg("\82 \82È\82½\82Í\93§\96¾\82È\82à\82Ì\82ð\8c©\82ç\82ê", "\82é", "\82½", "", from_what(SEE_INVIS));
         else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             enl_msg(You_, "will see", "would have seen",
                     " invisible when not blind", from_what(SEE_INVIS));
 #else
@@ -2767,7 +3468,7 @@ int final;
 */
         you_have("\8cx\89ú\94\\97Í", from_what(WARNING));
     if (Warn_of_mon && context.warntype.obj) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, "aware of the presence of %s",
                 (context.warntype.obj & M2_ORC) ? "orcs"
                 : (context.warntype.obj & M2_ELF) ? "elves"
@@ -2849,9 +3550,9 @@ int final;
         enl_msg(You_, "could be", "could have been", " clairvoyant", buf);
 #else
         /*JP:\81u\81c\82É\82æ\82Á\82Ä\81v*/
-        if (!strncmp(buf, "\82É\82æ\82Á\82Ä", 8))
+        if (!STRNCMP2(buf, "\82É\82æ\82Á\82Ä"))
             /*JP:\81u\81c\82ª\82È\82¯\82ê\82Î\81v\82É\8f\91\82«\8a·\82¦\82é*/
-            strcpy(eos(buf) - 8, "\82ª\82È\82¯\82ê\82Î");
+            strcpy(eos(buf) - strlen("\82É\82æ\82Á\82Ä"), "\82ª\82È\82¯\82ê\82Î");
         you_have("\90ç\97¢\8aá\94\\97Í", buf);
 #endif
     }
@@ -2953,13 +3654,23 @@ int final;
         long save_BLev = BLevitation;
 
         BLevitation = 0L;
-        if (Levitation)
+        if (Levitation) {
+            /* either trapped in the floor or inside solid rock
+               (or both if chained to buried iron ball and have
+               moved one step into solid rock somehow) */
 #if 0 /*JP*/
-            enl_msg(You_, "would levitate", "would have levitated",
-                    if_surroundings_permitted, "");
+            boolean trapped = (save_BLev & I_SPECIAL) != 0L,
+                    terrain = (save_BLev & FROMOUTSIDE) != 0L;
+
+            Sprintf(buf, "%s%s%s",
+                    trapped ? " if not trapped" : "",
+                    (trapped && terrain) ? " and" : "",
+                    terrain ? if_surroundings_permitted : "");
+            enl_msg(You_, "would levitate", "would have levitated", buf, "");
 #else
-            you_are("\95\82\97V\8fó\91Ô", "");
+            you_are("\8fó\8bµ\82ª\8b\96\82¹\82Î\95\82\97V\82·\82é\8fó\91Ô", "");
 #endif
+        }
         BLevitation = save_BLev;
     }
     /* actively flying handled earlier as a status condition */
@@ -2967,19 +3678,49 @@ int final;
         long save_BFly = BFlying;
 
         BFlying = 0L;
-        if (Flying)
-#if 0 /*JP*/
+        if (Flying) {
+#if 0 /*JP:T*/
             enl_msg(You_, "would fly", "would have flown",
+                    /* wording quibble: for past tense, "hadn't been"
+                       would sound better than "weren't" (and
+                       "had permitted" better than "permitted"), but
+                       "weren't" and "permitted" are adequate so the
+                       extra complexity to handle that isn't worth it */
                     Levitation
-                       ? "if you weren't levitating"
-                       : (save_BFly == FROMOUTSIDE)
-                          ? if_surroundings_permitted
-                          /* both surroundings and [latent] levitation */
-                          : " if circumstances permitted",
+                       ? " if you weren't levitating"
+                       : (save_BFly == I_SPECIAL)
+                          /* this is an oversimpliction; being trapped
+                             might also be blocking levitation so flight
+                             would still be blocked after escaping trap */
+                          ? " if you weren't trapped"
+                          : (save_BFly == FROMOUTSIDE)
+                             ? if_surroundings_permitted
+                             /* two or more of levitation, surroundings,
+                                and being trapped in the floor */
+                             : " if circumstances permitted",
                     "");
 #else
-            you_can("\94ò\82Ô\82±\82Æ\82ª", "");
+            enl_msg(You_, "\94ò\82Ô\82±\82Æ\82ª\82Å\82«\82é", "\94ò\82Ô\82±\82Æ\82ª\82Å\82«\82½",
+                    /* wording quibble: for past tense, "hadn't been"
+                       would sound better than "weren't" (and
+                       "had permitted" better than "permitted"), but
+                       "weren't" and "permitted" are adequate so the
+                       extra complexity to handle that isn't worth it */
+                    Levitation
+                       ? "\95\82\97V\82µ\82Ä\82¢\82È\82¯\82ê\82Î"
+                       : (save_BFly == I_SPECIAL)
+                          /* this is an oversimpliction; being trapped
+                             might also be blocking levitation so flight
+                             would still be blocked after escaping trap */
+                          ? "\95ß\82Ü\82Á\82Ä\82¢\82È\82¯\82ê\82Î"
+                          : (save_BFly == FROMOUTSIDE)
+                             ? "\8fó\8bµ\82ª\8b\96\82¹\82Î"
+                             /* two or more of levitation, surroundings,
+                                and being trapped in the floor */
+                             : "\8e\96\8fî\82ª\8b\96\82¹\82Î",
+                    "");
 #endif
+        }
         BFlying = save_BFly;
     }
     /* actively walking on water handled earlier as a status condition */
@@ -3050,7 +3791,7 @@ int final;
     if ((armpro = magic_negation(&youmonst)) > 0) {
         /* magic cancellation factor, conferred by worn armor */
         static const char *const mc_types[] = {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             "" /*ordinary*/, "warded", "guarded", "protected",
 #else
             "" /*ordinary*/, "\89q\82ç\82ê\82Ä", "\8cì\82ç\82ê\82Ä", "\8eç\82ç\82ê\82Ä",
@@ -3118,7 +3859,12 @@ int final;
         you_have("polymorph control", from_what(POLYMORPH_CONTROL));
 */
         you_have("\95Ï\89»\82Ì\90§\8cä\94\\97Í", from_what(POLYMORPH_CONTROL));
-    if (Upolyd && u.umonnum != u.ulycn) {
+    if (Upolyd && u.umonnum != u.ulycn
+        /* if we've died from turning into slime, we're polymorphed
+           right now but don't want to list it as a temporary attribute
+           [we need a more reliable way to detect this situation] */
+        && !(final == ENL_GAMEOVERDEAD
+             && u.umonnum == PM_GREEN_SLIME && !Unchanging)) {
         /* foreign shape (except were-form which is handled below) */
 /*JP
         Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname));
@@ -3194,7 +3940,7 @@ int final;
     /*** Miscellany ***/
     if (Luck) {
         ltmp = abs((int) Luck);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, "%s%slucky",
                 ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
                 Luck < 0 ? "un" : "");
@@ -3222,7 +3968,7 @@ int final;
 */
         you_have("\82³\82ç\82È\82é\95s\89^", "");
     if (carrying(LUCKSTONE) || stone_luck(TRUE)) {
-        ltmp = stone_luck(0);
+        ltmp = stone_luck(FALSE);
         if (ltmp <= 0)
 /*JP
             enl_msg("Bad luck ", "does", "did", " not time out for you", "");
@@ -3362,7 +4108,7 @@ int final;
             case 1:
                 break; /* just "are dead" */
             default:
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 Sprintf(buf, " (%d%s time!)", u.umortality,
                         ordin(u.umortality));
 #else
@@ -3503,7 +4249,7 @@ minimal_enlightenment()
              "Deities", FALSE);
 */
              "\90_", FALSE);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     Sprintf(buf2, deity_fmtstr, align_gname(A_CHAOTIC),
             (u.ualignbase[A_ORIGINAL] == u.ualign.type
              && u.ualign.type == A_CHAOTIC)               ? " (s,c)"
@@ -3522,7 +4268,7 @@ minimal_enlightenment()
     Sprintf(buf, fmtstr, "\8d¬\93×", buf2);
     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
 
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL),
             (u.ualignbase[A_ORIGINAL] == u.ualign.type
              && u.ualign.type == A_NEUTRAL)               ? " (s,c)"
@@ -3541,7 +4287,7 @@ minimal_enlightenment()
     Sprintf(buf, fmtstr, "\92\86\97§", buf2);
     add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE);
 
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL),
             (u.ualignbase[A_ORIGINAL] == u.ualign.type
              && u.ualign.type == A_LAWFUL)                ? " (s,c)"
@@ -3595,24 +4341,24 @@ int msgflag;          /* for variant message phrasing */
     Strcpy(buf, "hiding");
 */
     Strcpy(buf, "\89B\82ê");
-    if (youmonst.m_ap_type != M_AP_NOTHING) {
+    if (U_AP_TYPE != M_AP_NOTHING) {
         /* mimic; hero is only able to mimic a strange object or gold
            or hallucinatory alternative to gold, so we skip the details
            for the hypothetical furniture and monster cases */
 #if 0 /*JP*//*\8cã\82ë\82É\89ñ\82·*//* not used */
         bp = eos(strcpy(buf, "mimicking"));
 #endif
-        if (youmonst.m_ap_type == M_AP_OBJECT) {
+        if (U_AP_TYPE == M_AP_OBJECT) {
 /*JP
             Sprintf(bp, " %s", an(simple_typename(youmonst.mappearance)));
 */
             Strcpy(buf, simple_typename(youmonst.mappearance));
-        } else if (youmonst.m_ap_type == M_AP_FURNITURE) {
+        } else if (U_AP_TYPE == M_AP_FURNITURE) {
 /*JP
             Strcpy(bp, " something");
 */
             Strcpy(buf, "\89½\82©");
-        } else if (youmonst.m_ap_type == M_AP_MONSTER) {
+        } else if (U_AP_TYPE == M_AP_MONSTER) {
 /*JP
             Strcpy(bp, " someone");
 */
@@ -3650,7 +4396,7 @@ int msgflag;          /* for variant message phrasing */
             if (u.utrap && u.utraptype == TT_PIT) {
                 struct trap *t = t_at(u.ux, u.uy);
 
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 Sprintf(bp, " in a %spit",
                         (t && t->ttyp == SPIKED_PIT) ? "spiked " : "");
 #else
@@ -3752,7 +4498,7 @@ int final;
 */
         you_have_never("\82 \82È\82½\82Í\91\95\94õ\82µ\82Ä\82¢\82é\95\90\8aí\82Å\8dU\8c\82\82µ");
     } else if (wizard) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, "used a wielded weapon %ld time%s", u.uconduct.weaphit,
                 plur(u.uconduct.weaphit));
         you_have_X(buf);
@@ -3838,7 +4584,7 @@ int final;
 */
         you_have_never("\82 \82È\82½\82Í\8aè\82¢\8e\96\82ð\82µ");
     } else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, "used %ld wish%s", u.uconduct.wishes,
                 (u.uconduct.wishes > 1L) ? "es" : "");
 #else
@@ -3853,6 +4599,7 @@ int final;
              *  N wishes (1 for an artifact)
              *  N wishes (M for artifacts)
              */
+#if 0 /*JP*/
             if (u.uconduct.wisharti == u.uconduct.wishes)
                 Sprintf(eos(buf), " (%s",
                         (u.uconduct.wisharti > 2L) ? "all "
@@ -3863,6 +4610,9 @@ int final;
             Sprintf(eos(buf), "for %s)",
                     (u.uconduct.wisharti == 1L) ? "an artifact"
                                                 : "artifacts");
+#else
+            Sprintf(eos(buf), " (\90¹\8aí\82Í%ld\89ñ)", u.uconduct.wisharti);
+#endif
         }
         you_have_X(buf);
 
@@ -3881,65 +4631,69 @@ int final;
     en_win = WIN_ERR;
 }
 
-/* Macros for meta and ctrl modifiers:
- *   M and C return the meta/ctrl code for the given character;
- *     e.g., (C('c') is ctrl-c
- */
-#ifndef M
-#ifndef NHSTDC
-#define M(c) (0x80 | (c))
-#else
-#define M(c) ((c) - 128)
-#endif /* NHSTDC */
-#endif
-
-#ifndef C
-#define C(c) (0x1f & (c))
-#endif
-
 /* ordered by command name */
 struct ext_func_tab extcmdlist[] = {
     { '#', "#", "perform an extended command",
             doextcmd, IFBURIED | GENERALCMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('?'), "?", "list all extended commands",
 #else
     { M('?'), "?", "\82±\82Ì\8ag\92£\83R\83}\83\93\83h\88ê\97\97\82ð\95\\8e¦\82·\82é",
 #endif
             doextlist, IFBURIED | AUTOCOMPLETE | GENERALCMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('a'), "adjust", "adjust inventory letters",
 #else
     { M('a'), "adjust", "\8e\9d\82¿\95¨\88ê\97\97\82Ì\92²\90®",
 #endif
             doorganize, IFBURIED | AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('A'), "annotate", "name current level",
 #else
     { M('A'), "annotate", "\8c»\8dÝ\82Ì\8aK\82É\96¼\91O\82ð\82Â\82¯\82é",
 #endif
             donamelevel, IFBURIED | AUTOCOMPLETE },
+#if 0 /*JP*/
     { 'a', "apply", "apply (use) a tool (pick-axe, key, lamp...)",
+#else
+    { 'a', "apply", "\93¹\8bï\82ð\8eg\82¤\81D(\82Â\82é\82Í\82µ, \8c®, \83\89\83\93\83v\81c)",
+#endif
             doapply },
     { C('x'), "attributes", "show your attributes",
             doattributes, IFBURIED },
+#if 0 /*JP:T*/
     { '@', "autopickup", "toggle the pickup option on/off",
+#else
+    { '@', "autopickup", "\8e©\93®\8fE\82¢\83I\83v\83V\83\87\83\93\82ð\90Ø\82è\91Ö\82¦\82é",
+#endif
             dotogglepickup, IFBURIED },
+#if 0 /*JP:T*/
     { 'C', "call", "call (name) something", docallcmd, IFBURIED },
+#else
+    { 'C', "call", "\96¼\91O\82ð\82Â\82¯\82é", docallcmd, IFBURIED },
+#endif
+#if 0 /*JP:T*/
     { 'Z', "cast", "zap (cast) a spell", docast, IFBURIED },
-#if 0 /*JP*/
+#else
+    { 'Z', "cast", "\8eô\95\82ð\8f¥\82¦\82é", docast, IFBURIED },
+#endif
+#if 0 /*JP:T*/
     { M('c'), "chat", "talk to someone", dotalk, IFBURIED | AUTOCOMPLETE },
 #else
     { M('c'), "chat", "\92N\82©\82Æ\98b\82·", dotalk, IFBURIED | AUTOCOMPLETE },
 #endif
+#if 0 /*JP:T*/
     { 'c', "close", "close a door", doclose },
-#if 0 /*JP*/
+#else
+    { 'c', "close", "\83h\83A\82ð\95Â\82ß\82é", doclose },
+#endif
+#if 0 /*JP:T*/
     { M('C'), "conduct", "list voluntary challenges you have maintained",
 #else
     { M('C'), "conduct", "\82Ç\82¤\82¢\82¤\8ds\93®\82ð\82Æ\82Á\82½\82©\8c©\82é",
 #endif
             doconduct, IFBURIED | AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('d'), "dip", "dip an object into something", dodip, AUTOCOMPLETE },
 #else
     { M('d'), "dip", "\89½\82©\82É\95¨\82ð\90Z\82·", dodip, AUTOCOMPLETE },
@@ -3949,20 +4703,20 @@ struct ext_func_tab extcmdlist[] = {
     { 'D', "droptype", "drop specific item types", doddrop },
     { 'e', "eat", "eat something", doeat },
     { 'E', "engrave", "engrave writing on the floor", doengrave },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('e'), "enhance", "advance or check weapon and spell skills",
 #else
     { M('e'), "enhance", "\95\90\8aí\8fn\97û\93x\82ð\8d\82\82ß\82é",
 #endif
             enhance_weapon_skill, IFBURIED | AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "exploremode", "enter explore (discovery) mode",
 #else
     { '\0', "exploremode", "\92T\8c\9f(\94­\8c©)\83\82\81[\83h\82É\93ü\82é",
 #endif
             enter_explore_mode, IFBURIED },
     { 'f', "fire", "fire ammunition from quiver", dofire },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('f'), "force", "force a lock", doforce, AUTOCOMPLETE },
 #else
     { M('f'), "force", "\8c®\82ð\82±\82\82 \82¯\82é", doforce, AUTOCOMPLETE },
@@ -3977,13 +4731,13 @@ struct ext_func_tab extcmdlist[] = {
     { 'i', "inventory", "show your inventory", ddoinv, IFBURIED },
     { 'I', "inventtype", "inventory specific item types",
             dotypeinv, IFBURIED },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('i'), "invoke", "invoke an object's special powers",
 #else
     { M('i'), "invoke", "\95¨\82Ì\93Á\95Ê\82È\97Í\82ð\8eg\82¤",
 #endif
             doinvoke, IFBURIED | AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('j'), "jump", "jump to another location", dojump, AUTOCOMPLETE },
 #else
     { M('j'), "jump", "\91¼\82Ì\88Ê\92u\82É\94ò\82Ñ\82¤\82Â\82é", dojump, AUTOCOMPLETE },
@@ -3993,51 +4747,45 @@ struct ext_func_tab extcmdlist[] = {
             dodiscovered, IFBURIED | GENERALCMD },
     { '`', "knownclass", "show discovered types for one class of objects",
             doclassdisco, IFBURIED | GENERALCMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "levelchange", "change experience level",
 #else
     { '\0', "levelchange", "\8co\8c±\83\8c\83x\83\8b\82ð\95Ï\82¦\82é",
 #endif
             wiz_level_change, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "lightsources", "show mobile light sources",
 #else
     { '\0', "lightsources", "\88Ú\93®\8cõ\8c¹\82ð\8c©\82é",
 #endif
             wiz_light_sources, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
     { ':', "look", "look at what is here", dolook, IFBURIED },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('l'), "loot", "loot a box on the floor", doloot, AUTOCOMPLETE },
 #else
     { M('l'), "loot", "\8f°\82Ì\8fã\82Ì\94 \82ð\8aJ\82¯\82é", doloot, AUTOCOMPLETE },
 #endif
 #ifdef DEBUG_MIGRATING_MONS
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "migratemons", "migrate N random monsters",
 #else
     { '\0', "migratemons", "\83\89\83\93\83_\83\80\82È\89ö\95¨\82ð\89½\91Ì\82©\88Ú\8fZ\82³\82¹\82é",
 #endif
             wiz_migrate_mons, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
 #endif
-#if 0 /*JP*/
-    { '\0', "monpolycontrol", "control monster polymorphs",
-#else
-    { '\0', "monpolycontrol", "\89ö\95¨\82Ö\82Ì\95Ï\89»\82ð\90§\8cä\82·\82é",
-#endif
-            wiz_mon_polycontrol, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('m'), "monster", "use monster's special ability",
 #else
     { M('m'), "monster", "\89ö\95¨\82Ì\93Á\95Ê\94\\97Í\82ð\8eg\82¤",
 #endif
             domonability, IFBURIED | AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { 'N', "name", "name a monster or an object",
 #else
     { 'N', "name", "\83A\83C\83e\83\80\82â\95¨\82É\96¼\91O\82ð\82Â\82¯\82é",
 #endif
             docallcmd, IFBURIED | AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('o'), "offer", "offer a sacrifice to the gods",
 #else
     { M('o'), "offer", "\90_\82É\8b\9f\95¨\82ð\95ù\82°\82é",
@@ -4046,13 +4794,13 @@ struct ext_func_tab extcmdlist[] = {
     { 'o', "open", "open a door", doopen },
     { 'O', "options", "show option settings, possibly change them",
             doset, IFBURIED | GENERALCMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { C('o'), "overview", "show a summary of the explored dungeon",
 #else
     { C('o'), "overview", "\92T\8dõ\82µ\82½\96À\8b{\82Ì\8aT\97v\82ð\95\\8e¦\82·\82é",
 #endif
             dooverview, IFBURIED | AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "panic", "test panic routine (fatal to game)",
 #else
     { '\0', "panic", "\83p\83j\83b\83N\83\8b\81[\83`\83\93\82ð\83e\83X\83g\82·\82é(\92v\96½\93I)",
@@ -4060,21 +4808,13 @@ struct ext_func_tab extcmdlist[] = {
             wiz_panic, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
     { 'p', "pay", "pay your shopping bill", dopay },
     { ',', "pickup", "pick up things at the current location", dopickup },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "polyself", "polymorph self",
 #else
     { '\0', "polyself", "\95Ï\89»\82·\82é",
 #endif
             wiz_polyself, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#ifdef PORT_DEBUG
-#if 0 /*JP*/
-    { '\0', "portdebug", "wizard port debug command",
-#else
-    { '\0', "portdebug", "\83E\83B\83U\81[\83h\83|\81[\83g\83f\83o\83b\83O\83R\83}\83\93\83h",
-#endif
-            wiz_port_debug, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#endif
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('p'), "pray", "pray to the gods for help",
 #else
     { M('p'), "pray", "\90_\82É\8bF\82é",
@@ -4084,7 +4824,7 @@ struct ext_func_tab extcmdlist[] = {
             doprev_message, IFBURIED | GENERALCMD },
     { 'P', "puton", "put on an accessory (ring, amulet, etc)", doputon },
     { 'q', "quaff", "quaff (drink) something", dodrink },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('q'), "quit", "exit without saving current game",
 #else
     { M('q'), "quit", "\83Z\81[\83u\82µ\82È\82¢\82Å\8fI\97¹",
@@ -4094,27 +4834,32 @@ struct ext_func_tab extcmdlist[] = {
     { 'r', "read", "read a scroll or spellbook", doread },
     { C('r'), "redraw", "redraw screen", doredraw, IFBURIED | GENERALCMD },
     { 'R', "remove", "remove an accessory (ring, amulet, etc)", doremring },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('R'), "ride", "mount or dismount a saddled steed",
 #else
     { M('R'), "ride", "\89ö\95¨\82É\8fæ\82é(\82Ü\82½\82Í\8d~\82è\82é)",
 #endif
             doride, AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('r'), "rub", "rub a lamp or a stone", dorub, AUTOCOMPLETE },
 #else
     { M('r'), "rub", "\83\89\83\93\83v\82ð\82±\82·\82é", dorub, AUTOCOMPLETE },
 #endif
     { 'S', "save", "save the game and exit", dosave, IFBURIED | GENERALCMD },
+#if 0 /*JP:T*/
     { 's', "search", "search for traps and secret doors",
             dosearch, IFBURIED, "searching" },
+#else
+    { 's', "search", "ã©\82â\89B\82µ\94à\82ð\92T\82·",
+            dosearch, IFBURIED, "\92T\82·" },
+#endif
     { '*', "seeall", "show all equipment in use", doprinuse, IFBURIED },
     { AMULET_SYM, "seeamulet", "show the amulet currently worn",
             dopramulet, IFBURIED },
     { ARMOR_SYM, "seearmor", "show the armor currently worn",
             doprarm, IFBURIED },
     { GOLD_SYM, "seegold", "count your gold", doprgold, IFBURIED },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "seenv", "show seen vectors",
 #else
     { '\0', "seenv", "\8e\8b\90ü\83x\83N\83g\83\8b\82ð\8c©\82é",
@@ -4129,26 +4874,34 @@ struct ext_func_tab extcmdlist[] = {
     { '^', "seetrap", "show the type of adjacent trap", doidtrap, IFBURIED },
     { WEAPON_SYM, "seeweapon", "show the weapon currently wielded",
             doprwep, IFBURIED },
-#ifdef SHELL
-    { '!', "shell", "do a shell escape", dosh, IFBURIED | GENERALCMD },
+    { '!', "shell", "do a shell escape",
+            dosh_core, IFBURIED | GENERALCMD
+#ifndef SHELL
+                       | CMD_NOT_AVAILABLE
 #endif /* SHELL */
-#if 0 /*JP*/
+    },
+#if 0 /*JP:T*/
     { M('s'), "sit", "sit down", dosit, AUTOCOMPLETE },
-    { '\0', "stats", "show memory statistics",
 #else
     { M('s'), "sit", "\8dÀ\82é", dosit, AUTOCOMPLETE },
+#endif
+#if 0 /*JP:T*/
+    { '\0', "stats", "show memory statistics",
+#else
     { '\0', "stats", "\83\81\83\82\83\8a\8fó\91Ô\82ð\8c©\82é",
 #endif
             wiz_show_stats, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#ifdef SUSPEND
     { C('z'), "suspend", "suspend the game",
-            dosuspend_core, IFBURIED | GENERALCMD },
+            dosuspend_core, IFBURIED | GENERALCMD
+#ifndef SUSPEND
+                            | CMD_NOT_AVAILABLE
 #endif /* SUSPEND */
+    },
     { 'x', "swap", "swap wielded and secondary weapons", doswapweapon },
     { 'T', "takeoff", "take off one piece of armor", dotakeoff },
     { 'A', "takeoffall", "remove all armor", doddoremarm },
-    { C('t'), "teleport", "teleport around the level", dotele, IFBURIED },
-#if 0 /*JP*/
+    { C('t'), "teleport", "teleport around the level", dotelecmd, IFBURIED },
+#if 0 /*JP:T*/
     { '\0', "terrain", "show map without obstructions",
 #else
     { '\0', "terrain", "\8e×\96\82\82³\82ê\82¸\82É\92n\90}\82ð\8c©\82é",
@@ -4158,80 +4911,79 @@ struct ext_func_tab extcmdlist[] = {
             "menu of commands you can do from here to adjacent spot",
             dotherecmdmenu },
     { 't', "throw", "throw something", dothrow },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "timeout", "look at timeout queue and hero's timed intrinsics",
 #else
     { '\0', "timeout", "\8e\9e\8aÔ\90Ø\82ê\83L\83\85\81[\82Æ\83v\83\8c\83C\83\84\81[\82Ì\8e\9e\8aÔ\8co\89ß\82ð\8c©\82é",
 #endif
             wiz_timeout_queue, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('T'), "tip", "empty a container", dotip, AUTOCOMPLETE },
 #else
     { M('T'), "tip", "\93ü\82ê\95¨\82ð\8bó\82É\82·\82é", dotip, AUTOCOMPLETE },
 #endif
     { '_', "travel", "travel to a specific location on the map", dotravel },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('t'), "turn", "turn undead away", doturn, IFBURIED | AUTOCOMPLETE },
 #else
     { M('t'), "turn", "\83A\83\93\83f\83b\83g\82ð\93y\82É\95Ô\82·", doturn, IFBURIED | AUTOCOMPLETE },
 #endif
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { 'X', "twoweapon", "toggle two-weapon combat",
 #else
     { 'X', "twoweapon", "\97¼\8eè\8e\9d\82¿\82Ì\90Ø\82è\91Ö\82¦",
 #endif
             dotwoweapon, AUTOCOMPLETE },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('u'), "untrap", "untrap something", dountrap, AUTOCOMPLETE },
 #else
     { M('u'), "untrap", "ã©\82ð\82Í\82¸\82·", dountrap, AUTOCOMPLETE },
 #endif
     { '<', "up", "go up a staircase", doup },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "vanquished", "list vanquished monsters",
 #else
     { '\0', "vanquished", "\93|\82µ\82½\89ö\95¨\82Ì\88ê\97\97\82ð\8c©\82é",
 #endif
             dovanquished, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
     { M('v'), "version",
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             "list compile time options for this version of NetHack",
 #else
             "\83R\83\93\83p\83C\83\8b\8e\9e\82Ì\83I\83v\83V\83\87\83\93\82ð\95\\8e¦\82·\82é",
 #endif
             doextversion, IFBURIED | AUTOCOMPLETE | GENERALCMD },
     { 'v', "versionshort", "show version", doversion, IFBURIED | GENERALCMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "vision", "show vision array",
 #else
     { '\0', "vision", "\8e\8b\8aE\94z\97ñ\82ð\8c©\82é",
 #endif
             wiz_show_vision, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
+#if 0 /*JP:T*/
     { '.', "wait", "rest one move while doing nothing",
             donull, IFBURIED, "waiting" },
+#else
+    { '.', "wait", "\88ê\95à\95ª\89½\82à\82µ\82È\82¢",
+            donull, IFBURIED, "\8bx\8ce\82·\82é" },
+#endif
     { 'W', "wear", "wear a piece of armor", dowear },
     { '&', "whatdoes", "tell what a command does", dowhatdoes, IFBURIED },
     { '/', "whatis", "show what type of thing a symbol corresponds to",
             dowhatis, IFBURIED | GENERALCMD },
     { 'w', "wield", "wield (put in use) a weapon", dowield },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { M('w'), "wipe", "wipe off your face", dowipe, AUTOCOMPLETE },
 #else
     { M('w'), "wipe", "\8aç\82ð\90@\82¤", dowipe, AUTOCOMPLETE },
 #endif
 #ifdef DEBUG
-#if 0 /*JP*/
-    { '\0', "wizdebug_bury", "wizard debug: bury objs under and around you",
+#if 0 /*JP:T*/
+    { '\0', "wizbury", "bury objs under and around you",
 #else
-    { '\0', "wizdebug_bury", "\83E\83B\83U\81[\83h\82Å\83o\83b\83O: \95¨\82ð\82 \82È\82½\82Ì\8eü\82è\82É\96\84\82ß\82é",
+    { '\0', "wizbury", "\95¨\82ð\82 \82È\82½\82Ì\8eü\82è\82É\96\84\82ß\82é",
 #endif
             wiz_debug_cmd_bury, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#if 0 /*JP*/
-    { '\0', "wizdebug_traveldisplay", "wizard debug: toggle travel display",
-#else
-    { '\0', "wizdebug_traveldisplay", "\83E\83B\83U\81[\83h\83f\83o\83b\83O: \88Ú\93®\95\\8e¦\82ð\90Ø\82è\91Ö\82¦\82é",
-#endif
-          wiz_debug_cmd_traveldisplay, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
 #endif
     { C('e'), "wizdetect", "reveal hidden things within a small radius",
             wiz_detect, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
@@ -4247,13 +4999,13 @@ struct ext_func_tab extcmdlist[] = {
             wiz_makemap, IFBURIED | WIZMODECMD },
     { C('f'), "wizmap", "map the level",
             wiz_map, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "wizrumorcheck", "verify rumor boundaries",
 #else
     { '\0', "wizrumorcheck", "\89\\82Ì\8b«\8aE\82ð\8c\9f\8fØ\82·\82é",
 #endif
             wiz_rumor_check, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "wizsmell", "smell monster",
 #else
     { '\0', "wizsmell", "\89ö\95¨\82Ì\93õ\82¢\82ð\9ak\82®",
@@ -4263,7 +5015,7 @@ struct ext_func_tab extcmdlist[] = {
             wiz_where, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
     { C('w'), "wizwish", "wish for something",
             wiz_wish, IFBURIED | AUTOCOMPLETE | WIZMODECMD },
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     { '\0', "wmode", "show wall modes",
 #else
     { '\0', "wmode", "\95Ç\83\82\81[\83h\82ð\8c©\82é",
@@ -4273,12 +5025,71 @@ struct ext_func_tab extcmdlist[] = {
     { '\0', (char *) 0, (char *) 0, donull, 0, (char *) 0 } /* sentinel */
 };
 
+/* for key2extcmddesc() to support dowhatdoes() */
+struct movcmd {
+    uchar k1, k2, k3, k4; /* 'normal', 'qwertz', 'numpad', 'phone' */
+    const char *txt, *alt; /* compass direction, screen direction */
+};
+static const struct movcmd movtab[] = {
+    { 'h', 'h', '4', '4', "west",      "left" },
+    { 'j', 'j', '2', '8', "south",     "down" },
+    { 'k', 'k', '8', '2', "north",     "up" },
+    { 'l', 'l', '6', '6', "east",      "right" },
+    { 'b', 'b', '1', '7', "southwest", "lower left" },
+    { 'n', 'n', '3', '9', "southeast", "lower right" },
+    { 'u', 'u', '9', '3', "northeast", "upper right" },
+    { 'y', 'z', '7', '1', "northwest", "upper left" },
+    {   0,   0,   0,   0,  (char *) 0, (char *) 0 }
+};
+
+int extcmdlist_length = SIZE(extcmdlist) - 1;
+
 const char *
 key2extcmddesc(key)
 uchar key;
 {
-    if (Cmd.commands[key] && Cmd.commands[key]->ef_txt)
-        return Cmd.commands[key]->ef_desc;
+    static char key2cmdbuf[48];
+    const struct movcmd *mov;
+    int k, c;
+    uchar M_5 = (uchar) M('5'), M_0 = (uchar) M('0');
+
+    /* need to check for movement commands before checking the extended
+       commands table because it contains entries for number_pad commands
+       that match !number_pad movement (like 'j' for "jump") */
+    key2cmdbuf[0] = '\0';
+    if (movecmd(k = key))
+        Strcpy(key2cmdbuf, "move"); /* "move or attack"? */
+    else if (movecmd(k = unctrl(key)))
+        Strcpy(key2cmdbuf, "rush");
+    else if (movecmd(k = (Cmd.num_pad ? unmeta(key) : lowc(key))))
+        Strcpy(key2cmdbuf, "run");
+    if (*key2cmdbuf) {
+        for (mov = &movtab[0]; mov->k1; ++mov) {
+            c = !Cmd.num_pad ? (!Cmd.swap_yz ? mov->k1 : mov->k2)
+                             : (!Cmd.phone_layout ? mov->k3 : mov->k4);
+            if (c == k) {
+                Sprintf(eos(key2cmdbuf), " %s (screen %s)",
+                        mov->txt, mov->alt);
+                return key2cmdbuf;
+            }
+        }
+    } else if (digit(key) || (Cmd.num_pad && digit(unmeta(key)))) {
+        key2cmdbuf[0] = '\0';
+        if (!Cmd.num_pad)
+            Strcpy(key2cmdbuf, "start of, or continuation of, a count");
+        else if (key == '5' || key == M_5)
+            Sprintf(key2cmdbuf, "%s prefix",
+                    (!!Cmd.pcHack_compat ^ (key == M_5)) ? "run" : "rush");
+        else if (key == '0' || (Cmd.pcHack_compat && key == M_0))
+            Strcpy(key2cmdbuf, "synonym for 'i'");
+        if (*key2cmdbuf)
+            return key2cmdbuf;
+    }
+    if (Cmd.commands[key]) {
+        if (Cmd.commands[key]->ef_txt)
+            return Cmd.commands[key]->ef_desc;
+
+    }
     return (char *) 0;
 }
 
@@ -4299,6 +5110,14 @@ const char *command;
         if (strcmp(command, extcmd->ef_txt))
             continue;
         Cmd.commands[key] = extcmd;
+#if 0 /* silently accept key binding for unavailable command (!SHELL,&c) */
+        if ((extcmd->flags & CMD_NOT_AVAILABLE) != 0) {
+            char buf[BUFSZ];
+
+            Sprintf(buf, cmdnotavail, extcmd->ef_txt);
+            config_error_add("%s", buf);
+        }
+#endif
         return TRUE;
     }
 
@@ -4415,11 +5234,17 @@ dokeylist(VOID_ARGS)
 
     datawin = create_nhwindow(NHW_TEXT);
     putstr(datawin, 0, "");
+/*JP
     putstr(datawin, 0, "            Full Current Key Bindings List");
+*/
+    putstr(datawin, 0, "             \8c»\8dÝ\82Ì\8a®\91S\82È\83L\81[\8a\84\82è\93\96\82Ä\88ê\97\97");
 
     /* directional keys */
     putstr(datawin, 0, "");
+/*JP
     putstr(datawin, 0, "Directional keys:");
+*/
+    putstr(datawin, 0, "\95û\8cü\83L\81[:");
     show_direction_keys(datawin, '.', FALSE); /* '.'==self in direction grid */
 
     keys_used[(uchar) Cmd.move_NW] = keys_used[(uchar) Cmd.move_N]
@@ -4446,16 +5271,31 @@ dokeylist(VOID_ARGS)
             = keys_used[(uchar) C(Cmd.move_S)]
             = keys_used[(uchar) C(Cmd.move_SE)] = TRUE;
         putstr(datawin, 0, "");
+#if 0 /*JP:T*/
         putstr(datawin, 0,
           "Shift-<direction> will move in specified direction until you hit");
         putstr(datawin, 0, "        a wall or run into something.");
+#else
+        putstr(datawin, 0,
+          "Shift-<\95û\8cü> \82Í\81A\95Ç\82É\82Ô\82Â\82©\82é\82©\89½\82©\82ª\82 \82é\82Ü\82Å\8ew\92è\82³\82ê\82½\95û\8cü\82É");
+        putstr(datawin, 0, "        \88Ú\93®\82·\82é\81D");
+#endif
+#if 0 /*JP:T*/
         putstr(datawin, 0,
           "Ctrl-<direction> will run in specified direction until something");
         putstr(datawin, 0, "        very interesting is seen.");
+#else
+        putstr(datawin, 0,
+          "Ctrl-<\95û\8cü> \82Í\81A\89½\82©\8b»\96¡\90[\82¢\82à\82Ì\82ª\8c©\82¦\82é\82Ü\82Å\8ew\92è\82³\82ê\82½\95û\8cü\82É");
+        putstr(datawin, 0, "        \88Ú\93®\82·\82é\81D");
+#endif
     }
 
     putstr(datawin, 0, "");
+/*JP
     putstr(datawin, 0, "Miscellaneous keys:");
+*/
+    putstr(datawin, 0, "\97l\81X\82È\83L\81[:");
     for (i = 0; misc_keys[i].desc; i++) {
         key = Cmd.spkeys[misc_keys[i].nhkf];
         if (key && ((misc_keys[i].numpad && iflags.num_pad)
@@ -4475,21 +5315,30 @@ dokeylist(VOID_ARGS)
 
     if (dokeylist_putcmds(datawin, TRUE, GENERALCMD, WIZMODECMD, keys_used)) {
         putstr(datawin, 0, "");
+/*JP
         putstr(datawin, 0, "General commands:");
+*/
+        putstr(datawin, 0, "\88ê\94Ê\83R\83}\83\93\83h:");
         (void) dokeylist_putcmds(datawin, FALSE, GENERALCMD, WIZMODECMD,
                                  keys_used);
     }
 
     if (dokeylist_putcmds(datawin, TRUE, 0, WIZMODECMD, keys_used)) {
         putstr(datawin, 0, "");
+/*JP
         putstr(datawin, 0, "Game commands:");
+*/
+        putstr(datawin, 0, "\83Q\81[\83\80\83R\83}\83\93\83h:");
         (void) dokeylist_putcmds(datawin, FALSE, 0, WIZMODECMD, keys_used);
     }
 
     if (wizard
         && dokeylist_putcmds(datawin, TRUE, WIZMODECMD, 0, keys_used)) {
         putstr(datawin, 0, "");
+/*JP
         putstr(datawin, 0, "Wizard-mode commands:");
+*/
+        putstr(datawin, 0, "\83E\83B\83U\81[\83h\83\82\81[\83h\83R\83}\83\93\83h:");
         (void) dokeylist_putcmds(datawin, FALSE, WIZMODECMD, 0, keys_used);
     }
 
@@ -4521,18 +5370,18 @@ STATIC_OVL int
 size_obj(otmp)
 struct obj *otmp;
 {
-    int sz = (int) sizeof(struct obj);
+    int sz = (int) sizeof (struct obj);
 
     if (otmp->oextra) {
-        sz += (int) sizeof(struct oextra);
+        sz += (int) sizeof (struct oextra);
         if (ONAME(otmp))
             sz += (int) strlen(ONAME(otmp)) + 1;
         if (OMONST(otmp))
-            sz += (int) sizeof(struct monst);
+            sz += size_monst(OMONST(otmp), FALSE);
         if (OMID(otmp))
-            sz += (int) sizeof(unsigned);
+            sz += (int) sizeof (unsigned);
         if (OLONG(otmp))
-            sz += (int) sizeof(long);
+            sz += (int) sizeof (long);
         if (OMAILCMD(otmp))
             sz += (int) strlen(OMAILCMD(otmp)) + 1;
     }
@@ -4705,6 +5554,7 @@ long *total_size;
     int idx;
     struct trap *tt;
     struct damage *sd; /* shop damage */
+    struct kinfo *k; /* delayed killer */
     struct cemetery *bi; /* bones info */
 
     /* traps and engravings are output unconditionally;
@@ -4770,6 +5620,20 @@ long *total_size;
     }
 
     count = size = 0L;
+    for (k = killer.next; k; k = k->next) {
+        ++count;
+        size += (long) sizeof *k;
+    }
+    if (count || size) {
+        *total_count += count;
+        *total_size += size;
+        Sprintf(hdrbuf, "delayed killer%s, size %ld",
+                plur(count), (long) sizeof (struct kinfo));
+        Sprintf(buf, template, hdrbuf, count, size);
+        putstr(win, 0, buf);
+    }
+
+    count = size = 0L;
     for (bi = level.bonesinfo; bi; bi = bi->next) {
         ++count;
         size += (long) sizeof *bi;
@@ -4891,6 +5755,7 @@ sanity_check()
     timer_sanity_check();
     mon_sanity_check();
     light_sources_sanity_check();
+    bc_sanity_check();
 }
 
 #ifdef DEBUG_MIGRATING_MONS
@@ -4925,9 +5790,6 @@ wiz_migrate_mons()
 }
 #endif
 
-#define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
-#define unmeta(c) (0x7f & (c))
-
 struct {
     int nhkf;
     char key;
@@ -5250,14 +6112,95 @@ int NDECL((*cmd_func));
         || cmd_func == doloot
         /* travel: pop up a menu of interesting targets in view */
         || cmd_func == dotravel
-        /* wizard mode ^V */
-        || cmd_func == wiz_level_tele
+        /* wizard mode ^V and ^T */
+        || cmd_func == wiz_level_tele || cmd_func == dotelecmd
         /* 'm' prefix allowed for some extended commands */
         || cmd_func == doextcmd || cmd_func == doextlist)
         return TRUE;
     return FALSE;
 }
 
+char
+randomkey()
+{
+    static unsigned i = 0;
+    char c;
+
+    switch (rn2(16)) {
+    default:
+        c = '\033';
+        break;
+    case 0:
+        c = '\n';
+        break;
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+        c = (char) rn1('~' - ' ' + 1, ' ');
+        break;
+    case 5:
+        c = (char) (rn2(2) ? '\t' : ' ');
+        break;
+    case 6:
+        c = (char) rn1('z' - 'a' + 1, 'a');
+        break;
+    case 7:
+        c = (char) rn1('Z' - 'A' + 1, 'A');
+        break;
+    case 8:
+        c = extcmdlist[i++ % SIZE(extcmdlist)].key;
+        break;
+    case 9:
+        c = '#';
+        break;
+    case 10:
+    case 11:
+    case 12:
+        c = Cmd.dirchars[rn2(8)];
+        if (!rn2(7))
+            c = !Cmd.num_pad ? (!rn2(3) ? C(c) : (c + 'A' - 'a')) : M(c);
+        break;
+    case 13:
+        c = (char) rn1('9' - '0' + 1, '0');
+        break;
+    case 14:
+        /* any char, but avoid '\0' because it's used for mouse click */
+        c = (char) rnd(iflags.wc_eight_bit_input ? 255 : 127);
+        break;
+    }
+
+    return c;
+}
+
+void
+random_response(buf, sz)
+char *buf;
+int sz;
+{
+    char c;
+    int count = 0;
+
+    for (;;) {
+        c = randomkey();
+        if (c == '\n')
+            break;
+        if (c == '\033') {
+            count = 0;
+            break;
+        }
+        if (count < sz - 1)
+            buf[count++] = c;
+    }
+    buf[count] = '\0';
+}
+
+int
+rnd_extcmd_idx(VOID_ARGS)
+{
+    return rn2(extcmdlist_length + 1) - 1;
+}
+
 int
 ch2spkeys(c, start, end)
 char c;
@@ -5276,7 +6219,7 @@ rhack(cmd)
 register char *cmd;
 {
     int spkey;
-    boolean do_walk, do_rush, prefix_seen, bad_command,
+    boolean prefix_seen, bad_command,
         firsttime = (cmd == 0);
 
     iflags.menu_requested = FALSE;
@@ -5307,7 +6250,7 @@ register char *cmd;
     }
 
     /* handle most movement commands */
-    do_walk = do_rush = prefix_seen = FALSE;
+    prefix_seen = FALSE;
     context.travel = context.travel1 = 0;
     spkey = ch2spkeys(*cmd, NHKF_RUN, NHKF_CLICKLOOK);
 
@@ -5315,7 +6258,7 @@ register char *cmd;
     case NHKF_RUSH:
         if (movecmd(cmd[1])) {
             context.run = 2;
-            do_rush = TRUE;
+            domove_attempting |= DOMOVE_RUSH;
         } else
             prefix_seen = TRUE;
         break;
@@ -5326,7 +6269,7 @@ register char *cmd;
     case NHKF_RUN:
         if (movecmd(lowc(cmd[1]))) {
             context.run = 3;
-            do_rush = TRUE;
+            domove_attempting |= DOMOVE_RUSH;
         } else
             prefix_seen = TRUE;
         break;
@@ -5342,7 +6285,7 @@ register char *cmd;
     case NHKF_FIGHT:
         if (movecmd(cmd[1])) {
             context.forcefight = 1;
-            do_walk = TRUE;
+            domove_attempting |= DOMOVE_WALK;
         } else
             prefix_seen = TRUE;
         break;
@@ -5351,7 +6294,7 @@ register char *cmd;
             context.run = 0;
             context.nopick = 1;
             if (!u.dz)
-                do_walk = TRUE;
+                domove_attempting |= DOMOVE_WALK;
             else
                 cmd[0] = cmd[1]; /* "m<" or "m>" */
         } else
@@ -5361,7 +6304,7 @@ register char *cmd;
         if (movecmd(lowc(cmd[1]))) {
             context.run = 1;
             context.nopick = 1;
-            do_rush = TRUE;
+            domove_attempting |= DOMOVE_RUSH;
         } else
             prefix_seen = TRUE;
         break;
@@ -5384,20 +6327,20 @@ register char *cmd;
             context.travel1 = 1;
             context.run = 8;
             context.nopick = 1;
-            do_rush = TRUE;
+            domove_attempting |= DOMOVE_RUSH;
             break;
         }
         /*FALLTHRU*/
     default:
         if (movecmd(*cmd)) { /* ordinary movement */
             context.run = 0; /* only matters here if it was 8 */
-            do_walk = TRUE;
+            domove_attempting |= DOMOVE_WALK;
         } else if (movecmd(Cmd.num_pad ? unmeta(*cmd) : lowc(*cmd))) {
             context.run = 1;
-            do_rush = TRUE;
+            domove_attempting |= DOMOVE_RUSH;
         } else if (movecmd(unctrl(*cmd))) {
             context.run = 3;
-            do_rush = TRUE;
+            domove_attempting |= DOMOVE_RUSH;
         }
         break;
     }
@@ -5415,13 +6358,17 @@ register char *cmd;
         }
     }
 
-    if ((do_walk || do_rush) && !context.travel && !dxdy_moveok()) {
+    if (((domove_attempting & (DOMOVE_RUSH | DOMOVE_WALK)) != 0L)
+                            && !context.travel && !dxdy_moveok()) {
         /* trying to move diagonally as a grid bug;
            this used to be treated by movecmd() as not being
            a movement attempt, but that didn't provide for any
            feedback and led to strangeness if the key pressed
            ('u' in particular) was overloaded for num_pad use */
+/*JP
         You_cant("get there from here...");
+*/
+        You_cant("\82±\82±\82©\82ç\82»\82±\82Ö\82Í\8ds\82¯\82Ü\82¹\82ñ\81D\81D\81D");
         context.run = 0;
         context.nopick = context.forcefight = FALSE;
         context.move = context.mv = FALSE;
@@ -5429,13 +6376,13 @@ register char *cmd;
         return;
     }
 
-    if (do_walk) {
+    if ((domove_attempting & DOMOVE_WALK) != 0L) {
         if (multi)
             context.mv = TRUE;
         domove();
         context.forcefight = 0;
         return;
-    } else if (do_rush) {
+    } else if ((domove_attempting & DOMOVE_RUSH) != 0L) {
         if (firsttime) {
             if (!multi)
                 multi = max(COLNO, ROWNO);
@@ -5459,7 +6406,10 @@ register char *cmd;
         /* current - use *cmd to directly index cmdlist array */
         if ((tlist = Cmd.commands[*cmd & 0xff]) != 0) {
             if (!wizard && (tlist->flags & WIZMODECMD)) {
+/*JP
                 You_cant("do that!");
+*/
+                pline("\82»\82ê\82Í\82Å\82«\82Ü\82¹\82ñ\81I");
                 res = 0;
             } else if (u.uburied && !(tlist->flags & IFBURIED)) {
 /*JP
@@ -5626,7 +6576,7 @@ const char *s;
     char dirsym;
     int is_mov;
 
-retry:
+ retry:
     if (in_doagain || *readchar_queue)
         dirsym = readchar();
     else
@@ -5657,9 +6607,9 @@ retry:
                                     NHKF_ESC,
                                     help_requested ? (const char *) 0
 /*JP
-                                            : "Invalid direction key!");
+                                                  : "Invalid direction key!");
 */
-                                            : "\96³\8cø\82È\95û\8cü\8ew\92è\82Å\82·\81I");
+                                                  : "\96³\8cø\82È\95û\8cü\8ew\92è\82Å\82·\81I");
                 if (help_requested)
                     goto retry;
             }
@@ -5743,13 +6693,25 @@ const char *msg;
      * general message if it's on.
      */
     dothat = "do that";
+#if 0 /*JP*/
     how = " at"; /* for "<action> at yourself"; not used for up/down */
+#else
+    how = "";
+#endif
     switch (spkey) {
     case NHKF_NOPICKUP:
+#if 0 /*JP*/
         dothat = "move";
+#else
+        dothat = "\88Ú\93®\82·\82é";
+#endif
         break;
     case NHKF_RUSH:
+#if 0 /*JP*/
         dothat = "rush";
+#else
+        dothat = "\93Ë\90i\82·\82é";
+#endif
         break;
     case NHKF_RUN2:
         if (!Cmd.num_pad)
@@ -5757,14 +6719,22 @@ const char *msg;
         /*FALLTHRU*/
     case NHKF_RUN:
     case NHKF_RUN_NOPICKUP:
+#if 0 /*JP*/
         dothat = "run";
+#else
+        dothat = "\91\96\82é";
+#endif
         break;
     case NHKF_FIGHT2:
         if (!Cmd.num_pad)
             break;
         /*FALLTHRU*/
     case NHKF_FIGHT:
+#if 0 /*JP*/
         dothat = "fight";
+#else
+        dothat = "\90í\82¤";
+#endif
         how = ""; /* avoid "fight at yourself" */
         break;
     default:
@@ -5778,13 +6748,21 @@ const char *msg;
     if (prefixhandling
         && (sym == Cmd.spkeys[NHKF_GETDIR_SELF]
             || (Cmd.num_pad && sym == Cmd.spkeys[NHKF_GETDIR_SELF2]))) {
+/*JP
         Sprintf(buf, "You can't %s%s yourself.", dothat, how);
+*/
+        Sprintf(buf, "\8e©\95ª\8e©\90g\82É%s%s\82±\82Æ\82Í\82Å\82«\82È\82¢\81D", dothat, how);
     /* for movement prefix followed by up or down */
     } else if (prefixhandling && (sym == '<' || sym == '>')) {
+#if 0 /*JP*/
         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");
+#else
+        Sprintf(buf, "%s%s\82±\82Æ\82Í\82Å\82«\82È\82¢\81D",
+                (sym == '<') ? "\8fã\95û\8cü\82É" : "\89º\95û\8cü\82É", dothat);
+#endif
     }
 
     /* if '!cmdassist', display via pline() and we're done (note: asking
@@ -5792,8 +6770,13 @@ const char *msg;
     if (!viawindow) {
         if (prefixhandling) {
             if (!*buf)
+#if 0 /*JP*/
                 Sprintf(buf, "Invalid direction for '%s' prefix.",
                         visctrl(Cmd.spkeys[spkey]));
+#else
+                Sprintf(buf, "'%s'\90Ú\93ª\8e«\82É\82Í\95s\90³\82È\95û\8cü\81D",
+                        visctrl(Cmd.spkeys[spkey]));
+#endif
             pline("%s", buf);
             return TRUE;
         }
@@ -5836,9 +6819,15 @@ const char *msg;
         }
     }
 
+#if 0 /*JP:T*/
     Sprintf(buf, "Valid direction keys%s%s%s are:",
             prefixhandling ? " to " : "", prefixhandling ? dothat : "",
             NODIAG(u.umonnum) ? " in your current form" : "");
+#else
+    Sprintf(buf, "%s%s%s\97L\8cø\82È\95û\8cü\8ew\92è\82Í:",
+            prefixhandling ? dothat : "", prefixhandling ? "\82½\82ß\82Ì" : "",
+            NODIAG(u.umonnum) ? " \8c»\8dÝ\82Ì\8ep\82Å\82Ì" : "");
+#endif
     putstr(win, 0, buf);
     show_direction_keys(win, !prefixhandling ? '.' : ' ', NODIAG(u.umonnum));
 
@@ -5848,13 +6837,24 @@ const char *msg;
            given but we include up and down for 'm'+invalid_direction;
            self is excluded as a viable direction for every prefix */
         putstr(win, 0, "");
+/*JP
         putstr(win, 0, "          <  up");
+*/
+        putstr(win, 0, "          <  \8fã");
+/*JP
         putstr(win, 0, "          >  down");
+*/
+        putstr(win, 0, "          >  \89º");
         if (!prefixhandling) {
             int selfi = Cmd.num_pad ? NHKF_GETDIR_SELF2 : NHKF_GETDIR_SELF;
 
+#if 0 /*JP:T*/
             Sprintf(buf,   "       %4s  direct at yourself",
                     visctrl(Cmd.spkeys[selfi]));
+#else
+            Sprintf(buf,   "       %4s  \8e©\95ª\82É\8cü\82¯\82é",
+                    visctrl(Cmd.spkeys[selfi]));
+#endif
             putstr(win, 0, buf);
         }
     }
@@ -6339,15 +7339,16 @@ boolean historical; /* whether to include in message history: True => yes */
                 Sprintf(qbuf, "\90\94: %ld", cnt);
                 backspaced = FALSE;
             }
-            /* bypassing pline() keeps intermediate prompt out of
-               DUMPLOG message history */
-            putstr(WIN_MESSAGE, 0, qbuf);
+            custompline(SUPPRESS_HISTORY, "%s", qbuf);
             mark_synch();
         }
     }
 
     if (historical) {
+/*JP
         Sprintf(qbuf, "Count: %ld ", *count);
+*/
+        Sprintf(qbuf, "\90\94: %ld ", *count);
         (void) key2txt((uchar) key, eos(qbuf));
         putmsghistory(qbuf, FALSE);
     }
@@ -6365,7 +7366,6 @@ parse()
     static char in_line[COLNO];
 #endif
     register int foo;
-    boolean prezero = FALSE;
 
     iflags.in_parse = TRUE;
     multi = 0;
@@ -6385,6 +7385,12 @@ parse()
     alt_esc = FALSE; /* readchar() reset */
 #endif
 
+    if (iflags.debug_fuzzer /* if fuzzing, override '!' and ^Z */
+        && (Cmd.commands[foo & 0x0ff]
+            && (Cmd.commands[foo & 0x0ff]->ef_funct == dosuspend_core
+                || Cmd.commands[foo & 0x0ff]->ef_funct == dosh_core)))
+        foo = Cmd.spkeys[NHKF_ESC];
+
     if (foo == Cmd.spkeys[NHKF_ESC]) { /* esc cancels count (TH) */
         clear_nhwindow(WIN_MESSAGE);
         multi = last_multi = 0;
@@ -6432,8 +7438,6 @@ parse()
         in_line[2] = 0;
     }
     clear_nhwindow(WIN_MESSAGE);
-    if (prezero)
-        in_line[0] = Cmd.spkeys[NHKF_ESC];
 
     iflags.in_parse = FALSE;
     return in_line;
@@ -6472,7 +7476,7 @@ end_of_input()
 #ifdef NOSAVEONHANGUP
 #ifdef INSURANCE
     if (flags.ins_chkpt && program_state.something_worth_saving)
-        program_statue.preserve_locks = 1; /* keep files for recovery */
+        program_state.preserve_locks = 1; /* keep files for recovery */
 #endif
     program_state.something_worth_saving = 0; /* don't save */
 #endif
@@ -6497,6 +7501,8 @@ readchar()
     register int sym;
     int x = u.ux, y = u.uy, mod = 0;
 
+    if (iflags.debug_fuzzer)
+        return randomkey();
     if (*readchar_queue)
         sym = *readchar_queue++;
     else
@@ -6539,19 +7545,26 @@ readchar()
     return (char) sym;
 }
 
+/* '_' command, #travel, via keyboard rather than mouse click */
 STATIC_PTR int
 dotravel(VOID_ARGS)
 {
-    /* Keyboard travel command */
     static char cmd[2];
     coord cc;
 
+    /* [FIXME?  Supporting the ability to disable traveling via mouse
+       click makes some sense, depending upon overall mouse usage.
+       Disabling '_' on a user by user basis makes no sense at all since
+       even if it is typed by accident, aborting when picking a target
+       destination is trivial.  Travel via mouse predates travel via '_',
+       and this use of OPTION=!travel is probably just a mistake....] */
     if (!flags.travelcmd)
         return 0;
+
     cmd[1] = 0;
     cc.x = iflags.travelcc.x;
     cc.y = iflags.travelcc.y;
-    if (cc.x == -1 && cc.y == -1) {
+    if (cc.x == 0 && cc.y == 0) {
         /* No cached destination, start attempt from current position */
         cc.x = u.ux;
         cc.y = u.uy;
@@ -6568,13 +7581,13 @@ dotravel(VOID_ARGS)
         iflags.getloc_filter = gf;
     } else {
 /*JP
-    pline("Where do you want to travel to?");
+        pline("Where do you want to travel to?");
 */
-    pline("\82Ç\82±\82É\88Ú\93®\82·\82é\81H");
+        pline("\82Ç\82±\82É\88Ú\93®\82·\82é\81H");
 /*JP
-    if (getpos(&cc, TRUE, "the desired destination") < 0) {
+        if (getpos(&cc, TRUE, "the desired destination") < 0) {
 */
-    if (getpos(&cc, TRUE, "\88Ú\93®\90æ") < 0) {
+        if (getpos(&cc, TRUE, "\88Ú\93®\90æ") < 0) {
             /* user pressed ESC */
             iflags.getloc_travelmode = FALSE;
             return 0;
@@ -6588,56 +7601,6 @@ dotravel(VOID_ARGS)
     return 0;
 }
 
-#ifdef PORT_DEBUG
-extern void NDECL(win32con_debug_keystrokes);
-extern void NDECL(win32con_handler_info);
-
-int
-wiz_port_debug()
-{
-    int n, k;
-    winid win;
-    anything any;
-    int item = 'a';
-    int num_menu_selections;
-    struct menu_selection_struct {
-        char *menutext;
-        void NDECL((*fn));
-    } menu_selections[] = {
-#ifdef WIN32
-        { "test win32 keystrokes (tty only)", win32con_debug_keystrokes },
-        { "show keystroke handler information (tty only)",
-          win32con_handler_info },
-#endif
-        { (char *) 0, (void NDECL((*))) 0 } /* array terminator */
-    };
-
-    num_menu_selections = SIZE(menu_selections) - 1;
-    if (num_menu_selections > 0) {
-        menu_item *pick_list;
-
-        win = create_nhwindow(NHW_MENU);
-        start_menu(win);
-        for (k = 0; k < num_menu_selections; ++k) {
-            any.a_int = k + 1;
-            add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE,
-                     menu_selections[k].menutext, MENU_UNSELECTED);
-        }
-        end_menu(win, "Which port debugging feature?");
-        n = select_menu(win, PICK_ONE, &pick_list);
-        destroy_nhwindow(win);
-        if (n > 0) {
-            n = pick_list[0].item.a_int - 1;
-            free((genericptr_t) pick_list);
-            /* execute the function */
-            (*menu_selections[n].fn)();
-        }
-    } else
-        pline("No port-specific debug capability defined.");
-    return 0;
-}
-#endif /*PORT_DEBUG*/
-
 /*
  *   Parameter validator for generic yes/no function to prevent
  *   the core from sending too long a prompt string to the
@@ -6692,19 +7655,27 @@ const char *prompt;
        to give the go-ahead for this query; default is "no" unless the
        ParanoidConfirm flag is set in which case there's no default */
     if (be_paranoid) {
-        char qbuf[QBUFSZ], ans[BUFSZ] = DUMMY;
-        const char *promptprefix = "", *responsetype = ParanoidConfirm
-                                                           ? "(yes|no)"
-                                                           : "(yes) [no]";
-        int trylimit = 6; /* 1 normal, 5 more with "Yes or No:" prefix */
+        char pbuf[BUFSZ], qbuf[QBUFSZ], ans[BUFSZ];
+        const char *promptprefix = "",
+                *responsetype = ParanoidConfirm ? "(yes|no)" : "(yes) [no]";
+        int k, trylimit = 6; /* 1 normal, 5 more with "Yes or No:" prefix */
 
+        copynchars(pbuf, prompt, BUFSZ - 1);
         /* in addition to being paranoid about this particular
            query, we might be even more paranoid about all paranoia
            responses (ie, ParanoidConfirm is set) in which case we
            require "no" to reject in addition to "yes" to confirm
            (except we won't loop if response is ESC; it means no) */
         do {
-            Sprintf(qbuf, "%s%s %s", promptprefix, prompt, responsetype);
+            /* make sure we won't overflow a QBUFSZ sized buffer */
+            k = (int) (strlen(promptprefix) + 1 + strlen(responsetype));
+            if ((int) strlen(pbuf) + k > QBUFSZ - 1) {
+                /* chop off some at the end */
+                Strcpy(pbuf + (QBUFSZ - 1) - k - 4, "...?"); /* -4: "...?" */
+            }
+
+            Sprintf(qbuf, "%s%s %s", promptprefix, pbuf, responsetype);
+            *ans = '\0';
             getlin(qbuf, ans);
             (void) mungspaces(ans);
             confirmed_ok = !strcmpi(ans, "yes");
@@ -6718,8 +7689,9 @@ const char *prompt;
     return confirmed_ok;
 }
 
-int
-dosuspend_core()
+/* ^Z command, #suspend */
+STATIC_PTR int
+dosuspend_core(VOID_ARGS)
 {
 #ifdef SUSPEND
     /* Does current window system support suspend? */
@@ -6728,7 +7700,20 @@ dosuspend_core()
         dosuspend();
     } else
 #endif
-        Norep("Suspend command not available.");
+        Norep(cmdnotavail, "#suspend");
+    return 0;
+}
+
+/* '!' command, #shell */
+STATIC_PTR int
+dosh_core(VOID_ARGS)
+{
+#ifdef SHELL
+    /* access restrictions, if any, are handled in port code */
+    dosh();
+#else
+    Norep(cmdnotavail, "#shell");
+#endif
     return 0;
 }