OSDN Git Service

add translation
[jnethack/source.git] / src / invent.c
index 430894a..fbd0634 100644 (file)
@@ -1,31 +1,42 @@
-/* NetHack 3.6 invent.c        $NHDT-Date: 1447576348 2015/11/15 08:32:28 $  $NHDT-Branch: master $:$NHDT-Revision: 1.179 $ */
+/* NetHack 3.6 invent.c        $NHDT-Date: 1555196229 2019/04/13 22:57:09 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.253 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Derek S. Ray, 2015. */
 /* 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"
 
+#ifndef C /* same as cmd.c */
+#define C(c) (0x1f & (c))
+#endif
+
 #define NOINVSYM '#'
 #define CONTAINED_SYM '>' /* designator for inside a container */
+#define HANDS_SYM '-'
 
-STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (struct obj *, struct obj *));
+STATIC_DCL void FDECL(loot_classify, (Loot *, struct obj *));
+STATIC_DCL char *FDECL(loot_xname, (struct obj *));
+STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr,
+                                               const genericptr));
 STATIC_DCL void NDECL(reorder_invent);
-STATIC_DCL boolean FDECL(mergable, (struct obj *, struct obj *));
 STATIC_DCL void FDECL(noarmor, (BOOLEAN_P));
 STATIC_DCL void FDECL(invdisp_nothing, (const char *, const char *));
 STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
 STATIC_DCL boolean FDECL(only_here, (struct obj *));
 STATIC_DCL void FDECL(compactify, (char *));
-STATIC_DCL boolean FDECL(splittable, (struct obj *));
 STATIC_DCL boolean FDECL(taking_off, (const char *));
 STATIC_DCL boolean FDECL(putting_on, (const char *));
-STATIC_PTR int FDECL(ckunpaid, (struct obj *));
 STATIC_PTR int FDECL(ckvalidcat, (struct obj *));
+STATIC_PTR int FDECL(ckunpaid, (struct obj *));
 STATIC_PTR char *FDECL(safeq_xprname, (struct obj *));
 STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
-STATIC_DCL char FDECL(display_pickinv, (const char *, BOOLEAN_P, long *));
+STATIC_DCL char FDECL(display_pickinv, (const char *, const char *,
+                                        const char *, BOOLEAN_P, long *));
 STATIC_DCL char FDECL(display_used_invlets, (CHAR_P));
-STATIC_DCL void FDECL(tally_BUCX,
-                      (struct obj *, int *, int *, int *, int *, int *));
 STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
 STATIC_DCL void NDECL(dounpaid);
 STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
@@ -46,97 +57,532 @@ static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
  */
 static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
 
-STATIC_OVL int CFDECLSPEC
-sortloot_cmp(obj1, obj2)
-struct obj *obj1;
-struct obj *obj2;
+/* sortloot() classification; called at most once [per sort] for each object */
+STATIC_OVL void
+loot_classify(sort_item, obj)
+Loot *sort_item;
+struct obj *obj;
 {
-    int val1 = 0;
-    int val2 = 0;
+    /* we may eventually make this a settable option to always use
+       with sortloot instead of only when the 'sortpack' option isn't
+       set; it is similar to sortpack's inv_order but items most
+       likely to be picked up are moved to the front */
+    static char def_srt_order[MAXOCLASSES] = {
+        COIN_CLASS, AMULET_CLASS, RING_CLASS, WAND_CLASS, POTION_CLASS,
+        SCROLL_CLASS, SPBOOK_CLASS, GEM_CLASS, FOOD_CLASS, TOOL_CLASS,
+        WEAPON_CLASS, ARMOR_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0,
+    };
+    static char armcat[8];
+    const char *classorder;
+    char *p;
+    int k, otyp = obj->otyp, oclass = obj->oclass;
+    boolean seen, discovered = objects[otyp].oc_name_known ? TRUE : FALSE;
+
+    /*
+     * For the value types assigned by this classification, sortloot()
+     * will put lower valued ones before higher valued ones.
+     */
+    if (!Blind)
+        obj->dknown = 1; /* xname(obj) does this; we want it sooner */
+    seen = obj->dknown ? TRUE : FALSE,
+    /* class order */
+    classorder = flags.sortpack ? flags.inv_order : def_srt_order;
+    p = index(classorder, oclass);
+    if (p)
+        k = 1 + (int) (p - classorder);
+    else
+        k = 1 + (int) strlen(classorder) + (oclass != VENOM_CLASS);
+    sort_item->orderclass = (xchar) k;
+    /* subclass designation; only a few classes have subclasses
+       and the non-armor ones we use are fairly arbitrary */
+    switch (oclass) {
+    case ARMOR_CLASS:
+        if (!armcat[7]) {
+            /* one-time init; we use a different order than the subclass
+               values defined by objclass.h */
+            armcat[ARM_HELM]   = 1; /* [2] */
+            armcat[ARM_GLOVES] = 2; /* [3] */
+            armcat[ARM_BOOTS]  = 3; /* [4] */
+            armcat[ARM_SHIELD] = 4; /* [1] */
+            armcat[ARM_CLOAK]  = 5; /* [5] */
+            armcat[ARM_SHIRT]  = 6; /* [6] */
+            armcat[ARM_SUIT]   = 7; /* [0] */
+            armcat[7]          = 8; /* sanity protection */
+        }
+        k = objects[otyp].oc_armcat;
+        /* oc_armcat overloads oc_subtyp which is an 'schar' so guard
+           against somebody assigning something unexpected to it */
+        if (k < 0 || k >= 7)
+            k = 7;
+        k = armcat[k];
+        break;
+    case WEAPON_CLASS:
+        /* for weapons, group by ammo (arrows, bolts), launcher (bows),
+           missile (darts, boomerangs), stackable (daggers, knives, spears),
+           'other' (swords, axes, &c), polearms */
+        k = objects[otyp].oc_skill;
+        k = (k < 0) ? ((k >= -P_CROSSBOW && k <= -P_BOW) ? 1 : 3)
+                    : ((k >= P_BOW && k <= P_CROSSBOW) ? 2
+                       : (k == P_SPEAR || k == P_DAGGER || k == P_KNIFE) ? 4
+                          : !is_pole(obj) ? 5 : 6);
+        break;
+    case TOOL_CLASS:
+        if (seen && discovered
+            && (otyp == BAG_OF_TRICKS || otyp == HORN_OF_PLENTY))
+            k = 2; /* known pseudo-container */
+        else if (Is_container(obj))
+            k = 1; /* regular container or unknown bag of tricks */
+        else
+            switch (otyp) {
+            case WOODEN_FLUTE:
+            case MAGIC_FLUTE:
+            case TOOLED_HORN:
+            case FROST_HORN:
+            case FIRE_HORN:
+            case WOODEN_HARP:
+            case MAGIC_HARP:
+            case BUGLE:
+            case LEATHER_DRUM:
+            case DRUM_OF_EARTHQUAKE:
+            case HORN_OF_PLENTY: /* not a musical instrument */
+                k = 3; /* instrument or unknown horn of plenty */
+            default:
+                k = 4; /* 'other' tool */
+            }
+        break;
+    case FOOD_CLASS:
+        /* [what about separating "partly eaten" within each group?] */
+        switch (otyp) {
+        case SLIME_MOLD:
+            k = 1;
+            break;
+        default:
+            /* [maybe separate one-bite foods from rations and such?] */
+            k = obj->globby ? 6 : 2;
+            break;
+        case TIN:
+            k = 3;
+            break;
+        case EGG:
+            k = 4;
+            break;
+        case CORPSE:
+            k = 5;
+            break;
+        }
+        break;
+    case GEM_CLASS:
+        /*
+         * Normally subclass takes priority over discovery status, but
+         * that would give away information for gems (assuming we'll
+         * group them as valuable gems, next glass, then gray stones,
+         * and finally rocks once they're all fully identified).
+         *
+         * Order:
+         *  1) unseen gems and glass ("gem")
+         *  2) seen but undiscovered gems and glass ("blue gem"),
+         *  3) discovered gems ("sapphire"),
+         *  4) discovered glass ("worthless pieced of blue glass"),
+         *  5) unseen gray stones and rocks ("stone"),
+         *  6) seen but undiscovered gray stones ("gray stone"),
+         *  7) discovered gray stones ("touchstone"),
+         *  8) seen rocks ("rock").
+         */
+        switch (objects[obj->otyp].oc_material) {
+        case GEMSTONE:
+            k = !seen ? 1 : !discovered ? 2 : 3;
+            break;
+        case GLASS:
+            k = !seen ? 1 : !discovered ? 2 : 4;
+            break;
+        default: /* MINERAL */
+            k = !seen ? 5 : (obj->otyp != ROCK) ? (!discovered ? 6 : 7) : 8;
+            break;
+        }
+        break;
+    default:
+        /* other classes don't have subclasses; we assign a nonzero
+           value because sortloot() uses 0 to mean 'not yet classified' */
+        k = 1; /* any non-zero would do */
+        break;
+    }
+    sort_item->subclass = (xchar) k;
+    /* discovery status */
+    k = !seen ? 1 /* unseen */
+        : (discovered || !OBJ_DESCR(objects[otyp])) ? 4
+          : (objects[otyp].oc_uname) ? 3 /* named (partially discovered) */
+            : 2; /* undiscovered */
+    sort_item->disco = (xchar) k;
+}
 
