OSDN Git Service

fix indent
[jnethack/source.git] / src / do_name.c
index 2e2dfd1..a1b6032 100644 (file)
@@ -1,13 +1,26 @@
-/* NetHack 3.6 do_name.c       $NHDT-Date: 1446808440 2015/11/06 11:14:00 $  $NHDT-Branch: master $:$NHDT-Revision: 1.77 $ */
+/* NetHack 3.6 do_name.c       $NHDT-Date: 1555627306 2019/04/18 22:41:46 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.145 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Pasi Kallinen, 2018. */
 /* 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-2019            */
+/* JNetHack may be freely redistributed.  See license for details. */
+
 #include "hack.h"
 
 STATIC_DCL char *NDECL(nextmbuf);
 STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *));
+STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, const void *));
+STATIC_DCL boolean FDECL(gather_locs_interesting, (int, int, int));
+STATIC_DCL void FDECL(gather_locs, (coord **, int *, int));
+STATIC_DCL int FDECL(gloc_filter_floodfill_matcharea, (int, int));
+STATIC_DCL void FDECL(auto_describe, (int, int));
 STATIC_DCL void NDECL(do_mname);
+STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *));
 STATIC_DCL void FDECL(do_oname, (struct obj *));
+STATIC_PTR char *FDECL(docall_xname, (struct obj *));
 STATIC_DCL void NDECL(namefloorobj);
 STATIC_DCL char *FDECL(bogusmon, (char *,char *));
 
@@ -29,13 +42,82 @@ nextmbuf()
 /* function for getpos() to highlight desired map locations.
  * parameter value 0 = initialize, 1 = highlight, 2 = done
  */
-void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0;
+static void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0;
+static boolean FDECL((*getpos_getvalid), (int, int)) =
+                                           (boolean FDECL((*), (int, int))) 0;
+
+void
+getpos_sethilite(gp_hilitef, gp_getvalidf)
+void FDECL((*gp_hilitef), (int));
+boolean FDECL((*gp_getvalidf), (int, int));
+{
+    getpos_hilitefunc = gp_hilitef;
+    getpos_getvalid = gp_getvalidf;
+}
+
+/*JP:
+  [0] "cannot see %s"
+  [1] "pick a %s"
+  [2] "use XXX to move the cursor to %s"
+  */
+static const char *const gloc_descr[NUM_GLOCS][4] = {
+#if 0 /*JP*/
+    { "any monsters", "monster", "next/previous monster", "monsters" },
+    { "any items", "item", "next/previous object", "objects" },
+    { "any doors", "door", "next/previous door or doorway", "doors or doorways" },
+    { "any unexplored areas", "unexplored area", "unexplored location",
+      "unexplored locations" },
+    { "anything interesting", "interesting thing", "anything interesting",
+      "anything interesting" },
+    { "any valid locations", "valid location", "valid location",
+      "valid locations" }
+#else
+    { "\89ö\95¨", "\89ö\95¨", "\89ö\95¨\82Ì\97×", "\89ö\95¨" },
+    { "\95¨", "\95¨", "\95¨\82Ì\97×", "\95¨" },
+    { "\94à", "\94à", "\94à\82â\8fo\93ü\82è\8cû\82Ì\97×", "\94à\82â\8fo\93ü\82è\8cû" },
+    { "\96¢\92T\8dõ\95\94\95ª", "\96¢\92T\8dõ\95\94\95ª", "\96¢\92T\8dõ\82Ì\88Ê\92u", "\96¢\92T\8dõ\82Ì\88Ê\92u" },
+    { "\8aÖ\90S\82Ì\82 \82é\82à\82Ì", "\8aÖ\90S\82Ì\82 \82é\82à\82Ì", "\8aÖ\90S\82Ì\82 \82é\82à\82Ì", "\8aÖ\90S\82Ì\82 \82é\82à\82Ì" },
+    { "\97L\8cø\82È\88Ê\92u", "\97L\8cø\82È\88Ê\92u", "\97L\8cø\82È\88Ê\92u", "\97L\8cø\82È\88Ê\92u" },
+#endif
+};
+
+static const char *const gloc_filtertxt[NUM_GFILTER] = {
+#if 0 /*JP*/
+    "",
+    " in view",
+    " in this area"
+#else
+    "",
+    "\8e\8b\8aE\82Ì\92\86\82Ì",
+    "\82±\82Ì\83G\83\8a\83A\82Ì"
+#endif
+};
 
 void
-getpos_sethilite(f)
-void FDECL((*f), (int));
+getpos_help_keyxhelp(tmpwin, k1, k2, gloc)
+winid tmpwin;
+const char *k1;
+const char *k2;
+int gloc;
 {
-    getpos_hilitefunc = f;
+    char sbuf[BUFSZ];
+
+#if 0 /*JP*/
+    Sprintf(sbuf, "Use '%s'/'%s' to %s%s%s.",
+            k1, k2,
+            iflags.getloc_usemenu ? "get a menu of "
+                                  : "move the cursor to ",
+            gloc_descr[gloc][2 + iflags.getloc_usemenu],
+            gloc_filtertxt[iflags.getloc_filter]);
+#else
+    Sprintf(sbuf, "'%s'\82©'%s'\82Å%s%s%s\81D",
+            k1, k2,
+            gloc_filtertxt[iflags.getloc_filter],
+            gloc_descr[gloc][2 + iflags.getloc_usemenu],
+            iflags.getloc_usemenu ? "\82Ì\83\81\83j\83\85\81[\82ð\8fo\82·"
+                                  : "\82É\83J\81[\83\\83\8b\82ð\93®\82©\82·");
+#endif
+    putstr(tmpwin, 0, sbuf);
 }
 
 /* the response for '?' help request in getpos() */
@@ -44,52 +126,745 @@ getpos_help(force, goal)
 boolean force;
 const char *goal;
 {
+#if 0 /*JP*/
+    static const char *const fastmovemode[2] = { "8 units at a time",
+                                                 "skipping same glyphs" };
+#else
+    static const char *const fastmovemode[2] = { "\88ê\93x\82É8\83}\83X",
+                                                 "\93¯\82\92n\8c`\82ð\94ò\82Î\82µ\82Ä" };
+#endif
     char sbuf[BUFSZ];
     boolean doing_what_is;
     winid tmpwin = create_nhwindow(NHW_MENU);
 
-    Sprintf(sbuf, "Use [%c%c%c%c] to move the cursor to %s.", /* hjkl */
+#if 0 /*JP*/
+    Sprintf(sbuf,
+            "Use '%c', '%c', '%c', '%c' to move the cursor to %s.", /* hjkl */
             Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E, goal);
+#else
+    Sprintf(sbuf,
+            "[%c%c%c%c]\82Å%s\82Ö\88Ú\93®\82Å\82«\82é\81D",
+            Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E, goal);
+#endif
     putstr(tmpwin, 0, sbuf);
-    putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time.");
-    putstr(tmpwin, 0, "Or enter a background symbol (ex. <).");
-    putstr(tmpwin, 0, "Use @ to move the cursor on yourself.");
-    if (getpos_hilitefunc != NULL)
-        putstr(tmpwin, 0, "Use $ to display valid locations.");
-    putstr(tmpwin, 0, "Use # to toggle automatic description.");
-    /* disgusting hack; the alternate selection characters work for any
-       getpos call, but they only matter for dowhatis (and doquickwhatis) */
-    doing_what_is = (goal == what_is_an_unknown_object);
-    Sprintf(sbuf, "Type a .%s when you are at the right place.",
-            doing_what_is ? " or , or ; or :" : "");
+#if 0 /*JP*/
+    Sprintf(sbuf,
+            "Use 'H', 'J', 'K', 'L' to fast-move the cursor, %s.",
+            fastmovemode[iflags.getloc_moveskip]);
+#else
+    Sprintf(sbuf,
+            "'H', 'J', 'K', 'L' \82Å%s\88Ú\93®\82Å\82«\82é\81D",
+            fastmovemode[iflags.getloc_moveskip]);
+#endif
+    putstr(tmpwin, 0, sbuf);
+/*JP
+    putstr(tmpwin, 0, "Or enter a background symbol (ex. '<').");
+*/
+    putstr(tmpwin, 0, "\94w\8ci\82Ì\83V\83\93\83{\83\8b\82ð\93ü\97Í\82·\82é\82Æ\82»\82Ì\88Ê\92u\82É\88Ú\93®\82·\82é(\97á\81F'<')\81D");
+#if 0 /*JP*/
+    Sprintf(sbuf, "Use '%s' to move the cursor on yourself.",
+           visctrl(Cmd.spkeys[NHKF_GETPOS_SELF]));
+#else
+    Sprintf(sbuf, "'%s'\82Å\8e©\95ª\8e©\90g\82Ì\88Ê\92u\82É\88Ú\93®\82·\82é\81D",
+           visctrl(Cmd.spkeys[NHKF_GETPOS_SELF]));
+#endif
     putstr(tmpwin, 0, sbuf);
+    if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
+        getpos_help_keyxhelp(tmpwin,
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_MON_NEXT]),
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_MON_PREV]),
+                             GLOC_MONS);
+    }
+    if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
+        getpos_help_keyxhelp(tmpwin,
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_OBJ_NEXT]),
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_OBJ_PREV]),
+                             GLOC_OBJS);
+    }
+    if (!iflags.terrainmode || (iflags.terrainmode & TER_MAP) != 0) {
+        /* these are primarily useful when choosing a travel
+           destination for the '_' command */
+        getpos_help_keyxhelp(tmpwin,
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_DOOR_NEXT]),
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_DOOR_PREV]),
+                             GLOC_DOOR);
+        getpos_help_keyxhelp(tmpwin,
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_NEXT]),
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_PREV]),
+                             GLOC_EXPLORE);
+        getpos_help_keyxhelp(tmpwin,
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_INTERESTING_NEXT]),
+                             visctrl(Cmd.spkeys[NHKF_GETPOS_INTERESTING_PREV]),
+                             GLOC_INTERESTING);
+    }
+#if 0 /*JP*/
+    Sprintf(sbuf, "Use '%s' to change fast-move mode to %s.",
+            visctrl(Cmd.spkeys[NHKF_GETPOS_MOVESKIP]),
+            fastmovemode[!iflags.getloc_moveskip]);
+#else
+    Sprintf(sbuf, "'%s'\82Å\8d\82\91¬\88Ú\93®\83\82\81[\83h\82ð%s\88Ú\93®\82É\82·\82é\81D",
+            visctrl(Cmd.spkeys[NHKF_GETPOS_MOVESKIP]),
+            fastmovemode[!iflags.getloc_moveskip]);
+#endif
+    putstr(tmpwin, 0, sbuf);
+    if (!iflags.terrainmode || (iflags.terrainmode & TER_DETECT) == 0) {
+#if 0 /*JP*/
+        Sprintf(sbuf, "Use '%s' to toggle menu listing for possible targets.",
+                visctrl(Cmd.spkeys[NHKF_GETPOS_MENU]));
+#else
+        Sprintf(sbuf, "'%s'\82Å\89Â\94\\82È\83^\81[\83Q\83b\83g\82Ì\83\81\83j\83\85\81[\95\\8e¦\82ð\90Ø\82è\91Ö\82¦\82é\81D",
+                visctrl(Cmd.spkeys[NHKF_GETPOS_MENU]));
+#endif
+        putstr(tmpwin, 0, sbuf);
+#if 0 /*JP*/
+        Sprintf(sbuf,
+                "Use '%s' to change the mode of limiting possible targets.",
+                visctrl(Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]));
+#else
+        Sprintf(sbuf,
+                "'%s'\82Å\90§\8cÀ\82³\82ê\82½\89Â\94\\82È\83^\81[\83Q\83b\83g\82Ì\83\82\81[\83h\82ð\90Ø\82è\91Ö\82¦\82é\81D",
+                visctrl(Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]));
+#endif
+        putstr(tmpwin, 0, sbuf);
+    }
+    if (!iflags.terrainmode) {
+        char kbuf[BUFSZ];
+
+        if (getpos_getvalid) {
+#if 0 /*JP*/
+            Sprintf(sbuf, "Use '%s' or '%s' to move to valid locations.",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_NEXT]),
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_PREV]));
+#else
+            Sprintf(sbuf, "'%s'\82©'%s'\82Å\90³\93\96\82È\88Ê\92u\82É\88Ú\93®\82·\82é\81D",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_NEXT]),
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_PREV]));
+#endif
+            putstr(tmpwin, 0, sbuf);
+        }
+        if (getpos_hilitefunc) {
+#if 0 /*JP:T*/
+            Sprintf(sbuf, "Use '%s' to display valid locations.",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_SHOWVALID]));
+#else
+            Sprintf(sbuf, "'%s'\82Å\89Â\94\\82È\88Ê\92u\82ð\95\\8e¦\82·\82é\81D",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_SHOWVALID]));
+#endif
+            putstr(tmpwin, 0, sbuf);
+        }
+#if 0 /*JP:T*/
+        Sprintf(sbuf, "Use '%s' to toggle automatic description.",
+                visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
+#else
+        Sprintf(sbuf, "'%s'\82Å\90à\96¾\82Ì\8e©\93®\95\\8e¦\82ð\90Ø\82è\91Ö\82¦\82é\81D",
+                visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
+#endif
+        putstr(tmpwin, 0, sbuf);
+        if (iflags.cmdassist) { /* assisting the '/' command, I suppose... */
+#if 0 /*JP*/
+            Sprintf(sbuf,
+                    (iflags.getpos_coords == GPCOORDS_NONE)
+         ? "(Set 'whatis_coord' option to include coordinates with '%s' text.)"
+         : "(Reset 'whatis_coord' option to omit coordinates from '%s' text.)",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
+#else
+            Sprintf(sbuf,
+                    (iflags.getpos_coords == GPCOORDS_NONE)
+         ? "('%s'\82É\8dÀ\95W\82ð\8aÜ\82Þ\82É\82Í'whatis_coord'\83I\83v\83V\83\87\83\93\82ð\83I\83\93\82É\82·\82é\81D)"
+         : "('%s'\82©\82ç\8dÀ\95W\82ð\8f\9c\82­\82É\82Í'whatis_coord'\83I\83v\83V\83\87\83\93\82ð\83I\83t\82É\82·\82é\81D)",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
+#endif
+        }
+        /* disgusting hack; the alternate selection characters work for any
+           getpos call, but only matter for dowhatis (and doquickwhatis) */
+        doing_what_is = (goal == what_is_an_unknown_object);
+        if (doing_what_is) {
+#if 0 /*JP*/
+            Sprintf(kbuf, "'%s' or '%s' or '%s' or '%s'",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]),
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]),
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
+#else
+            Sprintf(kbuf, "'%s'\82©'%s'\82©'%s'\82©'%s'",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]),
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]),
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
+#endif
+        } else {
+            Sprintf(kbuf, "'%s'", visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
+        }
+#if 0 /*JP:T*/
+        Sprintf(sbuf, "Type a %s when you are at the right place.", kbuf);
+#else
+        Sprintf(sbuf, "[.]%s\82Å\8c\88\92è\81D", kbuf);
+#endif
+        putstr(tmpwin, 0, sbuf);
+        if (doing_what_is) {
+#if 0 /*JP:T*/
+            Sprintf(sbuf,
+       "  '%s' describe current spot, show 'more info', move to another spot.",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
+#else
+            Sprintf(sbuf,
+       "  '%s'\82Í\8c»\8dÝ\82Ì\88Ê\92u\82ð\90à\96¾\82µ\81A\92Ç\89Á\8fî\95ñ\82ð\95\\8e¦\82µ\81A\8e\9f\82Ì\88Ê\92u\82É\88Ú\93®\82·\82é\81D",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
+#endif
+            putstr(tmpwin, 0, sbuf);
+#if 0 /*JP:T*/
+            Sprintf(sbuf,
+                    "  '%s' describe current spot,%s move to another spot;",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
+                    flags.help ? " prompt if 'more info'," : "");
+#else
+            Sprintf(sbuf,
+                    "  '%s'\82Í\8c»\8dÝ\82Ì\88Ê\92u\82ð\90à\96¾\82µ\81C%s\8e\9f\82Ì\88Ê\92u\82É\88Ú\93®\82·\82é;",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
+                    flags.help ? "\92Ç\89Á\8fî\95ñ\82ª\82 \82ê\82Î\8am\94F\82µ\81C" : "");
+#endif
+            putstr(tmpwin, 0, sbuf);
+#if 0 /*JP:T*/
+            Sprintf(sbuf,
+                    "  '%s' describe current spot, move to another spot;",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]));
+#else
+            Sprintf(sbuf,
+                    "  '%s'\82Í\8c»\8dÝ\82Ì\88Ê\92u\82ð\90à\96¾\82µ\81C\8e\9f\82Ì\88Ê\92u\82É\88Ú\93®\82·\82é;",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]));
+#endif
+            putstr(tmpwin, 0, sbuf);
+#if 0 /*JP:T*/
+            Sprintf(sbuf,
+                    "  '%s' describe current spot, stop looking at things;",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]));
+#else
+            Sprintf(sbuf,
+                    "  '%s'\82Í\8c»\8dÝ\82Ì\88Ê\92u\82ð\90à\96¾\82µ\81C\8c©\82é\82Ì\82ð\82â\82ß\82é;",
+                    visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]));
+#endif
+            putstr(tmpwin, 0, sbuf);
+        }
+    }
     if (!force)
