OSDN Git Service

update year to 2023
[jnethack/source.git] / src / do_wear.c
index 8c76f0a..e7cf3cc 100644 (file)
@@ -1,17 +1,20 @@
-/* NetHack 3.6 do_wear.c       $NHDT-Date: 1446975698 2015/11/08 09:41:38 $  $NHDT-Branch: master $:$NHDT-Revision: 1.87 $ */
+/* NetHack 3.6 do_wear.c       $NHDT-Date: 1575214670 2019/12/01 15:37:50 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.116 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Robert Patrick Rankin, 2012. */
 /* NetHack may be freely redistributed.  See license for details. */
 
 /* JNetHack Copyright */
 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016            */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2023            */
 /* JNetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
 
+#if 0 /*JP*//*\96¢\8eg\97p*/
 static NEARDATA const char see_yourself[] = "see yourself";
+#endif
 static NEARDATA const char unknown_type[] = "Unknown type of %s (%d)";
-#if 0 /*JP*/
+#if 0 /*JP:T*/
 static NEARDATA const char c_armor[] = "armor", c_suit[] = "suit",
                            c_shirt[] = "shirt", c_cloak[] = "cloak",
                            c_gloves[] = "gloves", c_boots[] = "boots",
@@ -37,7 +40,7 @@ STATIC_DCL void FDECL(on_msg, (struct obj *));
 STATIC_DCL void FDECL(toggle_stealth, (struct obj *, long, BOOLEAN_P));
 STATIC_DCL void FDECL(toggle_displacement, (struct obj *, long, BOOLEAN_P));
 STATIC_PTR int NDECL(Armor_on);
-STATIC_PTR int NDECL(Boots_on);
+/* int NDECL(Boots_on); -- moved to extern.h */
 STATIC_PTR int NDECL(Cloak_on);
 STATIC_PTR int NDECL(Helmet_on);
 STATIC_PTR int NDECL(Gloves_on);
@@ -61,6 +64,16 @@ STATIC_DCL void FDECL(already_wearing, (const char*, struct obj *));
 #endif
 STATIC_DCL void FDECL(already_wearing2, (const char *, const char *));
 
+/* plural "fingers" or optionally "gloves" */
+const char *
+fingers_or_gloves(check_gloves)
+boolean check_gloves;
+{
+    return ((check_gloves && uarmg)
+            ? gloves_simple_name(uarmg) /* "gloves" or "gauntlets" */
+            : makeplural(body_part(FINGER))); /* "fingers" */
+}
+
 void
 off_msg(otmp)
 struct obj *otmp;
@@ -182,11 +195,11 @@ boolean on;
                 || Detect_monsters))) {
         makeknown(obj->otyp);
 
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         You_feel("that monsters%s have difficulty pinpointing your location.",
                  on ? "" : " no longer");
 #else
-        You_feel("\89ö\95¨\82Í\82 \82È\82½\82Ì\88Ê\92u\82ª\82Í\82Á\82«\82è\82Æ\95ª\82©%s\82È\82Á\82½\82æ\82¤\82¾\81D",
+        pline("\89ö\95¨\82Í\82 \82È\82½\82Ì\88Ê\92u\82ª\82Í\82Á\82«\82è\82Æ\95ª\82©%s\82È\82Á\82½\82æ\82¤\82¾\81D",
                  on ? "\82ç\82È\82­" : "\82é\82æ\82¤\82É");
 #endif
     }
@@ -198,7 +211,6 @@ boolean on;
  * [Blindf_on() is an exception and calls setworn() itself.]
  */
 
-STATIC_PTR
 int
 Boots_on(VOID_ARGS)
 {
@@ -223,7 +235,7 @@ Boots_on(VOID_ARGS)
         /* though not better than potion speed */
         if (!oldprop && !(HFast & TIMEOUT)) {
             makeknown(uarmf->otyp);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             You_feel("yourself speed up%s.",
                      (oldprop || HFast) ? " a bit more" : "");
 #else
@@ -240,17 +252,25 @@ Boots_on(VOID_ARGS)
             incr_itimeout(&HFumbling, rnd(20));
         break;
     case LEVITATION_BOOTS:
-        if (!oldprop && !HLevitation && !BLevitation) {
+        if (!oldprop && !HLevitation && !(BLevitation & FROMOUTSIDE)) {
+            uarmf->known = 1; /* might come off if putting on over a sink,
+                               * so uarmf could be Null below; status line
+                               * gets updated during brief interval they're
+                               * worn so hero and player learn enchantment */
+            context.botl = 1; /* status hilites might mark AC changed */
             makeknown(uarmf->otyp);
             float_up();
-            spoteffects(FALSE);
+            if (Levitation)
+                spoteffects(FALSE); /* for sink effect */
         } else {
-            float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */
+            float_vs_flight(); /* maybe toggle BFlying's I_SPECIAL */
         }
         break;
     default:
         impossible(unknown_type, c_boots, uarmf->otyp);
     }
+    if (uarmf) /* could be Null here (levitation boots put on over a sink) */
+        uarmf->known = 1; /* boots' +/- evident because of status line AC */
     return 0;
 }
 
@@ -296,7 +316,7 @@ Boots_off(VOID_ARGS)
             HFumbling = EFumbling = 0;
         break;
     case LEVITATION_BOOTS:
-        if (!oldprop && !HLevitation && !BLevitation
+        if (!oldprop && !HLevitation && !(BLevitation & FROMOUTSIDE)
             && !context.takeoff.cancelled_don) {
             (void) float_down(0L, 0L);
             makeknown(otyp);
@@ -343,7 +363,7 @@ Cloak_on(VOID_ARGS)
         /* Note: it's already being worn, so we have to cheat here. */
         if ((HInvis || EInvis) && !Blind) {
             newsym(u.ux, u.uy);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             You("can %s!", See_invisible ? "no longer see through yourself"
                                          : see_yourself);
 #else
@@ -359,7 +379,7 @@ Cloak_on(VOID_ARGS)
         if (!oldprop && !HInvis && !Blind) {
             makeknown(uarmc->otyp);
             newsym(u.ux, u.uy);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("Suddenly you can%s yourself.",
                   See_invisible ? " see through" : "not see");
 #else
@@ -381,6 +401,8 @@ Cloak_on(VOID_ARGS)
     default:
         impossible(unknown_type, c_cloak, uarmc->otyp);
     }
+    if (uarmc) /* no known instance of !uarmc here but play it safe */
+        uarmc->known = 1; /* cloak's +/- evident because of status line AC */
     return 0;
 }
 
@@ -412,7 +434,7 @@ Cloak_off(VOID_ARGS)
     case MUMMY_WRAPPING:
         if (Invis && !Blind) {
             newsym(u.ux, u.uy);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             You("can %s.", See_invisible ? "see through yourself"
                                          : "no longer see yourself");
 #else
@@ -425,7 +447,7 @@ Cloak_off(VOID_ARGS)
         if (!oldprop && !HInvis && !Blind) {
             makeknown(CLOAK_OF_INVISIBILITY);
             newsym(u.ux, u.uy);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("Suddenly you can %s.",
                   See_invisible ? "no longer see through yourself"
                                 : see_yourself);
@@ -463,23 +485,24 @@ Helmet_on(VOID_ARGS)
         adj_abon(uarmh, uarmh->spe);
         break;
     case CORNUTHAUM:
-        /* people think marked wizards know what they're talking
-         * about, but it takes trained arrogance to pull it off,
-         * and the actual enchantment of the hat is irrelevant.
-         */
+        /* people think marked wizards know what they're talking about,
+           but it takes trained arrogance to pull it off, and the actual
+           enchantment of the hat is irrelevant */
         ABON(A_CHA) += (Role_if(PM_WIZARD) ? 1 : -1);
         context.botl = 1;
         makeknown(uarmh->otyp);
         break;
     case HELM_OF_OPPOSITE_ALIGNMENT:
-        /* changing alignment can toggle off active artifact
-           properties, including levitation; uarmh could get
-           dropped or destroyed here */
+        uarmh->known = 1; /* do this here because uarmh could get cleared */
+        /* changing alignment can toggle off active artifact properties,
+           including levitation; uarmh could get dropped or destroyed here
+           by hero falling onto a polymorph trap or into water (emergency
+           disrobe) or maybe lava (probably not, helm isn't 'organic') */
         uchangealign((u.ualign.type != A_NEUTRAL)
                          ? -u.ualign.type
                          : (uarmh->o_id % 2) ? A_CHAOTIC : A_LAWFUL,
                      1);
-    /* makeknown(uarmh->otyp);   -- moved below, after xname() */
+        /* makeknown(HELM_OF_OPPOSITE_ALIGNMENT); -- below, after Tobjnam() */
     /*FALLTHRU*/
     case DUNCE_CAP:
         if (uarmh && !uarmh->cursed) {
@@ -489,24 +512,24 @@ Helmet_on(VOID_ARGS)
 */
                 pline("%s\82Í\88ê\8fu\90k\82¦\82½\81D", xname(uarmh));
             else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("%s %s for a moment.", Tobjnam(uarmh, "glow"),
                       hcolor(NH_BLACK));
 #else
                 pline("%s\82Í\88ê\8fu%s\8bP\82¢\82½\81D",
-                      xname(uarmh), jconj_adj(hcolor(NH_BLACK)));
+                      xname(uarmh), hcolor_adv(NH_BLACK));
 #endif
             curse(uarmh);
         }
         context.botl = 1; /* reveal new alignment or INT & WIS */
         if (Hallucination) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("My brain hurts!"); /* Monty Python's Flying Circus */
 #else
             pline("\82Ì\81[\82Ý\82»\83o\81[\83\93\81I"); /*\83\82\83\93\83e\83B\83p\83C\83\\83\93\82Æ\82Í\82¿\82å\82Á\82Æ\88á\82¤\82¯\82Ç*/
 #endif
         } else if (uarmh && uarmh->otyp == DUNCE_CAP) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             You_feel("%s.", /* track INT change; ignore WIS */
                      ACURR(A_INT)
                              <= (ABASE(A_INT) + ABON(A_INT) + ATEMP(A_INT))
@@ -520,13 +543,16 @@ Helmet_on(VOID_ARGS)
                          : "\96Ú\82ª\82Ü\82í\82Á\82½");
 #endif
         } else {
-            /* [message moved to uchangealign()] */
+            /* [message formerly given here moved to uchangealign()] */
             makeknown(HELM_OF_OPPOSITE_ALIGNMENT);
         }
         break;
     default:
         impossible(unknown_type, c_helmet, uarmh->otyp);
     }
+    /* uarmh could be Null due to uchangealign() */
+    if (uarmh)
+        uarmh->known = 1; /* helmet's +/- evident because of status line AC */
     return 0;
 }
 
@@ -599,6 +625,8 @@ Gloves_on(VOID_ARGS)
     default:
         impossible(unknown_type, c_gloves, uarmg->otyp);
     }