-    /* Sort object names in lexicographical order, ignoring quantity. */
-    int name_cmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2));
+/* sortloot() formatting routine; for alphabetizing, not shown to user */
+STATIC_OVL char *
+loot_xname(obj)
+struct obj *obj;
+{
+    struct obj saveo;
+    boolean save_debug;
+    char *res, *save_oname;
 
-    if (name_cmp != 0) {
-        return name_cmp;
+    /*
+     * Deal with things that xname() includes as a prefix.  We don't
+     * want such because they change alphabetical ordering.  First,
+     * remember 'obj's current settings.
+     */
+    saveo.odiluted = obj->odiluted;
+    saveo.blessed = obj->blessed, saveo.cursed = obj->cursed;
+    saveo.spe = obj->spe;
+    saveo.owt = obj->owt;
+    save_oname = has_oname(obj) ? ONAME(obj) : 0;
+    save_debug = flags.debug;
+    /* suppress "diluted" for potions and "holy/unholy" for water;
+       sortloot() will deal with them using other criteria than name */
+    if (obj->oclass == POTION_CLASS) {
+        obj->odiluted = 0;
+        if (obj->otyp == POT_WATER)
+            obj->blessed = 0, obj->cursed = 0;
+    }
+    /* make "wet towel" and "moist towel" format as "towel" so that all
+       three group together */
+    if (obj->otyp == TOWEL)
+        obj->spe = 0;
+    /* group "<size> glob of <foo>" by <foo> rather than by <size> */
+    if (obj->globby)
+        obj->owt = 200; /* 200: weight of combined glob from ten creatures
+                           (five or fewer is "small", more than fifteen is
+                           "large", in between has no prefix) */
+    /* suppress user-assigned name */
+    if (save_oname && !obj->oartifact)
+        ONAME(obj) = 0;
+    /* avoid wizard mode formatting variations */
+    if (wizard) { /* flags.debug */
+        /* paranoia:  before toggling off wizard mode, guard against a
+           panic in xname() producing a normal mode panic save file */
+        program_state.something_worth_saving = 0;
+        flags.debug = FALSE;
     }
 
-    /* Sort by BUC. Map blessed to 4, uncursed to 2, cursed to 1, and unknown
-     * to 0. */
-    val1 = obj1->bknown
-               ? (obj1->blessed << 2)
-                     + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed
-               : 0;
-    val2 = obj2->bknown
-               ? (obj2->blessed << 2)
-                     + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed
-               : 0;
-    if (val1 != val2) {
-        return val2 - val1; /* Because bigger is better. */
+    res = cxname_singular(obj);
+
+    if (save_debug) {
+        flags.debug = TRUE;
+        program_state.something_worth_saving = 1;
+    }
+    /* restore the object */
+    if (obj->oclass == POTION_CLASS) {
+        obj->odiluted = saveo.odiluted;
+        if (obj->otyp == POT_WATER)
+            obj->blessed = saveo.blessed, obj->cursed = saveo.cursed;
+    }
+    if (obj->otyp == TOWEL) {
+        obj->spe = saveo.spe;
+        /* give "towel" a suffix that will force wet ones to come first,
+           moist ones next, and dry ones last regardless of whether
+           they've been flagged as having spe known */
+        Strcat(res, is_wet_towel(obj) ? ((obj->spe >= 3) ? "x" : "y") : "z");
+    }
+    if (obj->globby) {
+        obj->owt = saveo.owt;
+        /* we've suppressed the size prefix (above); there normally won't
+           be more than one of a given creature type because they coalesce,
+           but globs with different bless/curse state won't merge so it is
+           feasible to have multiple at the same location; add a suffix to
+           get such sorted by size (small first) */
+        Strcat(res, (obj->owt <= 100) ? "a"
+                    : (obj->owt <= 300) ? "b"
+                      : (obj->owt <= 500) ? "c"
+                        : "d");
     }
+    if (save_oname && !obj->oartifact)
+        ONAME(obj) = save_oname;
 
-    /* Sort by greasing. This will put the objects in degreasing order. */
+    return res;
+}
+
+/* set by sortloot() for use by sortloot_cmp(); reset by sortloot when done */
+static unsigned sortlootmode = 0;
+
+/* qsort comparison routine for sortloot() */
+STATIC_OVL int CFDECLSPEC
+sortloot_cmp(vptr1, vptr2)
+const genericptr vptr1;
+const genericptr vptr2;
+{
+    struct sortloot_item *sli1 = (struct sortloot_item *) vptr1,
+                         *sli2 = (struct sortloot_item *) vptr2;
+    struct obj *obj1 = sli1->obj,
+               *obj2 = sli2->obj;
+    char *nam1, *nam2;
+    int val1, val2, c, namcmp;
+
+    /* order by object class unless we're doing by-invlet without sortpack */
+    if ((sortlootmode & (SORTLOOT_PACK | SORTLOOT_INVLET))
+        != SORTLOOT_INVLET) {
+        /* Classify each object at most once no matter how many
+           comparisons it is involved in. */
+        if (!sli1->orderclass)
+            loot_classify(sli1, obj1);
+        if (!sli2->orderclass)
+            loot_classify(sli2, obj2);
+
+        /* Sort by class. */
+        val1 = sli1->orderclass;
+        val2 = sli2->orderclass;
+        if (val1 != val2)
+            return (int) (val1 - val2);
+
+        /* skip sub-classes when ordering by sortpack+invlet */
+        if ((sortlootmode & SORTLOOT_INVLET) == 0) {
+            /* Class matches; sort by subclass. */
+            val1 = sli1->subclass;
+            val2 = sli2->subclass;
+            if (val1 != val2)
+                return val1 - val2;
+
+            /* Class and subclass match; sort by discovery status:
+             * first unseen, then seen but not named or discovered,
+             * then named, lastly discovered.
+             * 1) potion
+             * 2) pink potion
+             * 3) dark green potion called confusion
+             * 4) potion of healing
+             * Multiple entries within each group will be put into
+             * alphabetical order below.
+             */
+            val1 = sli1->disco;
+            val2 = sli2->disco;
+            if (val1 != val2)
+                return val1 - val2;
+        }
+    }
+
+    /* order by assigned inventory letter */
+    if ((sortlootmode & SORTLOOT_INVLET) != 0) {
+        c = obj1->invlet;
+        val1 = ('a' <= c && c <= 'z') ? (c - 'a' + 2)
+               : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26)
+                 : (c == '$') ? 1
+                   : (c == '#') ? 1 + 52 + 1
+                     : 1 + 52 + 1 + 1; /* none of the above */
+        c = obj2->invlet;
+        val2 = ('a' <= c && c <= 'z') ? (c - 'a' + 2)
+               : ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26)
+                 : (c == '$') ? 1
+                   : (c == '#') ? 1 + 52 + 1
+                     : 1 + 52 + 1 + 1; /* none of the above */
+        if (val1 != val2)
+            return val1 - val2;
+    }
+
+    if ((sortlootmode & SORTLOOT_LOOT) == 0)
+        goto tiebreak;
+
+    /*
+     * Sort object names in lexicographical order, ignoring quantity.
+     *
+     * Each obj gets formatted at most once (per sort) no matter how many
+     * comparisons it gets subjected to.
+     */
+    nam1 = sli1->str;
+    if (!nam1)
+        nam1 = sli1->str = dupstr(loot_xname(obj1));
+    nam2 = sli2->str;
+    if (!nam2)
+        nam2 = sli2->str = dupstr(loot_xname(obj2));
+    if ((namcmp = strcmpi(nam1, nam2)) != 0)
+        return namcmp;
+
+    /* Sort by BUCX. */
+    val1 = obj1->bknown ? (obj1->blessed ? 3 : !obj1->cursed ? 2 : 1) : 0;
+    val2 = obj2->bknown ? (obj2->blessed ? 3 : !obj2->cursed ? 2 : 1) : 0;
+    if (val1 != val2)
+        return val2 - val1; /* bigger is better */
+
+    /* Sort by greasing.  This will put the objects in degreasing order. */
     val1 = obj1->greased;
     val2 = obj2->greased;
-    if (val1 != val2) {
-        return val2 - val1; /* Because bigger is better. */
-    }
+    if (val1 != val2)
+        return val2 - val1; /* bigger is better */
 
-    /* Sort by erosion. The effective amount is what matters. */
+    /* Sort by erosion.  The effective amount is what matters. */
     val1 = greatest_erosion(obj1);
     val2 = greatest_erosion(obj2);
-    if (val1 != val2) {
-        return val1 - val2; /* Because bigger is WORSE. */
-    }
+    if (val1 != val2)
+        return val1 - val2; /* bigger is WORSE */
 
-    /* Sort by erodeproofing. Map known-invulnerable to 1, and both
-     * known-vulnerable and unknown-vulnerability to 0, because that's how
-     * they're displayed. */
+    /* Sort by erodeproofing.  Map known-invulnerable to 1, and both
+       known-vulnerable and unknown-vulnerability to 0, because that's
+       how they're displayed. */
     val1 = obj1->rknown && obj1->oerodeproof;
     val2 = obj2->rknown && obj2->oerodeproof;
-    if (val1 != val2) {
-        return val2 - val1; /* Because bigger is better. */
+    if (val1 != val2)
+        return val2 - val1; /* bigger is better */
+
+    /* Sort by enchantment.  Map unknown to -1000, which is comfortably
+       below the range of obj->spe.  oc_uses_known means that obj->known
+       matters, which usually indirectly means that obj->spe is relevant.
+       Lots of objects use obj->spe for some other purpose (see obj.h). */
+    if (objects[obj1->otyp].oc_uses_known
+        /* exclude eggs (laid by you) and tins (homemade, pureed, &c) */
+        && obj1->oclass != FOOD_CLASS) {
+        val1 = obj1->known ? obj1->spe : -1000;
+        val2 = obj2->known ? obj2->spe : -1000;
+        if (val1 != val2)
+            return val2 - val1; /* bigger is better */
     }
 
-    /* Sort by enchantment. Map unknown to -1000, which is comfortably below
-     * the range of ->spe. */
-    val1 = obj1->known ? obj1->spe : -1000;
-    val2 = obj2->known ? obj2->spe : -1000;
-    if (val1 != val2) {
-        return val2 - val1; /* Because bigger is better. */
-    }
+ tiebreak:
+    /* They're identical, as far as we're concerned.  We want
+       to force a deterministic order, and do so by producing a
+       stable sort: maintain the original order of equal items. */
+    return (sli1->indx - sli2->indx);
+}
 
-    /* They're identical, as far as we're concerned,
-       but we want to force a determistic order between them. */
-    return (obj1->o_id > obj2->o_id) ? 1 : -1;
+/*
+ * sortloot() - the story so far...
+ *
+ *      The original implementation constructed and returned an array
+ *      of pointers to objects in the requested order.  Callers had to
+ *      count the number of objects, allocate the array, pass one
+ *      object at a time to the routine which populates it, traverse
+ *      the objects via stepping through the array, then free the
+ *      array.  The ordering process used a basic insertion sort which
+ *      is fine for short lists but inefficient for long ones.
+ *
+ *      3.6.0 (and continuing with 3.6.1) changed all that so that
+ *      sortloot was self-contained as far as callers were concerned.
+ *      It reordered the linked list into the requested order and then
+ *      normal list traversal was used to process it.  It also switched
+ *      to qsort() on the assumption that the C library implementation
+ *      put some effort into sorting efficiently.  It also checked
+ *      whether the list was already sorted as it got ready to do the
+ *      sorting, so re-examining inventory or a pile of objects without
+ *      having changed anything would gobble up less CPU than a full
+ *      sort.  But it had at least two problems (aside from the ordinary
+ *      complement of bugs):
+ *      1) some players wanted to get the original order back when they
+ *      changed the 'sortloot' option back to 'none', but the list
+ *      reordering made that infeasible;
+ *      2) object identification giving the 'ID whole pack' result
+ *      would call makeknown() on each newly ID'd object, that would
+ *      call update_inventory() to update the persistent inventory
+ *      window if one existed, the interface would call the inventory
+ *      display routine which would call sortloot() which might change
+ *      the order of the list being traversed by the identify code,
+ *      possibly skipping the ID of some objects.  That could have been
+ *      avoided by suppressing 'perm_invent' during identification
+ *      (fragile) or by avoiding sortloot() during inventory display
+ *      (more robust).
+ *
+ *      3.6.2 reverts to the temporary array of ordered obj pointers
+ *      but has sortloot() do the counting and allocation.  Callers
+ *      need to use array traversal instead of linked list traversal
+ *      and need to free the temporary array when done.  And the
+ *      array contains 'struct sortloot_item' (aka 'Loot') entries
+ *      instead of simple 'struct obj *' entries.
+ */
+Loot *
+sortloot(olist, mode, by_nexthere, filterfunc)
+struct obj **olist; /* previous version might have changed *olist, we don't */
+unsigned mode; /* flags for sortloot_cmp() */
+boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */
+boolean FDECL((*filterfunc), (OBJ_P));
+{
+    Loot *sliarray;
+    struct obj *o;
+    unsigned n, i;
+    boolean augment_filter;
+
+    for (n = 0, o = *olist; o; o = by_nexthere ? o->nexthere : o->nobj)
+        ++n;
+    /* note: if there is a filter function, this might overallocate */
+    sliarray = (Loot *) alloc((n + 1) * sizeof *sliarray);
+
+    /* the 'keep cockatrice corpses' flag is overloaded with sort mode */
+    augment_filter = (mode & SORTLOOT_PETRIFY) ? TRUE : FALSE;
+    mode &= ~SORTLOOT_PETRIFY; /* remove flag, leaving mode */
+    /* populate aliarray[0..n-1] */
+    for (i = 0, o = *olist; o; o = by_nexthere ? o->nexthere : o->nobj) {
+        if (filterfunc && !(*filterfunc)(o)
+            /* caller may be asking us to override filterfunc (in order
+               to do a cockatrice corpse touch check during pickup even
+               if/when the filter rejects food class) */
+            && (!augment_filter || o->otyp != CORPSE
+                || !touch_petrifies(&mons[o->corpsenm])))
+            continue;
+        sliarray[i].obj = o, sliarray[i].indx = (int) i;
+        sliarray[i].str = (char *) 0;
+        sliarray[i].orderclass = sliarray[i].subclass = sliarray[i].disco = 0;
+        ++i;
+    }
+    n = i;
+    /* add a terminator so that we don't have to pass 'n' back to caller */
+    sliarray[n].obj = (struct obj *) 0, sliarray[n].indx = -1;
+    sliarray[n].str = (char *) 0;
+    sliarray[n].orderclass = sliarray[n].subclass = sliarray[n].disco = 0;
+
+    /* do the sort; if no sorting is requested, we'll just return
+       a sortloot_item array reflecting the current ordering */
+    if (mode && n > 1) {
+        sortlootmode = mode; /* extra input for sortloot_cmp() */
+        qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
+        sortlootmode = 0; /* reset static mode flags */
+        /* if sortloot_cmp formatted any objects, discard their strings now */
+        for (i = 0; i < n; ++i)
+            if (sliarray[i].str)
+                free((genericptr_t) sliarray[i].str), sliarray[i].str = 0;
+    }
+    return sliarray;
 }
 
-struct obj **
-objarr_init(n)
-int n;
+/* sortloot() callers should use this to free up memory it allocates */
+void
+unsortloot(loot_array_p)
+Loot **loot_array_p;
 {
-    return (struct obj **) alloc(n * sizeof(struct obj *));
+    if (*loot_array_p)
+        free((genericptr_t) *loot_array_p), *loot_array_p = (Loot *) 0;
 }
 
+#if 0 /* 3.6.0 'revamp' */
 void
-objarr_set(otmp, idx, oarray, dosort)
-struct obj *otmp;
-int idx;
-struct obj **oarray;
-boolean dosort;
-{
-    if (dosort) {
-        int j;
-        for (j = idx; j; j--) {
-            if (sortloot_cmp(otmp, oarray[j - 1]) > 0)
-                break;
-            oarray[j] = oarray[j - 1];
+sortloot(olist, mode, by_nexthere)
+struct obj **olist;
+unsigned mode; /* flags for sortloot_cmp() */
+boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */
+{
+    struct sortloot_item *sliarray, osli, nsli;
+    struct obj *o, **nxt_p;
+    unsigned n, i;
+    boolean already_sorted = TRUE;
+
+    sortlootmode = mode; /* extra input for sortloot_cmp() */
+    for (n = osli.indx = 0, osli.obj = *olist; (o = osli.obj) != 0;
+         osli = nsli) {
+        nsli.obj = by_nexthere ? o->nexthere : o->nobj;
+        nsli.indx = (int) ++n;
+        if (nsli.obj && already_sorted
+            && sortloot_cmp((genericptr_t) &osli, (genericptr_t) &nsli) > 0)
+            already_sorted = FALSE;
+    }
+    if (n > 1 && !already_sorted) {
+        sliarray = (struct sortloot_item *) alloc(n * sizeof *sliarray);
+        for (i = 0, o = *olist; o;
+             ++i, o = by_nexthere ? o->nexthere : o->nobj)
+            sliarray[i].obj = o, sliarray[i].indx = (int) i;
+
+        qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
+        for (i = 0; i < n; ++i) {
+            o = sliarray[i].obj;
+            nxt_p = by_nexthere ? &(o->nexthere) : &(o->nobj);
+            *nxt_p = (i < n - 1) ? sliarray[i + 1].obj : (struct obj *) 0;
         }
-        oarray[j] = otmp;
-    } else {
-        oarray[idx] = otmp;
+        *olist = sliarray[0].obj;
+        free((genericptr_t) sliarray);
     }
+    sortlootmode = 0;
 }
+#endif /*0*/
 
 void
 assigninvlet(otmp)
@@ -271,16 +717,18 @@ struct obj **potmp, **pobj;
          *
          * Don't do the age manipulation if lit.  We would need
          * to stop the burn on both items, then merge the age,
-         * then restart the burn.
+         * then restart the burn.  Glob ages are averaged in the
+         * absorb routine, which uses weight rather than quantity
+         * to adjust for proportion (glob quantity is always 1).
          */
-        if (!obj->lamplit)
+        if (!obj->lamplit && !obj->globby)
             otmp->age = ((otmp->age * otmp->quan) + (obj->age * obj->quan))
                         / (otmp->quan + obj->quan);
 
         otmp->quan += obj->quan;
         /* temporary special case for gold objects!!!! */
         if (otmp->oclass == COIN_CLASS)
-            otmp->owt = weight(otmp);
+            otmp->owt = weight(otmp), otmp->bknown = 0;
         /* and puddings!!!1!!one! */
         else if (!Is_pudding(otmp))
             otmp->owt += obj->owt;
@@ -332,10 +780,9 @@ struct obj **potmp, **pobj;
 #endif /*0*/
         }
 
-        /* handle puddings a bit differently; absorption will
-         * free the other object automatically so we can just
-         * return out from here.  */
-        if (Is_pudding(obj)) {
+        /* handle puddings a bit differently; absorption will free the
+           other object automatically so we can just return out from here */
+        if (obj->globby) {
             pudding_merge_message(otmp, obj);
             obj_absorb(potmp, pobj);
             return 1;
@@ -393,14 +840,23 @@ struct obj *obj;
         }
         set_artifact_intrinsic(obj, 1, W_ART);
     }
-    if (obj->otyp == LUCKSTONE && obj->record_achieve_special) {
+
+    /* "special achievements" aren't discoverable during play, they
+       end up being recorded in XLOGFILE at end of game, nowhere else;
+       record_achieve_special overloads corpsenm which is ordinarily
+       initialized to NON_PM (-1) rather than to 0; any special prize
+       must never be a corpse, egg, tin, figurine, or statue because
+       their use of obj->corpsenm for monster type would conflict,
+       nor be a leash (corpsenm overloaded for m_id of leashed
+       monster) or a novel (corpsenm overloaded for novel index) */
+    if (is_mines_prize(obj)) {
         u.uachieve.mines_luckstone = 1;
-        obj->record_achieve_special = 0;
-    } else if ((obj->otyp == AMULET_OF_REFLECTION
-                || obj->otyp == BAG_OF_HOLDING)
-               && obj->record_achieve_special) {
+        obj->record_achieve_special = NON_PM;
+        obj->nomerge = 0;
+    } else if (is_soko_prize(obj)) {
         u.uachieve.finish_sokoban = 1;
-        obj->record_achieve_special = 0;
+        obj->record_achieve_special = NON_PM;
+        obj->nomerge = 0;
     }
 }
 
@@ -434,6 +890,7 @@ struct obj *obj;
 {
     struct obj *otmp, *prev;
     int saved_otyp = (int) obj->otyp; /* for panic */
+    boolean obj_was_thrown;
 
     if (obj->where != OBJ_FREE)
         panic("addinv: obj not free");
@@ -442,6 +899,7 @@ struct obj *obj;
     obj->no_charge = 0; /* should not be set in hero's invent */
     if (Has_contents(obj))
         picked_container(obj); /* clear no_charge */
+    obj_was_thrown = obj->was_thrown;
     obj->was_thrown = 0;       /* not meaningful for invent */
 
     addinv_core1(obj);
@@ -476,7 +934,16 @@ struct obj *obj;
     }
     obj->where = OBJ_INVENT;
 
-added:
+    /* fill empty quiver if obj was thrown */
+    if (flags.pickup_thrown && !uquiver && obj_was_thrown
+        /* if Mjollnir is thrown and fails to return, we want to
+           auto-pick it when we move to its spot, but not into quiver;
+           aklyses behave like Mjollnir when thrown while wielded, but
+           we lack sufficient information here make them exceptions */
+        && obj->oartifact != ART_MJOLLNIR
+        && (throwing_weapon(obj) || is_ammo(obj)))
+        setuqwep(obj);
+ added:
     addinv_core2(obj);
     carry_obj_effects(obj); /* carrying affects the obj */
     update_inventory();
@@ -493,8 +960,7 @@ void
 carry_obj_effects(obj)
 struct obj *obj;
 {
-    /* Cursed figurines can spontaneously transform
-       when carried. */
+    /* Cursed figurines can spontaneously transform when carried. */
     if (obj->otyp == FIGURINE) {
         if (obj->cursed && obj->corpsenm != NON_PM
             && !dead_species(obj->corpsenm, TRUE)) {
@@ -547,9 +1013,9 @@ const char *drop_fmt, *drop_arg, *hold_msg;
         }
     }
     if (Fumbling) {
-        if (drop_fmt)
-            pline(drop_fmt, drop_arg);
-        dropy(obj);
+        obj->nomerge = 1;
+        obj = addinv(obj); /* dropping expects obj to be in invent */
+        goto drop_it;
     } else {
         long oquan = obj->quan;
         int prev_encumbr = near_capacity(); /* before addinv() */
@@ -566,12 +1032,10 @@ const char *drop_fmt, *drop_arg, *hold_msg;
         obj = addinv(obj);
         if (inv_cnt(FALSE) > 52 || ((obj->otyp != LOADSTONE || !obj->cursed)
                                     && near_capacity() > prev_encumbr)) {
-            if (drop_fmt)
-                pline(drop_fmt, drop_arg);
             /* undo any merge which took place */
             if (obj->quan > oquan)
                 obj = splitobj(obj, oquan);
-            dropx(obj);
+            goto drop_it;
         } else {
             if (flags.autoquiver && !uquiver && !obj->owornmask
                 && (is_missile(obj) || ammo_and_launcher(obj, uwep)
@@ -582,6 +1046,18 @@ const char *drop_fmt, *drop_arg, *hold_msg;
         }
     }
     return obj;
+
+ drop_it:
+    if (drop_fmt)
+        pline(drop_fmt, drop_arg);
+    obj->nomerge = 0;
+    if (can_reach_floor(TRUE)) {
+        dropx(obj);
+    } else {
+        freeinv(obj);
+        hitfloor(obj, FALSE);
+    }
+    return (struct obj *) 0; /* might be gone */
 }
 
 /* useup() all of an item regardless of its quantity */
@@ -774,6 +1250,7 @@ register int type;
  * http://concord.wikia.com/wiki/List_of_Fictional_Currencies
  */
 static const char *const currencies[] = {
+#if 0 /*JP*/
     "Altarian Dollar",       /* The Hitchhiker's Guide to the Galaxy */
     "Ankh-Morpork Dollar",   /* Discworld */
     "auric",                 /* The Domination of Draka */
@@ -795,6 +1272,29 @@ static const char *const currencies[] = {
     "Triganic Pu",           /* The Hitchhiker's Guide to the Galaxy */
     "woolong",               /* Cowboy Bebop */
     "zorkmid",               /* Zork, NetHack */
+#else
+    "\83A\83\8b\83^\83C\83\8b\81E\83h\83\8b",      /* The Hitchhiker's Guide to the Galaxy */
+    "\83A\83\93\83N\83\82\83\8b\83|\81[\83N\81E\83h\83\8b", /* Discworld */
+    "\83\86\81[\83\8a\83b\83N",            /* The Domination of Draka */
+    "\83o\83b\83J\83]\83C\83h",          /* Space Quest */
+    "\83T\81[\83{\83]\83C\83h",          /* Starslip */
+    "\83N\83\8c\83W\83b\83g\81E\83`\83b\83g",    /* Deus Ex */
+    "\83L\83\85\81[\83r\83b\83g",          /* Battlestar Galactica */
+    "\83t\83\8c\83j\83A\83\93\81E\83s\83b\83u\83\8b\81E\83r\81[\83h", /* The Hitchhiker's Guide to the Galaxy */
+    "\83t\83\8c\83b\83c\83@",            /* Jules Verne */
+    "\92é\8d\91\83N\83\8c\83W\83b\83g",        /* Star Wars */
+    "\8d\81\8d`\8c\8e\83h\83\8b",            /* The Moon is a Harsh Mistress */
+    "\83R\83\93\83o\83b\83N",            /* Snow Crash */
+    "\83i\81[\83i\83C\83g",            /* System Shock 2 */
+    "\83N\83@\83g\83\8d",              /* Star Trek, Sim City */
+    "\83V\83\82\83\8c\83I\83\93",            /* Sim City */
+    "\83\\83\89\83\8a",                /* Spaceballs */
+    "\83X\83y\81[\83X\83o\83b\83N",        /* Spaceballs */
+    "\83X\83|\83A\83o\83b\83N",          /* Spore */
+    "\83g\83\89\83C\83K\83j\83b\83N\81E\83v\81[",  /* The Hitchhiker's Guide to the Galaxy */
+    "\83E\81[\83\8d\83\93",              /* Cowboy Bebop */
+    "\83S\81[\83\8b\83h",              /* Zork, NetHack */
+#endif
 };
 
 const char *
@@ -803,9 +1303,13 @@ long amount;
 {
     const char *res;
 
+#if 0 /*JP*/
     res = Hallucination ? currencies[rn2(SIZE(currencies))] : "zorkmid";
     if (amount != 1L)
         res = makeplural(res);
+#else
+    res = Hallucination ? currencies[rn2(SIZE(currencies))] : "\83S\81[\83\8b\83h";
+#endif
     return res;
 }
 
@@ -820,7 +1324,7 @@ have_lizard()
     return FALSE;
 }
 
-/* 3.6.0 tribute */
+/* 3.6 tribute */
 struct obj *
 u_have_novel()
 {
@@ -915,7 +1419,7 @@ register char *buf;
 }
 
 /* some objects shouldn't be split when count given to getobj or askchain */
-STATIC_OVL boolean
+boolean
 splittable(obj)
 struct obj *obj;
 {
@@ -947,27 +1451,47 @@ const char *action;
 !!!! test if gold can be used in unusual ways (eaten etc.)
 !!!! may be able to remove "usegold"
  */
+/*JP
+** word \82É\82Í\89p\8cê\82Å\93®\8e\8c\82ª\93ü\82é\81D
+**
+** \93ú\96{\8cê\82Å\82Í\81C\81u\82Ç\82ê\82ð\8f\91\82«\82Ü\82·\82©\81v\82æ\82è\81u\82Ç\82ê\82É\8f\91\82«\82Ü\82·\82©\81v\82Ì\95û\82ª\8e©\91R\82È\82Ì\82Å\81C
+** \8dÅ\8f\89\82Ì\88ê\95\8e\9a\82É\81u\82É\81v\82â\81u\82Ì\81v\82ð\8ew\92è\82µ\82½\8fê\8d\87\82Í\8f\95\8e\8c\82ð\95Ï\8dX\82·\82é\81D
+**
+*/
 struct obj *
 getobj(let, word)
 register const char *let, *word;
 {
     register struct obj *otmp;
-    register char ilet;
+    register char ilet = 0;
     char buf[BUFSZ], qbuf[QBUFSZ];
     char lets[BUFSZ], altlets[BUFSZ], *ap;
     register int foo = 0;
     register char *bp = buf;
     xchar allowcnt = 0; /* 0, 1 or 2 */
-    struct obj *firstobj = invent;
     boolean usegold = FALSE; /* can't use gold because its illegal */
     boolean allowall = FALSE;
     boolean allownone = FALSE;
     boolean useboulder = FALSE;
     xchar foox = 0;
-    long cnt, prevcnt;
-    boolean prezero;
+    long cnt;
+    boolean cntgiven = FALSE;
+    boolean msggiven = FALSE;
+    boolean oneloop = FALSE;
     long dummymask;
+    Loot *sortedinvent, *srtinv;
+
+#if 1 /*JP*/
+    const char *jword;
+    const char *joshi;
+    const char *what;
 
+    struct trans_verb *tv = trans_verb(word);
+
+    jword = tv->jp;
+    what = tv->what;
+    joshi = tv->particle;
+#endif
     if (*let == ALLOW_COUNT)
         let++, allowcnt = 1;
     if (*let == COIN_CLASS)
@@ -998,15 +1522,18 @@ register const char *let, *word;
         useboulder = TRUE;
 
     if (allownone)
-        *bp++ = '-';
-    if (bp > buf && bp[-1] == '-')
-        *bp++ = ' ';
+        *bp++ = HANDS_SYM, *bp++ = ' '; /* '-' */
     ap = altlets;
 
     if (!flags.invlet_constant)
         reassign();
 
-    for (otmp = firstobj; otmp; otmp = otmp->nobj) {
+    /* force invent to be in invlet order before collecting candidate
+       inventory letters */
+    sortedinvent = sortloot(&invent, SORTLOOT_INVLET, FALSE,
+                            (boolean FDECL((*), (OBJ_P))) 0);
+
+    for (srtinv = sortedinvent; (otmp = srtinv->obj) != 0; ++srtinv) {
         if (&bp[foo] == &buf[sizeof buf - 1]
             || ap == &altlets[sizeof altlets - 1]) {
             /* we must have a huge number of NOINVSYM items somehow */
@@ -1018,8 +1545,8 @@ register const char *let, *word;
             || (usegold && otmp->invlet == GOLD_SYM)
             || (useboulder && otmp->otyp == BOULDER)) {
             register int otyp = otmp->otyp;
-            bp[foo++] = otmp->invlet;
 
+            bp[foo++] = otmp->invlet;
 /* clang-format off */
 /* *INDENT-OFF* */
             /* ugly check: remove inappropriate things */
@@ -1032,8 +1559,9 @@ register const char *let, *word;
              || (!strcmp(word, "wield")
                  && (otmp->owornmask & W_WEP))
 #endif
-             || (!strcmp(word, "ready") /* exclude if wielded */
-                 && (otmp == uwep || (otmp == uswapwep && u.twoweap)))
+             || (!strcmp(word, "ready")    /* exclude when wielded... */
+                 && ((otmp == uwep || (otmp == uswapwep && u.twoweap))
+                     && otmp->quan == 1L)) /* ...unless more than one */
              || ((!strcmp(word, "dip") || !strcmp(word, "grease"))
                  && inaccessible_equipment(otmp, (const char *) 0, FALSE))
              ) {
@@ -1099,7 +1627,10 @@ register const char *let, *word;
                  && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown
                      || !objects[HORN_OF_PLENTY].oc_name_known))
              || (!strcmp(word, "charge") && !is_chargeable(otmp))
+             || (!strcmp(word, "open") && otyp != TIN)
              || (!strcmp(word, "call") && !objtyp_is_callable(otyp))
+             || (!strcmp(word, "adjust") && otmp->oclass == COIN_CLASS
+                 && !usegold)
              ) {
                 foo--;
             }
@@ -1124,9 +1655,14 @@ register const char *let, *word;
                  && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS)))
              /* suppress container being stashed into */
              || (!strcmp(word, "stash") && !ck_bag(otmp))
-             /* worn armor or accessory covered by cursed worn armor */
+             /* worn armor (shirt, suit) covered by worn armor (suit, cloak)
+                or accessory (ring) covered by cursed worn armor (gloves) */
              || (taking_off(word)
-                 && inaccessible_equipment(otmp, (const char *) 0, TRUE))
+                 && inaccessible_equipment(otmp, (const char *) 0,
+                                      (boolean) (otmp->oclass == RING_CLASS)))
+             || (!strcmp(word, "write on")
+                 && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER)
+                     || !otmp->dknown || !objects[otyp].oc_name_known))
              ) {
                 /* acceptable but not listed as likely candidate */
                 foo--;
@@ -1141,6 +1677,7 @@ register const char *let, *word;
                 allowall = usegold = TRUE;
         }
     }