+/*JP
         putstr(tmpwin, 0, "Type Space or Escape when you're done.");
+*/
+        putstr(tmpwin, 0, "\83X\83y\81[\83X\82Ü\82½\82Í\83G\83X\83P\81[\83v\82Å\8fI\97¹\81D");
     putstr(tmpwin, 0, "");
     display_nhwindow(tmpwin, TRUE);
     destroy_nhwindow(tmpwin);
 }
 
+STATIC_OVL int
+cmp_coord_distu(a, b)
+const void *a;
+const void *b;
+{
+    const coord *c1 = a;
+    const coord *c2 = b;
+    int dx, dy, dist_1, dist_2;
+
+    dx = u.ux - c1->x;
+    dy = u.uy - c1->y;
+    dist_1 = max(abs(dx), abs(dy));
+    dx = u.ux - c2->x;
+    dy = u.uy - c2->y;
+    dist_2 = max(abs(dx), abs(dy));
+
+    if (dist_1 == dist_2)
+        return (c1->y != c2->y) ? (c1->y - c2->y) : (c1->x - c2->x);
+
+    return dist_1 - dist_2;
+}
+
+#define IS_UNEXPLORED_LOC(x,y) \
+    (isok((x), (y))                                     \
+     && glyph_is_cmap(levl[(x)][(y)].glyph)             \
+     && glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone  \
+     && !levl[(x)][(y)].seenv)
+
+static struct opvar *gloc_filter_map = (struct opvar *) 0;
+
+#define GLOC_SAME_AREA(x,y)                                     \
+    (isok((x), (y))                                             \
+     && (selection_getpoint((x),(y), gloc_filter_map)))
+
+static int gloc_filter_floodfill_match_glyph;
+
+int
+gloc_filter_classify_glyph(glyph)
+int glyph;
+{
+    int c;
+
+    if (!glyph_is_cmap(glyph))
+        return 0;
+
+    c = glyph_to_cmap(glyph);
+
+    if (is_cmap_room(c) || is_cmap_furniture(c))
+        return 1;
+    else if (is_cmap_wall(c) || c == S_tree)
+        return 2;
+    else if (is_cmap_corr(c))
+        return 3;
+    else if (is_cmap_water(c))
+        return 4;
+    else if (is_cmap_lava(c))
+        return 5;
+    return 0;
+}
+
+STATIC_OVL int
+gloc_filter_floodfill_matcharea(x, y)
+int x, y;
+{
+    int glyph = back_to_glyph(x, y);
+
+    if (!levl[x][y].seenv)
+        return FALSE;
+
+    if (glyph == gloc_filter_floodfill_match_glyph)
+        return TRUE;
+
+    if (gloc_filter_classify_glyph(glyph)
+        == gloc_filter_classify_glyph(gloc_filter_floodfill_match_glyph))
+        return TRUE;
+
+    return FALSE;
+}
+
+void
+gloc_filter_floodfill(x, y)
+int x, y;
+{
+    gloc_filter_floodfill_match_glyph = back_to_glyph(x, y);
+
+    set_selection_floodfillchk(gloc_filter_floodfill_matcharea);
+    selection_floodfill(gloc_filter_map, x, y, FALSE);
+}
+
+void
+gloc_filter_init()
+{
+    if (iflags.getloc_filter == GFILTER_AREA) {
+        if (!gloc_filter_map) {
+            gloc_filter_map = selection_opvar((char *) 0);
+        }
+        /* special case: if we're in a doorway, try to figure out which
+           direction we're moving, and use that side of the doorway */
+        if (IS_DOOR(levl[u.ux][u.uy].typ)) {
+            if (u.dx || u.dy) {
+                gloc_filter_floodfill(u.ux + u.dx, u.uy + u.dy);
+            } else {
+                /* TODO: maybe add both sides of the doorway? */
+            }
+        } else {
+            gloc_filter_floodfill(u.ux, u.uy);
+        }
+    }
+}
+
+void
+gloc_filter_done()
+{
+    if (gloc_filter_map) {
+        opvar_free_x(gloc_filter_map);
+        gloc_filter_map = (struct opvar *) 0;
+    }
+}
+
+STATIC_OVL boolean
+gather_locs_interesting(x, y, gloc)
+int x, y, gloc;
+{
+    /* TODO: if glyph is a pile glyph, convert to ordinary one
+     *       in order to keep tail/boulder/rock check simple.
+     */
+    int glyph = glyph_at(x, y);
+
+    if (iflags.getloc_filter == GFILTER_VIEW && !cansee(x, y))
+        return FALSE;
+    if (iflags.getloc_filter == GFILTER_AREA && !GLOC_SAME_AREA(x, y)
+        && !GLOC_SAME_AREA(x - 1, y) && !GLOC_SAME_AREA(x, y - 1)
+        && !GLOC_SAME_AREA(x + 1, y) && !GLOC_SAME_AREA(x, y + 1))
+        return FALSE;
+
+    switch (gloc) {
+    default:
+    case GLOC_MONS:
+        /* unlike '/M', this skips monsters revealed by
+           warning glyphs and remembered unseen ones */
+        return (glyph_is_monster(glyph)
+                && glyph != monnum_to_glyph(PM_LONG_WORM_TAIL));
+    case GLOC_OBJS:
+        return (glyph_is_object(glyph)
+                && glyph != objnum_to_glyph(BOULDER)
+                && glyph != objnum_to_glyph(ROCK));
+    case GLOC_DOOR:
+        return (glyph_is_cmap(glyph)
+                && (is_cmap_door(glyph_to_cmap(glyph))
+                    || is_cmap_drawbridge(glyph_to_cmap(glyph))
+                    || glyph_to_cmap(glyph) == S_ndoor));
+    case GLOC_EXPLORE:
+        return (glyph_is_cmap(glyph)
+                && (is_cmap_door(glyph_to_cmap(glyph))
+                    || is_cmap_drawbridge(glyph_to_cmap(glyph))
+                    || glyph_to_cmap(glyph) == S_ndoor
+                    || glyph_to_cmap(glyph) == S_room
+                    || glyph_to_cmap(glyph) == S_darkroom
+                    || glyph_to_cmap(glyph) == S_corr
+                    || glyph_to_cmap(glyph) == S_litcorr)
+                && (IS_UNEXPLORED_LOC(x + 1, y)
+                    || IS_UNEXPLORED_LOC(x - 1, y)
+                    || IS_UNEXPLORED_LOC(x, y + 1)
+                    || IS_UNEXPLORED_LOC(x, y - 1)));
+    case GLOC_VALID:
+        if (getpos_getvalid)
+            return (*getpos_getvalid)(x,y);
+        /*FALLTHRU*/
+    case GLOC_INTERESTING:
+        return gather_locs_interesting(x,y, GLOC_DOOR)
+            || !(glyph_is_cmap(glyph)
+                 && (is_cmap_wall(glyph_to_cmap(glyph))
+                     || glyph_to_cmap(glyph) == S_tree
+                     || glyph_to_cmap(glyph) == S_bars
+                     || glyph_to_cmap(glyph) == S_ice
+                     || glyph_to_cmap(glyph) == S_air
+                     || glyph_to_cmap(glyph) == S_cloud
+                     || glyph_to_cmap(glyph) == S_lava
+                     || glyph_to_cmap(glyph) == S_water
+                     || glyph_to_cmap(glyph) == S_pool
+                     || glyph_to_cmap(glyph) == S_ndoor
+                     || glyph_to_cmap(glyph) == S_room
+                     || glyph_to_cmap(glyph) == S_darkroom
+                     || glyph_to_cmap(glyph) == S_corr
+                     || glyph_to_cmap(glyph) == S_litcorr));
+    }
+    /*NOTREACHED*/
+    return FALSE;
+}
+
+/* gather locations for monsters or objects shown on the map */
+STATIC_OVL void
+gather_locs(arr_p, cnt_p, gloc)
+coord **arr_p;
+int *cnt_p;
+int gloc;
+{
+    int x, y, pass, idx;
+
+    /*
+     * We always include the hero's location even if there is no monster
+     * (invisible hero without see invisible) or object (usual case)
+     * displayed there.  That way, the count will always be at least 1,
+     * and player has a visual indicator (cursor returns to hero's spot)
+     * highlighting when successive 'm's or 'o's have cycled all the way
+     * through all monsters or objects.
+     *
+     * Hero's spot will always sort to array[0] because it will always
+     * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
+     */
+
+    gloc_filter_init();
+
+    *cnt_p = idx = 0;
+    for (pass = 0; pass < 2; pass++) {
+        for (x = 1; x < COLNO; x++)
+            for (y = 0; y < ROWNO; y++) {
+                if ((x == u.ux && y == u.uy)
+                    || gather_locs_interesting(x, y, gloc)) {
+                    if (!pass) {
+                        ++*cnt_p;
+                    } else {
+                        (*arr_p)[idx].x = x;
+                        (*arr_p)[idx].y = y;
+                        ++idx;
+                    }
+                }
+            }
+
+        if (!pass) /* end of first pass */
+            *arr_p = (coord *) alloc(*cnt_p * sizeof (coord));
+        else /* end of second pass */
+            qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu);
+    } /* pass */
+
+    gloc_filter_done();
+}
+
+char *
+dxdy_to_dist_descr(dx, dy, fulldir)
+int dx, dy;
+boolean fulldir;
+{
+    static char buf[30];
+    int dst;
+
+    if (!dx && !dy) {
+/*JP
+        Sprintf(buf, "here");
+*/
+        Sprintf(buf, "\82±\82±");
+    } else if ((dst = xytod(dx, dy)) != -1) {
+        /* explicit direction; 'one step' is implicit */
+        Sprintf(buf, "%s", directionname(dst));
+    } else {
+        static const char *dirnames[4][2] = {
+#if 0 /*JP*/
+            { "n", "north" },
+            { "s", "south" },
+            { "w", "west" },
+            { "e", "east" } };
+#else
+            { "n", "\96k" },
+            { "s", "\93ì" },
+            { "w", "\90¼" },
+            { "e", "\93\8c" } };
+#endif
+        buf[0] = '\0';
+        /* 9999: protect buf[] against overflow caused by invalid values */
+        if (dy) {
+            if (abs(dy) > 9999)
+                dy = sgn(dy) * 9999;
+            Sprintf(eos(buf), "%d%s%s", abs(dy), dirnames[(dy > 0)][fulldir],
+                    dx ? "," : "");
+        }
+        if (dx) {
+            if (abs(dx) > 9999)
+                dx = sgn(dx) * 9999;
+            Sprintf(eos(buf), "%d%s", abs(dx),
+                    dirnames[2 + (dx > 0)][fulldir]);
+        }
+    }
+    return buf;
+}
+
+/* coordinate formatting for 'whatis_coord' option */
+char *
+coord_desc(x, y, outbuf, cmode)
+int x, y;
+char *outbuf, cmode;
+{
+    static char screen_fmt[16]; /* [12] suffices: "[%02d,%02d]" */
+    int dx, dy;
+
+    outbuf[0] = '\0';
+    switch (cmode) {
+    default:
+        break;
+    case GPCOORDS_COMFULL:
+    case GPCOORDS_COMPASS:
+        /* "east", "3s", "2n,4w" */
+        dx = x - u.ux;
+        dy = y - u.uy;
+        Sprintf(outbuf, "(%s)",
+                dxdy_to_dist_descr(dx, dy, cmode == GPCOORDS_COMFULL));
+        break;
+    case GPCOORDS_MAP: /* x,y */
+        /* upper left corner of map is <1,0>;
+           with default COLNO,ROWNO lower right corner is <79,20> */
+        Sprintf(outbuf, "<%d,%d>", x, y);
+        break;
+    case GPCOORDS_SCREEN: /* y+2,x */
+        /* for normal map sizes, force a fixed-width formatting so that
+           /m, /M, /o, and /O output lines up cleanly; map sizes bigger
+           than Nx999 or 999xM will still work, but not line up like normal
+           when displayed in a column setting */
+        if (!*screen_fmt)
+            Sprintf(screen_fmt, "[%%%sd,%%%sd]",
+                    (ROWNO - 1 + 2 < 100) ? "02" :  "03",
+                    (COLNO - 1 < 100) ? "02" : "03");
+        /* map line 0 is screen row 2;
+           map column 0 isn't used, map column 1 is screen column 1 */
+        Sprintf(outbuf, screen_fmt, y + 2, x);
+        break;
+    }
+    return outbuf;
+}
+
+STATIC_OVL void
+auto_describe(cx, cy)
+int cx, cy;
+{
+    coord cc;
+    int sym = 0;
+    char tmpbuf[BUFSZ];
+/*JP
+    const char *firstmatch = "unknown";
+*/
+    const char *firstmatch = "\95s\96¾";
+
+    cc.x = cx;
+    cc.y = cy;
+    if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch,
+                              (struct permonst **) 0)) {
+        (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords);
+#if 0 /*JP*/
+        custompline(SUPPRESS_HISTORY,
+                    "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf,
+                    (iflags.autodescribe
+                     && getpos_getvalid && !(*getpos_getvalid)(cx, cy))
+                      ? " (illegal)" : "",
+                    (iflags.getloc_travelmode && !is_valid_travelpt(cx, cy))
+                      ? " (no travel path)" : "");
+#else
+        custompline(SUPPRESS_HISTORY,
+                    "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf,
+                    (iflags.autodescribe
+                     && getpos_getvalid && !getpos_getvalid(cx, cy))
+                      ? " (\95s\90³)" : "",
+                    (iflags.getloc_travelmode && !is_valid_travelpt(cx, cy))
+                      ? " (\8co\98H\82È\82µ)" : "");
+#endif
+        curs(WIN_MAP, cx, cy);
+        flush_screen(0);
+    }
+}
+
+boolean
+getpos_menu(ccp, gloc)
+coord *ccp;
+int gloc;
+{
+    coord *garr = DUMMY;
+    int gcount = 0;
+    winid tmpwin;
+    anything any;
+    int i, pick_cnt;
+    menu_item *picks = (menu_item *) 0;
+    char tmpbuf[BUFSZ];
+
+    gather_locs(&garr, &gcount, gloc);
+
+    if (gcount < 2) { /* gcount always includes the hero */
+        free((genericptr_t) garr);
+#if 0 /*JP*/
+        You("cannot %s %s.",
+            iflags.getloc_filter == GFILTER_VIEW ? "see" : "detect",
+            gloc_descr[gloc][0]);
+#else
+        You("%s\82ð%s\82±\82Æ\82ª\82Å\82«\82È\82¢\81D",
+            gloc_descr[gloc][0],
+            iflags.getloc_filter == GFILTER_VIEW ? "\8c©\82é" : "\8c©\82Â\82¯\82é");
+#endif
+        return FALSE;
+    }
+
+    tmpwin = create_nhwindow(NHW_MENU);
+    start_menu(tmpwin);
+    any = zeroany;
+
+    /* gather_locs returns array[0] == you. skip it. */
+    for (i = 1; i < gcount; i++) {
+        char fullbuf[BUFSZ];
+        coord tmpcc;
+/*JP
+        const char *firstmatch = "unknown";
+*/
+        const char *firstmatch = "\95s\96¾";
+        int sym = 0;
+
+        any.a_int = i + 1;
+        tmpcc.x = garr[i].x;
+        tmpcc.y = garr[i].y;
+        if (do_screen_description(tmpcc, TRUE, sym, tmpbuf,
+                              &firstmatch, (struct permonst **)0)) {
+            (void) coord_desc(garr[i].x, garr[i].y, tmpbuf,
+                              iflags.getpos_coords);
+            Sprintf(fullbuf, "%s%s%s", firstmatch,
+                    (*tmpbuf ? " " : ""), tmpbuf);
+            add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, fullbuf,
+                     MENU_UNSELECTED);
+        }
+    }
+
+#if 0 /*JP:T*/
+    Sprintf(tmpbuf, "Pick %s%s%s",
+            an(gloc_descr[gloc][1]),
+            gloc_filtertxt[iflags.getloc_filter],
+            iflags.getloc_travelmode ? " for travel destination" : "");
+#else
+    Sprintf(tmpbuf, "%s%s\82Å\96Ú\95W\82Æ\82·\82é%s\82ð\91I\91ð\82µ\82Ä\82­\82¾\82³\82¢",
+            iflags.getloc_travelmode ? "\88Ú\93®\82Ì\82½\82ß\82É" : "",
+            gloc_filtertxt[iflags.getloc_filter],
+            gloc_descr[gloc][1]);
+#endif
+    end_menu(tmpwin, tmpbuf);
+    pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
+    destroy_nhwindow(tmpwin);
+    if (pick_cnt > 0) {
+        ccp->x = garr[picks->item.a_int - 1].x;
+        ccp->y = garr[picks->item.a_int - 1].y;
+        free((genericptr_t) picks);
+    }
+    free((genericptr_t) garr);
+    return (pick_cnt > 0);
+}
+
 int
 getpos(ccp, force, goal)
 coord *ccp;
 boolean force;
 const char *goal;
 {
+    const char *cp;
+    static struct {
+        int nhkf, ret;
+    } const pick_chars_def[] = {
+        { NHKF_GETPOS_PICK, LOOK_TRADITIONAL },
+        { NHKF_GETPOS_PICK_Q, LOOK_QUICK },
+        { NHKF_GETPOS_PICK_O, LOOK_ONCE },
+        { NHKF_GETPOS_PICK_V, LOOK_VERBOSE }
+    };
+    static const int mMoOdDxX_def[] = {
+        NHKF_GETPOS_MON_NEXT,
+        NHKF_GETPOS_MON_PREV,
+        NHKF_GETPOS_OBJ_NEXT,
+        NHKF_GETPOS_OBJ_PREV,
+        NHKF_GETPOS_DOOR_NEXT,
+        NHKF_GETPOS_DOOR_PREV,
+        NHKF_GETPOS_UNEX_NEXT,
+        NHKF_GETPOS_UNEX_PREV,
+        NHKF_GETPOS_INTERESTING_NEXT,
+        NHKF_GETPOS_INTERESTING_PREV,
+        NHKF_GETPOS_VALID_NEXT,
+        NHKF_GETPOS_VALID_PREV
+    };
+    char pick_chars[6];
+    char mMoOdDxX[13];
     int result = 0;
     int cx, cy, i, c;
     int sidx, tx, ty;
     boolean msg_given = TRUE; /* clear message window by default */
-    boolean auto_msg = FALSE;
     boolean show_goal_msg = FALSE;
-    static const char pick_chars[] = ".,;:";
-    const char *cp;
     boolean hilite_state = FALSE;
+    coord *garr[NUM_GLOCS] = DUMMY;
+    int gcount[NUM_GLOCS] = DUMMY;
+    int gidx[NUM_GLOCS] = DUMMY;
+
+    for (i = 0; i < SIZE(pick_chars_def); i++)
+        pick_chars[i] = Cmd.spkeys[pick_chars_def[i].nhkf];
+    pick_chars[SIZE(pick_chars_def)] = '\0';
+
+    for (i = 0; i < SIZE(mMoOdDxX_def); i++)
+        mMoOdDxX[i] = Cmd.spkeys[mMoOdDxX_def[i]];
+    mMoOdDxX[SIZE(mMoOdDxX_def)] = '\0';
 
     if (!goal)
+/*JP
         goal = "desired location";
+*/
+        goal = "\96Ú\93I\92n";
     if (flags.verbose) {
-        pline("(For instructions type a ?)");
+#if 0 /*JP*/
+        pline("(For instructions type a '%s')",
+              visctrl(Cmd.spkeys[NHKF_GETPOS_HELP]));
+#else
+        pline("('%s'\82Å\83w\83\8b\83v)",
+              visctrl(Cmd.spkeys[NHKF_GETPOS_HELP]));
+#endif
         msg_given = TRUE;
     }
     cx = ccp->x;
@@ -104,23 +879,15 @@ const char *goal;
 #endif
     for (;;) {
         if (show_goal_msg) {
+/*JP
             pline("Move cursor to %s:", goal);
+*/
+            pline("\83J\81[\83\\83\8b\82ð%s\82É\93®\82©\82µ\82Ä\82­\82¾\82³\82¢:", goal);
             curs(WIN_MAP, cx, cy);
             flush_screen(0);
             show_goal_msg = FALSE;
-        } else if (auto_msg && !msg_given && !hilite_state) {
-            coord cc;
-            int sym = 0;
-            char tmpbuf[BUFSZ];
-            const char *firstmatch = NULL;
-
-            cc.x = cx;
-            cc.y = cy;
-            if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) {
-                pline1(firstmatch);
-                curs(WIN_MAP, cx, cy);
-                flush_screen(0);
-            }
+        } else if (iflags.autodescribe && !msg_given && !hilite_state) {
+            auto_describe(cx, cy);
         }
 
         c = nh_poskey(&tx, &ty, &sidx);
@@ -132,10 +899,10 @@ const char *goal;
             flush_screen(0);
         }
 