+    if (uarmg) /* no known instance of !uarmg here but play it safe */
+        uarmg->known = 1; /* gloves' +/- evident because of status line AC */
     return 0;
 }
 
@@ -615,7 +643,7 @@ boolean voluntary; /* taking gloves off on purpose? */
         return;
 
     if (touch_petrifies(&mons[obj->corpsenm]) && !Stone_resistance) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         You("now wield %s in your bare %s.",
             corpse_xname(obj, (const char *) 0, CXN_ARTICLE),
             makeplural(body_part(HAND)));
@@ -624,7 +652,7 @@ boolean voluntary; /* taking gloves off on purpose? */
             corpse_xname(obj, (const char *) 0, CXN_ARTICLE),
             body_part(HAND));
 #endif
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(kbuf, "%s gloves while wielding %s",
                 voluntary ? "removing" : "losing", killer_xname(obj));
 #else
@@ -668,6 +696,14 @@ Gloves_off(VOID_ARGS)
     context.takeoff.cancelled_don = FALSE;
     (void) encumber_msg(); /* immediate feedback for GoP */
 
+    /* usually can't remove gloves when they're slippery but it can
+       be done by having them fall off (polymorph), stolen, or
+       destroyed (scroll, overenchantment, monster spell); if that
+       happens, 'cure' slippery fingers so that it doesn't transfer
+       from gloves to bare hands */
+    if (Glib)
+        make_glib(0); /* for update_inventory() */
+
     /* prevent wielding cockatrice when not wearing gloves */
     if (uwep && uwep->otyp == CORPSE)
         wielding_corpse(uwep, on_purpose);
@@ -685,7 +721,9 @@ STATIC_PTR int
 Shield_on(VOID_ARGS)
 {
     /* no shield currently requires special handling when put on, but we
-       keep this uncommented in case somebody adds a new one which does */
+       keep this uncommented in case somebody adds a new one which does
+       [reflection is handled by setting u.uprops[REFLECTION].extrinsic
+       in setworn() called by armor_or_accessory_on() before Shield_on()] */
     switch (uarms->otyp) {
     case SMALL_SHIELD:
     case ELVEN_SHIELD:
@@ -698,7 +736,8 @@ Shield_on(VOID_ARGS)
     default:
         impossible(unknown_type, c_shield, uarms->otyp);
     }
-
+    if (uarms) /* no known instance of !uarmgs here but play it safe */
+        uarms->known = 1; /* shield's +/- evident because of status line AC */
     return 0;
 }
 
@@ -738,7 +777,8 @@ Shirt_on(VOID_ARGS)
     default:
         impossible(unknown_type, c_shirt, uarmu->otyp);
     }
-
+    if (uarmu) /* no known instances of !uarmu here but play it safe */
+        uarmu->known = 1; /* shirt's +/- evident because of status line AC */
     return 0;
 }
 
@@ -761,14 +801,17 @@ Shirt_off(VOID_ARGS)
     return 0;
 }
 
-/* This must be done in worn.c, because one of the possible intrinsics
- * conferred is fire resistance, and we have to immediately set
- * HFire_resistance in worn.c since worn.c will check it before returning.
- */
 STATIC_PTR
 int
 Armor_on(VOID_ARGS)
 {
+    /*
+     * No suits require special handling.  Special properties conferred by
+     * suits are set up as intrinsics (actually 'extrinsics') by setworn()
+     * which is called by armor_or_accessory_on() before Armor_on().
+     */
+    if (uarm) /* no known instances of !uarm here but play it safe */
+        uarm->known = 1; /* suit's +/- evident because of status line AC */
     return 0;
 }
 
@@ -782,7 +825,10 @@ Armor_off(VOID_ARGS)
 }
 
 /* The gone functions differ from the off functions in that if you die from
- * taking it off and have life saving, you still die.
+ * taking it off and have life saving, you still die.  [Obsolete reference
+ * to lack of fire resistance being fatal in hell (nethack 3.0) and life
+ * saving putting a removed item back on to prevent that from immediately
+ * repeating.]
  */
 int
 Armor_gone()