+    unsortloot(&sortedinvent);
 
     bp[foo] = 0;
     if (foo == 0 && bp > buf && bp[-1] == ' ')
@@ -1151,53 +1688,65 @@ register const char *let, *word;
     *ap = '\0';
 
     if (!foo && !allowall && !allownone) {
+/*JP
         You("don't have anything %sto %s.", foox ? "else " : "", word);
+*/
+        You("%s%s\82à\82Ì\82ð\8e\9d\82Á\82Ä\82¢\82È\82¢\81D", foox ? "\91¼\82É" : "", jconj(jword, "\82ê\82é"));
         return (struct obj *) 0;
+    } else if (!strcmp(word, "write on")) { /* ugly check for magic marker */
+        /* we wanted all scrolls and books in altlets[], but that came with
+           'allowall' which we don't want since it prevents "silly thing"
+           result if anything other than scroll or spellbook is chosen */
+        allowall = FALSE;
     }
     for (;;) {
         cnt = 0;
-        if (allowcnt == 2)
-            allowcnt = 1; /* abort previous count */
-        prezero = FALSE;
-        if (!buf[0]) {
-            Sprintf(qbuf, "What do you want to %s? [*]", word);
-        } else {
-            Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf);
-        }
+        cntgiven = FALSE;
+/*JP
+        Sprintf(qbuf, "What do you want to %s?", word);
+*/
+        Sprintf(qbuf, "%s%s%s\82©\81H", what, joshi, jpolite(jword));
         if (in_doagain)
             ilet = readchar();