-        if (auto_msg)
+        if (iflags.autodescribe)
             msg_given = FALSE;
 
-        if (c == '\033') {
+        if (c == Cmd.spkeys[NHKF_ESC]) {
             cx = cy = -10;
             msg_given = TRUE; /* force clear */
             result = -1;
@@ -151,7 +918,7 @@ const char *goal;
         }
         if ((cp = index(pick_chars, c)) != 0) {
             /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
-            result = (int) (cp - pick_chars);
+            result = pick_chars_def[(int) (cp - pick_chars)].ret;
             break;
         }
         for (i = 0; i < 8; i++) {
@@ -164,8 +931,24 @@ const char *goal;
             } else if (Cmd.alphadirchars[i] == lowc((char) c)
                        || (Cmd.num_pad && Cmd.dirchars[i] == (c & 0177))) {
                 /* a shifted movement letter or Meta-digit */
-                dx = 8 * xdir[i];
-                dy = 8 * ydir[i];
+                if (iflags.getloc_moveskip) {
+                    /* skip same glyphs */
+                    int glyph = glyph_at(cx, cy);
+
+                    dx = xdir[i];
+                    dy = ydir[i];
+                    while (isok(cx + dx, cy + dy)
+                           && glyph == glyph_at(cx + dx, cy + dy)
+                           && isok(cx + dx + xdir[i], cy + dy + ydir[i])
+                           && glyph == glyph_at(cx + dx + xdir[i],
+                                                cy + dy + ydir[i])) {
+                        dx += xdir[i];
+                        dy += ydir[i];
+                    }
+                } else {
+                    dx = 8 * xdir[i];
+                    dy = 8 * ydir[i];
+                }
             } else
                 continue;
 
@@ -189,42 +972,141 @@ const char *goal;
             goto nxtc;
         }
 