@@ -826,7 +872,7 @@ Amulet_on()
         /* Don't use same message as polymorph */
         if (orig_sex != poly_gender()) {
             makeknown(AMULET_OF_CHANGE);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             You("are suddenly very %s!",
                 flags.female ? "feminine" : "masculine");
 #else
@@ -855,11 +901,12 @@ Amulet_on()
     case AMULET_OF_STRANGULATION:
         if (can_be_strangled(&youmonst)) {
             makeknown(AMULET_OF_STRANGULATION);
+            Strangled = 6L;
+            context.botl = TRUE;
 /*JP
             pline("It constricts your throat!");
 */
             pline("\96\82\8f\9c\82¯\82Í\82 \82È\82½\82Ì\8dA\82ð\8di\82ß\82Â\82¯\82½\81I");
-            Strangled = 6L;
         }
         break;
     case AMULET_OF_RESTFUL_SLEEP: {
@@ -900,10 +947,13 @@ Amulet_off()
             setworn((struct obj *) 0, W_AMUL);
             if (!breathless(youmonst.data) && !amphibious(youmonst.data)
                 && !Swimming) {
-/*JP
-                You("suddenly inhale an unhealthy amount of water!");
-*/
-                You("\93Ë\91R\81C\91å\97Ê\82Ì\90\85\82ð\88ù\82Ý\8d\9e\82ñ\82¾\81I");
+#if 0 /*JP:T*/
+                You("suddenly inhale an unhealthy amount of %s!",
+                    hliquid("water"));
+#else
+                You("\93Ë\91R\81C\91å\97Ê\82Ì%s\82ð\88ù\82Ý\8d\9e\82ñ\82¾\81I",
+                    hliquid("\90\85"));
+#endif
                 (void) drown();
             }
             return;
@@ -911,6 +961,8 @@ Amulet_off()
         break;
     case AMULET_OF_STRANGULATION:
         if (Strangled) {
+            Strangled = 0L;
+            context.botl = TRUE;
             if (Breathless)
 /*JP
                 Your("%s is no longer constricted!", body_part(NECK));
@@ -921,7 +973,6 @@ Amulet_off()
                 You("can breathe more easily!");
 */
                 You("\8ay\82É\8cÄ\8bz\82Å\82«\82é\82æ\82¤\82É\82È\82Á\82½\81I");
-            Strangled = 0L;
         }
         break;
     case AMULET_OF_RESTFUL_SLEEP:
@@ -1039,10 +1090,11 @@ register struct obj *obj;
         }
         break;
     case RIN_LEVITATION:
-        if (!oldprop && !HLevitation && !BLevitation) {
+        if (!oldprop && !HLevitation && !(BLevitation & FROMOUTSIDE)) {
             float_up();
             learnring(obj, TRUE);
-            spoteffects(FALSE); /* for sinks */
+            if (Levitation)
+                spoteffects(FALSE); /* for sinks */
         } else {
             float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */
         }
@@ -1055,7 +1107,7 @@ register struct obj *obj;
         goto adjust_attrib;
     case RIN_ADORNMENT:
         which = A_CHA;
   adjust_attrib:
+ adjust_attrib:
         old_attrib = ACURR(which);
         ABON(which) += obj->spe;
         observable = (old_attrib != ACURR(which));
@@ -1150,7 +1202,7 @@ boolean gone;
     case RIN_INVISIBILITY:
         if (!Invis && !BInvis && !Blind) {
             newsym(u.ux, u.uy);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             Your("body seems to unfade%s.",
                  See_invisible ? " completely" : "..");
 #else
@@ -1161,7 +1213,7 @@ boolean gone;
         }
         break;
     case RIN_LEVITATION:
-        if (!BLevitation) {
+        if (!(BLevitation & FROMOUTSIDE)) {
             (void) float_down(0L, 0L);
             if (!Levitation)
                 learnring(obj, TRUE);
@@ -1177,7 +1229,7 @@ boolean gone;
         goto adjust_attrib;
     case RIN_ADORNMENT:
         which = A_CHA;
   adjust_attrib:
+ adjust_attrib:
         old_attrib = ACURR(which);
         ABON(which) -= obj->spe;
         observable = (old_attrib != ACURR(which));
@@ -1225,12 +1277,12 @@ struct obj *obj;
 
 void
 Blindf_on(otmp)
-register struct obj *otmp;
+struct obj *otmp;
 {
     boolean already_blind = Blind, changed = FALSE;
 
     /* blindfold might be wielded; release it for wearing */
-    if (otmp->owornmask & W_WEAPON)
+    if (otmp->owornmask & W_WEAPONS)
         remove_worn_item(otmp, FALSE);
     setworn(otmp, W_TOOL);
     on_msg(otmp);
@@ -1264,19 +1316,13 @@ register struct obj *otmp;
             You("\96Ú\82ª\8c©\82¦\82é\82æ\82¤\82É\82È\82Á\82½\81I");
     }
     if (changed) {
-        /* blindness has just been toggled */
-        if (Blind_telepat || Infravision)
-            see_monsters();
-        vision_full_recalc = 1; /* recalc vision limits */
-        if (!Blind)
-            learn_unseen_invent();
-        context.botl = 1;
+        toggle_blindness(); /* potion.c */
     }
 }
 
 void
 Blindf_off(otmp)
-register struct obj *otmp;
+struct obj *otmp;
 {
     boolean was_blind = Blind, changed = FALSE;
 
@@ -1318,13 +1364,7 @@ register struct obj *otmp;
         }
     }
     if (changed) {
-        /* blindness has just been toggled */
-        if (Blind_telepat || Infravision)
-            see_monsters();
-        vision_full_recalc = 1; /* recalc vision limits */
-        if (!Blind)
-            learn_unseen_invent();
-        context.botl = 1;
+        toggle_blindness(); /* potion.c */
     }
 }
 
@@ -1364,43 +1404,37 @@ struct obj *obj; /* if null, do all worn items; otherwise just obj itself */
 }
 
 /* check whether the target object is currently being put on (or taken off--
-   also checks for doffing) */
+   also checks for doffing--[why?]) */
 boolean
 donning(otmp)
 struct obj *otmp;
 {
-    /* long what = (occupation == take_off) ? context.takeoff.what : 0L; */
-    long what = context.takeoff.what; /* if nonzero, occupation is implied */
     boolean result = FALSE;
 
-    /* 'W' and 'T' set afternmv, 'A' sets context.takeoff.what */
-    if (otmp == uarm)
-        result = (afternmv == Armor_on || afternmv == Armor_off
-                  || what == WORN_ARMOR);
+    /* 'W' (or 'P' used for armor) sets afternmv */
+    if (doffing(otmp))
+        result = TRUE;
+    else if (otmp == uarm)
+        result = (afternmv == Armor_on);
     else if (otmp == uarmu)
-        result = (afternmv == Shirt_on || afternmv == Shirt_off
-                  || what == WORN_SHIRT);
+        result = (afternmv == Shirt_on);
     else if (otmp == uarmc)
-        result = (afternmv == Cloak_on || afternmv == Cloak_off
-                  || what == WORN_CLOAK);
+        result = (afternmv == Cloak_on);
     else if (otmp == uarmf)
-        result = (afternmv == Boots_on || afternmv == Boots_off
-                  || what == WORN_BOOTS);
+        result = (afternmv == Boots_on);
     else if (otmp == uarmh)
-        result = (afternmv == Helmet_on || afternmv == Helmet_off
-                  || what == WORN_HELMET);
+        result = (afternmv == Helmet_on);
     else if (otmp == uarmg)
-        result = (afternmv == Gloves_on || afternmv == Gloves_off
-                  || what == WORN_GLOVES);
+        result = (afternmv == Gloves_on);
     else if (otmp == uarms)
-        result = (afternmv == Shield_on || afternmv == Shield_off
-                  || what == WORN_SHIELD);
+        result = (afternmv == Shield_on);
 
     return result;
 }
 
 /* check whether the target object is currently being taken off,
-   so that stop_donning() and steal() can vary messages */
+   so that stop_donning() and steal() can vary messages and doname()
+   can vary "(being worn)" suffix */
 boolean
 doffing(otmp)
 struct obj *otmp;