-        else
+        else if (iflags.force_invmenu) {
+            /* don't overwrite a possible quitchars */
+            if (!oneloop)
+                ilet = *let ? '?' : '*';
+            if (!msggiven)
+                putmsghistory(qbuf, FALSE);
+            msggiven = TRUE;
+            oneloop = TRUE;
+        } else {
+            if (!buf[0])
+                Strcat(qbuf, " [*]");
+            else
+                Sprintf(eos(qbuf), " [%s or ?*]", buf);
             ilet = yn_function(qbuf, (char *) 0, '\0');
-        if (digit(ilet) && !allowcnt) {
-            pline("No count allowed with this command.");
-            continue;
         }
-        if (ilet == '0')
-            prezero = TRUE;
-        while (digit(ilet)) {
-            if (ilet != '?' && ilet != '*')
-                savech(ilet);
-            /* accumulate unless cnt has overflowed */
-            if (allowcnt < 3) {
-                prevcnt = cnt;
-                cnt = 10L * cnt + (long) (ilet - '0');
-                /* signal presence of cnt */
-                allowcnt = (cnt >= prevcnt) ? 2 : 3;
+        if (digit(ilet)) {
+            long tmpcnt = 0;
+
+            if (!allowcnt) {
+/*JP
+            pline("No count allowed with this command.");
+*/
+            pline("\82±\82Ì\83R\83}\83\93\83h\82É\90\94\8e\9a\82Í\82Â\82©\82¦\82È\82¢\81D");
+                continue;
+            }
+            ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt, TRUE);
+            if (tmpcnt) {
+                cnt = tmpcnt;
+                cntgiven = TRUE;
             }
-            ilet = readchar();
-        }
-        if (allowcnt == 3) {
-            /* overflow detected; force cnt to be invalid */
-            cnt = -1L;
-            allowcnt = 2;
         }
         if (index(quitchars, ilet)) {
             if (flags.verbose)
                 pline1(Never_mind);
             return (struct obj *) 0;
         }
-        if (ilet == '-') {
+        if (ilet == HANDS_SYM) { /* '-' */
             if (!allownone) {
+#if 0 /*JP*/
                 char *suf = (char *) 0;
 
                 strcpy(buf, word);
@@ -1213,32 +1762,55 @@ register const char *let, *word;
                     bp = buf;
                 You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "",
                     suf ? suf : "");
+#else
+                You("\89½\82©\82ð%s\82Ó\82è\82ð\82µ\82½\81D", bp);
+#endif
             }
-            return (allownone ? &zeroobj : (struct obj *) 0);
+            return (allownone ? (struct obj *) &zeroobj : (struct obj *) 0);
         }
+ redo_menu:
         /* since gold is now kept in inventory, we need to do processing for
            select-from-invent before checking whether gold has been picked */
         if (ilet == '?' || ilet == '*') {
             char *allowed_choices = (ilet == '?') ? lets : (char *) 0;
             long ctmp = 0;
+            char menuquery[QBUFSZ];
+
+            menuquery[0] = qbuf[0] = '\0';
+            if (iflags.force_invmenu)
+                Sprintf(menuquery, "What do you want to %s?", word);
+            if (!strcmp(word, "grease"))
+                Sprintf(qbuf, "your %s", makeplural(body_part(FINGER)));
+            else if (!strcmp(word, "write with"))
+                Sprintf(qbuf, "your %s", body_part(FINGERTIP));
+            else if (!strcmp(word, "wield"))
+                Sprintf(qbuf, "your %s %s%s", uarmg ? "gloved" : "bare",
+                        makeplural(body_part(HAND)),
+                        !uwep ? " (wielded)" : "");
+            else if (!strcmp(word, "ready"))
+                Sprintf(qbuf, "empty quiver%s",
+                        !uquiver ? " (nothing readied)" : "");
 
             if (ilet == '?' && !*lets && *altlets)
                 allowed_choices = altlets;
-            ilet = display_pickinv(allowed_choices, TRUE,
-                                   allowcnt ? &ctmp : (long *) 0);
+            ilet = display_pickinv(allowed_choices, *qbuf ? qbuf : (char *) 0,
+                                   menuquery,
+                                   TRUE, allowcnt ? &ctmp : (long *) 0);
             if (!ilet)
                 continue;
-            if (allowcnt && ctmp >= 0) {
-                cnt = ctmp;
-                if (!cnt)
-                    prezero = TRUE;
-                allowcnt = 2;
-            }
+            if (ilet == HANDS_SYM)
+                return (struct obj *) &zeroobj; /* cast away 'const' */
             if (ilet == '\033') {
                 if (flags.verbose)
                     pline1(Never_mind);
                 return (struct obj *) 0;
             }
+            if (ilet == '*')
+                goto redo_menu;
+            if (allowcnt && ctmp >= 0) {
+                cnt = ctmp;
+                cntgiven = TRUE;
+            }
             /* they typed a letter (not a space) at the prompt */
         }
         /* find the item which was picked */
@@ -1251,7 +1823,10 @@ register const char *let, *word;
                than one invent slot of gold and picking the non-'$' one */
             || (otmp && otmp->oclass == COIN_CLASS)) {
             if (!usegold) {
+/*JP
                 You("cannot %s gold.", word);
+*/
+                You("\8bà\89Ý%s%s\82±\82Æ\82Í\82Å\82«\82È\82¢\81D", joshi, jword);
                 return (struct obj *) 0;
             }
             /* Historic note: early Nethack had a bug which was
@@ -1260,24 +1835,28 @@ register const char *let, *word;
              * to your money supply.  The LRS is the tax bureau
              * from Larn.
              */
-            if (allowcnt == 2 && cnt <= 0) {
-                if (cnt < 0 || !prezero)
+            if (cntgiven && cnt <= 0) {
+                if (cnt < 0)
                     pline_The(
+/*JP
                   "LRS would be very interested to know you have that much.");
+*/
+                  "\82»\82Ì\8bZ\82Í\82Æ\82 \82é\83Q\81[\83\80\82Ì\83J\83W\83m\82Å\8eg\82¦\82½\82¯\82Ç\81C\82à\82Í\82â\8eg\82¦\82È\82¢\82æ\81D");
                 return (struct obj *) 0;
             }
         }
-        if (allowcnt == 2 && !strcmp(word, "throw")) {
+        if (cntgiven && !strcmp(word, "throw")) {
             /* permit counts for throwing gold, but don't accept
              * counts for other things since the throw code will
              * split off a single item anyway */
-            if (ilet != def_oc_syms[COIN_CLASS].sym
-                && !(otmp && otmp->oclass == COIN_CLASS))
-                allowcnt = 1;
-            if (cnt == 0 && prezero)
+            if (cnt == 0)
                 return (struct obj *) 0;
-            if (cnt > 1) {
+            if (cnt > 1 && (ilet != def_oc_syms[COIN_CLASS].sym
+                && !(otmp && otmp->oclass == COIN_CLASS))) {
+/*JP
                 You("can only throw one item at a time.");
+*/
+                You("\93¯\8e\9e\82É\82½\82­\82³\82ñ\82Ì\82à\82Ì\82ð\93\8a\82°\82ç\82ê\82È\82¢\81D");
                 continue;
             }
         }
@@ -1287,12 +1866,18 @@ register const char *let, *word;
            that's been moved above so that otmp can be checked earlier] */
         /* verify the chosen object */
         if (!otmp) {
+/*JP
             You("don't have that object.");
+*/
+            You("\82»\82ñ\82È\82à\82Ì\82Í\8e\9d\82Á\82Ä\82¢\82È\82¢\81D");
             if (in_doagain)
                 return (struct obj *) 0;
             continue;
         } else if (cnt < 0 || otmp->quan < cnt) {
+/*JP
             You("don't have that many!  You have only %ld.", otmp->quan);
+*/
+            pline("\82»\82ñ\82È\82É\82½\82­\82³\82ñ\82Í\8e\9d\82Á\82Ä\82¢\82È\82¢\81I\82¹\82¢\82º\82¢%ld\8cÂ\82Á\82Ä\82Æ\82±\82¾\81D", otmp->quan);
             if (in_doagain)
                 return (struct obj *) 0;
             continue;
@@ -1301,10 +1886,14 @@ register const char *let, *word;
     }
     if (!allowall && let && !index(let, otmp->oclass)
         && !(usegold && otmp->oclass == COIN_CLASS)) {
+#if 0 /*JP*/
         silly_thing(word, otmp);
+#else
+        silly_thing(jword, otmp);
+#endif
         return (struct obj *) 0;
     }
-    if (allowcnt == 2) { /* cnt given */
+    if (cntgiven) {
         if (cnt == 0)
             return (struct obj *) 0;
         if (cnt != otmp->quan) {
@@ -1327,33 +1916,47 @@ struct obj *otmp;
 #if 1 /* 'P','R' vs 'W','T' handling is obsolete */
     nhUse(otmp);
 #else
-    const char *s1, *s2, *s3, *what;
+    const char *s1, *s2, *s3;
     int ocls = otmp->oclass, otyp = otmp->otyp;
 
     s1 = s2 = s3 = 0;
     /* check for attempted use of accessory commands ('P','R') on armor
        and for corresponding armor commands ('W','T') on accessories */
     if (ocls == ARMOR_CLASS) {
+#if 0 /*JP*/
         if (!strcmp(word, "put on"))
             s1 = "W", s2 = "wear", s3 = "";
         else if (!strcmp(word, "remove"))
             s1 = "T", s2 = "take", s3 = " off";
+#else
+        if (!strcmp(word, "\90g\82É\82Â\82¯\82é"))
+            s1 = "W", s2 = "\90g\82É\82Â\82¯\82é", s3 = "";
+        else if (!strcmp(word, "\82Í\82¸\82·"))
+            s1 = "T", s2 = "\82Í\82¸\82·", s3 = "";
+#endif
     } else if ((ocls == RING_CLASS || otyp == MEAT_RING)
                || ocls == AMULET_CLASS
                || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) {
+#if 0 /*JP*/
         if (!strcmp(word, "wear"))
             s1 = "P", s2 = "put", s3 = " on";
         else if (!strcmp(word, "take off"))
             s1 = "R", s2 = "remove", s3 = "";
+#else
+        if (!strcmp(word, "\90g\82É\82Â\82¯\82é"))
+            s1 = "P", s2 = "\90g\82É\82Â\82¯\82é", s3 = "";
+        else if (!strcmp(word, "\82Í\82¸\82·"))
+            s1 = "R", s2 = "\82Í\82¸\82·", s3 = "";
+#endif
     }
-    if (s1) {
-        what = "that";
-        /* quantity for armor and accessory objects is always 1,
-           but some things should be referred to as plural */
-        if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp))
-            what = "those";
-        pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3);
-    else
+    if (s1)
+#if 0 /*JP*/
+        pline("Use the '%s' command to %s %s%s.", s1, s2,
+              !(is_plural(otmp) || pair_of(otmp)) ? "that" : "those", s3);
+#else
+        pline("\82»\82ê\82ð%s\82É\82Í'%s'\83R\83}\83\93\83h\82ð\8eg\82¤\82±\82Æ\81D", s2, s1);
+#endif
+    else
 #endif
         pline(silly_thing_to, word);
 }
@@ -1417,9 +2020,16 @@ static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
                                              RING_CLASS,  AMULET_CLASS,
                                              TOOL_CLASS,  0 };
 
-/* interactive version of getobj - used for Drop, Identify and */
-/* Takeoff (A). Return the number of times fn was called successfully */
-/* If combo is TRUE, we just use this to get a category list */
+/* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
+   Return the number of times fn was called successfully.
+   If combo is TRUE, we just use this to get a category list. */
+/*JP CHECK: 3.6.0 \82Ì\8cÄ\82Ñ\8fo\82µ\8c³
+do.c:962:        || (result = ggetobj("drop", drop, 0, FALSE, (unsigned *) 0)) < -1)
+do.c:1009:        i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
+do_wear.c:2955:        || (result = ggetobj("take off", select_off, 0, FALSE,
+do_wear.c:3007:        if (ggetobj("take off", select_off, 0, TRUE, (unsigned *) 0) == -2)
+invent.c:2014:                n = ggetobj("identify", identify, id_limit, FALSE,
+*/
 int
 ggetobj(word, fn, mx, combo, resultflags)
 const char *word;
@@ -1428,51 +2038,61 @@ boolean combo; /* combination menu flag */
 unsigned *resultflags;
 {
     int FDECL((*ckfn), (OBJ_P)) = (int FDECL((*), (OBJ_P))) 0;
-    boolean FDECL((*filter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
+    boolean FDECL((*ofilter), (OBJ_P)) = (boolean FDECL((*), (OBJ_P))) 0;
     boolean takeoff, ident, allflag, m_seen;
     int itemcount;
     int oletct, iletct, unpaid, oc_of_sym;
-    char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 5];
+    char sym, *ip, olets[MAXOCLASSES + 5], ilets[MAXOCLASSES + 10];
     char extra_removeables[3 + 1]; /* uwep,uswapwep,uquiver */
-    char buf[BUFSZ], qbuf[QBUFSZ];
+    char buf[BUFSZ] = DUMMY, qbuf[QBUFSZ];
+#if 1 /*JP*/
+    const char *joshi = "\82ð";
+    const char *jword;
+
+    const struct trans_verb *tv = trans_verb(word);
+    jword = tv->jp;
+    joshi = tv->particle;
+#endif
 
-    if (resultflags)
-        *resultflags = 0;
-    takeoff = ident = allflag = m_seen = FALSE;
     if (!invent) {
+/*JP
         You("have nothing to %s.", word);
+*/
+        You("%s\82à\82Ì\82Í\8e\9d\82Á\82Ä\82¢\82È\82¢\81D", jcan(jword));
+        if (resultflags)
+            *resultflags = ALL_FINISHED;
         return 0;
     }
+    if (resultflags)
+        *resultflags = 0;
+    takeoff = ident = allflag = m_seen = FALSE;
     add_valid_menu_class(0); /* reset */
     if (taking_off(word)) {
         takeoff = TRUE;
-        filter = is_worn;
+        ofilter = is_worn;
     } else if (!strcmp(word, "identify")) {
         ident = TRUE;
-        filter = not_fully_identified;
+        ofilter = not_fully_identified;
     }
 
-    iletct = collect_obj_classes(ilets, invent, FALSE, filter, &itemcount);
+    iletct = collect_obj_classes(ilets, invent, FALSE, ofilter, &itemcount);
     unpaid = count_unpaid(invent);
 
     if (ident && !iletct) {
         return -1; /* no further identifications */
-    } else if (!takeoff && (unpaid || invent)) {
+    } else if (invent) {
         ilets[iletct++] = ' ';
         if (unpaid)
             ilets[iletct++] = 'u';
-        if (count_buc(invent, BUC_BLESSED))
+        if (count_buc(invent, BUC_BLESSED, ofilter))
             ilets[iletct++] = 'B';
-        if (count_buc(invent, BUC_UNCURSED))
+        if (count_buc(invent, BUC_UNCURSED, ofilter))
             ilets[iletct++] = 'U';
-        if (count_buc(invent, BUC_CURSED))
+        if (count_buc(invent, BUC_CURSED, ofilter))
             ilets[iletct++] = 'C';
-        if (count_buc(invent, BUC_UNKNOWN))
+        if (count_buc(invent, BUC_UNKNOWN, ofilter))
             ilets[iletct++] = 'X';
-        if (invent)
-            ilets[iletct++] = 'a';
-    } else if (takeoff && invent) {
-        ilets[iletct++] = ' ';
+        ilets[iletct++] = 'a';
     }
     ilets[iletct++] = 'i';
     if (!combo)
@@ -1480,13 +2100,28 @@ unsigned *resultflags;
     ilets[iletct] = '\0';
 
     for (;;) {
-        Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", word,
-                ilets);
+#if 0 /*JP*/
+        Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]",
+                word, ilets);
+#else
+        Sprintf(qbuf,"\82Ç\82Ì\8eí\97Þ\82Ì\82à\82Ì%s%s\82©\81H[%s]", joshi,
+                jpolite(jword), ilets);
+#endif
         getlin(qbuf, buf);
         if (buf[0] == '\033')
             return 0;
         if (index(buf, 'i')) {
-            if (display_inventory((char *) 0, TRUE) == '\033')
+            char ailets[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */
+            struct obj *otmp;
+
+            /* applicable inventory letters; if empty, show entire invent */
+            ailets[0] = '\0';
+            if (ofilter)
+                for (otmp = invent; otmp; otmp = otmp->nobj)
+                    /* index() check: limit overflow items to one '#' */
+                    if ((*ofilter)(otmp) && !index(ailets, otmp->invlet))
+                        (void) strkitten(ailets, otmp->invlet);
+            if (display_inventory(ailets, TRUE) == '\033')
                 return 0;
         } else
             break;
@@ -1514,23 +2149,38 @@ unsigned *resultflags;
             if (index(extra_removeables, oc_of_sym)) {
                 ; /* skip rest of takeoff checks */
             } else if (!index(removeables, oc_of_sym)) {
+/*JP
                 pline("Not applicable.");
+*/
+                pline("\82»\82ê\82Í\82Å\82«\82È\82¢\81D");
                 return 0;
             } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
                 noarmor(FALSE);
                 return 0;
             } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep
                        && !uquiver) {
+/*JP
                 You("are not wielding anything.");
+*/
+                You("\89½\82à\91\95\94õ\82µ\82Ä\82¢\82È\82¢\81D");
                 return 0;
             } else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
+/*JP
                 You("are not wearing rings.");
+*/
+                You("\8ew\97Ö\82ð\90g\82É\82Â\82¯\82Ä\82¢\82È\82¢\81D");
                 return 0;
             } else if (oc_of_sym == AMULET_CLASS && !uamul) {
+/*JP
                 You("are not wearing an amulet.");
+*/
+                You("\96\82\8f\9c\82¯\82ð\90g\82É\82Â\82¯\82Ä\82¢\82È\82¢\81D");
                 return 0;
             } else if (oc_of_sym == TOOL_CLASS && !ublindf) {
+/*JP
                 You("are not wearing a blindfold.");
+*/
+                You("\96Ú\89B\82µ\82ð\82µ\82Ä\82¢\82È\82¢\81D");
                 return 0;
             }
         }
@@ -1540,26 +2190,20 @@ unsigned *resultflags;
         } else if (sym == 'a') {
             allflag = TRUE;
         } else if (sym == 'A') {
-            /* same as the default */;
+            ; /* same as the default */
         } else if (sym == 'u') {
             add_valid_menu_class('u');
             ckfn = ckunpaid;
-        } else if (sym == 'B') {
-            add_valid_menu_class('B');
-            ckfn = ckvalidcat;
-        } else if (sym == 'U') {
-            add_valid_menu_class('U');
-            ckfn = ckvalidcat;
-        } else if (sym == 'C') {
-            add_valid_menu_class('C');
-            ckfn = ckvalidcat;
-        } else if (sym == 'X') {
-            add_valid_menu_class('X');
+        } else if (index("BUCX", sym)) {
+            add_valid_menu_class(sym); /* 'B','U','C',or 'X' */
             ckfn = ckvalidcat;
         } else if (sym == 'm') {
             m_seen = TRUE;
         } else if (oc_of_sym == MAXOCLASSES) {
+/*JP
             You("don't have any %c's.", sym);
+*/
+            You("%c\82É\91®\82·\82é\95¨\82ð\8e\9d\82Á\82Ä\82¢\82È\82¢\81D", sym);
         } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */
             if (!index(olets, oc_of_sym)) {
                 add_valid_menu_class(oc_of_sym);
@@ -1570,7 +2214,9 @@ unsigned *resultflags;
     }
 
     if (m_seen) {
-        return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
+        return (allflag
+                || (!oletct && ckfn != ckunpaid && ckfn != ckvalidcat))
+               ? -2 : -3;
     } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
         return 0;
 #if 0
@@ -1596,21 +2242,27 @@ unsigned *resultflags;
  * Walk through the chain starting at objchn and ask for all objects
  * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
  * whether the action in question (i.e., fn) has to be performed.
- * If allflag then no questions are asked. Max gives the max nr of
- * objects to be treated. Return the number of objects treated.
+ * If allflag then no questions are asked.  Mx gives the max number
+ * of objects to be treated.  Return the number of objects treated.
  */
+/*JP CHECK: 3.6.2 \82Å\82Ì\8cÄ\82Ñ\8fo\82µ\8c³
+invent.c:2228:        int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word);
+pickup.c:3208:        if (askchain(objlist, (one_by_one ? (char *) 0 : selection), allflag,
+  word\82É\82Í\93®\8e\8c\82ª\89p\8cê\82Å\93ü\82é\81B
+*/
 int
 askchain(objchn, olets, allflag, fn, ckfn, mx, word)
-struct obj **objchn;
-register int allflag, mx;
-register const char *olets, *word; /* olets is an Obj Class char array */
-register int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
+struct obj **objchn; /* *objchn might change */
+int allflag, mx;
+const char *olets, *word; /* olets is an Obj Class char array */
+int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
 {
     struct obj *otmp, *otmpo;
     register char sym, ilet;
-    register int cnt = 0, dud = 0, tmp;
-    boolean takeoff, nodot, ident, take_out, put_in, first, ininv;
+    int cnt = 0, dud = 0, tmp;
+    boolean takeoff, nodot, ident, take_out, put_in, first, ininv, bycat;
     char qbuf[QBUFSZ], qpfx[QBUFSZ];
+    Loot *sortedchn = 0;
 
     takeoff = taking_off(word);
     ident = !strcmp(word, "identify");
@@ -1619,12 +2271,22 @@ register int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
     nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
              || takeoff || take_out || put_in);
     ininv = (*objchn == invent);
+    bycat = (menu_class_present('u')
+             || menu_class_present('B') || menu_class_present('U')
+             || menu_class_present('C') || menu_class_present('X'));
+
+    /* someday maybe we'll sort by 'olets' too (temporarily replace
+       flags.packorder and pass SORTLOOT_PACK), but not yet... */
+    sortedchn = sortloot(objchn, SORTLOOT_INVLET, FALSE,
+                         (boolean FDECL((*), (OBJ_P))) 0);
+
     first = TRUE;
-/* Changed so the askchain is interrogated in the order specified.
- * For example, if a person specifies =/ then first all rings will be
- * asked about followed by all wands -dgk
- */
-nextclass:
+    /*
+     * Interrogate in the object class order specified.
+     * For example, if a person specifies =/ then first all rings
+     * will be asked about followed by all wands.  -dgk
+     */
+ nextclass:
     ilet = 'a' - 1;
     if (*objchn && (*objchn)->oclass == COIN_CLASS)
         ilet--;                     /* extra iteration */
@@ -1641,9 +2303,11 @@ nextclass:
      * track of which list elements have already been processed.
      */
     bypass_objlist(*objchn, FALSE); /* clear chain's bypass bits */
-    while ((otmp = nxt_unbypassed_obj(*objchn)) != 0) {
+    while ((otmp = nxt_unbypassed_loot(sortedchn, *objchn)) != 0) {
         if (ilet == 'z')
             ilet = 'A';
+        else if (ilet == 'Z')
+            ilet = NOINVSYM; /* '#' */
         else
             ilet++;
         if (olets && *olets && otmp->oclass != *olets)
@@ -1654,6 +2318,8 @@ nextclass:
             continue;
         if (ckfn && !(*ckfn)(otmp))
             continue;
+        if (bycat && !ckvalidcat(otmp))
+            continue;
         if (!allflag) {
             safeq_xprn_ctx.let = ilet;
             safeq_xprn_ctx.dot = !nodot;
@@ -1666,9 +2332,17 @@ nextclass:
                     Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
                 first = FALSE;
             }
-            (void) safe_qbuf(
-                qbuf, qpfx, "?", otmp, ininv ? safeq_xprname : doname,
-                ininv ? safeq_shortxprname : ansimpleoname, "item");
+#if 0 /*JP*/
+            (void) safe_qbuf(qbuf, qpfx, "?", otmp,
+                             ininv ? safeq_xprname : doname,
+                             ininv ? safeq_shortxprname : ansimpleoname,
+                             "item");
+#else
+            (void) safe_qbuf(qbuf, qpfx, "\81H", otmp,
+                             ininv ? safeq_xprname : doname,
+                             ininv ? safeq_shortxprname : ansimpleoname,
+                             "\83A\83C\83e\83\80");
+#endif
             sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf)
                                                         : nyNaq(qbuf);
         } else
@@ -1680,11 +2354,10 @@ nextclass:
                to 'none' or 'all'.  2 special cases: cursed loadstones and
                welded weapons (eg, multiple daggers) will remain as merged
                unit; done to avoid splitting an object that won't be