-        if (c == '?' || redraw_cmd(c)) {
-            if (c == '?')
+        if (c == Cmd.spkeys[NHKF_GETPOS_HELP] || redraw_cmd(c)) {
+            if (c == Cmd.spkeys[NHKF_GETPOS_HELP])
                 getpos_help(force, goal);
-            else         /* ^R */
+            else /* ^R */
                 docrt(); /* redraw */
             /* update message window to reflect that we're still targetting */
             show_goal_msg = TRUE;
             msg_given = TRUE;
-        } else if ((c == '$') && (getpos_hilitefunc != NULL)) {
+        } else if (c == Cmd.spkeys[NHKF_GETPOS_SHOWVALID]
+                   && getpos_hilitefunc) {
             if (!hilite_state) {
                 (*getpos_hilitefunc)(0);
                 (*getpos_hilitefunc)(1);
                 hilite_state = TRUE;
             }
             goto nxtc;
-        } else if (c == '#') {
-            auto_msg = !auto_msg;
+        } else if (c == Cmd.spkeys[NHKF_GETPOS_AUTODESC]) {
+            iflags.autodescribe = !iflags.autodescribe;
+#if 0 /*JP:T*/
             pline("Automatic description %sis %s.",
                   flags.verbose ? "of features under cursor " : "",
-                  auto_msg ? "on" : "off");
-            if (!auto_msg)
+                  iflags.autodescribe ? "on" : "off");
+#else
+            pline("%s\90à\96¾\8e©\93®\95\\8e¦\81F%s",
+                  flags.verbose ? "\83J\81[\83\\83\8b\82Ì\89º\82É\82 \82é\82à\82Ì\82Ì" : "",
+                  iflags.autodescribe ? "\83I\83\93" : "\83I\83t");
+#endif
+            if (!iflags.autodescribe)
                 show_goal_msg = TRUE;
             msg_given = TRUE;
             goto nxtc;
-        } else if (c == '@') {
+        } else if (c == Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]) {
+            static const char *const view_filters[NUM_GFILTER] = {
+#if 0 /*JP*/
+                "Not limiting targets",
+                "Limiting targets to those in sight",
+                "Limiting targets to those in same area"
+#else
+                "\83^\81[\83Q\83b\83g\82ð\90§\8cÀ\82µ\82È\82¢",
+                "\8e\8b\8aE\93à\82É\83^\81[\83Q\83b\83g\82ð\90§\8cÀ\82·\82é",
+                "\93¯\82\83G\83\8a\83A\82É\83^\81[\83Q\83b\83g\82ð\90§\8cÀ\82·\82é"
+#endif
+            };
+
+            iflags.getloc_filter = (iflags.getloc_filter + 1) % NUM_GFILTER;
+            for (i = 0; i < NUM_GLOCS; i++) {
+                if (garr[i]) {
+                    free((genericptr_t) garr[i]);
+                    garr[i] = NULL;
+                }
+                gidx[i] = gcount[i] = 0;
+            }
+/*JP
+            pline("%s.", view_filters[iflags.getloc_filter]);
+*/
+            pline("%s\81D", view_filters[iflags.getloc_filter]);
+            msg_given = TRUE;
+            goto nxtc;
+        } else if (c == Cmd.spkeys[NHKF_GETPOS_MENU]) {
+            iflags.getloc_usemenu = !iflags.getloc_usemenu;
+#if 0 /*JP:T*/
+            pline("%s a menu to show possible targets%s.",
+                  iflags.getloc_usemenu ? "Using" : "Not using",
+                  iflags.getloc_usemenu
+                      ? " for 'm|M', 'o|O', 'd|D', and 'x|X'" : "");
+#else
+            pline("\89Â\94\\82È\83^\81[\83Q\83b\83g\82ð\8c©\82é\82Ì\82É\83\81\83j\83\85\81[\82ð\8eg%s\81D%s",
+                  iflags.getloc_usemenu ? "\82¤" : "\82í\82È\82¢",
+                  iflags.getloc_usemenu
+                      ? "('m|M', 'o|O', 'd|D', 'x|X'\97p)" : "");
+#endif
+            msg_given = TRUE;
+            goto nxtc;
+        } else if (c == Cmd.spkeys[NHKF_GETPOS_SELF]) {
+            /* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
+               to achieve that except by manually cycling through all spots */
+            for (i = 0; i < NUM_GLOCS; i++)
+                gidx[i] = 0;
             cx = u.ux;
             cy = u.uy;
             goto nxtc;
+        } else if (c == Cmd.spkeys[NHKF_GETPOS_MOVESKIP]) {
+            iflags.getloc_moveskip = !iflags.getloc_moveskip;
+#if 0 /*JP*/
+            pline("%skipping over similar terrain when fastmoving the cursor.",
+                  iflags.getloc_moveskip ? "S" : "Not s");
+#else
+            pline("\83J\81[\83\\83\8b\82ð\8d\82\91¬\88Ú\93®\82³\82¹\82é\82Æ\82«\82É\8e\97\82½\82æ\82¤\82È\92n\8c`\82ð\94ò\82Î%s\81D",
+                  iflags.getloc_moveskip ? "\82·" : "\82³\82È\82¢");
+#endif
+        } else if ((cp = index(mMoOdDxX, c)) != 0) { /* 'm|M', 'o|O', &c */
+            /* nearest or farthest monster or object or door or unexplored */
+            int gtmp = (int) (cp - mMoOdDxX), /* 0..7 */
+                gloc = gtmp >> 1;             /* 0..3 */
+
+            if (iflags.getloc_usemenu) {
+                coord tmpcrd;
+
+                if (getpos_menu(&tmpcrd, gloc)) {
+                    cx = tmpcrd.x;
+                    cy = tmpcrd.y;
+                }
+                goto nxtc;
+            }
+
+            if (!garr[gloc]) {
+                gather_locs(&garr[gloc], &gcount[gloc], gloc);
+                gidx[gloc] = 0; /* garr[][0] is hero's spot */
+            }
+            if (!(gtmp & 1)) {  /* c=='m' || c=='o' || c=='d' || c=='x') */
+                gidx[gloc] = (gidx[gloc] + 1) % gcount[gloc];
+            } else {            /* c=='M' || c=='O' || c=='D' || c=='X') */
+                if (--gidx[gloc] < 0)
+                    gidx[gloc] = gcount[gloc] - 1;
+            }
+            cx = garr[gloc][gidx[gloc]].x;
+            cy = garr[gloc][gidx[gloc]].y;
+            goto nxtc;
         } else {
             if (!index(quitchars, c)) {
                 char matching[MAXPCHARS];
                 int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
+
                 (void) memset((genericptr_t) matching, 0, sizeof matching);
-                for (sidx = 1; sidx < MAXPCHARS; sidx++)
+                for (sidx = 1; sidx < MAXPCHARS; sidx++) { /* [0] left as 0 */
+                    if (IS_DOOR(sidx) || IS_WALL(sidx)
+                        || sidx == SDOOR || sidx == SCORR
+                        || glyph_to_cmap(k) == S_room
+                        || glyph_to_cmap(k) == S_darkroom
+                        || glyph_to_cmap(k) == S_corr
+                        || glyph_to_cmap(k) == S_litcorr)
+                        continue;
                     if (c == defsyms[sidx].sym || c == (int) showsyms[sidx])
                         matching[sidx] = (char) ++k;
+                }
                 if (k) {
                     for (pass = 0; pass <= 1; pass++) {
                         /* pass 0: just past current pos to lower right;
@@ -235,57 +1117,80 @@ const char *goal;
                             lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
                             hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
                             for (tx = lo_x; tx <= hi_x; tx++) {
-                                /* look at dungeon feature, not at
-                                 * user-visible glyph */
-                                k = back_to_glyph(tx, ty);
-                                /* uninteresting background glyph */
+                                /* first, look at what is currently visible
+                                   (might be monster) */
+                                k = glyph_at(tx, ty);
                                 if (glyph_is_cmap(k)
-                                    && (IS_DOOR(levl[tx][ty].typ)
-                                        || glyph_to_cmap(k) == S_room
-                                        || glyph_to_cmap(k) == S_darkroom
-                                        || glyph_to_cmap(k) == S_corr
-                                        || glyph_to_cmap(k) == S_litcorr)) {
-                                    /* what hero remembers to be at tx,ty */
-                                    k = glyph_at(tx, ty);
+                                    && matching[glyph_to_cmap(k)])
+                                    goto foundc;
+                                /* next, try glyph that's remembered here
+                                   (might be trap or object) */
+                                if (level.flags.hero_memory
+                                    /* !terrainmode: don't move to remembered
+                                       trap or object if not currently shown */
+                                    && !iflags.terrainmode) {
+                                    k = levl[tx][ty].glyph;
+                                    if (glyph_is_cmap(k)
+                                        && matching[glyph_to_cmap(k)])
+                                        goto foundc;
                                 }
-                                if (glyph_is_cmap(k)
-                                    && matching[glyph_to_cmap(k)]
-                                    && levl[tx][ty].seenv
-                                    && (!IS_WALL(levl[tx][ty].typ))
-                                    && (levl[tx][ty].typ != SDOOR)
-                                    && glyph_to_cmap(k) != S_room
-                                    && glyph_to_cmap(k) != S_corr
-                                    && glyph_to_cmap(k) != S_litcorr) {
-                                    cx = tx, cy = ty;
-                                    if (msg_given) {
-                                        clear_nhwindow(WIN_MESSAGE);
-                                        msg_given = FALSE;
-                                    }
-                                    goto nxtc;
+                                /* last, try actual terrain here (shouldn't
+                                   we be using lastseentyp[][] instead?) */
+                                if (levl[tx][ty].seenv) {
+                                    k = back_to_glyph(tx, ty);
+                                    if (glyph_is_cmap(k)
+                                        && matching[glyph_to_cmap(k)])
+                                        goto foundc;
+                                }
+                                continue;
+                            foundc:
+                                cx = tx, cy = ty;
+                                if (msg_given) {
+                                    clear_nhwindow(WIN_MESSAGE);
+                                    msg_given = FALSE;
                                 }
+                                goto nxtc;
                             } /* column */
                         }     /* row */
                     }         /* pass */
+/*JP
                     pline("Can't find dungeon feature '%c'.", c);
+*/
+                    pline("'%c'\81H", c);
                     msg_given = TRUE;
                     goto nxtc;
                 } else {
                     char note[QBUFSZ];
 
                     if (!force)
+/*JP
                         Strcpy(note, "aborted");
-                    else
-                        Sprintf(note, "use %c%c%c%c or .", /* hjkl */
-                                Cmd.move_W, Cmd.move_S, Cmd.move_N,
-                                Cmd.move_E);
+*/
+                        Strcpy(note, "\92\86\92f\82µ\82½");
+                    else /* hjkl */
+#if 0 /*JP*/
+                        Sprintf(note, "use '%c', '%c', '%c', '%c' or '%s'",
+                                Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E,
+                                visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
+#else
+                        Sprintf(note, "%c%c%c%c\82Å\88Ú\93®\81C%s\82Å\8fI\97¹",
+                                Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E,
+                                visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
+#endif
+/*JP
                     pline("Unknown direction: '%s' (%s).", visctrl((char) c),
+*/
+                    pline("\82»\82Ì\95û\8cü\82Í\82È\82¢\81F'%s' (%s)", visctrl((char) c),
                           note);
                     msg_given = TRUE;
                 } /* k => matching */
             }     /* !quitchars */
             if (force)
                 goto nxtc;
+/*JP
             pline("Done.");
+*/
+            pline("\88È\8fã\81D");
             msg_given = FALSE; /* suppress clear */
             cx = -1;
             cy = 0;
@@ -307,7 +1212,11 @@ const char *goal;
         clear_nhwindow(WIN_MESSAGE);
     ccp->x = cx;
     ccp->y = cy;
-    getpos_hilitefunc = NULL;
+    for (i = 0; i < NUM_GLOCS; i++)
+        if (garr[i])
+            free((genericptr_t) garr[i]);
+    getpos_hilitefunc = (void FDECL((*), (int))) 0;
+    getpos_getvalid = (boolean FDECL((*), (int, int))) 0;
     return result;
 }
 