@@ -1408,7 +1442,7 @@ struct obj *otmp;
     long what = context.takeoff.what;
     boolean result = FALSE;
 
-    /* 'T' (also 'W') sets afternmv, 'A' sets context.takeoff.what */
+    /* 'T' (or 'R' used for armor) sets afternmv, 'A' sets takeoff.what */
     if (otmp == uarm)
         result = (afternmv == Armor_off || what == WORN_ARMOR);
     else if (otmp == uarmu)
@@ -1423,10 +1457,48 @@ struct obj *otmp;
         result = (afternmv == Gloves_off || what == WORN_GLOVES);
     else if (otmp == uarms)
         result = (afternmv == Shield_off || what == WORN_SHIELD);
+    /* these 1-turn items don't need 'afternmv' checks */
+    else if (otmp == uamul)
+        result = (what == WORN_AMUL);
+    else if (otmp == uleft)
+        result = (what == LEFT_RING);
+    else if (otmp == uright)
+        result = (what == RIGHT_RING);
+    else if (otmp == ublindf)
+        result = (what == WORN_BLINDF);
+    else if (otmp == uwep)
+        result = (what == W_WEP);
+    else if (otmp == uswapwep)
+        result = (what == W_SWAPWEP);
+    else if (otmp == uquiver)
+        result = (what == W_QUIVER);
 
     return result;
 }
 
+/* despite their names, cancel_don() and cancel_doff() both apply to both
+   donning and doffing... */
+void
+cancel_doff(obj, slotmask)
+struct obj *obj;
+long slotmask;
+{
+    /* Called by setworn() for old item in specified slot or by setnotworn()
+     * for specified item.  We don't want to call cancel_don() if we got
+     * here via <X>_off() -> setworn((struct obj *)0) -> cancel_doff()
+     * because that would stop the 'A' command from continuing with next
+     * selected item.  So do_takeoff() sets a flag in takeoff.mask for us.
+     * [For taking off an individual item with 'T'/'R'/'w-', it doesn't
+     * matter whether cancel_don() gets called here--the item has already
+     * been removed by now.]
+     */
+    if (!(context.takeoff.mask & I_SPECIAL) && donning(obj))
+        cancel_don(); /* applies to doffing too */
+    context.takeoff.mask &= ~slotmask;
+}
+
+/* despite their names, cancel_don() and cancel_doff() both apply to both
+   donning and doffing... */
 void
 cancel_don()
 {
@@ -1437,7 +1509,7 @@ cancel_don()
     context.takeoff.cancelled_don =
         (afternmv == Boots_on || afternmv == Helmet_on
          || afternmv == Gloves_on || afternmv == Armor_on);
-    afternmv = 0;
+    afternmv = (int NDECL((*))) 0;
     nomovemsg = (char *) 0;
     multi = 0;
     context.takeoff.delay = 0;
@@ -1463,13 +1535,13 @@ struct obj *stolenobj; /* no message if stolenobj is already being doffing */
 
     /* donning() returns True when doffing too; doffing() is more specific */
     putting_on = !doffing(otmp);
-    /* cancel_don() looks at afternmv; it also serves as cancel_doff() */
+    /* cancel_don() looks at afternmv; it can also cancel doffing */
     cancel_don();
     /* don't want <armor>_on() or <armor>_off() being called
        by unmul() since the on or off action isn't completing */
-    afternmv = 0;
+    afternmv = (int NDECL((*))) 0;
     if (putting_on || otmp != stolenobj) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Sprintf(buf, "You stop %s %s.",
                 putting_on ? "putting on" : "taking off",
                 thesimpleoname(otmp));
@@ -1546,6 +1618,10 @@ STATIC_OVL int
 armor_or_accessory_off(obj)
 struct obj *obj;
 {
+#if 1 /*JP*/
+    const char *j;
+    const char *m;
+#endif
     if (!(obj->owornmask & (W_ARMOR | W_ACCESSORY))) {
 /*JP
         You("are not wearing that.");
@@ -1553,6 +1629,44 @@ struct obj *obj;
         You("\82»\82ê\82ð\90g\82É\82Â\82¯\82Ä\82¢\82È\82¢\81D");
         return 0;
     }
+    if (obj == uskin
+        || ((obj == uarm) && uarmc)
+        || ((obj == uarmu) && (uarmc || uarm))) {
+        char why[QBUFSZ], what[QBUFSZ];
+
+        why[0] = what[0] = '\0';
+        if (obj != uskin) {
+            if (uarmc)
+                Strcat(what, cloak_simple_name(uarmc));
+            if ((obj == uarmu) && uarm) {
+                if (uarmc)
+#if 0 /*JP*/
+                    Strcat(what, " and ");
+#else
+                    Strcat(what, "\82Æ");
+#endif
+                Strcat(what, suit_simple_name(uarm));
+            }
+#if 0 /*JP*/
+            Sprintf(why, " without taking off your %s first", what);
+#else
+            Sprintf(why, "\90æ\82É%s\82ð\82Í\82¸\82³\82È\82¢\82Æ", what);
+#endif
+        } else {
+#if 0 /*JP*/
+            Strcpy(why, "; it's embedded");
+#else
+            Strcpy(why, "\82­\82Á\82Â\82¢\82Ä\82¢\82é\82Ì\82Å");
+#endif
+        }
+#if 0 /*JP*/
+        You_cant("take that off%s.", why);
+#else
+        m = joffmsg(obj, &j);
+        pline("%s\82»\82ê%s%s\82±\82Æ\82Í\82Å\82«\82È\82¢\81D", why, j, m);
+#endif
+        return 0;
+    }
 
     reset_remarm(); /* clear context.takeoff.mask and context.takeoff.what */
     (void) select_off(obj);