-               droppable (even if we're picking up rather than dropping).
-             */
-            if (!yn_number)
+               droppable (even if we're picking up rather than dropping). */
+            if (!yn_number) {
                 sym = 'n';
-            else {
+            else {
                 sym = 'y';
                 if (yn_number < otmp->quan && splittable(otmp))
                     otmp = splitobj(otmp, yn_number);
@@ -1693,6 +2366,7 @@ nextclass:
         switch (sym) {
         case 'a':
             allflag = 1;
+            /*FALLTHRU*/
         case 'y':
             tmp = (*fn)(otmp);
             if (tmp < 0) {
@@ -1709,6 +2383,7 @@ nextclass:
             cnt += tmp;
             if (--mx == 0)
                 goto ret;
+            /*FALLTHRU*/
         case 'n':
             if (nodot)
                 dud++;
@@ -1723,11 +2398,19 @@ nextclass:
     }
     if (olets && *olets && *++olets)
         goto nextclass;
+
     if (!takeoff && (dud || cnt))
+/*JP
         pline("That was all.");
+*/
+        pline("\82±\82ê\82Å\91S\95\94\82¾\81D");
     else if (!dud && !cnt)
+/*JP
         pline("No applicable objects.");
-ret:
+*/
+        pline("\82»\82ê\82Í\82Å\82«\82È\82¢\81D");
+ ret:
+    unsortloot(&sortedchn);
     bypass_objlist(*objchn, FALSE);
     return cnt;
 }
@@ -1772,10 +2455,15 @@ int id_limit;
     /* assumptions:  id_limit > 0 and at least one unID'd item is present */
 
     while (id_limit) {
+#if 0 /*JP:T*/
         Sprintf(buf, "What would you like to identify %s?",
                 first ? "first" : "next");
-        n = query_objlist(buf, invent, SIGNAL_NOMENU | SIGNAL_ESCAPE
-                                           | USE_INVLET | INVORDER_SORT,
+#else
+        Sprintf(buf, "\82Ç\82ê\82ð%s\82É\8e¯\95Ê\82µ\82Ü\82·\82©\81H",
+                first ? "\8dÅ\8f\89" : "\8e\9f");
+#endif
+        n = query_objlist(buf, &invent, (SIGNAL_NOMENU | SIGNAL_ESCAPE
+                                         | USE_INVLET | INVORDER_SORT),
                           &pick_list, PICK_ANY, not_fully_identified);
 
         if (n > 0) {
@@ -1789,16 +2477,35 @@ int id_limit;
         } else if (n == -2) { /* player used ESC to quit menu */
             break;
         } else if (n == -1) { /* no eligible items found */
+/*JP
             pline("That was all.");
+*/
+            pline("\82±\82ê\82Å\91S\95\94\82¾\81D");
             break;
         } else if (!--tryct) { /* stop re-prompting */
             pline1(thats_enough_tries);
             break;
         } else { /* try again */
+/*JP
             pline("Choose an item; use ESC to decline.");
+*/
+            pline("\83A\83C\83e\83\80\82ð\91I\82ñ\82Å\82­\82¾\82³\82¢;\82â\82ß\82é\82È\82çESC\81D");
         }
     }
 }
+/* count the unidentified items */
+int
+count_unidentified(objchn)
+struct obj *objchn;
+{
+    int unid_cnt = 0;
+    struct obj *obj;
+
+    for (obj = objchn; obj; obj = obj->nobj)
+        if (not_fully_identified(obj))
+            ++unid_cnt;
+    return unid_cnt;
+}
 
 /* dialog with user to identify a given number of items; 0 means all */
 void
@@ -1806,28 +2513,26 @@ identify_pack(id_limit, learning_id)
 int id_limit;
 boolean learning_id; /* true if we just read unknown identify scroll */
 {
-    struct obj *obj, *the_obj;
-    int n, unid_cnt;
-
-    unid_cnt = 0;
-    the_obj = 0; /* if unid_cnt ends up 1, this will be it */
-    for (obj = invent; obj; obj = obj->nobj)
-        if (not_fully_identified(obj))
-            ++unid_cnt, the_obj = obj;
+    struct obj *obj;
+    int n, unid_cnt = count_unidentified(invent);
 
     if (!unid_cnt) {
+#if 0 /*JP:T*/
         You("have already identified all %sof your possessions.",
             learning_id ? "the rest " : "");
+#else
+        You("%s\91S\82Ä\82Ì\8f\8a\97L\95¨\82ð\8e¯\95Ê\82µ\82Ä\82µ\82Ü\82Á\82Ä\82¢\82é\81D",
+            learning_id ? "\8ec\82è" : "");
+#endif
     } else if (!id_limit || id_limit >= unid_cnt) {
         /* identify everything */
-        if (unid_cnt == 1) {
-            (void) identify(the_obj);
-        } else {
-            /* TODO:  use fully_identify_obj and cornline/menu/whatever here
-             */
-            for (obj = invent; obj; obj = obj->nobj)
-                if (not_fully_identified(obj))
-                    (void) identify(obj);
+        /* TODO:  use fully_identify_obj and cornline/menu/whatever here */
+        for (obj = invent; obj; obj = obj->nobj) {
+            if (not_fully_identified(obj)) {
+                (void) identify(obj);
+                if (unid_cnt == 1)
+                    break;
+            }
         }
     } else {
         /* identify up to `id_limit' items */
@@ -1892,8 +2597,14 @@ long quan;
 {
     if (!prefix)
         prefix = "";
+#if 0 /*JP*/
     pline("%s%s%s", prefix, *prefix ? " " : "",
           xprname(obj, (char *) 0, obj_to_let(obj), TRUE, 0L, quan));
+#else
+    pline("%s%s",
+          xprname(obj, (char *)0, obj_to_let(obj), *prefix ? FALSE : TRUE, 0L, quan),
+          prefix);
+#endif
 }
 
 char *
@@ -1910,28 +2621,42 @@ long quan;       /* if non-0, print this quantity, not obj->quan */
 #else
     static char li[BUFSZ];
 #endif
-    boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
+    boolean use_invlet = (flags.invlet_constant
+                          && let != CONTAINED_SYM && let != HANDS_SYM);
     long savequan = 0;
 
     if (quan && obj) {
         savequan = obj->quan;
         obj->quan = quan;
     }
-
     /*
      * If let is:
+     *  -  Then obj == null and 'txt' refers to hands or fingers.
      *  *  Then obj == null and we are printing a total amount.
      *  >  Then the object is contained and doesn't have an inventory letter.
      */
     if (cost != 0 || let == '*') {
         /* if dot is true, we're doing Iu, otherwise Ix */
-        Sprintf(li, "%c - %-45s %6ld %s",
+#if 0 /*JP*/
+        Sprintf(li,
+                iflags.menu_tab_sep ? "%c - %s\t%6ld %s"
+                                    : "%c - %-45s %6ld %s",
+                (dot && use_invlet ? obj->invlet : let),
+                (txt ? txt : doname(obj)), cost, currency(cost));
+#else
+        Sprintf(li,
+                iflags.menu_tab_sep ? "%c - %s\t%6ld%s"
+                                    : "%c - %-45s %6ld%s",
                 (dot && use_invlet ? obj->invlet : let),
                 (txt ? txt : doname(obj)), cost, currency(cost));
+#endif
     } else {
         /* ordinary inventory display or pickup message */
         Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
+/*JP
                 (txt ? txt : doname(obj)), (dot ? "." : ""));
+*/
+                (txt ? txt : doname(obj)), (dot ? "\81D" : ""));
     }
     if (savequan)
         obj->quan = savequan;
@@ -2000,21 +2725,32 @@ free_pickinv_cache()
  * any count returned from the menu selection is placed here.
  */
 STATIC_OVL char
-display_pickinv(lets, want_reply, out_cnt)
+display_pickinv(lets, xtra_choice, query, want_reply, out_cnt)
 register const char *lets;
+const char *xtra_choice; /* "fingers", pick hands rather than an object */
+const char *query;
 boolean want_reply;
 long *out_cnt;
 {
-    struct obj *otmp;
+/*JP
+    static const char not_carrying_anything[] = "Not carrying anything";
+*/
+    static const char not_carrying_anything[] = "\89½\82à\8e\9d\82Á\82Ä\82¢\82È\82¢";
+    struct obj *otmp, wizid_fakeobj;
     char ilet, ret;
     char *invlet = flags.inv_order;
-    int i, n, classcount;
+    int n, classcount;
     winid win;                        /* windows being used */
     anything any;
     menu_item *selected;
-    struct obj **oarray;
+    unsigned sortflags;
+    Loot *sortedinvent, *srtinv;
+    boolean wizid = FALSE;
 
-    if (flags.perm_invent && lets && *lets) {
+    if (lets && !*lets)
+        lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */
+
+    if (iflags.perm_invent && (lets || xtra_choice)) {
         /* partial inventory in perm_invent setting; don't operate on
            full inventory window, use an alternate one instead; create
            the first time needed and keep it for re-use as needed later */
@@ -2034,9 +2770,25 @@ long *out_cnt;
      * don't know at this level if its up or not.  This may not be
      * an issue if empty checks are done before hand and the call
      * to here is short circuited away.
+     *
+     * 2: our count here is only to distinguish between 0 and 1 and
+     * more than 1; for the last one, we don't need a precise number.
+     * For perm_invent update we force 'more than 1'.
      */
-    if (!invent && !(flags.perm_invent && !lets && !want_reply)) {
-        pline("Not carrying anything.");
+    n = (iflags.perm_invent && !lets && !want_reply) ? 2
+        : lets ? (int) strlen(lets)
+               : !invent ? 0 : !invent->nobj ? 1 : 2;
+    /* for xtra_choice, there's another 'item' not included in initial 'n';
+       for !lets (full invent) and for override_ID (wizard mode identify),
+       skip message_menu handling of single item even if item count was 1 */
+    if (xtra_choice || (n == 1 && (!lets || iflags.override_ID)))
+        ++n;
+
+    if (n == 0) {
+/*JP
+        pline("%s.", not_carrying_anything);
+*/
+        pline("%s\81D", not_carrying_anything);
         return 0;
     }
 
@@ -2044,58 +2796,89 @@ long *out_cnt;
     if (!flags.invlet_constant)
         reassign();
 
-    if (lets && strlen(lets) == 1 && !iflags.override_ID) {
+    if (n == 1 && !iflags.force_invmenu) {
         /* when only one item of interest, use pline instead of menus;
            we actually use a fake message-line menu in order to allow
            the user to perform selection at the --More-- prompt for tty */
         ret = '\0';
-        for (otmp = invent; otmp; otmp = otmp->nobj) {
-            if (otmp->invlet == lets[0]) {
-                ret = message_menu(
-                    lets[0], want_reply ? PICK_ONE : PICK_NONE,
-                    xprname(otmp, (char *) 0, lets[0], TRUE, 0L, 0L));
-                if (out_cnt)
-                    *out_cnt = -1L; /* select all */
-                break;
-            }
+        if (xtra_choice) {
+            /* xtra_choice is "bare hands" (wield), "fingertip" (Engrave),
+               "nothing" (ready Quiver), or "fingers" (apply grease) */
+            ret = message_menu(HANDS_SYM, PICK_ONE,
+                               xprname((struct obj *) 0, xtra_choice,
+                                       HANDS_SYM, TRUE, 0L, 0L)); /* '-' */
+        } else {
+            for (otmp = invent; otmp; otmp = otmp->nobj)
+                if (!lets || otmp->invlet == lets[0])
+                    break;
+            if (otmp)
+                ret = message_menu(otmp->invlet,
+                                   want_reply ? PICK_ONE : PICK_NONE,
+                                   xprname(otmp, (char *) 0, lets[0],
+                                           TRUE, 0L, 0L));
         }
+        if (out_cnt)
+            *out_cnt = -1L; /* select all */
         return ret;
     }
 
-    /* count the number of items */
-    for (n = 0, otmp = invent; otmp; otmp = otmp->nobj)
-        if (!lets || !*lets || index(lets, otmp->invlet))
-            n++;
-
-    oarray = objarr_init(n);
-
-    /* Add objects to the array */
-    i = 0;
-    for (otmp = invent; otmp; otmp = otmp->nobj)
-        if (!lets || !*lets || index(lets, otmp->invlet)) {
-            objarr_set(otmp, i++, oarray, (flags.sortloot == 'f'));
-        }
+    sortflags = (flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET;
+    if (flags.sortpack)
+        sortflags |= SORTLOOT_PACK;
+    sortedinvent = sortloot(&invent, sortflags, FALSE,
+                            (boolean FDECL((*), (OBJ_P))) 0);
 
     start_menu(win);
     any = zeroany;
     if (wizard && iflags.override_ID) {
-        char prompt[BUFSZ];
-        any.a_char = -1;
-        /* wiz_identify stuffed the wiz_identify cmd character
-           into iflags.override_ID */
-        Sprintf(prompt, "Debug Identify (%s to permanently identify)",
-                visctrl(iflags.override_ID));
-        add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
-                 prompt, MENU_UNSELECTED);
-    }
-nextclass:
+        int unid_cnt;
+        char prompt[QBUFSZ];
+
+        unid_cnt = count_unidentified(invent);
+        Sprintf(prompt, "Debug Identify"); /* 'title' rather than 'prompt' */
+        if (unid_cnt)
+            Sprintf(eos(prompt),
+                    " -- unidentified or partially identified item%s",
+                    plur(unid_cnt));
+        add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, prompt, MENU_UNSELECTED);
+        if (!unid_cnt) {
+            add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE,
+                     "(all items are permanently identified already)",
+                     MENU_UNSELECTED);
+        } else {
+            any.a_obj = &wizid_fakeobj;
+            Sprintf(prompt, "select %s to permanently identify",
+                    (unid_cnt == 1) ? "it": "any or all of them");
+            /* wiz_identify stuffed the wiz_identify command character (^I)
+               into iflags.override_ID for our use as an accelerator;
+               it could be ambiguous if player has assigned a letter to
+               the #wizidentify command */
+            if (unid_cnt > 1)
+                Sprintf(eos(prompt), " (%s for all)",
+                        visctrl(iflags.override_ID));
+            add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE,
+                     prompt, MENU_UNSELECTED);
+            wizid = TRUE;
+        }
+   } else if (xtra_choice) {
+        /* wizard override ID and xtra_choice are mutually exclusive */
+        if (flags.sortpack)
+            add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                     "Miscellaneous", MENU_UNSELECTED);
+        any.a_char = HANDS_SYM; /* '-' */
+        add_menu(win, NO_GLYPH, &any, HANDS_SYM, 0, ATR_NONE,
+                 xtra_choice, MENU_UNSELECTED);
+    }
+ nextclass:
     classcount = 0;
-    any = zeroany; /* set all bits to zero */
-    for (i = 0; i < n; i++) {
-        otmp = oarray[i];
-        ilet = otmp->invlet;
-        any = zeroany; /* zero */
+    for (srtinv = sortedinvent; (otmp = srtinv->obj) != 0; ++srtinv) {
+        if (lets && !index(lets, otmp->invlet))
+            continue;
         if (!flags.sortpack || otmp->oclass == *invlet) {
+            if (wizid && !not_fully_identified(otmp))
+                continue;
+            any = zeroany; /* all bits zero */
+            ilet = otmp->invlet;
             if (flags.sortpack && !classcount) {
                 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
                          let_to_name(*invlet, FALSE,
@@ -2103,9 +2886,13 @@ nextclass:
                          MENU_UNSELECTED);
                 classcount++;
             }
-            any.a_char = ilet;
-            add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
-                     doname(otmp), MENU_UNSELECTED);
+            if (wizid)
+                any.a_obj = otmp;
+            else
+                any.a_char = ilet;
+            add_menu(win, obj_to_glyph(otmp, rn2_on_display_rng), &any, ilet,
+                     wizid ? def_oc_syms[(int) otmp->oclass].sym : 0,
+                     ATR_NONE, doname(otmp), MENU_UNSELECTED);
         }
     }
     if (flags.sortpack) {
@@ -2116,14 +2903,59 @@ nextclass:
             goto nextclass;
         }
     }
-    free(oarray);
-    end_menu(win, (char *) 0);
+    if (iflags.force_invmenu && lets && want_reply) {
+        any = zeroany;
+#if 0 /*JP*/
+        add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                 "Special", MENU_UNSELECTED);
+#else
+        add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
+                 "\93Á\8eê", MENU_UNSELECTED);
+#endif
+        any.a_char = '*';
+#if 0 /*JP*/
+        add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE,
+                 "(list everything)", MENU_UNSELECTED);
+#else
+        add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE,
+                 "(\91S\82Ä\82Ì\88ê\97\97)", MENU_UNSELECTED);
+#endif
+    }
+    unsortloot(&sortedinvent);
+    /* for permanent inventory where we intend to show everything but
+       nothing has been listed (because there isn't anyhing to list;
+       recognized via any.a_char still being zero; the n==0 case above
+       gets skipped for perm_invent), put something into the menu */
+    if (iflags.perm_invent && !lets && !any.a_char) {
+        any = zeroany;
+        add_menu(win, NO_GLYPH, &any, 0, 0, 0,
+                 not_carrying_anything, MENU_UNSELECTED);
+        want_reply = FALSE;
+    }
+    end_menu(win, query && *query ? query : (char *) 0);
 
-    n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
+    n = select_menu(win,
+                    wizid ? PICK_ANY : want_reply ? PICK_ONE : PICK_NONE,
+                    &selected);
     if (n > 0) {
-        ret = selected[0].item.a_char;
-        if (out_cnt)
-            *out_cnt = selected[0].count;
+        if (wizid) {
+            int i;
+
+            ret = '\0';
+            for (i = 0; i < n; ++i) {
+                otmp = selected[i].item.a_obj;
+                if (otmp == &wizid_fakeobj) {
+                    identify_pack(0, FALSE);
+                } else {
+                    if (not_fully_identified(otmp))
+                        (void) identify(otmp);
+                }
+            }
+        } else {
+            ret = selected[0].item.a_char;
+            if (out_cnt)
+                *out_cnt = selected[0].count;
+        }
         free((genericptr_t) selected);
     } else
         ret = !n ? '\0' : '\033'; /* cancelled */
@@ -2143,7 +2975,8 @@ display_inventory(lets, want_reply)
 const char *lets;
 boolean want_reply;
 {
-    return display_pickinv(lets, want_reply, (long *) 0);
+    return display_pickinv(lets, (char *) 0, (char *) 0,
+                           want_reply, (long *) 0);
 }
 
 /*
@@ -2182,7 +3015,8 @@ char avoidlet;
                         classcount++;
                     }
                     any.a_char = ilet;
-                    add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE,
+                    add_menu(win, obj_to_glyph(otmp, rn2_on_display_rng),
+                             &any, ilet, 0, ATR_NONE,
                              doname(otmp), MENU_UNSELECTED);
                 }
             }
@@ -2192,7 +3026,7 @@ char avoidlet;
         }
         end_menu(win, "Inventory letters used:");
 
-        n = select_menu(win, PICK_NONE, &selected);
+        n = select_menu(win, PICK_ONE, &selected);
         if (n > 0) {
             ret = selected[0].item.a_char;
             free((genericptr_t) selected);
@@ -2231,20 +3065,27 @@ struct obj *list;
  * at some point:  bknown is forced for priest[ess], like in xname().
  */
 int
-count_buc(list, type)
+count_buc(list, type, filterfunc)
 struct obj *list;
 int type;
+boolean FDECL((*filterfunc), (OBJ_P));
 {
     int count = 0;
 
     for (; list; list = list->nobj) {
-        /* coins are "none of the above" as far as BUCX filtering goes */
-        if (list->oclass == COIN_CLASS)
-            continue;
         /* priests always know bless/curse state */
         if (Role_if(PM_PRIEST))
-            list->bknown = 1;
+            list->bknown = (list->oclass != COIN_CLASS);
+        /* some actions exclude some or most items */
+        if (filterfunc && !(*filterfunc)(list))
+            continue;
 
+        /* coins are either uncursed or unknown based upon option setting */
+        if (list->oclass == COIN_CLASS) {
+            if (type == (iflags.goldX ? BUC_UNKNOWN : BUC_UNCURSED))
+                ++count;
+            continue;
+        }
         /* check whether this object matches the requested type */
         if (!list->bknown
                 ? (type == BUC_UNKNOWN)
@@ -2258,21 +3099,32 @@ int type;
 
 /* similar to count_buc(), but tallies all states at once
    rather than looking for a specific type */
-STATIC_OVL void
-tally_BUCX(list, bcp, ucp, ccp, xcp, ocp)
+void
+tally_BUCX(list, by_nexthere, bcp, ucp, ccp, xcp, ocp)
 struct obj *list;
+boolean by_nexthere;
 int *bcp, *ucp, *ccp, *xcp, *ocp;
 {
+    /* Future extensions:
+     *  Skip current_container when list is invent, uchain when
+     *  first object of list is located on the floor.  'ocp' will then
+     *  have a function again (it was a counter for having skipped gold,
+     *  but that's not skipped anymore).
+     */
     *bcp = *ucp = *ccp = *xcp = *ocp = 0;
-    for (; list; list = list->nobj) {
+    for ( ; list; list = (by_nexthere ? list->nexthere : list->nobj)) {
+        /* priests always know bless/curse state */
+        if (Role_if(PM_PRIEST))
+            list->bknown = (list->oclass != COIN_CLASS);
+        /* coins are either uncursed or unknown based upon option setting */
         if (list->oclass == COIN_CLASS) {
-            ++(*ocp); /* "other" */
+            if (iflags.goldX)
+                ++(*xcp);
+            else
+                ++(*ucp);
             continue;
         }
-        /* priests always know bless/curse state */
-        if (Role_if(PM_PRIEST))
-            list->bknown = 1;
-
+        /* ordinary items */
         if (!list->bknown)
             ++(*xcp);
         else if (list->blessed)
@@ -2284,6 +3136,7 @@ int *bcp, *ucp, *ccp, *xcp, *ocp;
     }
 }
 
+/* count everything inside a container, or just shop-owned items inside */
 long
 count_contents(container, nested, quantity, everything)
 struct obj *container;
@@ -2291,13 +3144,25 @@ boolean nested, /* include contents of any nested containers */
     quantity,   /* count all vs count separate stacks */
     everything; /* all objects vs only unpaid objects */
 {
-    struct obj *otmp;
+    struct obj *otmp, *topc;
+    boolean shoppy = FALSE;
     long count = 0L;
 
+    if (!everything) {
+        for (topc = container; topc->where == OBJ_CONTAINED;
+             topc = topc->ocontainer)
+            continue;
+        if (topc->where == OBJ_FLOOR) {
+            xchar x, y;
+
+            (void) get_obj_location(topc, &x, &y, CONTAINED_TOO);
+            shoppy = costly_spot(x, y);
+        }
+    }
     for (otmp = container->cobj; otmp; otmp = otmp->nobj) {
         if (nested && Has_contents(otmp))
             count += count_contents(otmp, nested, quantity, everything);
-        if (everything || otmp->unpaid)
+        if (everything || otmp->unpaid || (shoppy && !otmp->no_charge))
             count += quantity ? otmp->quan : 1L;
     }
     return count;
@@ -2307,22 +3172,26 @@ STATIC_OVL void
 dounpaid()
 {
     winid win;
-    struct obj *otmp, *marker;
+    struct obj *otmp, *marker, *contnr;
     register char ilet;
     char *invlet = flags.inv_order;
     int classcount, count, num_so_far;
     long cost, totcost;
 
     count = count_unpaid(invent);
+    otmp = marker = contnr = (struct obj *) 0;
 
     if (count == 1) {
-        marker = (struct obj *) 0;
         otmp = find_unpaid(invent, &marker);
+        contnr = unknwn_contnr_contents(otmp);
+    }
+    if  (otmp && !contnr) {
+        /* 1 item; use pline instead of popup menu */
         cost = unpaid_cost(otmp, FALSE);
         iflags.suppress_price++; /* suppress "(unpaid)" suffix */
         pline1(xprname(otmp, distant_name(otmp, doname),
-                       carried(otmp) ? otmp->invlet : CONTAINED_SYM, TRUE,
-                       cost, 0L));
+                       carried(otmp) ? otmp->invlet : CONTAINED_SYM,
+                       TRUE, cost, 0L));
         iflags.suppress_price--;
         return;
     }
@@ -2384,7 +3253,10 @@ dounpaid()
                     char contbuf[BUFSZ];
 
                     /* Shopkeeper knows what to charge for contents */
+/*JP
                     Sprintf(contbuf, "%s contents", s_suffix(xname(otmp)));
+*/
+                    Sprintf(contbuf, "%s\82Ì\92\86\90g", xname(otmp));
                     putstr(win, 0,
                            xprname((struct obj *) 0, contbuf, CONTAINED_SYM,
                                    TRUE, contcost, 0L));
@@ -2394,8 +3266,13 @@ dounpaid()
     }
 
     putstr(win, 0, "");
+#if 0 /*JP*/
     putstr(win, 0,
            xprname((struct obj *) 0, "Total:", '*', FALSE, totcost, 0L));
+#else
+    putstr(win, 0,
+           xprname((struct obj *) 0, "\8d\87\8cv\81F", '*', FALSE, totcost, 0L));
+#endif
     display_nhwindow(win, FALSE);
     destroy_nhwindow(win);
 }
@@ -2409,7 +3286,12 @@ struct obj *obj;
 {
     boolean res = (obj->oclass == this_type);
 
-    if (obj->oclass != COIN_CLASS) {
+    if (obj->oclass == COIN_CLASS) {
+        /* if filtering by bless/curse state, gold is classified as
+           either unknown or uncursed based on user option setting */
+        if (this_type && index("BUCX", this_type))
+            res = (this_type == (iflags.goldX ? 'X' : 'U'));
+    } else {
         switch (this_type) {
         case 'B':
             res = (obj->bknown && obj->blessed);
@@ -2442,14 +3324,20 @@ dotypeinv()
     boolean billx = *u.ushops && doinvbill(0);
     menu_item *pick_list;
     boolean traditional = TRUE;
+/*JP
     const char *prompt = "What type of object do you want an inventory of?";
+*/
+    const char *prompt = "\82Ç\82Ì\8eí\97Þ\82Ì\8e\9d\82¿\95¨\82ð\8c©\82Ü\82·\82©\81H";
 
     if (!invent && !billx) {
+/*JP
         You("aren't carrying anything.");
+*/
+        You("\82»\82Ì\8eí\97Þ\82Ì\95¨\82Í\89½\82à\8e\9d\82Á\82Ä\82¢\82È\82¢\81D");
         return 0;
     }
     unpaid_count = count_unpaid(invent);
-    tally_BUCX(invent, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
+    tally_BUCX(invent, FALSE, &bcnt, &ucnt, &ccnt, &xcnt, &ocnt);
 
     if (flags.menu_style != MENU_TRADITIONAL) {
         if (flags.menu_style == MENU_FULL
@@ -2477,9 +3365,9 @@ dotypeinv()
         /* collect a list of classes of objects carried, for use as a prompt
          */
         types[0] = 0;
-        class_count =
-            collect_obj_classes(types, invent, FALSE,
-                                (boolean FDECL((*), (OBJ_P))) 0, &itemcount);
+        class_count = collect_obj_classes(types, invent, FALSE,
+                                          (boolean FDECL((*), (OBJ_P))) 0,
+                                          &itemcount);
         if (unpaid_count || billx || (bcnt + ccnt + ucnt + xcnt) != 0)
             types[class_count++] = ' ';
         if (unpaid_count)
@@ -2538,15 +3426,23 @@ dotypeinv()
         if (billx)
             (void) doinvbill(1);
         else
+#if 0 /*JP*/
             pline("No used-up objects%s.",
                   unpaid_count ? " on your shopping bill" : "");
+#else
+          pline("\8eg\82Á\82Ä\82µ\82Ü\82Á\82½\95¨\82Í%s\82È\82¢\81D",
+                  unpaid_count ? "\8f¤\93X\82Ì\90¿\8b\81\8f\91\82É\82Í" : "");
+#endif
         return 0;
     }
     if (c == 'u' || (c == 'U' && unpaid_count && !ucnt)) {
         if (unpaid_count)
             dounpaid();
         else
+/*JP
             You("are not carrying any unpaid objects.");
+*/
+            You("\96¢\95¥\82¢\82Ì\83A\83C\83e\83\80\82ð\8e\9d\82Á\82Ä\82¢\82È\82¢\81D");
         return 0;
     }
     if (traditional) {
@@ -2559,35 +3455,57 @@ dotypeinv()
             return doprgold();
         if (index(types, c) > index(types, '\033')) {
             /* '> ESC' => hidden choice, something known not to be carried */
-            const char *which = 0;
+            const char *before = "", *after = "";
 
             switch (c) {
             case 'B':
-                which = "known to be blessed";
+/*JP
+                before = "known to be blessed ";
+*/
+                before = "\8fj\95\9f\82³\82ê\82Ä\82¢\82é\82Æ\82í\82©\82Á\82Ä\82¢\82é";
                 break;
             case 'U':
-                which = "known to be uncursed";
+/*JP
+                before = "known to be uncursed ";
+*/
+                before = "\8eô\82í\82ê\82Ä\82¢\82È\82¢\82Æ\82í\82©\82Á\82Ä\82¢\82é";
                 break;
             case 'C':
-                which = "known to be cursed";
+/*JP
+                before = "known to be cursed ";
+*/
+                before = "\8eô\82í\82ê\82Ä\82¢\82é\82Æ\82í\82©\82Á\82Ä\82¢\82é";
                 break;
             case 'X':
-                You(
-          "have no objects whose blessed/uncursed/cursed status is unknown.");
+/*JP
+                after = " whose blessed/uncursed/cursed status is unknown";
+*/
+                after = "\8fj\95\9f\81^\8eô\82¢\82ª\82í\82©\82ç\82È\82¢";
                 break; /* better phrasing is desirable */
             default:
-                which = "such";
+                /* 'c' is an object class, because we've already handled
+                   all the non-class letters which were put into 'types[]';
+                   could/should move object class names[] array from below
+                   to somewhere above so that we can access it here (via
+                   lcase(strcpy(classnamebuf, names[(int) c]))), but the
+                   game-play value of doing so is low... */
+/*JP
+                before = "such ";
+*/
+                before = "\82»\82Ì\82æ\82¤\82È";
                 break;
             }
-            if (which)
-                You("have no %s objects.", which);
+/*JP
+            You("have no %sobjects%s.", before, after);
+*/
+                You("%s%s\82à\82Ì\82Í\89½\82à\8e\9d\82Á\82Ä\82¢\82È\82¢\81D", before, after);
             return 0;
         }
         this_type = oclass;
     }
-    if (query_objlist((char *) 0, invent,
-                      (flags.invlet_constant ? USE_INVLET : 0)
-                          | INVORDER_SORT,
+    if (query_objlist((char *) 0, &invent,
+                      ((flags.invlet_constant ? USE_INVLET : 0)
+                       | INVORDER_SORT),
                       &pick_list, PICK_NONE, this_type_only) > 0)
         free((genericptr_t) pick_list);
     return 0;
@@ -2614,7 +3532,10 @@ char *buf;
             cmap = S_vodoor;
             break; /* "open door" */
         case D_BROKEN:
+/*JP
             dfeature = "broken door";
+*/
+            dfeature = "\89ó\82ê\82½\94à";
             break;
         default:
             cmap = S_vcdoor;
@@ -2622,7 +3543,10 @@ char *buf;
         }
         /* override door description for open drawbridge */
         if (is_drawbridge_wall(x, y) >= 0)
+/*JP
             dfeature = "open drawbridge portcullis", cmap = -1;
+*/
+            dfeature = "\8d~\82è\82Ä\82¢\82é\92µ\82Ë\8b´", cmap = -1;
     } else if (IS_FOUNTAIN(ltyp))
         cmap = S_fountain; /* "fountain" */
     else if (IS_THRONE(ltyp))
@@ -2632,10 +3556,14 @@ char *buf;
     else if (is_ice(x, y))
         cmap = S_ice; /* "ice" */
     else if (is_pool(x, y))
+/*JP
         dfeature = "pool of water";
+*/
+        dfeature = "\90\85\82½\82Ü\82è";
     else if (IS_SINK(ltyp))
         cmap = S_sink; /* "sink" */
     else if (IS_ALTAR(ltyp)) {
+#if 0 /*JP*/
         Sprintf(altbuf, "%saltar to %s (%s)",
                 ((lev->altarmask & AM_SHRINE)
                  && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
@@ -2643,6 +3571,15 @@ char *buf;
                     : "",
                 a_gname(),
                 align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
+#else
+        Sprintf(altbuf, "%s%s\82Ì\8dÕ\92d(%s)",
+                ((lev->altarmask & AM_SHRINE)
+                 && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)))
+                    ? "\8d\82\88Ê\82Ì"
+                    : "",
+                a_gname(),
+                align_str(Amask2align(lev->altarmask & ~AM_SHRINE)));
+#endif
         dfeature = altbuf;
     } else if ((x == xupstair && y == yupstair)
                || (x == sstairs.sx && y == sstairs.sy && sstairs.up))
@@ -2663,7 +3600,10 @@ char *buf;
     else if (ltyp == TREE)
         cmap = S_tree; /* "tree" */
     else if (ltyp == IRONBARS)
+/*JP
         dfeature = "set of iron bars";
+*/
+        dfeature = "\93S\82Ì\96_";
 
     if (cmap >= 0)
         dfeature = defsyms[cmap].explanation;
@@ -2681,7 +3621,11 @@ boolean picked_some;
 {
     struct obj *otmp;
     struct trap *trap;
+#if 0 /*JP:C*/
     const char *verb = Blind ? "feel" : "see";
+#else
+    const char *verb = Blind ? "\82ª\82 \82é\82æ\82¤\82È\8bC\82ª\82µ\82½" : "\82ð\82Ý\82Â\82¯\82½";
+#endif
     const char *dfeature = (char *) 0;
     char fbuf[BUFSZ], fbuf2[BUFSZ];
     winid tmpwin;
@@ -2692,11 +3636,23 @@ boolean picked_some;
     skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit);
     if (u.uswallow && u.ustuck) {
         struct monst *mtmp = u.ustuck;
+
+#if 0 /*JP:T*/
         Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)),
                 mbodypart(mtmp, STOMACH));
+#else
+        Sprintf(fbuf, "%s\82Ì%s\82Ì\92\86\90g", mon_nam(mtmp),
+                mbodypart(mtmp, STOMACH));
+#endif
+#if 0 /*JP*//*\8cê\8f\87\82ª\88á\82¤\82Ì\82Å\91f\92¼\82É*/
         /* Skip "Contents of " by using fbuf index 12 */
         You("%s to %s what is lying in %s.", Blind ? "try" : "look around",
             verb, &fbuf[12]);
+#else
+        You("%s\82Ì%s\82É\89½\82ª\82 \82é\82©%s\81D",
+            mon_nam(mtmp), mbodypart(mtmp, STOMACH),
+            Blind ? "\82³\82®\82Á\82½" : "\8c©\89ñ\82µ\82½");
+#endif
         otmp = mtmp->minvent;
         if (otmp) {
             for (; otmp; otmp = otmp->nobj) {
@@ -2705,31 +3661,53 @@ boolean picked_some;
                 if (otmp->otyp == CORPSE)
                     feel_cockatrice(otmp, FALSE);
             }
+#if 0 /*JP*/
             if (Blind)
                 Strcpy(fbuf, "You feel");
             Strcat(fbuf, ":");
-            (void) display_minventory(mtmp, MINV_ALL, fbuf);
+#else
+            Sprintf(fbuf, "\82±\82±\82É\82 \82é%s\82à\82Ì\82Í\81F", Blind ? "\82ç\82µ\82¢" : "");
+#endif
+            (void) display_minventory(mtmp, MINV_ALL | PICK_NONE, fbuf);
         } else {
+#if 0 /*JP*/
             You("%s no objects here.", verb);
+#else
+            pline(Blind ? "\82 \82È\82½\82Í\89½\82à\82È\82¢\82æ\82¤\82È\8bC\82ª\82µ\82½\81D"
+                  : "\82 \82È\82½\82Í\89½\82à\82Ý\82Â\82¯\82ç\82ê\82È\82©\82Á\82½\81D");
+#endif
         }
         return !!Blind;
     }
     if (!skip_objects && (trap = t_at(u.ux, u.uy)) && trap->tseen)
+/*JP
         There("is %s here.",
+*/
+        pline("\82±\82±\82É\82Í%s\82ª\82 \82é\81D",
               an(defsyms[trap_to_defsym(trap->ttyp)].explanation));
 
     otmp = level.objects[u.ux][u.uy];
     dfeature = dfeature_at(u.ux, u.uy, fbuf2);
+/*JP
     if (dfeature && !strcmp(dfeature, "pool of water") && Underwater)
+*/
+    if (dfeature && !strcmp(dfeature, "\90\85\82½\82Ü\82è") && Underwater)
         dfeature = 0;
 
     if (Blind) {
         boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
 
+/*JP
         if (dfeature && !strncmp(dfeature, "altar ", 6)) {
+*/
+        if (dfeature && !strncmp(dfeature, "\8dÕ\92d", 4)) {
             /* don't say "altar" twice, dfeature has more info */
+/*JP
             You("try to feel what is here.");
+*/
+            You("\82±\82±\82É\89½\82ª\82 \82é\82Ì\82©\92²\82×\82æ\82¤\82Æ\82µ\82½\81D");
         } else {
+#if 0 /*JP*/
             const char *where = (Blind && !can_reach_floor(TRUE))
                                     ? "lying beneath you"
                                     : "lying here on the ",
@@ -2739,17 +3717,32 @@ boolean picked_some;
 
             You("try to feel what is %s%s.", drift ? "floating here" : where,
                 drift ? "" : onwhat);
+#else
+            if (drift) {
+                You("\89½\82ª\95\82\82¢\82Ä\82¢\82é\82Ì\82©\92²\82×\82æ\82¤\82Æ\82µ\82½\81D");
+            } else if (Blind && !can_reach_floor(TRUE)) {
+                You("\89½\82ª\91«\89º\82É\82 \82é\82Ì\82©\92²\82×\82æ\82¤\82Æ\82µ\82½\81D");
+            } else {
+                You("\89½\82ª%s\82Ì\8fã\82É\82 \82é\82Ì\82©\92²\82×\82æ\82¤\82Æ\82µ\82½\81D", surface(u.ux, u.uy));
+            }
+#endif
         }
         if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy)))
             dfeature = 0; /* ice already identified */
         if (!can_reach_floor(TRUE)) {
+/*JP
             pline("But you can't reach it!");
+*/
+            pline("\82µ\82©\82µ\93Í\82©\82È\82¢\81I");
             return 0;
         }
     }
 
     if (dfeature)
+/*JP
         Sprintf(fbuf, "There is %s here.", an(dfeature));
+*/
+        Sprintf(fbuf, "\82±\82±\82É\82Í%s\82ª\82 \82é\81D", an(dfeature));
 
     if (!otmp || is_lava(u.ux, u.uy)
         || (is_pool(u.ux, u.uy) && !Underwater)) {
@@ -2757,7 +3750,13 @@ boolean picked_some;
             pline1(fbuf);
         read_engr_at(u.ux, u.uy); /* Eric Backus */
         if (!skip_objects && (Blind || !dfeature))
+#if 0 /*JP:C*/
             You("%s no objects here.", verb);
+#else
+          pline(Blind ?
+                "\82È\82É\82à\82È\82¢\82æ\82¤\82È\8bC\82ª\82·\82é\81D" :
+                "\82È\82É\82à\82Ý\82Â\82¯\82ç\82ê\82È\82©\82Á\82½\81D");
+#endif
         return !!Blind;
     }
     /* we know there is something here */
@@ -2767,8 +3766,12 @@ boolean picked_some;
             pline1(fbuf);
         read_engr_at(u.ux, u.uy); /* Eric Backus */
         if (obj_cnt == 1 && otmp->quan == 1L)
+/*JP
             There("is %s object here.", picked_some ? "another" : "an");
+*/
+            There("\82±\82±\82É\82Í%s\88ê\82Â\82à\82Ì\82ª\82 \82é\81D", picked_some ? "\82à\82¤" : "");
         else
+#if 0 /*JP*/
             There("are %s%s objects here.",
                   (obj_cnt < 5)
                       ? "a few"
@@ -2776,8 +3779,16 @@ boolean picked_some;
                           ? "several"
                           : "many",
                   picked_some ? " more" : "");
+#else
+            pline("\82±\82±\82É\82Í%s%s\82à\82Ì\82ª\82 \82é\81D",
+                  picked_some ? "\82³\82ç\82É" : "",
+                  (obj_cnt < 10)
+                      ? "\82¢\82­\82Â\82©\82Ì"
+                      : "\82½\82­\82³\82ñ\82Ì");
+#endif
         for (; otmp; otmp = otmp->nexthere)
             if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
+#if 0 /*JP*//*"It's (corpse_name), unfortunately"*/
                 pline("%s %s%s.",
                       (obj_cnt > 1)
                           ? "Including"
@@ -2788,6 +3799,16 @@ boolean picked_some;
                       poly_when_stoned(youmonst.data)
                           ? ""
                           : ", unfortunately");
+#else
+                pline("%s%s%s\81D",
+                      poly_when_stoned(youmonst.data)
+                          ? ""
+                          : "\8ec\94O\82È\82ª\82ç",
+                      corpse_xname(otmp, (const char *) 0, CXN_ARTICLE),
+                      (obj_cnt > 1)
+                          ? "\82ð\8aÜ\82ñ\82Å\82¢\82é"
+                          : "\82¾");
+#endif
                 feel_cockatrice(otmp, FALSE);
                 break;
             }
@@ -2796,7 +3817,10 @@ boolean picked_some;
         if (dfeature)
             pline1(fbuf);
         read_engr_at(u.ux, u.uy); /* Eric Backus */
+/*JP
         You("%s here %s.", verb, doname_with_price(otmp));
+*/
+        pline("%s%s\81D", doname_with_price(otmp), verb);
         iflags.last_msg = PLNMSG_ONE_ITEM_HERE;
         if (otmp->otyp == CORPSE)
             feel_cockatrice(otmp, FALSE);
@@ -2809,14 +3833,23 @@ boolean picked_some;
             putstr(tmpwin, 0, fbuf);
             putstr(tmpwin, 0, "");
         }
+#if 0 /*JP*/
         Sprintf(buf, "%s that %s here:",
                 picked_some ? "Other things" : "Things",
                 Blind ? "you feel" : "are");
+#else
+        Sprintf(buf, "%s\82±\82±\82É\82 \82é%s\82à\82Ì\82Í\81F",
+                picked_some ? "\91¼\82É" : "",
+                Blind ? "\82ç\82µ\82¢" : "");
+#endif
         putstr(tmpwin, 0, buf);
         for (; otmp; otmp = otmp->nexthere) {
             if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
                 felt_cockatrice = TRUE;
+/*JP
                 Sprintf(buf, "%s...", doname(otmp));
+*/
+                Sprintf(buf, "%s\81D\81D\81D", doname(otmp));
                 putstr(tmpwin, 0, buf);
                 break;
             }
@@ -2835,7 +3868,16 @@ boolean picked_some;
 int
 dolook()
 {
-    return look_here(0, FALSE);
+    int res;
+
+    /* don't let
+       MSGTYPE={norep,noshow} "You see here"
+       interfere with feedback from the look-here command */
+    hide_unhide_msgtypes(TRUE, MSGTYP_MASK_REP_SHOW);
+    res = look_here(0, FALSE);
+    /* restore normal msgtype handling */
+    hide_unhide_msgtypes(FALSE, MSGTYP_MASK_REP_SHOW);
+    return res;
 }
 
 boolean
@@ -2861,12 +3903,23 @@ boolean force_touch;
         Strcpy(kbuf, corpse_xname(otmp, (const char *) 0, CXN_PFX_THE));
 
         if (poly_when_stoned(youmonst.data))
+#if 0 /*JP*/
             You("touched %s with your bare %s.", kbuf,
                 makeplural(body_part(HAND)));
+#else
+            You("%s\82Ì\8e\80\91Ì\82É\91f%s\82Å\90G\82Á\82½\81D", kbuf,
+                body_part(HAND));
+#endif
         else
+/*JP
             pline("Touching %s is a fatal mistake...", kbuf);
+*/
+            pline("%s\82Ì\8e\80\91Ì\82É\90G\82ê\82é\82Ì\82Í\92v\96½\93I\82È\8aÔ\88á\82¢\82¾\81D\81D\81D", kbuf);
         /* normalize body shape here; hand, not body_part(HAND) */
+/*JP
         Sprintf(kbuf, "touching %s bare-handed", killer_xname(otmp));
+*/
+        Sprintf(kbuf, "%s\82Ì\8e\80\91Ì\82É\90G\82ê\82Ä", killer_xname(otmp));
         /* will call polymon() for the poly_when_stoned() case */
         instapetrify(kbuf);
     }
@@ -2884,30 +3937,44 @@ struct obj *obj;
     return;
 }
 
-/* returns TRUE if obj  & otmp can be merged */
-STATIC_OVL boolean
+/* returns TRUE if obj & otmp can be merged; used in invent.c and mkobj.c */
+boolean
 mergable(otmp, obj)
 register struct obj *otmp, *obj;
 {
     int objnamelth = 0, otmpnamelth = 0;
-    if (obj == otmp)
-        return FALSE; /* already the same object */
-    if (obj->otyp != otmp->otyp)
+
+    /* fail if already the same object, if different types, if either is
+       explicitly marked to prevent merge, or if not mergable in general */
+    if (obj == otmp || obj->otyp != otmp->otyp
+        || obj->nomerge || otmp->nomerge || !objects[obj->otyp].oc_merge)
         return FALSE;
+
     /* coins of the same kind will always merge */
     if (obj->oclass == COIN_CLASS)
         return TRUE;
+
     if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe
-        || obj->dknown != otmp->dknown
-        || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST))
         || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed
         || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken
         || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit
-        || obj->greased != otmp->greased || obj->oeroded != otmp->oeroded
-        || obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass)
+        || obj->bypass != otmp->bypass)
         return FALSE;
 