@@ -400,6 +1309,10 @@ const char *name;
     /* dogname & catname are PL_PSIZ arrays; object names have same limit */
     lth = (name && *name) ? ((int) strlen(name) + 1) : 0;
     if (lth > PL_PSIZ) {
+#if 1 /*JP*/
+        if (is_kanji2(buf, lth - 1))
+            --lth;
+#endif
         lth = PL_PSIZ;
         name = strncpy(buf, name, PL_PSIZ - 1);
         buf[PL_PSIZ - 1] = '\0';
@@ -410,32 +1323,78 @@ const char *name;
     return mtmp;
 }
 
+/* check whether user-supplied name matches or nearly matches an unnameable
+   monster's name; if so, give an alternate reject message for do_mname() */
+STATIC_OVL boolean
+alreadynamed(mtmp, monnambuf, usrbuf)
+struct monst *mtmp;
+char *monnambuf, *usrbuf;
+{
+    char pronounbuf[10], *p;
+
+    if (fuzzymatch(usrbuf, monnambuf, " -_", TRUE)
+        /* catch trying to name "the Oracle" as "Oracle" */
+        || (!strncmpi(monnambuf, "the ", 4)
+            && fuzzymatch(usrbuf, monnambuf + 4, " -_", TRUE))
+        /* catch trying to name "invisible Orcus" as "Orcus" */
+        || ((p = strstri(monnambuf, "invisible ")) != 0
+            && fuzzymatch(usrbuf, p + 10, " -_", TRUE))
+        /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
+        || ((p = strstri(monnambuf, " of ")) != 0
+            && fuzzymatch(usrbuf, p + 4, " -_", TRUE))) {
+#if 0 /*JP*/
+        pline("%s is already called %s.",
+              upstart(strcpy(pronounbuf, mhe(mtmp))), monnambuf);
+#else
+        pline("%s\82Í\8aù\82É%s\82Æ\8cÄ\82Î\82ê\82Ä\82¢\82é\81D",
+              upstart(strcpy(pronounbuf, mhe(mtmp))), monnambuf);
+#endif
+        return TRUE;
+#if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\8eg\82í\82È\82¢*/
+    } else if (mtmp->data == &mons[PM_JUIBLEX]
+               && strstri(monnambuf, "Juiblex")
+               && !strcmpi(usrbuf, "Jubilex")) {
+        pline("%s doesn't like being called %s.", upstart(monnambuf), usrbuf);
+        return TRUE;
+#endif
+    }
+    return FALSE;
+}
+
 /* allow player to assign a name to some chosen monster */
 STATIC_OVL void
 do_mname()
 {
-    char buf[BUFSZ], monnambuf[BUFSZ];
+    char buf[BUFSZ] = DUMMY, monnambuf[BUFSZ], qbuf[QBUFSZ];
     coord cc;
-    register int cx, cy;
-    register struct monst *mtmp;
-    char qbuf[QBUFSZ];
+    int cx, cy;
+    struct monst *mtmp = 0;
 
     if (Hallucination) {
+/*JP
         You("would never recognize it anyway.");
+*/
+        You("\82»\82ê\82ð\94F\8e¯\82Å\82«\82È\82¢\81D");
         return;
     }
     cc.x = u.ux;
     cc.y = u.uy;
+/*JP
     if (getpos(&cc, FALSE, "the monster you want to name") < 0
+*/
+    if (getpos(&cc, FALSE, "\82 \82È\82½\82ª\96¼\82Ã\82¯\82½\82¢\89ö\95¨") < 0
         || (cx = cc.x) < 0)
         return;
     cy = cc.y;
 
     if (cx == u.ux && cy == u.uy) {
-        if (u.usteed && canspotmon(u.usteed))
+        if (u.usteed && canspotmon(u.usteed)) {
             mtmp = u.usteed;
-        else {
+        } else {
+/*JP
             pline("This %s creature is called %s and cannot be renamed.",
+*/
+            pline("\82±\82Ì%s\90\82«\95¨\82Í%s\82Æ\8cÄ\82Î\82ê\82Ä\82¢\82Ä\81C\96¼\91O\82Í\95Ï\8dX\82Å\82«\82È\82¢\81D",
                   beautiful(), plname);
             return;
         }
@@ -445,14 +1404,20 @@ do_mname()
     if (!mtmp
         || (!sensemon(mtmp)
             && (!(cansee(cx, cy) || see_with_infrared(mtmp))
-                || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE
-                || mtmp->m_ap_type == M_AP_OBJECT
+                || mtmp->mundetected || M_AP_TYPE(mtmp) == M_AP_FURNITURE
+                || M_AP_TYPE(mtmp) == M_AP_OBJECT
                 || (mtmp->minvis && !See_invisible)))) {
+/*JP
         pline("I see no monster there.");
+*/
+        pline("\82»\82±\82É\89ö\95¨\82Í\82¢\82È\82¢\81D");
         return;
     }
     /* special case similar to the one in lookat() */
+/*JP
     Sprintf(qbuf, "What do you want to call %s?",
+*/
+    Sprintf(qbuf, "%s\82ð\89½\82Æ\8cÄ\82Ñ\82Ü\82·\82©\81H",
             distant_monnam(mtmp, ARTICLE_THE, monnambuf));
     getlin(qbuf, buf);
     if (!*buf || *buf == '\033')
@@ -460,56 +1425,94 @@ do_mname()
     /* strip leading and trailing spaces; unnames monster if all spaces */
     (void) mungspaces(buf);
 
-    /* unique monsters have their own specific names or titles;
-       shopkeepers, temple priests and other minions use alternate
-       name formatting routines which ignore any user-supplied name */
-    if (mtmp->data->geno & G_UNIQ)
-        pline("%s doesn't like being called names!", upstart(monnambuf));
-    else if (mtmp->isshk
-             && !(Deaf || mtmp->msleeping || !mtmp->mcanmove
-                  || mtmp->data->msound <= MS_ANIMAL))
-        verbalize("I'm %s, not %s.", shkname(mtmp), buf);
-    else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk)
-        pline("%s will not accept the name %s.", upstart(monnambuf), buf);
-    else
+    /* Unique monsters have their own specific names or titles.
+     * Shopkeepers, temple priests and other minions use alternate
+     * name formatting routines which ignore any user-supplied name.
+     *
+     * Don't say the name is being rejected if it happens to match
+     * the existing name.
+     */
+    if ((mtmp->data->geno & G_UNIQ) && !mtmp->ispriest) {
+        if (!alreadynamed(mtmp, monnambuf, buf))
+/*JP
+            pline("%s doesn't like being called names!", upstart(monnambuf));
+*/
+            pline("%s\82Í\82 \82¾\96¼\82Å\8cÄ\82Î\82ê\82é\82Ì\82ª\8c\99\82¢\82È\82æ\82¤\82¾\81I", Monnam(mtmp));
+    } else if (mtmp->isshk
+               && !(Deaf || mtmp->msleeping || !mtmp->mcanmove
+                    || mtmp->data->msound <= MS_ANIMAL)) {
+        if (!alreadynamed(mtmp, monnambuf, buf))
+/*JP
+            verbalize("I'm %s, not %s.", shkname(mtmp), buf);
+*/
+            verbalize("\8e\84\82Í%s\82¾\81C%s\82Å\82Í\82È\82¢\81D", shkname(mtmp), buf);
+    } else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk) {
+        if (!alreadynamed(mtmp, monnambuf, buf))
+/*JP
+            pline("%s will not accept the name %s.", upstart(monnambuf), buf);
+*/
+            pline("%s\82Í%s\82Æ\82¢\82¤\96¼\91O\82ð\8eó\82¯\82¢\82ê\82È\82©\82Á\82½\81D", monnambuf, buf);
+    } else
         (void) christen_monst(mtmp, buf);
 }
 