@@ -1590,16 +1704,12 @@ int
 dotakeoff()
 {
     struct obj *otmp = (struct obj *) 0;
-#if 1 /*JP*/
-    const char *j;
-    const char *m;
-#endif
 
     count_worn_stuff(&otmp, FALSE);
     if (!Narmorpieces && !Naccessories) {
         /* assert( GRAY_DRAGON_SCALES > YELLOW_DRAGON_SCALE_MAIL ); */
         if (uskin)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline_The("%s merged with your skin!",
                       uskin->otyp >= GRAY_DRAGON_SCALES
                           ? "dragon scales are"
@@ -1620,30 +1730,6 @@ dotakeoff()
         otmp = getobj(clothes, "take off");
     if (!otmp)
         return 0;
-    if (otmp == uskin
-        || ((otmp == uarm) && uarmc)
-        || ((otmp == uarmu) && (uarmc || uarm))) {
-        char why[BUFSZ], what[BUFSZ];
-
-        why[0] = what[0] = '\0';
-        if (otmp != uskin) {
-            if (uarmc)
-                Strcat(what, cloak_simple_name(uarmc));
-            if ((otmp == uarmu) && uarm) {
-                if (uarmc)
-                    Strcat(what, " and ");
-                Strcat(what, suit_simple_name(uarm));
-            }
-            Sprintf(why, " without taking off your %s first", what);
-        }
-#if 0 /*JP*/
-        You_cant("take that off%s.", why);
-#else
-        m = joffmsg(otmp, &j);
-        You("\82»\82ê%s%s\82±\82Æ\82Í\82Å\82«\82È\82¢\81D", j, m);
-#endif
-        return 0;
-    }
 
     return armor_or_accessory_off(otmp);
 }
@@ -1673,19 +1759,37 @@ doremring()
 /* Check if something worn is cursed _and_ unremovable. */
 int
 cursed(otmp)
-register struct obj *otmp;
+struct obj *otmp;
 {
+    if (!otmp) {
+        impossible("cursed without otmp");
+        return 0;
+    }
     /* Curses, like chickens, come home to roost. */
     if ((otmp == uwep) ? welded(otmp) : (int) otmp->cursed) {
-#if 0 /*JP*/
+#if 0 /*JP*//*unused*/
         boolean use_plural = (is_boots(otmp) || is_gloves(otmp)
                               || otmp->otyp == LENSES || otmp->quan > 1L);
+#endif
 
-        You("can't.  %s cursed.", use_plural ? "They are" : "It is");
+        /* might be trying again after applying grease to hands */
+        if (Glib && otmp->bknown
+            /* for weapon, we'll only get here via 'A )' */
+            && (uarmg ? (otmp == uwep)
+                      : ((otmp->owornmask & (W_WEP | W_RING)) != 0)))
+#if 0 /*JP:T*/
+            pline("Despite your slippery %s, you can't.",
+                  fingers_or_gloves(TRUE));
 #else
-        pline("\96³\97\9d\82¾\81D\82»\82ê\82Í\8eô\82í\82ê\82Ä\82¢\82é\81D");
+            pline("%s\82Í\82·\82×\82è\82â\82·\82¢\82¯\82ê\82Ç\82à\81C\82»\82ê\82Í\82Å\82«\82È\82¢\81D",
+                  fingers_or_gloves(TRUE));
 #endif
-        otmp->bknown = TRUE;
+        else
+/*JP
+            You("can't.  %s cursed.", use_plural ? "They are" : "It is");
+*/
+            pline("\96³\97\9d\82¾\81D\82»\82ê\82Í\8eô\82í\82ê\82Ä\82¢\82é\81D");
+        set_bknown(otmp, 1);
         return 1;
     }
     return 0;
@@ -1693,12 +1797,16 @@ register struct obj *otmp;
 
 int
 armoroff(otmp)
-register struct obj *otmp;
+struct obj *otmp;
 {
-    register int delay = -objects[otmp->otyp].oc_delay;
+    static char offdelaybuf[60];
+    int delay = -objects[otmp->otyp].oc_delay;
+    const char *what = 0;
 
     if (cursed(otmp))
         return 0;
+    /* this used to make assumptions about which types of armor had
+       delays and which didn't; now both are handled for all types */
     if (delay) {
         nomul(delay);
 /*JP
@@ -1706,38 +1814,36 @@ register struct obj *otmp;
 */
         multi_reason = "\92E\82¢\82Å\82¢\82é\8e\9e\82É";
         if (is_helmet(otmp)) {
-            /* ick... */
-/*JP
-            nomovemsg = !strcmp(helm_simple_name(otmp), "hat")
-*/
-            nomovemsg = !strcmp(helm_simple_name(otmp), "\96X\8eq")
-/*JP
-                            ? "You finish taking off your hat."
-*/
-                            ? "\82 \82È\82½\82Í\8a\95\82ð\92E\82¬\82¨\82¦\82½\81D"
-/*JP
-                            : "You finish taking off your helmet.";
-*/
-                            : "\82 \82È\82½\82Í\96X\8eq\82ð\92E\82¬\82¨\82¦\82½\81D";
+            what = helm_simple_name(otmp);
             afternmv = Helmet_off;
         } else if (is_gloves(otmp)) {
-/*JP
-            nomovemsg = "You finish taking off your gloves.";
-*/
-            nomovemsg = "\82 \82È\82½\82Í\8f¬\8eè\82ð\92E\82¬\82¨\82¦\82½\81D";
+            what = gloves_simple_name(otmp);
             afternmv = Gloves_off;
         } else if (is_boots(otmp)) {
-/*JP
-            nomovemsg = "You finish taking off your boots.";
-*/
-            nomovemsg = "\82 \82È\82½\82Í\8cC\82ð\92E\82¬\82¨\82¦\82½\81D";
+            what = c_boots;
             afternmv = Boots_off;
+        } else if (is_suit(otmp)) {
+            what = suit_simple_name(otmp);
+            afternmv = Armor_off;
+        } else if (is_cloak(otmp)) {
+            what = cloak_simple_name(otmp);
+            afternmv = Cloak_off;
+        } else if (is_shield(otmp)) {
+            what = c_shield;
+            afternmv = Shield_off;
+        } else if (is_shirt(otmp)) {
+            what = c_shirt;
+            afternmv = Shirt_off;
         } else {
+            impossible("Taking off unknown armor (%d: %d), delay %d",
+                       otmp->otyp, objects[otmp->otyp].oc_armcat, delay);
+        }
+        if (what) {
 /*JP
-            nomovemsg = "You finish taking off your suit.";
+            Sprintf(offdelaybuf, "You finish taking off your %s.", what);
 */
-            nomovemsg = "\82 \82È\82½\82Í\92\85\82Ä\82¢\82é\95¨\82ð\92E\82¬\82¨\82¦\82½\81D";
-            afternmv = Armor_off;
+            Sprintf(offdelaybuf, "\82 \82È\82½\82Í%s\82ð\92E\82¬\82¨\82¦\82½\81D", what);
+            nomovemsg = offdelaybuf;
         }
     } else {
         /* Be warned!  We want off_msg after removing the item to
@@ -1761,8 +1867,19 @@ register struct obj *otmp;
             (void) Cloak_off();
         else if (is_shield(otmp))
             (void) Shield_off();
+        else if (is_helmet(otmp))
+            (void) Helmet_off();
+        else if (is_gloves(otmp))
+            (void) Gloves_off();
+        else if (is_boots(otmp))
+            (void) Boots_off();
+        else if (is_shirt(otmp))
+            (void) Shirt_off();
+        else if (is_suit(otmp))
+            (void) Armor_off();
         else
-            setworn((struct obj *) 0, otmp->owornmask & W_ARMOR);
+            impossible("Taking off unknown armor (%d: %d), no delay",
+                       otmp->otyp, objects[otmp->otyp].oc_armcat);
         off_msg(otmp);
     }
     context.takeoff.mask = context.takeoff.what = 0L;
@@ -1785,12 +1902,12 @@ struct obj *otmp;
 #if 1 /*JP*/
     const char *j;
     const char *m;
-    m = jconj(jonmsg(otmp, &j), "\82Ä\82¢\82é");
+    m = jconj(jonmsg(otmp, &j), "\82Ä");
 #endif
 /*JP
     You("are already wearing %s%c", cc, (cc == c_that_) ? '!' : '.');
 */
-    You("\82à\82¤%s%s%s%s", cc, j,  m, (cc == c_that_) ? "\81I" : "\81D");
+    You("\82à\82¤%s%s%s\82¢\82é%s", cc, j,  m, (cc == c_that_) ? "\81I" : "\81D");
 }
 
 STATIC_OVL void
@@ -1823,6 +1940,17 @@ boolean noisy;
     const char *j;
 #endif
 
+    /* this is the same check as for 'W' (dowear), but different message,
+       in case we get here via 'P' (doputon) */
+    if (verysmall(youmonst.data) || nohands(youmonst.data)) {
+        if (noisy)
+/*JP
+            You("can't wear any armor in your current form.");
+*/
+            You("\8c»\8dÝ\82Ì\8ep\82Å\82Í\96h\8bï\82ð\90g\82É\82Â\82¯\82é\82±\82Æ\82Í\82Å\82«\82È\82¢\81D");
+        return 0;
+    }
+
     which = is_cloak(otmp)
                 ? c_cloak
                 : is_shirt(otmp)
@@ -1872,7 +2000,7 @@ boolean noisy;
         } else if (Upolyd && has_horns(youmonst.data) && !is_flimsy(otmp)) {
             /* (flimsy exception matches polyself handling) */
             if (noisy)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline_The("%s won't fit over your horn%s.",
                           helm_simple_name(otmp),
                           plur(num_horns(youmonst.data)));
@@ -1901,8 +2029,8 @@ boolean noisy;
                                                    : c_weapon);
 #else
                 {
-                    m = jconj(jonmsg(uwep, &j), "\82Ä\82¢\82é");
-                    You("\97¼\8eè\8e\9d\82¿\82Ì%s%s%s\82Ì\82Å\8f\82\82Å\90g\82ð\8eç\82ê\82È\82¢\81D",
+                    m = jconj(jonmsg(uwep, &j), "\82Ä");
+                    You("\97¼\8eè\8e\9d\82¿\82Ì%s%s%s\82¢\82é\82Ì\82Å\8f\82\82Å\90g\82ð\8eç\82ê\82È\82¢\81D",
                         is_sword(uwep) ? c_sword :
                         uwep->otyp == BATTLE_AXE ? c_axe : c_weapon,
                         j, m);
@@ -1929,7 +2057,7 @@ boolean noisy;
             err++;
         } else if (Upolyd && slithy(youmonst.data)) {
             if (noisy)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 You("have no feet..."); /* not body_part(FOOT) */
 #else
                 You("\91«\82ª\82È\82¢\81D\81D\81D");  /* not body_part(FOOT) */
@@ -1939,7 +2067,7 @@ boolean noisy;
             /* break_armor() pushes boots off for centaurs,
                so don't let dowear() put them back on... */
             if (noisy)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("You have too many hooves to wear %s.",
                       c_boots); /* makeplural(body_part(FOOT)) yields
                                    "rear hooves" which sounds odd */
@@ -1959,7 +2087,7 @@ boolean noisy;
                     Your("%s\82Íã©\82É\82©\82©\82Á\82Ä\82¢\82é\81I", body_part(FOOT));
             } else if (u.utraptype == TT_INFLOOR || u.utraptype == TT_LAVA) {
                 if (noisy)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                     Your("%s are stuck in the %s!",
                          makeplural(body_part(FOOT)), surface(u.ux, u.uy));
 #else
@@ -1968,7 +2096,7 @@ boolean noisy;
 #endif
             } else { /*TT_BURIEDBALL*/
                 if (noisy)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                     Your("%s is attached to the buried ball!",
                          body_part(LEG));
 #else
@@ -1996,6 +2124,18 @@ boolean noisy;
                 You("%s\82Ì\8fã\82©\82ç\8f¬\8eè\82ð\91\95\94õ\82Å\82«\82È\82¢\81D",
                     is_sword(uwep) ? c_sword : c_weapon);
             err++;
+        } else if (Glib) {
+            /* prevent slippery bare fingers from transferring to
+               gloved fingers */
+            if (noisy)
+#if 0 /*JP:T*/
+                Your("%s are too slippery to pull on %s.",
+                     fingers_or_gloves(FALSE), gloves_simple_name(otmp));
+#else
+                Your("%s\82ª\82·\82×\82é\82Ì\82Å%s\82ð\82Ð\82Á\82Ï\82ê\82È\82¢\81D",
+                     fingers_or_gloves(FALSE), gloves_simple_name(otmp));
+#endif
+            err++;
         } else
             *mask = W_ARMG;
     } else if (is_shirt(otmp)) {
@@ -2126,11 +2266,11 @@ struct obj *obj;
 #if 0 /*JP*/
                 There("are no more %s%s to fill.",
                       humanoid(youmonst.data) ? "ring-" : "",
-                      makeplural(body_part(FINGER)));
+                      fingers_or_gloves(FALSE));
 #else
                 pline("\82Í\82ß\82é\82±\82Æ\82Ì\82Å\82«\82é%s%s\82ª\82È\82¢\81D",
                       humanoid(youmonst.data) ? "\96ò" : "",
-                      body_part(FINGER));
+                      fingers_or_gloves(FALSE));
 #endif
                 return 0;
             }
@@ -2140,7 +2280,7 @@ struct obj *obj;
                 mask = LEFT_RING;
             } else {
                 do {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                     Sprintf(qbuf, "Which %s%s, Right or Left?",
                             humanoid(youmonst.data) ? "ring-" : "",
                             body_part(FINGER));
@@ -2164,13 +2304,25 @@ struct obj *obj;
                     }
                 } while (!mask);
             }