-    if (obj->nomerge) /* explicitly marked to prevent merge */
+    if (obj->globby)
+        return TRUE;
+    /* Checks beyond this point either aren't applicable to globs
+     * or don't inhibit their merger.
+     */
+
+    if (obj->oclass == FOOD_CLASS
+        && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
+        return FALSE;
+
+    if (obj->dknown != otmp->dknown
+        || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST))
+        || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2
+        || obj->greased != otmp->greased)
         return FALSE;
 
     if ((obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS)
@@ -2915,10 +3982,6 @@ register struct obj *otmp, *obj;
             || obj->rknown != otmp->rknown))
         return FALSE;
 
-    if (obj->oclass == FOOD_CLASS
-        && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten))
-        return FALSE;
-
     if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
         if (obj->corpsenm != otmp->corpsenm)
             return FALSE;
@@ -2973,10 +4036,17 @@ doprgold()
     /* the messages used to refer to "carrying gold", but that didn't
        take containers into account */
     long umoney = money_cnt(invent);
+
     if (!umoney)
+/*JP
         Your("wallet is empty.");
+*/
+        Your("\8dà\95z\82Í\8bó\82Á\82Û\82¾\81D");
     else
+/*JP
         Your("wallet contains %ld %s.", umoney, currency(umoney));
+*/
+        Your("\8dà\95z\82É\82Í%ld%s\93ü\82Á\82Ä\82¢\82é\81D", umoney, currency(umoney));
     shopper_financial_report();
     return 0;
 }