+STATIC_VAR int via_naming = 0;
+
 /*
- * This routine changes the address of obj. Be careful not to call it
- * when there might be pointers around in unknown places. For now: only
- * when obj is in the inventory.
+ * This routine used to change the address of 'obj' so be unsafe if not
+ * used with extreme care.  Applying a name to an object no longer
+ * allocates a replacement object, so that old risk is gone.
  */
 STATIC_OVL
 void
 do_oname(obj)
 register struct obj *obj;
 {
-    char *bufp, buf[BUFSZ], bufcpy[BUFSZ], qbuf[QBUFSZ];
+    char *bufp, buf[BUFSZ] = DUMMY, bufcpy[BUFSZ], qbuf[QBUFSZ];
     const char *aname;
     short objtyp;
 
     /* Do this now because there's no point in even asking for a name */
     if (obj->otyp == SPE_NOVEL) {
+/*JP
         pline("%s already has a published name.", Ysimple_name2(obj));
+*/
+        pline("%s\82É\82Í\82·\82Å\82É\8fo\94Å\8e\9e\82Ì\96¼\91O\82ª\82 \82é\81D", Ysimple_name2(obj));
         return;
     }
 
+#if 0 /*JP*/
     Sprintf(qbuf, "What do you want to name %s ",
             is_plural(obj) ? "these" : "this");
     (void) safe_qbuf(qbuf, qbuf, "?", obj, xname, simpleonames, "item");
+#else
+    (void) safe_qbuf(qbuf, "", "\82ð\89½\82Æ\96¼\82Ã\82¯\82Ü\82·\82©\81H", obj, xname, simpleonames, "item");
+#endif
     getlin(qbuf, buf);
     if (!*buf || *buf == '\033')
         return;
     /* strip leading and trailing spaces; unnames item if all spaces */
     (void) mungspaces(buf);
 
+    /*
+     * We don't violate illiteracy conduct here, although it is
+     * arguable that we should for anything other than "X".  Doing so
+     * would make attaching player's notes to hero's inventory have an
+     * in-game effect, which may or may not be the correct thing to do.
+     *
+     * We do violate illiteracy in oname() if player creates Sting or
+     * Orcrist, clearly being literate (no pun intended...).
+     */
+
     /* relax restrictions over proper capitalization for artifacts */
     if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
         Strcpy(buf, aname);
 
     if (obj->oartifact) {
+/*JP
         pline_The("artifact seems to resist the attempt.");
+*/
+        pline("\90¹\8aí\82Í\96¼\82Ã\82¯\82ð\8b\91\94Û\82µ\82Ä\82¢\82é\82æ\82¤\82¾\81D");
         return;
     } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
         /* this used to change one letter, substituting a value
@@ -527,13 +1530,24 @@ register struct obj *obj;
         /* for "the Foo of Bar", only scuff "Foo of Bar" part */
         bufp = !strncmpi(bufcpy, "the ", 4) ? (buf + 4) : buf;
         do {
-            wipeout_text(bufp, rnd(2), (unsigned) 0);
+            wipeout_text(bufp, rn2_on_display_rng(2), (unsigned) 0);
         } while (!strcmp(buf, bufcpy));
+/*JP
         pline("While engraving, your %s slips.", body_part(HAND));
+*/
+        pline("\8d\8f\82ñ\82Å\82¢\82é\8aÔ\82É%s\82ª\8a\8a\82Á\82Ä\82µ\82Ü\82Á\82½\81D", body_part(HAND));
         display_nhwindow(WIN_MESSAGE, FALSE);
+/*JP
         You("engrave: \"%s\".", buf);
+*/
+        You("\8d\8f\82ñ\82¾: \81u%s\81v\81D",buf);
+        /* violate illiteracy conduct since hero attempted to write
+           a valid artifact name */
+        u.uconduct.literate++;
     }
+    ++via_naming; /* This ought to be an argument rather than a static... */
     obj = oname(obj, buf);
+    --via_naming; /* ...but oname() is used in a lot of places, so defer. */
 }
 
 struct obj *
@@ -547,8 +1561,15 @@ const char *name;
     lth = *name ? (int) (strlen(name) + 1) : 0;
     if (lth > PL_PSIZ) {
         lth = PL_PSIZ;
+#if 0 /*JP*/
         name = strncpy(buf, name, PL_PSIZ - 1);
         buf[PL_PSIZ - 1] = '\0';
+#else
+        if (is_kanji2(name, lth - 1))
+            --lth;
+        name = strncpy(buf, name, lth - 1);
+        buf[lth - 1] = '\0';
+#endif
     }
     /* If named artifact exists in the game, do not create another.
      * Also trying to create an artifact shouldn't de-artifact
@@ -573,6 +1594,10 @@ const char *name;
         /* if obj is owned by a shop, increase your bill */
         if (obj->unpaid)
             alter_cost(obj, 0L);
+        if (via_naming) {
+            /* violate illiteracy conduct since successfully wrote arti-name */
+            u.uconduct.literate++;
+        }
     }
     if (carried(obj))
         update_inventory();
@@ -610,27 +1635,48 @@ docallcmd()
     any = zeroany;
     any.a_char = 'm'; /* group accelerator 'C' */
     add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'C', ATR_NONE,
+/*JP
              "a monster", MENU_UNSELECTED);
+*/
+             "\89ö\95¨", MENU_UNSELECTED);
     if (invent) {
         /* we use y and n as accelerators so that we can accept user's
            response keyed to old "name an individual object?" prompt */
         any.a_char = 'i'; /* group accelerator 'y' */
         add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'y', ATR_NONE,
+/*JP
                  "a particular object in inventory", MENU_UNSELECTED);
+*/
+                 "\8e\9d\82¿\95¨\82Ì\92\86\82Ì\88ê\82Â\82Ì\83A\83C\83e\83\80", MENU_UNSELECTED);
         any.a_char = 'o'; /* group accelerator 'n' */
         add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'n', ATR_NONE,
+/*JP
                  "the type of an object in inventory", MENU_UNSELECTED);
+*/
+                 "\8e\9d\82¿\95¨\82Ì\92\86\82Ì\88ê\82Â\82Ì\83A\83C\83e\83\80\82Ì\8eí\97Þ", MENU_UNSELECTED);
     }
     any.a_char = 'f'; /* group accelerator ',' (or ':' instead?) */
     add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, ',', ATR_NONE,
+/*JP
              "the type of an object upon the floor", MENU_UNSELECTED);
+*/
+             "\8f°\82Ì\8fã\82É\82 \82é\88ê\82Â\82Ì\83A\83C\83e\83\80\82Ì\8eí\97Þ", MENU_UNSELECTED);
     any.a_char = 'd'; /* group accelerator '\' */
     add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, '\\', ATR_NONE,
+/*JP
              "the type of an object on discoveries list", MENU_UNSELECTED);
+*/
+             "\94­\8c©\95¨\88ê\97\97\82É\82 \82é\88ê\82Â\82Ì\83A\83C\83e\83\80\82Ì\8eí\97Þ", MENU_UNSELECTED);
     any.a_char = 'a'; /* group accelerator 'l' */
     add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'l', ATR_NONE,