+            if (uarmg && Glib) {
+#if 0 /*JP:T*/
+                Your(
+              "%s are too slippery to remove, so you cannot put on the ring.",
+                     gloves_simple_name(uarmg));
+#else
+                Your(
+              "%s\82ª\82·\82×\82Á\82Ä\92E\82°\82È\82¢\82Ì\82Å\81A\8ew\97Ö\82ð\82Â\82¯\82ç\82ê\82È\82¢\81D",
+                     gloves_simple_name(uarmg));
+#endif
+                return 1; /* always uses move */
+            }
             if (uarmg && uarmg->cursed) {
                 res = !uarmg->bknown;
-                uarmg->bknown = 1;
+                set_bknown(uarmg, 1);
 /*JP
-                You("cannot remove your gloves to put on the ring.");
+                You("cannot remove your %s to put on the ring.", c_gloves);
 */
-                You("\8ew\97Ö\82ð\82Í\82ß\82æ\82¤\82Æ\82µ\82½\82ª\8f¬\8eè\82ª\92E\82°\82È\82¢\81D");
+                You("\8ew\97Ö\82ð\82Í\82ß\82æ\82¤\82Æ\82µ\82½\82ª%s\82ª\92E\82°\82È\82¢\81D", c_gloves);
                 return res; /* uses move iff we learned gloves are cursed */
             }
             if (uwep) {
@@ -2256,11 +2408,39 @@ struct obj *obj;
     if (armor) {
         int delay;
 
-        obj->known = 1; /* since AC is shown on the status line */
-        /* if the armor is wielded, release it for wearing */
-        if (obj->owornmask & W_WEAPON)
+        /* if the armor is wielded, release it for wearing (won't be
+           welded even if cursed; that only happens for weapons/weptools) */
+        if (obj->owornmask & W_WEAPONS)
             remove_worn_item(obj, FALSE);
+        /*
+         * Setting obj->known=1 is done because setworn() causes hero's AC
+         * to change so armor's +/- value is evident via the status line.
+         * We used to set it here because of that, but then it would stick
+         * if a nymph stole the armor before it was fully worn.  Delay it
+         * until the aftermv action.  The player may still know this armor's
+         * +/- amount if donning gets interrupted, but the hero won't.
+         *
+        obj->known = 1;
+         */
         setworn(obj, mask);
+        /* if there's no delay, we'll execute 'aftermv' immediately */
+        if (obj == uarm)
+            afternmv = Armor_on;
+        else if (obj == uarmh)
+            afternmv = Helmet_on;
+        else if (obj == uarmg)
+            afternmv = Gloves_on;
+        else if (obj == uarmf)
+            afternmv = Boots_on;
+        else if (obj == uarms)
+            afternmv = Shield_on;
+        else if (obj == uarmc)
+            afternmv = Cloak_on;
+        else if (obj == uarmu)
+            afternmv = Shirt_on;
+        else
+            panic("wearing armor not worn as armor? [%08lx]", obj->owornmask);
+
         delay = -objects[obj->otyp].oc_delay;
         if (delay) {
             nomul(delay);
@@ -2268,25 +2448,12 @@ struct obj *obj;
             multi_reason = "dressing up";
 */
             multi_reason = "\91\95\94õ\82µ\82Ä\82¢\82é\8e\9e\82É";
-            if (is_boots(obj))
-                afternmv = Boots_on;
-            if (is_helmet(obj))
-                afternmv = Helmet_on;
-            if (is_gloves(obj))
-                afternmv = Gloves_on;
-            if (obj == uarm)
-                afternmv = Armor_on;
 /*JP
             nomovemsg = "You finish your dressing maneuver.";
 */
             nomovemsg = "\91\95\94õ\82µ\8fI\82¦\82½\81D";
         } else {
-            if (is_cloak(obj))
-                (void) Cloak_on();
-            if (is_shield(obj))
-                (void) Shield_on();
-            if (is_shirt(obj))
-                (void) Shirt_on();
+            unmul(""); /* call (*aftermv)(), clear it+nomovemsg+multi_reason */
             on_msg(obj);
         }
         context.takeoff.mask = context.takeoff.what = 0L;
@@ -2323,7 +2490,7 @@ dowear()
 
     /* cantweararm() checks for suits of armor, not what we want here;
        verysmall() or nohands() checks for shields, gloves, etc... */
-    if ((verysmall(youmonst.data) || nohands(youmonst.data))) {
+    if (verysmall(youmonst.data) || nohands(youmonst.data)) {
 /*JP
         pline("Don't even bother.");
 */
@@ -2352,15 +2519,15 @@ doputon()
     if (uleft && uright && uamul && ublindf
         && uarm && uarmu && uarmc && uarmh && uarms && uarmg && uarmf) {
         /* 'P' message doesn't mention armor */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Your("%s%s are full, and you're already wearing an amulet and %s.",
              humanoid(youmonst.data) ? "ring-" : "",
-             makeplural(body_part(FINGER)),
+             fingers_or_gloves(FALSE),
              (ublindf->otyp == LENSES) ? "some lenses" : "a blindfold");
 #else
         Your("%s%s\82Í\82Ó\82³\82ª\82Á\82Ä\82é\82µ\81C\82·\82Å\82É\96\82\8f\9c\82¯\82Æ%s\82à\90g\82É\82Â\82¯\82Ä\82¢\82é\81D",
              humanoid(youmonst.data) ? "\96ò" : "",
-             body_part(FINGER),
+             fingers_or_gloves(FALSE),
              ublindf->otyp==LENSES ? "\83\8c\83\93\83Y" : "\96Ú\89B\82µ");
 #endif
         return 0;
@@ -2429,13 +2596,15 @@ glibr()
     rightfall = (uright && !uright->cursed && (!welded(uwep)));
     if (!uarmg && (leftfall || rightfall) && !nolimbs(youmonst.data)) {
         /* changed so cursed rings don't fall off, GAN 10/30/86 */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         Your("%s off your %s.",
              (leftfall && rightfall) ? "rings slip" : "ring slips",
-             (leftfall && rightfall) ? makeplural(body_part(FINGER))
+             (leftfall && rightfall) ? fingers_or_gloves(FALSE)
                                      : body_part(FINGER));
 #else
-        Your("\8ew\97Ö\82Í%s\82©\82ç\8a\8a\82è\97\8e\82¿\82½\81D", body_part(FINGER));
+        Your("\8ew\97Ö\82Í%s\82©\82ç\8a\8a\82è\97\8e\82¿\82½\81D",
+             (leftfall && rightfall) ? fingers_or_gloves(FALSE)
+                                     : body_part(FINGER));
 #endif
         xfl++;
         if (leftfall) {
@@ -2461,13 +2630,16 @@ glibr()
         if (otmp->quan > 1L)
             otherwep = makeplural(otherwep);
         hand = body_part(HAND);
+/*JP
         which = "left ";
-#if 0 /*JP*/
+*/
+        which = "\8d¶";
+#if 0 /*JP:T*/
         Your("%s %s%s from your %s%s.", otherwep, xfl ? "also " : "",
              otense(otmp, "slip"), which, hand);
 #else
-        You("%s%s%s\82©\82ç\8a\8a\82è\97\8e\82Æ\82µ\82½\81D", otherwep, xfl ? "\82à\82Ü\82½" : "\82ð",
-            body_part(HAND));
+        You("%s%s%s%s\82©\82ç\8a\8a\82è\97\8e\82Æ\82µ\82½\81D", otherwep, xfl ? "\82à\82Ü\82½" : "\82ð",
+            which, body_part(HAND));
 #endif
         xfl++;
         wastwoweap = TRUE;
@@ -2483,6 +2655,7 @@ glibr()
         thiswep = is_sword(otmp) ? c_sword : weapon_descr(otmp);
         if (otherwep && strcmp(thiswep, makesingular(otherwep)))
             otherwep = 0;
+#if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\95s\97v*/
         if (otmp->quan > 1L) {
             /* most class names for unconventional wielded items
                are ok, but if wielding multiple apples or rations
@@ -2494,22 +2667,27 @@ glibr()
             else
                 thiswep = makeplural(thiswep);
         }
+#endif
         hand = body_part(HAND);
         which = "";
         if (bimanual(otmp))
             hand = makeplural(hand);
         else if (wastwoweap)
+#if 0 /*JP:T*/
             which = "right "; /* preceding msg was about left */
-#if 0 /*JP*/
+#else
+            which = "\89E"; /* preceding msg was about left */
+#endif
+#if 0 /*JP:T*/
         pline("%s %s%s %s%s from your %s%s.",
               !strncmp(thiswep, "corpse", 6) ? "The" : "Your",
               otherwep ? "other " : "", thiswep, xfl ? "also " : "",
               otense(otmp, "slip"), which, hand);
 #else
-        You("%s%s%s%s\82©\82ç\8a\8a\82è\97\8e\82Æ\82µ\82½\81D",
+        You("%s%s%s%s%s\82©\82ç\8a\8a\82è\97\8e\82Æ\82µ\82½\81D",
             otherwep ? "\82à\82¤\82Ð\82Æ\82Â\82Ì" : "", thiswep,
             xfl ? "\82à\82Ü\82½" : "\82ð",
-            body_part(HAND));
+            which, body_part(HAND));
 #endif
         /* xfl++; */
         otmp->quan = savequan;
@@ -2569,6 +2747,10 @@ int otyp;
             return uarmg;
         if (ring->cursed)
             return ring;
+        /* normally outermost layer is processed first, but slippery gloves
+           wears off quickly so uncurse ring itself before handling those */
+        if (uarmg && Glib)
+            return uarmg;
     }
     /* either no ring or not right type or nothing prevents its removal */
     return (struct obj *) 0;
@@ -2597,14 +2779,17 @@ register struct obj *otmp;
 
     /* special ring checks */
     if (otmp == uright || otmp == uleft) {
+        struct obj glibdummy;
+
         if (nolimbs(youmonst.data)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline_The("ring is stuck.");
 #else
             pline("\8ew\97Ö\82Í\91Ì\82É\96\84\82Ü\82Á\82Ä\82µ\82Ü\82Á\82Ä\82¢\82é\81D");
 #endif
             return 0;
         }
+        glibdummy = zeroobj;
         why = 0; /* the item which prevents ring removal */
         if (welded(uwep) && (otmp == uright || bimanual(uwep))) {
 /*JP
@@ -2612,41 +2797,45 @@ register struct obj *otmp;
 */
             Sprintf(buf, "\97\98\98r\82Ì\8e©\97R\82ª\82«\82©\82È\82¢");
             why = uwep;
-        } else if (uarmg && uarmg->cursed) {
-/*JP
-            Sprintf(buf, "take off your %s", c_gloves);
-*/
-            Sprintf(buf, "%s\82ª\92E\82°\82È\82¢", c_gloves);
-            why = uarmg;
+        } else if (uarmg && (uarmg->cursed || Glib)) {
+#if 0 /*JP*/
+            Sprintf(buf, "take off your %s%s",
+                    Glib ? "slippery " : "", gloves_simple_name(uarmg));
+#else
+            Sprintf(buf, "%s%s\82ª\92E\82°\82È\82¢",
+                    Glib ? "\82Ê\82é\82Ê\82é\82Ì" : "", gloves_simple_name(uarmg));
+#endif
+            why = !Glib ? uarmg : &glibdummy;
         }
         if (why) {
 /*JP
             You("cannot %s to remove the ring.", buf);
 */
             You("\8ew\97Ö\82ð\82Í\82¸\82»\82¤\82Æ\82µ\82½\82ª%s\81D", buf);
-            why->bknown = TRUE;
+            set_bknown(why, 1);
             return 0;
         }
     }
     /* special glove checks */
     if (otmp == uarmg) {
         if (welded(uwep)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             You("are unable to take off your %s while wielding that %s.",
                 c_gloves, is_sword(uwep) ? c_sword : c_weapon);
 #else
             You("%s\82ð\8e\9d\82Á\82½\82Ü\82Ü%s\82ð\82Í\82¸\82·\82±\82Æ\82Í\82Å\82«\82È\82¢\81D",
                 is_sword(uwep) ? c_sword : c_weapon, c_gloves);
 #endif
-            uwep->bknown = TRUE;
+            set_bknown(uwep, 1);
             return 0;
         } else if (Glib) {
-#if 0 /*JP*/
-            You_cant("take off the slippery %s with your slippery %s.",
-                     c_gloves, makeplural(body_part(FINGER)));
+#if 0 /*JP:T*/
+            pline("%s %s are too slippery to take off.",
+                  uarmg->unpaid ? "The" : "Your", /* simplified Shk_Your() */
+                  gloves_simple_name(uarmg));
 #else
-            You_cant("\8a\8a\82è\82â\82·\82¢%s\82ð\8a\8a\82è\82â\82·\82¢%s\82Å\82Í\82¸\82¹\82È\82¢\81D",
-                     c_gloves, body_part(FINGER));
+            pline("%s\82Í\82·\82×\82é\82Ì\82Å\92E\82®\82±\82Æ\82ª\82Å\82«\82È\82¢\81D",
+                  gloves_simple_name(uarmg));
 #endif
             return 0;
         }
@@ -2685,7 +2874,7 @@ register struct obj *otmp;
             Sprintf(buf, "%s\82ª\92E\82°\82È\82¢", c_suit);
             why = uarm;
         } else if (welded(uwep) && bimanual(uwep)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             Sprintf(buf, "release your %s",
                     is_sword(uwep) ? c_sword : (uwep->otyp == BATTLE_AXE)
                                                    ? c_axe
@@ -2703,7 +2892,7 @@ register struct obj *otmp;
             You("cannot %s to take off %s.", buf, the(xname(otmp)));
 */
             You("%s\82ð\82Í\82¸\82»\82¤\82Æ\82µ\82½\82ª%s\81D", xname(otmp), buf);
-            why->bknown = TRUE;
+            set_bknown(why, 1);
             return 0;
         }
     }
@@ -2757,6 +2946,7 @@ do_takeoff()
     struct obj *otmp = (struct obj *) 0;
     struct takeoff_info *doff = &context.takeoff;
 
+    context.takeoff.mask |= I_SPECIAL; /* set flag for cancel_doff() */
     if (doff->what == W_WEP) {
         if (!cursed(uwep)) {
             setuwep((struct obj *) 0);
@@ -2825,6 +3015,7 @@ do_takeoff()
     } else {
         impossible("do_takeoff: taking off %lx", doff->what);
     }
+    context.takeoff.mask &= ~I_SPECIAL; /* clear cancel_doff() flag */
 
     return otmp;
 }
@@ -2842,10 +3033,9 @@ take_off(VOID_ARGS)
         if (doff->delay > 0) {
             doff->delay--;
             return 1; /* still busy */
-        } else {
-            if ((otmp = do_takeoff()))
-                off_msg(otmp);
         }
+        if ((otmp = do_takeoff()) != 0)
+            off_msg(otmp);
         doff->mask &= ~doff->what;
         doff->what = 0L;
     }
@@ -2903,7 +3093,9 @@ take_off(VOID_ARGS)
     } else if (doff->what == RIGHT_RING) {
         doff->delay = 1;
     } else if (doff->what == WORN_BLINDF) {
-        doff->delay = 2;
+        /* [this used to be 2, but 'R' (and 'T') only require 1 turn to
+           remove a blindfold, so 'A' shouldn't have been requiring 2] */
+        doff->delay = 1;
     } else {
         impossible("take_off: taking off %lx", doff->what);
         return 0; /* force done */
@@ -2968,7 +3160,7 @@ doddoremarm()
            possibly combined with weapons */
         (void) strncpy(context.takeoff.disrobing, "disrobing", CONTEXTVERBSZ);
         /* specific activity when handling weapons only */
-        if (!(context.takeoff.mask & ~W_WEAPON))
+        if (!(context.takeoff.mask & ~W_WEAPONS))
             (void) strncpy(context.takeoff.disrobing, "disarming",
                            CONTEXTVERBSZ);
 #endif
@@ -2997,8 +3189,9 @@ int retry;
         n = query_category("What type of things do you want to take off?",
 */
         n = query_category("\82Ç\82Ì\83^\83C\83v\82Ì\95¨\82Ì\91\95\94õ\82ð\89ð\82«\82Ü\82·\82©\81H",
-                           invent, WORN_TYPES | ALL_TYPES, &pick_list,
-                           PICK_ANY);
+                           invent, (WORN_TYPES | ALL_TYPES
+                                    | UNPAID_TYPES | BUCX_TYPES),
+                           &pick_list, PICK_ANY);
         if (!n)
             return 0;
         for (i = 0; i < n; i++) {
@@ -3009,18 +3202,29 @@ int retry;
         }
         free((genericptr_t) pick_list);
     } else if (flags.menu_style == MENU_COMBINATION) {
-        all_worn_categories = FALSE;
-        if (ggetobj("take off", select_off, 0, TRUE, (unsigned *) 0) == -2)
-            all_worn_categories = TRUE;
+        unsigned ggofeedback = 0;
+
+        i = ggetobj("take off", select_off, 0, TRUE, &ggofeedback);
+        if (ggofeedback & ALL_FINISHED)
+            return 0;
+        all_worn_categories = (i == -2);
     }
+    if (menu_class_present('u')
+        || menu_class_present('B') || menu_class_present('U')
+        || menu_class_present('C') || menu_class_present('X'))
+        all_worn_categories = FALSE;
 
-/*JP
-    n = query_objlist("What do you want to take off?", invent,
-*/
-    n = query_objlist("\82Ç\82Ì\91\95\94õ\82ð\89ð\82«\82Ü\82·\82©\81H", invent,
-                      SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT, &pick_list,
-                      PICK_ANY,
+#if 0 /*JP:T*/
+    n = query_objlist("What do you want to take off?", &invent,
+                      (SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT),
+                      &pick_list, PICK_ANY,
                       all_worn_categories ? is_worn : is_worn_by_type);
+#else
+    n = query_objlist("\82Ç\82Ì\91\95\94õ\82ð\89ð\82«\82Ü\82·\82©\81H", &invent,
+                      (SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT),
+                      &pick_list, PICK_ANY,
+                      all_worn_categories ? is_worn : is_worn_by_type);
+#endif
     if (n > 0) {
         for (i = 0; i < n; i++)
             (void) select_off(pick_list[i].item.a_obj);
@@ -3088,7 +3292,7 @@ register struct obj *atmp;
 /*JP
         Your("gloves vanish!");
 */
-                Your("\8f¬\8eè\82Í\8fÁ\82¦\82½\81I");
+        Your("\8f¬\8eè\82Í\8fÁ\82¦\82½\81I");
         (void) Gloves_off();
         useup(otmp);
 /*JP