@@ -2986,7 +4056,10 @@ int
 doprwep()
 {
     if (!uwep) {
+/*JP
         You("are empty %s.", body_part(HANDED));
+*/
+        if(!uwep) You("%s\82É\95\90\8aí\82ð\82à\82Á\82Ä\82¢\82È\82¢\81D", body_part(HAND));
     } else {
         prinv((char *) 0, uwep, 0L);
         if (u.twoweap)
@@ -3001,11 +4074,15 @@ noarmor(report_uskin)
 boolean report_uskin;
 {
     if (!uskin || !report_uskin) {
+/*JP
         You("are not wearing any armor.");
+*/
+        You("\8aZ\82ð\92\85\82Ä\82¢\82È\82¢\81D");
     } else {
         char *p, *uskinname, buf[BUFSZ];
 
         uskinname = strcpy(buf, simpleonames(uskin));
+#if 0 /*JP*/
         /* shorten "set of <color> dragon scales" to "<color> scales"
            and "<color> dragon scale mail" to "<color> scale mail" */
         if (!strncmpi(uskinname, "set of ", 7))
@@ -3013,8 +4090,15 @@ boolean report_uskin;
         if ((p = strstri(uskinname, " dragon ")) != 0)
             while ((p[1] = p[8]) != '\0')
                 ++p;
+#else /*\81u<\90F>\83h\83\89\83S\83\93\82Ì\97Ø\81v\82ð\81u<\90F>\82Ì\97Ø\81v\82É\82·\82é*/
+        if ((p = strstri(uskinname, "\83h\83\89\83S\83\93\82Ì\97Ø")) != 0)
+            strcpy(p, "\97Ø");
+#endif
 
+/*JP
         You("are not wearing armor but have %s embedded in your skin.",
+*/
+        You("\82Í\8aZ\82ð\92\85\82Ä\82¢\82È\82¢\82ª\81C%s\82ª\94§\82É\96\84\82ß\8d\9e\82Ü\82ê\82Ä\82¢\82é\81D",
             uskinname);
     }
 }
@@ -3059,7 +4143,10 @@ int
 doprring()
 {
     if (!uleft && !uright)
+/*JP
         You("are not wearing any rings.");
+*/
+        You("\8ew\97Ö\82ð\90g\82É\82Â\82¯\82Ä\82¢\82È\82¢\81D");
     else {
         char lets[3];
         register int ct = 0;
@@ -3079,7 +4166,10 @@ int
 dopramulet()
 {
     if (!uamul)
+/*JP
         You("are not wearing an amulet.");
+*/
+        You("\96\82\8f\9c\82¯\82ð\90g\82É\82Â\82¯\82Ä\82¢\82È\82¢\81D");
     else
         prinv((char *) 0, uamul, 0L);
     return 0;
@@ -3110,7 +4200,10 @@ doprtool()
             lets[ct++] = obj_to_let(otmp);
     lets[ct] = '\0';
     if (!ct)
+/*JP
         You("are not using any tools.");
+*/
+        You("\8eg\82¦\82é\93¹\8bï\82ð\82à\82Á\82Ä\82¢\82È\82¢\81D");
     else
         (void) display_inventory(lets, FALSE);
     return 0;
@@ -3130,7 +4223,10 @@ doprinuse()
             lets[ct++] = obj_to_let(otmp);
     lets[ct] = '\0';
     if (!ct)
+/*JP
         You("are not wearing or wielding anything.");
+*/
+        You("\89½\82à\92\85\82Ä\82¢\82È\82¢\82µ\81C\91\95\94õ\82µ\82Ä\82¢\82È\82¢\81D");
     else
         (void) display_inventory(lets, FALSE);
     return 0;
@@ -3169,17 +4265,24 @@ long numused;
  * This must match the object class order.
  */
 STATIC_VAR NEARDATA const char *names[] = {
+#if 0 /*JP*/
     0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools",
     "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins",
     "Gems/Stones", "Boulders/Statues", "Iron balls", "Chains", "Venoms"
+#else
+    0, "\96­\82È\95¨\91Ì", "\95\90\8aí", "\8aZ", "\8ew\97Ö", "\96\82\8f\9c\82¯", "\93¹\8bï",
+    "\90H\97¿", "\96ò", "\8aª\95¨", "\96\82\96@\8f\91", "\8fñ", "\8bà\89Ý",
+    "\95ó\90Î", "\8aâ\82Ü\82½\82Í\92¤\91\9c", "\93S\8b\85", "\8d½", "\93Å"
+#endif
 };
+STATIC_VAR NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
+/*JP
+STATIC_VAR NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
+*/
+STATIC_VAR NEARDATA const char *oth_names[] = { "\8bl\82ß\82ç\82ê\82½\93¹\8bï" };
 
-static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' };
-
-static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" };
-
-static NEARDATA char *invbuf = (char *) 0;
-static NEARDATA unsigned invbufsiz = 0;
+STATIC_VAR NEARDATA char *invbuf = (char *) 0;
+STATIC_VAR NEARDATA unsigned invbufsiz = 0;
 
 char *
 let_to_name(let, unpaid, showsym)
@@ -3200,7 +4303,10 @@ boolean unpaid, showsym;
     else
         class_name = names[0];
 
+/*JP
     len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "")
+*/
+    len = strlen(class_name) + (unpaid ? sizeof "\96¢\95¥\82¢\82Ì" : sizeof "")
           + (oclass ? (strlen(ocsymfmt) + invbuf_sympadding) : 0);
     if (len > invbufsiz) {
         if (invbuf)
@@ -3209,7 +4315,10 @@ boolean unpaid, showsym;
         invbuf = (char *) alloc(invbufsiz);
     }
     if (unpaid)
+/*JP
         Strcat(strcpy(invbuf, "Unpaid "), class_name);
+*/
+        Strcat(strcpy(invbuf, "\96¢\95¥\82¢\82Ì"), class_name);
     else
         Strcpy(invbuf, class_name);
     if ((oclass != 0) && showsym) {
@@ -3274,10 +4383,18 @@ reassign()
  *      then a 'to' slot for its destination.  Open slots and those
  *      filled by compatible stacks are listed as likely candidates
  *      but user can pick any inventory letter (including 'from').
- *      All compatible items found are gathered into the 'from'
- *      stack as it is moved.  If the 'to' slot isn't empty and
- *      doesn't merge, then its stack is swapped to the 'from' slot.
  *
+ *  to == from, 'from' has a name
+ *      All compatible items (same name or no name) are gathered
+ *      into the 'from' stack.  No count is allowed.
+ *  to == from, 'from' does not have a name
+ *      All compatible items without a name are gathered into the
+ *      'from' stack.  No count is allowed.  Compatible stacks with
+ *      names are left as-is.
+ *  to != from, no count
+ *      Move 'from' to 'to'.  If 'to' is not empty, merge 'from'
+ *      into it if possible, otherwise swap it with the 'from' slot.
+ *  to != from, count given
  *      If the user specifies a count when choosing the 'from' slot,
  *      and that count is less than the full size of the stack,
  *      then the stack will be split.  The 'count' portion is moved
@@ -3287,24 +4404,41 @@ reassign()
  *      will be moved to an open slot; if there isn't any open slot
  *      available, the adjustment attempt fails.
  *
- *      Splitting has one special case:  if 'to' slot is non-empty
- *      and is compatible with 'from' in all respects except for
- *      user-assigned names, the 'count' portion being moved is
- *      effectively renamed so that it will merge with 'to' stack.
+ *      To minimize merging for 'from == to', unnamed stacks will
+ *      merge with named 'from' but named ones won't merge with
+ *      unnamed 'from'.  Otherwise attempting to collect all unnamed
+ *      stacks would lump the first compatible named stack with them
+ *      and give them its name.
+ *
+ *      To maximize merging for 'from != to', compatible stacks will
+ *      merge when either lacks a name (or they already have the same
+ *      name).  When no count is given and one stack has a name and
+ *      the other doesn't, the merged result will have that name.
+ *      However, when splitting results in a merger, the name of the
+ *      destination overrides that of the source, even if destination
+ *      is unnamed and source is named.
  */
 int
 doorganize() /* inventory organizer by Del Lamb */
 {
     struct obj *obj, *otmp, *splitting, *bumped;
-    int ix, cur, trycnt;
+    int ix, cur, trycnt, goldstacks;
     char let;
-    char alphabet[52 + 1], buf[52 + 1];
+#define GOLD_INDX   0
+#define GOLD_OFFSET 1
+#define OVRFLW_INDX (GOLD_OFFSET + 52) /* past gold and 2*26 letters */
+    char lets[1 + 52 + 1 + 1]; /* room for '$a-zA-Z#\0' */
     char qbuf[QBUFSZ];
-    char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */
+    char allowall[4]; /* { ALLOW_COUNT, ALL_CLASSES, 0, 0 } */
+    char *objname, *otmpname;
     const char *adj_type;
+    boolean ever_mind = FALSE, collect;
 
     if (!invent) {
+/*JP
         You("aren't carrying anything to adjust.");
+*/
+        You("\8f\87\8f\98\82ð\95Ï\82¦\82é\82à\82Ì\82ð\89½\82à\8e\9d\82Á\82Ä\82¢\82È\82¢\81D");
         return 0;
     }
 
@@ -3314,6 +4448,20 @@ doorganize() /* inventory organizer by Del Lamb */
     allowall[0] = ALLOW_COUNT;
     allowall[1] = ALL_CLASSES;
     allowall[2] = '\0';
+    for (goldstacks = 0, otmp = invent; otmp; otmp = otmp->nobj) {
+        /* gold should never end up in a letter slot, nor should two '$'
+           slots occur, but if they ever do, allow #adjust to handle them
+           (in the past, things like this have happened, usually due to
+           bknown being erroneously set on one stack, clear on another;
+           object merger isn't fooled by that anymore) */
+        if (otmp->oclass == COIN_CLASS
+            && (otmp->invlet != GOLD_SYM || ++goldstacks > 1)) {
+            allowall[1] = COIN_CLASS;
+            allowall[2] = ALL_CLASSES;
+            allowall[3] = '\0';
+            break;
+        }
+    }
     if (!(obj = getobj(allowall, "adjust")))
         return 0;
 
@@ -3327,40 +4475,49 @@ doorganize() /* inventory organizer by Del Lamb */
         }
 
     /* initialize the list with all lower and upper case letters */
-    for (ix = 0, let = 'a'; let <= 'z';)
-        alphabet[ix++] = let++;
+    lets[GOLD_INDX] = (obj->oclass == COIN_CLASS) ? GOLD_SYM : ' ';
+    for (ix = GOLD_OFFSET, let = 'a'; let <= 'z';)
+        lets[ix++] = let++;
     for (let = 'A'; let <= 'Z';)
-        alphabet[ix++] = let++;
-    alphabet[ix] = '\0';
+        lets[ix++] = let++;
+    lets[OVRFLW_INDX] = ' ';
+    lets[sizeof lets - 1] = '\0';
     /* for floating inv letters, truncate list after the first open slot */
     if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52)
-        alphabet[ix + (splitting ? 0 : 1)] = '\0';
+        lets[ix + (splitting ? 0 : 1)] = '\0';
 
-    /* blank out all the letters currently in use in the inventory */
-    /* except those that will be merged with the selected object   */
+    /* blank out all the letters currently in use in the inventory
+       except those that will be merged with the selected object */
     for (otmp = invent; otmp; otmp = otmp->nobj)
         if (otmp != obj && !mergable(otmp, obj)) {
             let = otmp->invlet;
             if (let >= 'a' && let <= 'z')
-                alphabet[let - 'a'] = ' ';
+                lets[GOLD_OFFSET + let - 'a'] = ' ';
             else if (let >= 'A' && let <= 'Z')
-                alphabet[let - 'A' + 26] = ' ';
+                lets[GOLD_OFFSET + let - 'A' + 26] = ' ';
+            /* overflow defaults to off, but it we find a stack using that
+               slot, switch to on -- the opposite of normal invlet handling */
+            else if (let == NOINVSYM)
+                lets[OVRFLW_INDX] = NOINVSYM;
         }
 
     /* compact the list by removing all the blanks */
-    for (ix = cur = 0; alphabet[ix]; ix++)
-        if (alphabet[ix] != ' ')
-            buf[cur++] = alphabet[ix];
-    if (!cur && obj->invlet == NOINVSYM)
-        buf[cur++] = NOINVSYM;
-    buf[cur] = '\0';
+    for (ix = cur = 0; lets[ix]; ix++)
+        if (lets[ix] != ' ' && cur++ < ix)
+            lets[cur - 1] = lets[ix];
+    lets[cur] = '\0';
     /* and by dashing runs of letters */
     if (cur > 5)
-        compactify(buf);
+        compactify(lets);
 
     /* get 'to' slot to use as destination */
-    Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf,
+#if 0 /*JP:T*/
+    Sprintf(qbuf, "Adjust letter to what [%s]%s?", lets,
             invent ? " (? see used letters)" : "");
+#else
+    Sprintf(qbuf, "\82Ç\82Ì\95\8e\9a\82É\92²\90®\82µ\82Ü\82·\82©[%s]%s\81H", lets,
+            invent ? " (? \82Å\8eg\82Á\82Ä\82¢\82é\95\8e\9a\82ð\95\\8e¦)" : "");
+#endif
     for (trycnt = 1; ; ++trycnt) {
         let = yn_function(qbuf, (char *) 0, '\0');
         if (let == '?' || let == '*') {
@@ -3375,21 +4532,43 @@ doorganize() /* inventory organizer by Del Lamb */
                compatible stacks get collected along the way,
                but splitting to same slot is not */
             || (splitting && let == obj->invlet)) {
       noadjust:
+ noadjust:
             if (splitting)
                 (void) merged(&splitting, &obj);
-            pline1(Never_mind);
+            if (!ever_mind)
+                pline1(Never_mind);
             return 0;
+        } else if (let == GOLD_SYM && obj->oclass != COIN_CLASS) {
+#if 0 /*JP*/
+            pline("Only gold coins may be moved into the '%c' slot.",
+                  GOLD_SYM);
+#else
+            pline("'%c'\82É\82Å\82«\82é\82Ì\82Í\8bà\89Ý\82¾\82¯\81D",
+                  GOLD_SYM);
+#endif
+            ever_mind = TRUE;
+            goto noadjust;
         }
-        if ((letter(let) && let != '@') || index(buf, let))
+        /* letter() classifies '@' as one; compactify() can put '-' in lets;
+           the only thing of interest that index() might find is '$' or '#'
+           since letter() catches everything else that we put into lets[] */
+        if ((letter(let) && let != '@') || (index(lets, let) && let != '-'))
             break; /* got one */
         if (trycnt == 5)
             goto noadjust;
+#if 0 /*JP*/
         pline("Select an inventory slot letter."); /* else try again */
+#else
+        pline("\8e\9d\82¿\95¨\82Ì\95\8e\9a\82ð\91I\82ñ\82Å\82­\82¾\82³\82¢\81D");
+#endif
     }
 
+    collect = (let == obj->invlet);
     /* change the inventory and print the resulting item */
-    adj_type = !splitting ? "Moving:" : "Splitting:";
+/*JP
+    adj_type = collect ? "Collecting" : !splitting ? "Moving:" : "Splitting:";
+*/
+    adj_type = collect ? "\82ð\8fW\82ß\82½\81D" : !splitting ? "\82ð\88Ú\93®\82µ\82½\81D" : "\82ð\95ª\8a\84\82µ\82½\81D";
 
     /*
      * don't use freeinv/addinv to avoid double-touching artifacts,
@@ -3398,55 +4577,75 @@ doorganize() /* inventory organizer by Del Lamb */
     extract_nobj(obj, &invent);
 
     for (otmp = invent; otmp;) {
-        if (!splitting) {
-            if (merged(&otmp, &obj)) {
+        /* it's tempting to pull this outside the loop, but merged() could
+           free ONAME(obj) [via obfree()] and replace it with ONAME(otmp) */
+        objname = has_oname(obj) ? ONAME(obj) : (char *) 0;
+
+        if (collect) {
+            /* Collecting: #adjust an inventory stack into its same slot;
+               keep it there and merge other compatible stacks into it.
+               Traditional inventory behavior is to merge unnamed stacks
+               with compatible named ones; we only want that if it is
+               the 'from' stack (obj) with a name and candidate (otmp)
+               without one, not unnamed 'from' with named candidate. */
+            otmpname = has_oname(otmp) ? ONAME(otmp) : (char *) 0;
+            if ((!otmpname || (objname && !strcmp(objname, otmpname)))
+                && merged(&otmp, &obj)) {
+/*JP
                 adj_type = "Merging:";
+*/
+                adj_type = "\82ð\8d\87\82í\82¹\82½\81D";
                 obj = otmp;
                 otmp = otmp->nobj;
                 extract_nobj(obj, &invent);
                 continue; /* otmp has already been updated */
-            } else if (otmp->invlet == let) {
+            }
+        } else if (otmp->invlet == let) {
+            /* Moving or splitting: don't merge extra compatible stacks.
+               Found 'otmp' in destination slot; merge if compatible,
+               otherwise bump whatever is there to an open slot. */
+            if (!splitting) {
+/*JP
                 adj_type = "Swapping:";
+*/
+                adj_type = "\82ð\8cð\8a·\82µ\82½\81D";
                 otmp->invlet = obj->invlet;
-            }
-        } else {
-            /* splitting: don't merge extra compatible stacks;
-               if destination is compatible, do merge with it,
-               otherwise bump whatever is there to an open slot */
-            if (otmp->invlet == let) {
-                int olth = 0;
-
-                if (has_oname(obj))
-                    olth = strlen(ONAME(obj));
-                /* ugly hack:  if these objects aren't going to merge
-                   solely because they have conflicting user-assigned
-                   names, strip off the name of the one being moved */
-                if (olth && !obj->oartifact && !mergable(otmp, obj)) {
-                    char *holdname = ONAME(obj);
+            } else {
+                /* strip 'from' name if it has one */
+                if (objname && !obj->oartifact)
                     ONAME(obj) = (char *) 0;
-                    /* restore name iff merging is still not possible */
-                    if (!mergable(otmp, obj)) {
-                        ONAME(obj) = holdname;
-                        holdname = (char *) 0;
-                    } else
-                        free((genericptr_t) holdname);
+                if (!mergable(otmp, obj)) {
+                    /* won't merge; put 'from' name back */
+                    if (objname)
+                        ONAME(obj) = objname;
+                } else {
+                    /* will merge; discard 'from' name */
+                    if (objname)
+                        free((genericptr_t) objname), objname = 0;
                 }
 
                 if (merged(&otmp, &obj)) {
+/*JP
+                    adj_type = "Splitting and merging:";
+*/
+                    adj_type = "\82ð\95ª\8a\84\82µ\82Ä\8d\87\82í\82¹\82½\81D";
                     obj = otmp;
                     extract_nobj(obj, &invent);
                 } else if (inv_cnt(FALSE) >= 52) {
                     (void) merged(&splitting, &obj); /* undo split */
                     /* "knapsack cannot accommodate any more items" */
+/*JP
                     Your("pack is too full.");
+*/
+                    Your("\8e\9d\82¿\95¨\82Í\88ê\94t\82¾\81D");
                     return 0;
                 } else {
                     bumped = otmp;
                     extract_nobj(bumped, &invent);
                 }
-                break;
-            } /* found 'to' slot */
-        }     /* splitting */
+            } /* moving vs splitting */
+            break; /* not collecting and found 'to' slot */
+        } /* collect */
         otmp = otmp->nobj;
     }
 
@@ -3470,7 +4669,10 @@ doorganize() /* inventory organizer by Del Lamb */
     /* messages deferred until inventory has been fully reestablished */
     prinv(adj_type, obj, 0L);
     if (bumped)
+/*JP
         prinv("Moving:", bumped, 0L);
+*/
+        prinv("\88Ú\93®:", bumped, 0L);
     if (splitting)
         clear_splitobjs(); /* reset splitobj context */
     update_inventory();
@@ -3529,8 +4731,10 @@ struct obj *obj;
  * By default, only worn and wielded items are displayed.  The caller
  * can pick one.  Modifier flags are:
  *
- *      MINV_NOLET      - nothing selectable
- *      MINV_ALL        - display all inventory
+ *      PICK_NONE, PICK_ONE - standard menu control
+ *      PICK_ANY            - allowed, but we only return a single object
+ *      MINV_NOLET          - nothing selectable
+ *      MINV_ALL            - display all inventory
  */
 struct obj *
 display_minventory(mon, dflags, title)
@@ -3544,26 +4748,38 @@ char *title;
     menu_item *selected = 0;
     int do_all = (dflags & MINV_ALL) != 0,
         incl_hero = (do_all && u.uswallow && mon == u.ustuck),
-        have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero);
+        have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero),
+        pickings = (dflags & MINV_PICKMASK);
 
+#if 0 /*JP*/
     Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
             do_all ? "possessions" : "armament");
+#else
+    Sprintf(tmp, "%s\82Ì%s\81F", Monnam(mon),
+            do_all ? "\8e\9d\82¿\95¨" : "\91\95\94õ");
+#endif
 
     if (do_all ? have_any : (mon->misc_worn_check || MON_WEP(mon))) {
         /* Fool the 'weapon in hand' routine into
          * displaying 'weapon in claw', etc. properly.
          */
         youmonst.data = mon->data;
+        /* in case inside a shop, don't append "for sale" prices */
+        iflags.suppress_price++;
 
-        n = query_objlist(title ? title : tmp, mon->minvent,
-                          INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0),
-                          &selected,
-                          (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
+        n = query_objlist(title ? title : tmp, &(mon->minvent),
+                          (INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0)),
+                          &selected, pickings,
                           do_all ? allow_all : worn_wield_only);
 
-        set_uasmon();
+        iflags.suppress_price--;
+        /* was 'set_uasmon();' but that potentially has side-effects */
+        youmonst.data = &mons[u.umonnum]; /* most basic part of set_uasmon */
     } else {
+/*JP
         invdisp_nothing(title ? title : tmp, "(none)");
+*/
+        invdisp_nothing(title ? title : tmp, "(\89½\82à\82È\82¢)");
         n = 0;
     }
 
@@ -3588,14 +4804,22 @@ register struct obj *obj;
     int n;
     menu_item *selected = 0;
 
+#if 0 /*JP*/
     (void) safe_qbuf(qbuf, "Contents of ", ":", obj, doname, ansimpleoname,
                      "that");
+#else
+    (void) safe_qbuf(qbuf, "", "\82Ì\92\86\90g\81F", obj, doname, ansimpleoname,
+                     "\82»");
+#endif
 
     if (obj->cobj) {
-        n = query_objlist(qbuf, obj->cobj, INVORDER_SORT, &selected,
-                          PICK_NONE, allow_all);
+        n = query_objlist(qbuf, &(obj->cobj), INVORDER_SORT,
+                          &selected, PICK_NONE, allow_all);
     } else {
+/*JP
         invdisp_nothing(qbuf, "(empty)");
+*/
+        invdisp_nothing(qbuf, "(\8bó\82Á\82Û)");
         n = 0;
     }
     if (n > 0) {
@@ -3643,8 +4867,12 @@ boolean as_if_seen;
     if (n) {
         only.x = x;
         only.y = y;
-        if (query_objlist("Things that are buried here:", level.buriedobjlist,
-                          INVORDER_SORT, &selected, PICK_NONE, only_here) > 0)
+/*JP
+        if (query_objlist("Things that are buried here:",
+*/
+        if (query_objlist("\82±\82±\82É\96\84\82ß\82ç\82ê\82Ä\82¢\82é\82à\82Ì\81F",
+                          &level.buriedobjlist, INVORDER_SORT,
+                          &selected, PICK_NONE, only_here) > 0)
             free((genericptr_t) selected);
         only.x = only.y = 0;
     }