+/*JP
              "record an annotation for the current level", MENU_UNSELECTED);
+*/
+             "\8c»\8dÝ\82Ì\8aK\82É\91Î\82·\82é\83\81\83\82\82Ì\8bL\98^", MENU_UNSELECTED);
+/*JP
     end_menu(win, "What do you want to name?");
+*/
+    end_menu(win, "\82Ç\82ê\82É\96¼\91O\82ð\82Â\82¯\82Ü\82·\82©\81H");
     if (select_menu(win, PICK_ONE, &pick_list) > 0) {
         ch = pick_list[0].item.a_char;
         free((genericptr_t) pick_list);
@@ -661,7 +1707,10 @@ docallcmd()
             (void) xname(obj);
 
             if (!obj->dknown) {
+/*JP
                 You("would never recognize another one.");
+*/
+                You("\91¼\82É\94F\8e¯\82Å\82«\82È\82¢\81D");
 #if 0
             } else if (!objtyp_is_callable(obj->otyp)) {
                 You("know those as well as you ever will.");
@@ -684,26 +1733,64 @@ docallcmd()
     return 0;
 }
 
+/* for use by safe_qbuf() */
+STATIC_PTR char *
+docall_xname(obj)
+struct obj *obj;
+{
+    struct obj otemp;
+
+    otemp = *obj;
+    otemp.oextra = (struct oextra *) 0;
+    otemp.quan = 1L;
+    /* in case water is already known, convert "[un]holy water" to "water" */
+    otemp.blessed = otemp.cursed = 0;
+    /* remove attributes that are doname() caliber but get formatted
+       by xname(); most of these fixups aren't really needed because the
+       relevant type of object isn't callable so won't reach this far */
+    if (otemp.oclass == WEAPON_CLASS)
+        otemp.opoisoned = 0; /* not poisoned */
+    else if (otemp.oclass == POTION_CLASS)
+        otemp.odiluted = 0; /* not diluted */
+    else if (otemp.otyp == TOWEL || otemp.otyp == STATUE)
+        otemp.spe = 0; /* not wet or historic */
+    else if (otemp.otyp == TIN)
+        otemp.known = 0; /* suppress tin type (homemade, &c) and mon type */
+    else if (otemp.otyp == FIGURINE)
+        otemp.corpsenm = NON_PM; /* suppress mon type */
+    else if (otemp.otyp == HEAVY_IRON_BALL)
+        otemp.owt = objects[HEAVY_IRON_BALL].oc_weight; /* not "very heavy" */
+    else if (otemp.oclass == FOOD_CLASS && otemp.globby)
+        otemp.owt = 120; /* 6*20, neither a small glob nor a large one */
+
+    return an(xname(&otemp));
+}
+
 void
 docall(obj)
-register struct obj *obj;
+struct obj *obj;
 {
-    char buf[BUFSZ], qbuf[QBUFSZ];
-    struct obj otemp;
-    register char **str1;
+    char buf[BUFSZ] = DUMMY, qbuf[QBUFSZ];
+    char **str1;
 
     if (!obj->dknown)
         return; /* probably blind */
-    otemp = *obj;
-    otemp.quan = 1L;
-    otemp.oextra = (struct oextra *) 0;
 
-    if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.fromsink)
+    if (obj->oclass == POTION_CLASS && obj->fromsink)
         /* kludge, meaning it's sink water */
+/*JP
         Sprintf(qbuf, "Call a stream of %s fluid:",
-                OBJ_DESCR(objects[otemp.otyp]));
+*/
+        Sprintf(qbuf, "%s\89t\91Ì:",
+                OBJ_DESCR(objects[obj->otyp]));
     else
-        Sprintf(qbuf, "Call %s:", an(xname(&otemp)));
+#if 0 /*JP*/
+        (void) safe_qbuf(qbuf, "Call ", ":", obj,
+                         docall_xname, simpleonames, "thing");
+#else
+        (void) safe_qbuf(qbuf, "", "\82É\89½\82Æ\96¼\91O\82ð\95t\82¯\82é\81H", obj,
+                         docall_xname, simpleonames, "\82±\82ê");
+#endif
     getlin(qbuf, buf);
     if (!*buf || *buf == '\033')
         return;
@@ -735,14 +1822,22 @@ namefloorobj()
     int glyph;
     char buf[BUFSZ];
     struct obj *obj = 0;
+#if 0 /*JP*/
     boolean fakeobj = FALSE, use_plural;
+#else
+    boolean fakeobj = FALSE;
+#endif
 
     cc.x = u.ux, cc.y = u.uy;
     /* "dot for under/over you" only makes sense when the cursor hasn't
        been moved off the hero's '@' yet, but there's no way to adjust
        the help text once getpos() has started */
+#if 0 /*JP*/
     Sprintf(buf, "object on map (or '.' for one %s you)",
             (u.uundetected && hides_under(youmonst.data)) ? "over" : "under");
+#else
+    Strcpy(buf, "\92n\90}\8fã\82Ì\95¨\91Ì(\82 \82é\82¢\82Í'.'\82Å\82 \82È\82½\82Ì\82¢\82é\8fê\8f\8a");
+#endif
     if (getpos(&cc, FALSE, buf) < 0 || cc.x <= 0)
         return;
     if (cc.x == u.ux && cc.y == u.uy) {
@@ -755,11 +1850,16 @@ namefloorobj()
     }
     if (!obj) {
         /* "under you" is safe here since there's no object to hide under */
+#if 0 /*JP*/
         pline("There doesn't seem to be any object %s.",
               (cc.x == u.ux && cc.y == u.uy) ? "under you" : "there");
+#else
+        pline("%s\82É\82Í\89½\82à\82È\82¢\82æ\82¤\82¾\81D",
+              (cc.x == u.ux && cc.y == u.uy) ? "\82 \82È\82½\82Ì\89º" : "\82»\82±");
+#endif
         return;
     }
-    /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
+    /* note well: 'obj' might be an instance of STRANGE_OBJECT if target
        is a mimic; passing that to xname (directly or via simpleonames)
        would yield "glorkum" so we need to handle it explicitly; it will
        always fail the Hallucination test and pass the !callable test,
@@ -767,7 +1867,9 @@ namefloorobj()
     Strcpy(buf, (obj->otyp != STRANGE_OBJECT)
                  ? simpleonames(obj)
                  : obj_descr[STRANGE_OBJECT].oc_name);
+#if 0 /*JP*/
     use_plural = (obj->quan > 1L);
+#endif
     if (Hallucination) {
         const char *unames[6];
         char tmpbuf[BUFSZ];
@@ -776,8 +1878,12 @@ namefloorobj()
         unames[0] = ((Upolyd ? u.mfemale : flags.female) && urole.name.f)
                      ? urole.name.f
                      : urole.name.m;
-        /* random rank title for hero's role */
-        unames[1] = rank_of(rnd(30), Role_switch, flags.female);
+        /* random rank title for hero's role
+
+           note: the 30 is hardcoded in xlev_to_rank, so should be
+           hardcoded here too */
+        unames[1] = rank_of(rn2_on_display_rng(30) + 1,
+                            Role_switch, flags.female);
         /* random fake monster */
         unames[2] = bogusmon(tmpbuf, (char *) 0);
         /* increased chance for fake monster */
@@ -785,21 +1891,42 @@ namefloorobj()
         /* traditional */
         unames[4] = roguename();
         /* silly */
+/*JP
         unames[5] = "Wibbly Wobbly";
+*/
+        unames[5] = "\82¤\82ë\82¤\82ë";
+#if 0 /*JP:T*/
         pline("%s %s to call you \"%s.\"",
               The(buf), use_plural ? "decide" : "decides",
-              unames[rn2(SIZE(unames))]);
+              unames[rn2_on_display_rng(SIZE(unames))]);
+#else
+        pline("%s\82Í\82 \82È\82½\82ð\81u%s\81v\82Æ\8cÄ\82Ô\82±\82Æ\82É\8c\88\82ß\82½\81D",
+              buf,
+              unames[rn2_on_display_rng(SIZE(unames))]);
+#endif
     } else if (!objtyp_is_callable(obj->otyp)) {
+#if 0 /*JP:T*/
         pline("%s %s can't be assigned a type name.",
               use_plural ? "Those" : "That", buf);
+#else
+        pline("%s\82É\8eí\97Þ\82Ì\96¼\91O\82ð\8a\84\82è\93\96\82Ä\82é\82±\82Æ\82Í\82Å\82«\82È\82¢\81D",
+              buf);
+#endif
     } else if (!obj->dknown) {
+#if 0 /*JP:T*/
         You("don't know %s %s well enough to name %s.",
             use_plural ? "those" : "that", buf, use_plural ? "them" : "it");
+#else
+        You("\96¼\91O\82ð\95t\82¯\82ç\82ê\82é\82Ù\82Ç%s\82Ì\82±\82Æ\82ð\82æ\82­\92m\82ç\82È\82¢\81D",
+            buf);
+#endif
     } else {
         docall(obj);
     }
-    if (fakeobj)
+    if (fakeobj) {
+        obj->where = OBJ_FREE; /* object_from_map() sets it to OBJ_FLOOR */
         dealloc_obj(obj);
+    }
 }
 
 static const char *const ghostnames[] = {
@@ -834,6 +1961,8 @@ rndghostname()
  * a_monnam:    a newt          it      an invisible orc        Fido
  * m_monnam:    newt            xan     orc                     Fido
  * y_monnam:    your newt     your xan  your invisible orc      Fido
+ * noname_monnam(mon,article):
+ *              article newt    art xan art invisible orc       art dog
  */
 
 /* Bug: if the monster is a priest or shopkeeper, not every one of these
@@ -854,15 +1983,18 @@ const char *adjective;
 int suppress;
 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
  * EXACT_NAME: combination of all the above
+ * SUPPRESS_NAME: omit monster's assigned name (unless uniq w/ pname).
  */
 boolean called;
 {
     char *buf = nextmbuf();
     struct permonst *mdat = mtmp->data;
     const char *pm_name = mdat->mname;
-    boolean do_hallu, do_invis, do_it, do_saddle;
+    boolean do_hallu, do_invis, do_it, do_saddle, do_name;
+#if 0 /*JP*/
     boolean name_at_start, has_adjectives;
     char *bp;
+#endif
 
     if (program_state.gameover)
         suppress |= SUPPRESS_HALLUCINATION;
@@ -875,12 +2007,16 @@ boolean called;
             && !program_state.gameover && mtmp != u.usteed
             && !(u.uswallow && mtmp == u.ustuck) && !(suppress & SUPPRESS_IT);
     do_saddle = !(suppress & SUPPRESS_SADDLE);
+    do_name = !(suppress & SUPPRESS_NAME) || type_is_pname(mdat);
 
     buf[0] = '\0';
 
     /* unseen monsters, etc.  Use "it" */
     if (do_it) {
+/*JP
         Strcpy(buf, "it");
+*/
+        Strcpy(buf, "\89½\8eÒ\82©");
         return buf;
     }
 
@@ -899,16 +2035,24 @@ boolean called;
         name = priestname(mtmp, priestnambuf);
         EHalluc_resistance = save_prop;
         mtmp->minvis = save_invis;
+#if 0 /*JP*/
         if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
             name += 4;
+#endif
         return strcpy(buf, name);
     }
     /* an "aligned priest" not flagged as a priest or minion should be
        "priest" or "priestess" (normally handled by priestname()) */
     if (mdat == &mons[PM_ALIGNED_PRIEST])
+/*JP
         pm_name = mtmp->female ? "priestess" : "priest";
+*/
+        pm_name = mtmp->female ? "\93ò\91m" : "\91m\97µ";
     else if (mdat == &mons[PM_HIGH_PRIEST] && mtmp->female)
+/*JP
         pm_name = "high priestess";
+*/
+        pm_name = "\96@\89¤";
 
     /* Shopkeepers: use shopkeeper name.  For normal shopkeepers, just
      * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
@@ -916,6 +2060,7 @@ boolean called;
      * none of this applies.
      */
     if (mtmp->isshk && !do_hallu) {
+#if 0 /*JP*/
         if (adjective && article == ARTICLE_THE) {
             /* pathological case: "the angry Asidonhopo the blue dragon"
                sounds silly */
@@ -932,20 +2077,38 @@ boolean called;
             Strcat(buf, "invisible ");
         Strcat(buf, pm_name);
         return buf;
+#else
+        if (mdat == &mons[PM_SHOPKEEPER] && !do_invis){
+            Strcpy(buf, shkname(mtmp));
+        } else {
+            Sprintf(buf, "%s\82Æ\82¢\82¤\96¼\82Ì%s%s",
+                    shkname(mtmp), do_invis ? "\8ep\82Ì\8c©\82¦\82È\82¢" : "",
+                    pm_name);
+        }
+        return buf;
+#endif
     }
 
     /* Put the adjectives in the buffer */
     if (adjective)
+/*JP
         Strcat(strcat(buf, adjective), " ");
+*/
+        Strcat(buf, adjective);
     if (do_invis)
+/*JP
         Strcat(buf, "invisible ");
+*/
+        Strcat(buf, "\8ep\82Ì\8c©\82¦\82È\82¢");
     if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind
         && !Hallucination)
+/*JP
         Strcat(buf, "saddled ");
-    if (buf[0] != 0)
-        has_adjectives = TRUE;
-    else
-        has_adjectives = FALSE;
+*/
+        Strcat(buf, "\88Æ\82Ì\82Â\82¢\82Ä\82¢\82é");
+#if 0 /*JP*/
+    has_adjectives = (buf[0] != '\0');
+#endif
 
     /* Put the actual monster name or type into the buffer now */
     /* Be sure to remember whether the buffer starts with a name */
@@ -954,16 +2117,29 @@ boolean called;
         char *rname = rndmonnam(&rnamecode);
 
         Strcat(buf, rname);
+#if 0 /*JP*/
         name_at_start = bogon_is_pname(rnamecode);
-    } else if (has_mname(mtmp)) {
+#endif
+    } else if (do_name && has_mname(mtmp)) {
         char *name = MNAME(mtmp);
 
         if (mdat == &mons[PM_GHOST]) {
+/*JP
             Sprintf(eos(buf), "%s ghost", s_suffix(name));
+*/
+            Sprintf(buf, "%s\82Ì\97H\97ì", name);
+#if 0 /*JP*/
             name_at_start = TRUE;
+#endif
         } else if (called) {
+/*JP
             Sprintf(eos(buf), "%s called %s", pm_name, name);
+*/
+            Sprintf(eos(buf), "%s\82Æ\82¢\82¤\96¼\82Ì%s", name, pm_name);
+#if 0 /*JP*/
             name_at_start = (boolean) type_is_pname(mdat);
+#endif
+#if 0 /*JP*//*\92è\8a¥\8e\8c\82Ì\8f\88\97\9d\82Í\95s\97v*/
         } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) {
             /* <name> the <adjective> <invisible> <saddled> <rank> */
             char pbuf[BUFSZ];
@@ -976,22 +2152,34 @@ boolean called;
             Strcpy(buf, pbuf);
             article = ARTICLE_NONE;
             name_at_start = TRUE;
+#endif
         } else {
             Strcat(buf, name);
+#if 0 /*JP*/
             name_at_start = TRUE;
+#endif
         }
     } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
         char pbuf[BUFSZ];
 
         Strcpy(pbuf, rank_of((int) mtmp->m_lev, monsndx(mdat),
                              (boolean) mtmp->female));
+#if 0 /*JP*/
         Strcat(buf, lcase(pbuf));
+#else
+        Strcat(buf, pbuf);
+#endif
+#if 0 /*JP*/
         name_at_start = FALSE;
+#endif
     } else {
         Strcat(buf, pm_name);
+#if 0 /*JP*/
         name_at_start = (boolean) type_is_pname(mdat);
+#endif
     }
 
+#if 0 /*JP*//*\93ú\96{\8cê\82É\8a¥\8e\8c\82Í\82È\82¢*/
     if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
         if (mdat == &mons[PM_WIZARD_OF_YENDOR])
             article = ARTICLE_THE;
@@ -1022,6 +2210,9 @@ boolean called;
             return buf;
         }
     }
+#else
+    return buf;
+#endif
 }
 
 char *
@@ -1050,7 +2241,7 @@ struct monst *mtmp;
 {
     return x_monnam(mtmp, ARTICLE_THE, (char *) 0,
                     (has_mname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT)
-                                       : SUPPRESS_IT,
+                                      : SUPPRESS_IT,
                     FALSE);
 }
 
@@ -1074,7 +2265,17 @@ struct monst *mtmp;
     return  bp;
 }
 
-/* monster's own name */
+/* return "a dog" rather than "Fido", honoring hallucination and visibility */
+char *
+noname_monnam(mtmp, article)
+struct monst *mtmp;
+int article;
+{
+    return x_monnam(mtmp, article, (char *) 0, SUPPRESS_NAME, FALSE);
+}
+
+/* monster's own name -- overrides hallucination and [in]visibility
+   so shouldn't be used in ordinary messages (mainly for disclosure) */
 char *
 m_monnam(mtmp)
 struct monst *mtmp;
@@ -1142,8 +2343,12 @@ char *outbuf;
        its own obfuscation) */
     if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination
         && Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) {
+#if 0 /*JP*/
         Strcpy(outbuf, article == ARTICLE_THE ? "the " : "");
         Strcat(outbuf, mon->female ? "high priestess" : "high priest");
+#else
+        Strcpy(outbuf, "\96@\89¤");
+#endif
     } else {
         Strcpy(outbuf, x_monnam(mon, article, (char *) 0, 0, TRUE));
     }
@@ -1157,7 +2362,7 @@ char *buf, *code;
 {
     char *mname = buf;
 
-    get_rnd_text(BOGUSMONFILE, buf);
+    get_rnd_text(BOGUSMONFILE, buf, rn2_on_display_rng);
     /* strip prefix if present */
     if (!letter(*mname)) {
         if (code)
@@ -1184,7 +2389,7 @@ char *code;
         *code = '\0';
 
     do {
-        name = rn1(SPECIAL_PM + BOGUSMONSIZE - LOW_PM, LOW_PM);
+        name = rn2_on_display_rng(SPECIAL_PM + BOGUSMONSIZE - LOW_PM) + LOW_PM;
     } while (name < SPECIAL_PM
              && (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN)));
 
@@ -1222,11 +2427,13 @@ roguename()
                 return i + 5;
             }
     }
+    /*JP:Rogue\82Ì\8aJ\94­\8eÒ\82Ì\96¼\91O*/
     return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
                   : "Glenn Wichman";
 }
 
 static NEARDATA const char *const hcolors[] = {
+#if 0 /*JP*/
     "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
     "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
     "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
@@ -1234,14 +2441,24 @@ static NEARDATA const char *const hcolors[] = {
     "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
     "strawberry-banana", "peppermint", "romantic", "incandescent",
     "octarine", /* Discworld: the Colour of Magic */
+#else
+    "\8e\87\8aO\90F\82Ì", "\90Ô\8aO\90F\82Ì", "\90Â\90F\82ª\82©\82Á\82½\83I\83\8c\83\93\83W\90F\82Ì", "\90Ô\82Ý\82ª\82©\82Á\82½\97Î\90F\82Ì", "\88Ã\82¢\94\92\90F\82Ì",
+    "\96¾\82é\82¢\8d\95\82Ì", "\90\85\90F\82ª\82©\82Á\82½\83s\83\93\83N\90F\82Ì", "\89\96\90h\82¢", "\8aÃ\82¢", "\82·\82Á\82Ï\82¢", "\8bê\82¢",
+    "\82µ\82Ü\96Í\97l\82Ì", "\82ç\82¹\82ñ\8fó\82Ì", "\94g\8fó\82Ì", "\8ai\8eq\96Í\97l\8fó\82Ì", "\83`\83F\83b\83N\8fó\82Ì", "\95ú\8eË\8fó\82Ì", "\83y\81[\83Y\83\8a\81[\96Í\97l\82Ì",
+    "\82µ\82Ý\8fó\82Ì", "\90Â\90F\82Ì\94Á\93_\8fó\82Ì", "\93_\8fó\82Ì", "\8el\8ap\8c`\8fó\82Ì", "\8aÛ\8fó\82Ì",
+    "\8eO\8ap\8fó\82Ì", "\83J\83x\83\8b\83l\90F\82Ì", "\83T\83\93\83O\83\8a\83A\90F\82Ì", "\91N\82â\82©\82È\90Ô\8e\87\90F\82Ì", "\93¡\90F\82Ì", "\83\8c\83\82\83\93\83\89\83C\83\80\90F\82Ì",
+    "ä\95\83o\83i\83i\90F\82Ì", "\83y\83p\81[\83~\83\93\83g\90F\82Ì", "\83\8d\83}\83\93\83`\83b\83N\82È\90F\82Ì", "\94\92\94M\90F\82Ì",
+    "\83I\83N\83^\83\8a\83\93\90F\82Ì",
+#endif
 };
 
 const char *
 hcolor(colorpref)
 const char *colorpref;
 {
-    return (Hallucination || !colorpref) ? hcolors[rn2(SIZE(hcolors))]
-                                         : colorpref;
+    return (Hallucination || !colorpref)
+        ? hcolors[rn2_on_display_rng(SIZE(hcolors))]
+        : colorpref;
 }
 
 /* return a random real color unless hallucinating */
@@ -1251,10 +2468,41 @@ rndcolor()
     int k = rn2(CLR_MAX);
 
     return Hallucination ? hcolor((char *) 0)
+/*JP
                          : (k == NO_COLOR) ? "colorless"
+*/
+                         : (k == NO_COLOR) ? "\96³\90F\82Ì"
                                            : c_obj_colors[k];
 }
 
+static NEARDATA const char *const hliquids[] = {
+#if 0 /*JP*/
+    "yoghurt", "oobleck", "clotted blood", "diluted water", "purified water",
+    "instant coffee", "tea", "herbal infusion", "liquid rainbow",
+    "creamy foam", "mulled wine", "bouillon", "nectar", "grog", "flubber",
+    "ketchup", "slow light", "oil", "vinaigrette", "liquid crystal", "honey",
+    "caramel sauce", "ink", "aqueous humour", "milk substitute",
+    "fruit juice", "glowing lava", "gastric acid", "mineral water",
+    "cough syrup", "quicksilver", "sweet vitriol", "grey goo", "pink slime",
+#else
+    "\83\88\81[\83O\83\8b\83g", "\83E\81[\83u\83\8c\83b\83N", "\8c\8c\8cÐ", "\8fö\97¯\90\85", "\90¸\90»\90\85",
+    "\83C\83\93\83X\83^\83\93\83g\83R\81[\83q\81[", "\8dg\92\83", "\83n\81[\83u\89t", "\89t\91Ì\82Ì\93ø",
+    "\83N\83\8a\81[\83~\81[\83t\83H\81[\83\80", "\83z\83b\83g\83\8f\83C\83\93", "\83u\83C\83\88\83\93", "\89Ê\8f`", "\83O\83\8d\83b\83O", "\83t\83\89\83o\81[",
+    "\83P\83`\83\83\83b\83v", "\92á\91¬\8cõ", "\96û", "\83r\83l\83O\83\8c\83b\83g\83\\81[\83X", "\89t\91Ì\90\85\8f»", "\96I\96¨",
+    "\83J\83\89\83\81\83\8b\83\\81[\83X", "\83C\83\93\83N", "\96[\90\85", "\91ã\97p\93û",
+    "\83t\83\8b\81[\83c\83W\83\85\81[\83X", "\97¬\82ê\82é\97n\8aâ", "\88Ý\8e_", "\83~\83l\83\89\83\8b\83E\83H\81[\83^\81[",
+    "\8aP\8e~\82ß\83V\83\8d\83b\83v", "\90\85\8bâ", "\83W\83G\83`\83\8b\83G\81[\83e\83\8b", "\83O\83\8c\83C\83O\81[", "\83s\83\93\83N\83X\83\89\83C\83\80",
+#endif
+};
+
+const char *
+hliquid(liquidpref)
+const char *liquidpref;
+{
+    return (Hallucination || !liquidpref) ? hliquids[rn2(SIZE(hliquids))]
+                                          : liquidpref;
+}
+
 /* Aliases for road-runner nemesis
  */
 static const char *const coynames[] = {
@@ -1277,11 +2525,64 @@ char *buf;
         Sprintf(buf, "%s - %s",
                 x_monnam(mtmp, ARTICLE_NONE, (char *) 0, 0, TRUE),
                 mtmp->mcan ? coynames[SIZE(coynames) - 1]
-                           : coynames[rn2(SIZE(coynames) - 1)]);
+                           : coynames[mtmp->m_id % (SIZE(coynames) - 1)]);
     }
     return buf;
 }
 
+char *
+rndorcname(s)
+char *s;
+{
+    static const char *v[] = { "a", "ai", "og", "u" };
+    static const char *snd[] = { "gor", "gris", "un", "bane", "ruk",
+                                 "oth","ul", "z", "thos","akh","hai" };
+    int i, iend = rn1(2, 3), vstart = rn2(2);
+
+    if (s) {
+        *s = '\0';
+        for (i = 0; i < iend; ++i) {
+            vstart = 1 - vstart;                /* 0 -> 1, 1 -> 0 */
+            Sprintf(eos(s), "%s%s", (i > 0 && !rn2(30)) ? "-" : "",
+                    vstart ? v[rn2(SIZE(v))] : snd[rn2(SIZE(snd))]);
+        }
+    }
+    return s;
+}
+
+struct monst *
+christen_orc(mtmp, gang, other)
+struct monst *mtmp;
+const char *gang, *other;
+{
+    int sz = 0;
+    char buf[BUFSZ], buf2[BUFSZ], *orcname;
+
+    orcname = rndorcname(buf2);
+    sz = (int) strlen(orcname);
+    if (gang)
+        sz += (int) (strlen(gang) + sizeof " of " - sizeof "");
+    else if (other)
+        sz += (int) strlen(other);
+
+    if (sz < BUFSZ) {
+        char gbuf[BUFSZ];
+        boolean nameit = FALSE;
+
+        if (gang && orcname) {
+            Sprintf(buf, "%s of %s", upstart(orcname),
+                    upstart(strcpy(gbuf, gang)));
+            nameit = TRUE;
+        } else if (other && orcname) {
+            Sprintf(buf, "%s%s", upstart(orcname), other);
+            nameit = TRUE;
+        }
+        if (nameit)
+            mtmp = christen_monst(mtmp, buf);
+    }
+    return mtmp;
+}
+
 /* make sure "The Colour of Magic" remains the first entry in here */
 static const char *const sir_Terry_novels[] = {
     "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
@@ -1290,7 +2591,7 @@ static const char *const sir_Terry_novels[] = {
     "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
     "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
     "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
-    "The Last Hero", "The Amazing Maurice and his Educated Rodents",
+    "The Last Hero", "The Amazing Maurice and His Educated Rodents",
     "Night Watch", "The Wee Free Men", "Monstrous Regiment",
     "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
     "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",