OSDN Git Service

update year to 2022
[jnethack/source.git] / src / read.c
index 2978023..07ebe43 100644 (file)
@@ -1,10 +1,11 @@
-/* NetHack 3.6 read.c  $NHDT-Date: 1448862378 2015/11/30 05:46:18 $  $NHDT-Branch: master $:$NHDT-Revision: 1.125 $ */
+/* NetHack 3.6 read.c  $NHDT-Date: 1561485713 2019/06/25 18:01:53 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.172 $ */
 /* 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-2022            */
 /* JNetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
@@ -23,18 +24,23 @@ static NEARDATA const char readable[] = { ALL_CLASSES, SCROLL_CLASS,
 static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 };
 
 STATIC_DCL boolean FDECL(learnscrolltyp, (SHORT_P));
-STATIC_DCL char * FDECL(erode_obj_text, (struct obj *, char *));
-STATIC_DCL void NDECL(do_class_genocide);
+STATIC_DCL char *FDECL(erode_obj_text, (struct obj *, char *));
+STATIC_DCL char *FDECL(apron_text, (struct obj *, char *buf));
 STATIC_DCL void FDECL(stripspe, (struct obj *));
 STATIC_DCL void FDECL(p_glow1, (struct obj *));
 STATIC_DCL void FDECL(p_glow2, (struct obj *, const char *));
-STATIC_DCL void FDECL(randomize, (int *, int));
 STATIC_DCL void FDECL(forget_single_object, (int));
+#if 0 /* not used */
+STATIC_DCL void FDECL(forget_objclass, (int));
+#endif
+STATIC_DCL void FDECL(randomize, (int *, int));
 STATIC_DCL void FDECL(forget, (int));
 STATIC_DCL int FDECL(maybe_tame, (struct monst *, struct obj *));
+STATIC_DCL boolean FDECL(get_valid_stinking_cloud_pos, (int, int));
 STATIC_DCL boolean FDECL(is_valid_stinking_cloud_pos, (int, int, BOOLEAN_P));
-STATIC_DCL void FDECL(display_stinking_cloud_positions, (int));
+STATIC_PTR void FDECL(display_stinking_cloud_positions, (int));
 STATIC_PTR void FDECL(set_lit, (int, int, genericptr));
+STATIC_DCL void NDECL(do_class_genocide);
 
 STATIC_OVL boolean
 learnscrolltyp(scrolltyp)
@@ -59,12 +65,13 @@ struct obj *sobj;
         (void) learnscrolltyp(sobj->otyp);
 }
 
-char *
+STATIC_OVL char *
 erode_obj_text(otmp, buf)
 struct obj *otmp;
 char *buf;
 {
     int erosion = greatest_erosion(otmp);
+
     if (erosion)
         wipeout_text(buf, (int) (strlen(buf) * erosion / (2 * MAX_ERODE)),
                      otmp->o_id ^ (unsigned) ubirthday);
@@ -78,6 +85,7 @@ char *buf;
 {
     static const char *shirt_msgs[] = {
         /* Scott Bigham */
+#if 0 /*JP:T*/
       "I explored the Dungeons of Doom and all I got was this lousy T-shirt!",
         "Is that Mjollnir in your pocket or are you just happy to see me?",
       "It's not the size of your sword, it's how #enhance'd you are with it.",
@@ -94,7 +102,26 @@ char *buf;
         "Don't Panic", /* HHGTTG */
         "Furinkan High School Athletic Dept.",                /* Ranma 1/2 */
         "Hel-LOOO, Nurse!",                                   /* Animaniacs */
+#else
+        "\8e\84\82Í\89^\96½\82Ì\96À\8b{\82ð\92²\8d¸\82µ\82Ä\82¢\82½\82ª\81C\8eè\82É\93ü\82ê\82½\82Ì\82Í\82«\82½\82È\82¢\82s\83V\83\83\83c\82¾\82¯\82¾\82Á\82½\81I",
+        "\83|\83P\83b\83g\82É\83~\83\85\83\8b\83j\81[\83\8b\82ª\93ü\82Á\82Ä\82¢\82é\82Ì\81H\82»\82ê\82Æ\82à\8e\84\82É\89ï\82¦\82Ä\82¤\82ê\82µ\82¢\81H",
+        "\8c\95\82Ì\91å\82«\82³\82ª\96â\91è\82È\82Ì\82Å\82Í\82È\82¢\81D\82»\82ê\82ª\94@\89½\82É#enhance\82³\82ê\82Ä\82¢\82é\82©\82È\82Ì\82¾\81D",
+        "\83}\83_\83\80\81E\83G\83\8b\83o\83C\83\89\82Ì\83T\83L\83\85\83o\83X\8aÙ \89i\8bv\8cÚ\8bq",
+        "\83}\83_\83\80\81E\83G\83\8b\83o\83C\83\89\82Ì\83T\83L\83\85\83o\83X\8aÙ \8d¡\8c\8e\82Ì\8dÅ\97D\8fG\8c÷\98J\8eÒ",
+        "\83\8d\81[\83f\83B\83I\83X\8bà\8cÉ\82Ì\94Ô\90l\81C\82»\82ê\82Í\88Ã\82­\8f¬\82³\82¢\95\94\89®\82Ì\92\86",
+        "\83C\83F\83\93\83_\81[\8cR\95º\8em\81C\82»\82ê\82Í\8b\90\91å\82È\92c\91Ì\82Ì\92\86",
+        "\8e\84\82Í\83C\83F\83\93\83_\81[\8cR\82Ì\90V\95º\8cP\97û\8f\8a\82ð\8fæ\82è\89z\82¦\82Ü\82µ\82½",
+        "\83\8d\81[\83f\83B\83I\83X\89ï\8cv\8aw\8d\8eº\93à\83\89\83N\83\8d\83X\83`\81[\83\80",
+        "Oracle(TM) \82Ì\90ò \91æ\82P\82O\89ñ\94G\82ê\82s\83V\83\83\83c\83R\83\93\83e\83X\83g",
+        "\82¨\82¢\81C\8d\95\83h\83\89\83S\83\93\81I\82±\82¢\82Â\82ð\95ª\89ð\82µ\82ë\81I",
+        "\94n\8e­\82Æ\88ê\8f\8f\82É\82¢\82Ü\82· \81¨ ",
+        "\8e\84\82Í\88«\82­\82È\82¢\81IIzchak\82É\93\8a\95[\82µ\82½\82à\82Ì\81I",
+        "\82  \82í \82Ä \82é \82È", /* \8bâ\89Í\83q\83b\83`\83n\83C\83N\83K\83C\83h */
+        "\95\97\97Ñ\8aÙ\8d\82\8dZ\97¤\8fã\95\94",                                   /* Ranma 1/2 */
+        "\82g\82\85\82\8c\81|\82k\82n\82n\82n\81C\82m\82\95\82\92\82\93\82\85\81I",                     /* Animaniacs */
+#endif
         "=^.^=",
+#if 0 /*JP:T*/
         "100% goblin hair - do not wash",
         "Aberzombie and Fitch",
         "cK -- Cockatrice touches the Kop",
@@ -105,13 +132,33 @@ char *buf;
         "Go team ant!",
         "Got newt?",
         "Hello, my darlings!", /* Charlie Drake */
-        "Hey! Nymphs! Steal This T-Shirt!",
+        "Hey!  Nymphs!  Steal This T-Shirt!",
         "I <3 Dungeon of Doom",
         "I <3 Maud",
-        "I am a Valkyrie. If you see me running, try to keep up.",
+        "I am a Valkyrie.  If you see me running, try to keep up.",
         "I am not a pack rat - I am a collector",
         "I bounced off a rubber tree",         /* Monkey Island */
         "Plunder Island Brimstone Beach Club", /* Monkey Island */
+#else
+        "\83S\83u\83\8a\83\93\96Ñ100% - \90ô\82¦\82Ü\82¹\82ñ",
+        "\83A\83o\83]\83\93\83r&\83t\83B\83b\83`",
+        "cK -- \83R\83J\83g\83\8a\83X\82ª\8cx\8a¯\82É\83^\83b\83`",
+        "\8e¿\96â\82µ\82È\82¢\82Å; \8e\84\82Í\82±\82±\82ð\92T\8c\9f\82µ\82Ä\82¢\82é\82¾\82¯",
+        "Down with pants!",
+        "d\82Í\82 \82È\82½\82Ì\8c¢\82©\8eE\90l\8eÒ\82©\81H",
+        "FREE PUG AND NEWT!",
+        "Go team ant!",
+        "Got newt?",
+        "\82±\82ñ\82É\82¿\82Í\83_\81[\83\8a\83\93\81I", /* Charlie Drake */
+        "\82â\82 \81I\83j\83\93\83t\81I\82±\82Ì\82s\83V\83\83\83c\82ð\93\90\82ñ\82Å\81I",
+        "I <3 Dungeon of Doom",
+        "I <3 Maud",
+        "\8e\84\82Í\83o\83\8b\83L\83\8a\81[\82¾\81D\8e\84\82ª\91\96\82Á\82Ä\82¢\82é\82Ì\82ð\8c©\82½\82ç\81C\82Â\82¢\82Ä\82±\82¢\81D",
+        "\8e\84\82Í\83S\83~\8fW\82ß\82Å\82Í\82È\82¢\81D\8e\84\82Í\8eû\8fW\89Æ\82¾",
+        "\8e\84\82Í\83S\83\80\82Ì\96Ø\82É\92µ\82Ë\95Ô\82Á\82½",         /* Monkey Island */
+        "\97ª\92D\93\87\97°\89©\8aC\8aÝ\83N\83\89\83u", /* Monkey Island */
+#endif
+#if 0 /*JP:T*/
         "If you can read this, I can hit you with my polearm",
         "I'm confused!",
         "I scored with the princess",
@@ -127,6 +174,24 @@ char *buf;
         "Somebody stole my Mojo!",
         "The Hellhound Gang",
         "The Werewolves",
+#else
+        "\82±\82ê\82ª\93Ç\82ß\82é\82È\82ç\81A\8e\84\82Ì\92·\95\80\82ª\93Í\82­\82Æ\82¢\82¤\82±\82Æ\82¾",
+        "\8e\84\82Í\8d¬\97\90\82µ\82Ä\82¢\82Ü\82·\81I",
+        "I scored with the princess",
+        "\8e\84\82Í\89i\89\93\82É\90\82«\82é\82©\81A\82»\82Ì\82½\82ß\82É\8e\80\82É\82½\82¢\81D",
+        "Lichen Park",
+        "\8dl\82¦\8d\9e\82ñ\82Å\82¢\82Ü\82· - \91{\8dõ\91à\82ð\8fo\82µ\82Ä\82­\82¾\82³\82¢",
+        "\93÷\82Í\83\82\83\8b\83h\81[\83\8b",
+        "\8dz\8eR\8aX\8f¤\8bÆ\89ü\91P\8b¦\89ï",
+        "\8dz\8eR\8aX\82Ì\8c©\92£\82è",
+ "\83p\81[\83\80\8f\97\8ej\82Ì\8cð\8fÂ\8bZ\8fp\82Ì\89Æ -- \82Æ\82Ä\82à\95]\94»\82Ì\88«\95]\82Ì\89Æ",
+        "\8dz\8eR\83_\83b\83V\83\85\92\86",
+        "\96{\95¨\82Ì\92j\82Í\83N\83\8d\83\80\82ð\88¤\82·\82é",
+        "\92N\82©\82ª\89´\82Ì\83A\83\8c\82ð\93\90\82ñ\82¾\81I",
+        "The Hellhound Gang",
+        "The Werewolves",
+#endif
+#if 0 /*JP:T*/
         "They Might Be Storm Giants",
         "Weapons don't kill people, I kill people",
         "White Zombie",
@@ -144,27 +209,88 @@ char *buf;
         "Pudding farmer",
         "Vegetarian",
         "Hello, I'm War!",
+        "It is better to light a candle than to curse the darkness",
+        "It is easier to curse the darkness than to light a candle",
+#else
+        "\83[\83C\81E\83}\83C\83g\81E\83r\81[\81E\83X\83g\81[\83\80\81E\83W\83\83\83C\83A\83\93\83c",
+        "\95\90\8aí\82ª\90l\82ð\8eE\82·\82Ì\82Å\82Í\82È\82¢\81C\8e\84\82ª\90l\82ð\8eE\82·\82Ì\82¾",
+        "White Zombie",
+        "\82¢\82¢\89Á\8c¸\82É\82µ\82Ä\81I",
+        "\83A\83\93\83t\83\8b\8fB\97§\91å\8aw - \89Î\8ba\82Æ\82Ì\90í\82¢\82Ì\96{\8b\92\92n\81I",
+        "FREE HUGS",
+        "\93Á\95Ê\8f¸\93V\8eÒ",
+        "\96{\93\96\82Ì\92j\82Í\83o\83\8b\83L\83\8a\81[\82¾",
+        "\90Â\94N\93´\8cA\8c@\8dí\98A\96¿",
+        "\83\8d\81[\83f\83B\83I\83X\8dÔ\82ð\90è\8b\92\82¹\82æ",
+        "\82±\82Ì\82s\83V\83\83\83c\82ð\94\83\82¤\82¨\8bà\82ª\82È\82©\82Á\82½\82Ì\82Å\82±\82ê\82Í\93\90\82ñ\82¾\81I",
+        "\83}\83C\83\93\83h\83t\83\8c\83\84\8e\81\82Ë",
+        "\8e\84\82Í\83p\83\93\83c\82ð\90ú\82¢\82Ä\82¢\82Ü\82¹\82ñ",
+        "\90\8a\88\82ð\82Ô\82Á\89ó\82¹\81I",
+        "\83v\83\8a\83\93\94_\89Æ",
+        "\83x\83W\83^\83\8a\83A\83\93",
+        "\82â\82 \81C\8e\84\82ª\81w\90í\91\88\81x\82¾\81I",
+        "\88Ã\82¢\82Æ\95s\95½\82ð\8c¾\82¤\82æ\82è\82à\81C\82·\82·\82ñ\82Å\82 \82©\82è\82ð\82Â\82¯\82Ü\82µ\82å\82¤",
+        "\82·\82·\82ñ\82Å\82 \82©\82è\82ð\82Â\82¯\82é\82æ\82è\81C\88Ã\82¢\82Æ\95s\95½\82ð\8c¾\82¤\95û\82ª\8aÈ\92P",
+#endif
+        /* expanded "rock--paper--scissors" featured in TV show "Big Bang
+           Theory" although they didn't create it (and an actual T-shirt
+           with pentagonal diagram showing which choices defeat which) */
+/*JP
+        "rock--paper--scissors--lizard--Spock!",
+*/
+        "\8aâ--\8e\86--\83n\83T\83~--\83g\83J\83Q--\83X\83|\83b\83N\81I",
+        /* "All men must die -- all men must serve" challange and response
+           from book series _A_Song_of_Ice_and_Fire_ by George R.R. Martin,
+           TV show "Game of Thrones" (probably an actual T-shirt too...) */
+        "/Valar morghulis/ -- /Valar dohaeris/",
     };
 
     Strcpy(buf, shirt_msgs[tshirt->o_id % SIZE(shirt_msgs)]);
     return erode_obj_text(tshirt, buf);
 }
 
-char *
+STATIC_OVL char *
 apron_text(apron, buf)
 struct obj *apron;
 char *buf;
 {
     static const char *apron_msgs[] = {
+/*JP
         "Kiss the cook",
+*/
+        "\83R\83b\83N\82É\83L\83X\82¹\82æ",
+/*JP
         "I'm making SCIENCE!",
+*/
+        "\8e\84\82Í*\89È\8aw*\82ð\8ds\82Á\82Ä\82¢\82é\81I",
+/*JP
         "Don't mess with the chef",
+*/
+        "\83V\83F\83t\82É\82Í\8eè\82ð\8fo\82·\82È",
+/*JP
         "Don't make me poison you",
+*/
+        "\82 \82È\82½\82É\93Å\82ð\90·\82ç\82³\82¹\82È\82¢\82Å",
+/*JP
         "Gehennom's Kitchen",
+*/
+        "\83Q\83w\83i\83L\83b\83`\83\93",
+/*JP
         "Rat: The other white meat",
+*/
+        "\83l\83Y\83~: \82à\82¤\88ê\82Â\82Ì\94\92\90g\93÷",
+/*JP
         "If you can't stand the heat, get out of Gehennom!",
+*/
+        "\94M\82É\91Ï\82¦\82ç\82ê\82È\82¢\82È\82ç\81A\83Q\83w\83i\82©\82ç\8fo\82Ä\8ds\82¯\81I",
+/*JP
         "If we weren't meant to eat animals, why are they made out of meat?",
+*/
+        "\82à\82µ\89ä\81X\82ª\93÷\82ð\90H\82×\82é\89^\96½\82Å\82Í\82È\82¢\82Ì\82È\82ç\81C\82È\82º\93®\95¨\82É\82Í\93÷\82ª\82 \82é\82Ì\81H",
+/*JP
         "If you don't like the food, I'll stab you",
+*/
+        "\90H\82×\95¨\82ª\8bC\82É\93ü\82ç\82È\82¢\82È\82ç\81C\8eh\82·\82æ",
     };
 
     Strcpy(buf, apron_msgs[apron->o_id % SIZE(apron_msgs)]);
@@ -197,7 +323,11 @@ doread()
         useup(scroll);
         return 1;
     } else if (scroll->otyp == T_SHIRT || scroll->otyp == ALCHEMY_SMOCK) {
-        char buf[BUFSZ];
+        char buf[BUFSZ], *mesg;
+#if 0 /*JP*/
+        const char *endpunct;
+#endif
+
         if (Blind) {
 /*JP
             You_cant("feel any Braille writing.");
@@ -218,23 +348,37 @@ doread()
             return 0;
         }
         u.uconduct.literate++;
-        if (flags.verbose)
+        /* populate 'buf[]' */
+        mesg = (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf)
+                                         : apron_text(scroll, buf);
+#if 0 /*JP*/
+        endpunct = "";
+#endif
+        if (flags.verbose) {
+#if 0 /*JP*/
+            int ln = (int) strlen(mesg);
+
+            /* we will be displaying a sentence; need ending punctuation */
+            if (ln > 0 && !index(".!?", mesg[ln - 1]))
+                endpunct = ".";
+#endif
 /*JP
             pline("It reads:");
 */
             pline("\82»\82ê\82ð\93Ç\82ñ\82¾\81F");
+        }
 #if 0 /*JP*/
-        pline("\"%s\"", (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf)
-                                                  : apron_text(scroll, buf));
+        pline("\"%s\"%s", mesg, endpunct);
 #else
-        pline("\81u%s\81v", (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf)
-                                                  : apron_text(scroll, buf));
+        pline("\81u%s\81v", mesg);
 #endif
         return 1;
     } else if (scroll->otyp == CREDIT_CARD) {
         static const char *card_msgs[] = {
+#if 0 /*JP:T*/
             "Leprechaun Gold Tru$t - Shamrock Card",
-            "Magic Memory Vault Charge Card", "Larn National Bank", /* Larn */
+            "Magic Memory Vault Charge Card",
+            "Larn National Bank",                /* Larn */
             "First Bank of Omega",               /* Omega */
             "Bank of Zork - Frobozz Magic Card", /* Zork */
             "Ankh-Morpork Merchant's Guild Barter Card",
@@ -246,6 +390,21 @@ doread()
             "Yendorian Express - Gold Card",
             "Yendorian Express - Mithril Card",
             "Yendorian Express - Platinum Card", /* must be last */
+#else
+            "\83\8c\83v\83\89\83R\81[\83\93\90M\97p\8bà\8cÉ - \83N\83\8d\81[\83o\81[\83J\81[\83h",
+            "\96\82\96@\8bL\94O\91q\8cÉ\83N\83\8c\83W\83b\83g\83J\81[\83h", "\83\89\81[\83\93\8d\91\89c\8bâ\8ds", /* Larn */
+            "\83I\83\81\83K\91æ\88ê\8bâ\8ds",               /* Omega */
+            "\83]\81[\83N\8bâ\8ds - Bank of Zork - \83t\83\8d\83{\83Y\96\82\96@\83J\81[\83h", /* Zork */
+            "\83A\83\93\83N\83\82\83\8b\83|\81[\83N\8f¤\90l\83M\83\8b\83\8cð\88Õ\83J\81[\83h",
+            "\83A\83\93\83N\83\82\83\8b\83|\81[\83N\93\90\91¯\83M\83\8b\83\96³\90§\8cÀ\8eæ\88ø\83J\81[\83h",
+            "\83\89\83\93\83X\83}\83\93\83X\83x\83C\91Ý\8bà\8bÆ\8b¦\89ï",
+            "\83Q\83w\83i\8bâ\8ds - \97\98\8eq99%\83J\81[\83h",
+            "\83C\83F\83\93\83_\81[\88ó\83G\83L\83X\83v\83\8c\83X\83J\81[\83h - \83J\83b\83p\81[\83J\81[\83h",
+            "\83C\83F\83\93\83_\81[\88ó\83G\83L\83X\83v\83\8c\83X\83J\81[\83h - \83V\83\8b\83o\81[\83J\81[\83h",
+            "\83C\83F\83\93\83_\81[\88ó\83G\83L\83X\83v\83\8c\83X\83J\81[\83h - \83S\81[\83\8b\83h\83J\81[\83h",
+            "\83C\83F\83\93\83_\81[\88ó\83G\83L\83X\83v\83\8c\83X\83J\81[\83h - \83~\83X\83\8a\83\8b\83J\81[\83h",
+            "\83C\83F\83\93\83_\81[\88ó\83G\83L\83X\83v\83\8c\83X\83J\81[\83h - \83v\83\89\83`\83i\83J\81[\83h", /* must be last */
+#endif
         };
 
         if (Blind) {
@@ -268,10 +427,14 @@ doread()
                       : card_msgs[scroll->o_id % (SIZE(card_msgs) - 1)]);
         }
         /* Make a credit card number */
-        pline("\"%d0%d %d%d1 0%d%d0\"", ((scroll->o_id % 89) + 10),
-              (scroll->o_id % 4), (((scroll->o_id * 499) % 899999) + 100000),
-              (scroll->o_id % 10), (!(scroll->o_id % 3)),
-              ((scroll->o_id * 7) % 10));
+        pline("\"%d0%d %ld%d1 0%d%d0\"%s",
+              (((int) scroll->o_id % 89) + 10),
+              ((int) scroll->o_id % 4),
+              ((((long) scroll->o_id * 499L) % 899999L) + 100000L),
+              ((int) scroll->o_id % 10),
+              (!((int) scroll->o_id % 3)),
+              (((int) scroll->o_id * 7) % 10),
+              (flags.verbose || Blind) ? "." : "");
         u.uconduct.literate++;
         return 1;
     } else if (scroll->otyp == CAN_OF_GREASE) {
@@ -285,7 +448,7 @@ doread()
 /*JP
             You_cant("feel any Braille writing.");
 */
-            You("\93_\8e\9a\82Í\82Ç\82¤\82à\8f\91\82¢\82Ä\82È\82¢\82æ\82¤\82¾\81D");
+            pline("\93_\8e\9a\82Í\82Ç\82¤\82à\8f\91\82¢\82Ä\82È\82¢\82æ\82¤\82¾\81D");
             return 0;
         }
         if (flags.verbose)
@@ -294,7 +457,7 @@ doread()
 */
             pline("\82»\82ê\82ð\93Ç\82ñ\82¾\81F");
 /*JP
-        pline("\"Magic Marker(TM) Red Ink Marker Pen. Water Soluble.\"");
+        pline("\"Magic Marker(TM) Red Ink Marker Pen.  Water Soluble.\"");
 */
         pline("\81u\96\82\96@\82Ì\83}\81[\83J(TM) \90Ô\83C\83\93\83N\83}\81[\83J\83y\83\93\81D\90\85\90«\81D\81v");
         u.uconduct.literate++;
@@ -310,7 +473,7 @@ doread()
             You("read:");
 */
             pline("\82»\82ê\82ð\93Ç\82ñ\82¾\81F");
-        pline("\"1 Zorkmid. 857 GUE. In Frobs We Trust.\"");
+        pline("\"1 Zorkmid.  857 GUE.  In Frobs We Trust.\"");
         u.uconduct.literate++;
         return 1;
     } else if (scroll->oartifact == ART_ORB_OF_FATE) {
@@ -345,14 +508,16 @@ doread()
 /*JP
             You_cant("feel any Braille writing.");
 */
-            You("\93_\8e\9a\82Í\82Ç\82¤\82à\8f\91\82¢\82Ä\82È\82¢\82æ\82¤\82¾\81D");
+            pline("\93_\8e\9a\82Í\82Ç\82¤\82à\8f\91\82¢\82Ä\82È\82¢\82æ\82¤\82¾\81D");
             return 0;
         }
-/*JP
-        pline("The wrapper reads: \"%s\"",
-*/
-        pline("\95ï\82Ý\8e\86\82Ì\95\8e\9a\82ð\93Ç\82ñ\82¾\81F\81u%s\81v",
+#if 0 /*JP:T*/
+        pline("The wrapper reads: \"%s\".",
+              wrapper_msgs[scroll->o_id % SIZE(wrapper_msgs)]);
+#else
+        pline("\95ï\82Ý\8e\86\82Ì\95\8e\9a\82ð\93Ç\82ñ\82¾\81F\81u%s\81v.",
               wrapper_msgs[scroll->o_id % SIZE(wrapper_msgs)]);
+#endif
         u.uconduct.literate++;
         return 1;
     } else if (scroll->oclass != SCROLL_CLASS
@@ -364,6 +529,7 @@ doread()
         return 0;
     } else if (Blind && (scroll->otyp != SPE_BOOK_OF_THE_DEAD)) {
         const char *what = 0;
+
         if (scroll->oclass == SPBOOK_CLASS)
 /*JP
             what = "mystic runes";
@@ -395,9 +561,15 @@ doread()
            maintained illiterate conduct so far, and this mail
            scroll didn't come from bones, ask for confirmation */
         if (!u.uconduct.literate) {
+#if 0 /*JP:T*/
             if (!scroll->spe && yn(
              "Reading mail will violate \"illiterate\" conduct.  Read anyway?"
                                    ) != 'y')
+#else
+            if (!scroll->spe && yn(
+             "\83\81\81[\83\8b\82ð\93Ç\82Þ\82Æ\81u\95\8e\9a\82ð\93Ç\82Ü\82È\82¢\81v\92§\90í\82É\88á\94½\82·\82é\82¯\82Ç\81C\82»\82ê\82Å\82à\93Ç\82Þ\81H"
+                                   ) != 'y')
+#endif
                 return 0;
         }
     }
@@ -415,25 +587,27 @@ doread()
     }
     scroll->in_use = TRUE; /* scroll, not spellbook, now being read */
     if (scroll->otyp != SCR_BLANK_PAPER) {
+        boolean silently = !can_chant(&youmonst);
+
         /* a few scroll feedback messages describe something happening
            to the scroll itself, so avoid "it disappears" for those */
         nodisappear = (scroll->otyp == SCR_FIRE
                        || (scroll->otyp == SCR_REMOVE_CURSE
                            && scroll->cursed));
         if (Blind)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline(nodisappear
                       ? "You %s the formula on the scroll."
                       : "As you %s the formula on it, the scroll disappears.",
-                  is_silent(youmonst.data) ? "cogitate" : "pronounce");
+                  silently ? "cogitate" : "pronounce");
 #else
             pline(nodisappear
                       ? "\82 \82È\82½\82Í\8eô\95\82ð%s\82½\81D"
                       : "\8eô\95\82ð%s\82é\82Æ\81C\8aª\95¨\82Í\8fÁ\82¦\82½\81D",
-                  is_silent(youmonst.data) ? "\94O\82¶" : "\8f¥\82¦");
+                  silently ? "\94O\82¶" : "\8f¥\82¦");
 #endif
         else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline(nodisappear ? "You read the scroll."
                               : "As you read the scroll, it disappears.");
 #else
@@ -447,10 +621,9 @@ doread()
 */
                 pline("\82Æ\82Ä\82à\82Ö\82ë\82Ö\82ë\82È\82Ì\82Å\81C\82­\82µ\82á\82­\82µ\82á\82É\82µ\82Ä\82µ\82Ü\82Á\82½\81D\81D\81D");
             else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("Being confused, you %s the magic words...",
-                      is_silent(youmonst.data) ? "misunderstand"
-                                               : "mispronounce");
+                      silently ? "misunderstand" : "mispronounce");
 #else
                 pline("\8d¬\97\90\82µ\82Ä\82¢\82é\82Ì\82Å\81C\8eô\95\82ð\8aÔ\88á\82Á\82Ä\82µ\82Ü\82Á\82½\81D\81D\81D");
 #endif
@@ -504,12 +677,12 @@ p_glow2(otmp, color)
 register struct obj *otmp;
 register const char *color;
 {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     pline("%s%s%s for a moment.", Yobjnam2(otmp, Blind ? "vibrate" : "glow"),
           Blind ? "" : " ", Blind ? "" : hcolor(color));
 #else
     Your("%s\82Í\88ê\8fu%s%s\81D", xname(otmp),
-         Blind ? "" : jconj_adj(hcolor(color)),
+         Blind ? "" : hcolor_adv(color),
          Blind ? "\90U\93®\82µ\82½" : "\8bP\82¢\82½");
 #endif
 }
@@ -614,7 +787,7 @@ int curse_bless;
 
         /* destruction depends on current state, not adjustment */
         if (obj->spe > rn2(7) || obj->spe <= -5) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("%s momentarily, then %s!", Yobjnam2(obj, "pulsate"),
                   otense(obj, "explode"));
 #else
@@ -631,7 +804,7 @@ int curse_bless;
         } else {
             long mask = is_on ? (obj == uleft ? LEFT_RING : RIGHT_RING) : 0L;
 
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("%s spins %sclockwise for a moment.", Yname2(obj),
                   s < 0 ? "counter" : "");
 #else
@@ -722,7 +895,7 @@ int curse_bless;
                 stripspe(obj);
                 if (obj->lamplit) {
                     if (!Blind)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                         pline("%s out!", Tobjnam(obj, "go"));
 #else
                         pline("%s\82Í\8fÁ\82¦\82½\81I", xname(obj));
@@ -1031,7 +1204,7 @@ struct obj *sobj;
     unsigned was_peaceful = mtmp->mpeaceful;
 
     if (sobj->cursed) {
-        setmangry(mtmp);
+        setmangry(mtmp, FALSE);
         if (was_peaceful && !mtmp->mpeaceful)
             return -1;
     } else {
@@ -1045,12 +1218,21 @@ struct obj *sobj;
     return 0;
 }
 
-boolean
+STATIC_OVL boolean
+get_valid_stinking_cloud_pos(x,y)
+int x,y;
+{
+    return (!(!isok(x,y) || !cansee(x, y)
+              || !ACCESSIBLE(levl[x][y].typ)
+              || distu(x, y) >= 32));
+}
+
+STATIC_OVL boolean
 is_valid_stinking_cloud_pos(x, y, showmsg)
 int x, y;
 boolean showmsg;
 {
-    if (!cansee(x, y) || !ACCESSIBLE(levl[x][y].typ) || distu(x, y) >= 32) {
+    if (!get_valid_stinking_cloud_pos(x,y)) {
         if (showmsg)
 /*JP
             You("smell rotten eggs.");
@@ -1061,7 +1243,7 @@ boolean showmsg;
     return TRUE;
 }
 
-void
+STATIC_PTR void
 display_stinking_cloud_positions(state)
 int state;
 {
@@ -1075,7 +1257,7 @@ int state;
             for (dy = -dist; dy <= dist; dy++) {
                 x = u.ux + dx;
                 y = u.uy + dy;
-                if (isok(x, y) && is_valid_stinking_cloud_pos(x, y, FALSE))
+                if (get_valid_stinking_cloud_pos(x,y))
                     tmp_at(x, y);
             }
     } else {
@@ -1104,15 +1286,22 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
 #ifdef MAIL
     case SCR_MAIL:
         known = TRUE;
-        if (sobj->spe)
+        if (sobj->spe == 2)
+            /* "stamped scroll" created via magic marker--without a stamp */
+/*JP
+            pline("This scroll is marked \"postage due\".");
+*/
+            pline("\82±\82Ì\8aª\95¨\82É\82Í\81u\97¿\8bà\95s\91«\81v\82Æ\8f\91\82¢\82Ä\82 \82é\81D");
+        else if (sobj->spe)
+            /* scroll of mail obtained from bones file or from wishing;
+             * note to the puzzled: the game Larn actually sends you junk
+             * mail if you win!
+             */
             pline(
 /*JP
     "This seems to be junk mail addressed to the finder of the Eye of Larn.");
 */
     "Eye of Larn\82Ì\94­\8c©\8eÒ\82É\88\82Ä\82ç\82ê\82½\83S\83~\83\81\83C\83\8b\82Ì\82æ\82¤\82¾\81D");
-        /* note to the puzzled: the game Larn actually sends you junk
-         * mail if you win!
-         */
         else
             readmail(sobj);
         break;
@@ -1124,7 +1313,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
 
         otmp = some_armor(&youmonst);
         if (!otmp) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             strange_feeling(sobj, !Blind
                                       ? "Your skin glows then fades."
                                       : "Your skin feels warm for a moment.");
@@ -1150,7 +1339,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                 Your("%s\82Í\88ê\8fu\92g\82©\82­\82È\82Á\82½\81D", xname(otmp));
             } else {
                 otmp->rknown = TRUE;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("%s covered by a %s %s %s!", Yobjnam2(otmp, "are"),
                       scursed ? "mottled" : "shimmering",
                       hcolor(scursed ? NH_BLACK : NH_GOLDEN),
@@ -1158,7 +1347,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                               : (is_shield(otmp) ? "layer" : "shield"));
 #else
                 Your("%s\82Í%s%s%s\82Å\95¢\82í\82ê\82½\81I", xname(otmp),
-                     jconj_adj(hcolor(scursed ? NH_BLACK : NH_GOLDEN)),
+                     hcolor_adv(scursed ? NH_BLACK : NH_GOLDEN),
                      scursed ? "\8cõ\82é\82Ü\82¾\82ç\82Ì" : "\82ä\82ç\82ß\82­",
                      scursed ? "\8bP\82«"
                              : "\83o\83\8a\83A");
@@ -1166,7 +1355,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             }
             if (new_erodeproof && (otmp->oeroded || otmp->oeroded2)) {
                 otmp->oeroded = otmp->oeroded2 = 0;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("%s as good as new!",
                       Yobjnam2(otmp, Blind ? "feel" : "look"));
 #else
@@ -1199,7 +1388,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
         s = scursed ? -otmp->spe : otmp->spe;
         if (s > (special_armor ? 5 : 3) && rn2(s)) {
             otmp->in_use = TRUE;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("%s violently %s%s%s for a while, then %s.", Yname2(otmp),
                   otense(otmp, Blind ? "vibrate" : "glow"),
                   (!Blind && !same_color) ? " " : "",
@@ -1208,16 +1397,19 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                   otense(otmp, "evaporate"));
 #else
             Your("%s\82Í\82µ\82Î\82ç\82­\82Ì\8aÔ\8c\83\82µ\82­%s%s\81C\8fö\94­\82µ\82½\81D", xname(otmp),
-                 (Blind || same_color) ? "" : jconj_adj(hcolor(scursed ? NH_BLACK : NH_SILVER)),
+                 (Blind || same_color) ? "" : hcolor_adv(scursed ? NH_BLACK : NH_SILVER),
                  Blind ? "\90U\93®\82µ" : "\8bP\82«");
 #endif
             remove_worn_item(otmp, FALSE);
             useup(otmp);
             break;
         }
-        s = scursed ? -1 : otmp->spe >= 9
-                               ? (rn2(otmp->spe) == 0)
-                               : sblessed ? rnd(3 - otmp->spe / 3) : 1;
+        s = scursed ? -1
+                    : (otmp->spe >= 9)
+                       ? (rn2(otmp->spe) == 0)
+                       : sblessed
+                          ? rnd(3 - otmp->spe / 3)
+                          : 1;
         if (s >= 0 && Is_dragon_scales(otmp)) {
             /* dragon scales get turned into dragon scale mail */
 /*JP
@@ -1239,20 +1431,20 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                 alter_cost(otmp, 0L); /* shop bill */
             break;
         }
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         pline("%s %s%s%s%s for a %s.", Yname2(otmp),
               s == 0 ? "violently " : "",
               otense(otmp, Blind ? "vibrate" : "glow"),
               (!Blind && !same_color) ? " " : "",
-              (Blind || same_color) ? ""
-                                    : hcolor(scursed ? NH_BLACK : NH_SILVER),
+              (Blind || same_color)
+                 ? "" : hcolor(scursed ? NH_BLACK : NH_SILVER),
               (s * s > 1) ? "while" : "moment");
 #else
         Your("%s\82Í%s%s%s%s\81D", xname(otmp),
              (s * s > 1) ? "\82µ\82Î\82ç\82­\82Ì\8aÔ" : "\88ê\8fu",
              s == 0 ? "\8c\83\82µ\82­" : "",
              (Blind || same_color) ? ""
-                                   : jconj_adj(hcolor(sobj->cursed ? NH_BLACK : NH_SILVER)),
+                                   : hcolor_adv(sobj->cursed ? NH_BLACK : NH_SILVER),
              Blind ? "\90U\93®\82µ\82½" : "\8bP\82¢\82½");
 #endif
         /* [this cost handling will need updating if shop pricing is
@@ -1263,6 +1455,8 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             curse(otmp);
         else if (sblessed && !otmp->blessed)
             bless(otmp);
+        else if (!scursed && otmp->cursed)
+            uncurse(otmp);
         if (s) {
             otmp->spe += s;
             adj_abon(otmp, s);
@@ -1274,7 +1468,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
 
         if ((otmp->spe > (special_armor ? 5 : 3))
             && (special_armor || !rn2(7)))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("%s %s.", Yobjnam2(otmp, "suddenly vibrate"),
                   Blind ? "again" : "unexpectedly");
 #else
@@ -1339,28 +1533,28 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
 /*JP
                 You_feel("confused.");
 */
-                You_feel("confused.");
+                You_feel("\8d¬\97\90\82µ\82½\81D");
             make_confused(HConfusion + rnd(100), FALSE);
         } else if (confused) {
             if (!sblessed) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 Your("%s begin to %s%s.", makeplural(body_part(HAND)),
                      Blind ? "tingle" : "glow ",
                      Blind ? "" : hcolor(NH_PURPLE));
 #else
                 Your("%s\82Í%s%s\82Í\82\82ß\82½\81D", makeplural(body_part(HAND)),
-                     Blind ? "" : jconj_adj(hcolor(NH_PURPLE)),
+                     Blind ? "" : hcolor_adv(NH_PURPLE),
                      Blind ? "\83q\83\8a\83q\83\8a\82µ" : "\8bP\82«");
 #endif
                 make_confused(HConfusion + rnd(100), FALSE);
             } else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("A %s%s surrounds your %s.",
                       Blind ? "" : hcolor(NH_RED),
                       Blind ? "faint buzz" : " glow", body_part(HEAD));
 #else
                 pline("%s%s\82ª\82 \82È\82½\82Ì%s\82ð\8eæ\82è\8aª\82¢\82½\81D",
-                      Blind ? "" : jconj_adj(hcolor(NH_RED)),
+                      Blind ? "" : hcolor_adv(NH_RED),
                       Blind ? "\82©\82·\82©\82É\83u\81[\83\93\82Æ\96Â\82é\82à\82Ì" : "\8bP\82­\82à\82Ì",
                       body_part(HEAD));
 #endif
@@ -1368,7 +1562,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             }
         } else {
             if (!sblessed) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 Your("%s%s %s%s.", makeplural(body_part(HAND)),
                      Blind ? "" : " begin to glow",
                      Blind ? (const char *) "tingle" : hcolor(NH_RED),
@@ -1376,13 +1570,13 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
 #else
                 Your("%s\82Í%s%s%s\81D", makeplural(body_part(HAND)),
                      u.umconf ? "\8f­\82µ" : "",
-                     Blind ? (const char *) "\83q\83\8a\83q\83\8a\82µ\82½" : jconj_adj(hcolor(NH_RED)),
+                     Blind ? (const char *) "\83q\83\8a\83q\83\8a\82µ\82½" : hcolor_adv(NH_RED),
                      Blind ? "" : "\8bP\82«\82Í\82\82ß\82½");
 #endif
                 u.umconf++;
             } else {
                 if (Blind)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                     Your("%s tingle %s sharply.", makeplural(body_part(HAND)),
                          u.umconf ? "even more" : "very");
 #else
@@ -1390,14 +1584,14 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                          u.umconf ? "\8f­\82µ" : "\82Æ\82Ä\82à");
 #endif
                 else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                     Your("%s glow a%s brilliant %s.",
                          makeplural(body_part(HAND)),
                          u.umconf ? "n even more" : "", hcolor(NH_RED));
 #else
                     Your("%s\82Í%s%s\96¾\82é\82­\8bP\82¢\82½\81D",
                          makeplural(body_part(HAND)),
-                         u.umconf ? "\8f­\82µ" : "", jconj_adj(hcolor(NH_RED)));
+                         u.umconf ? "\8f­\82µ" : "", hcolor_adv(NH_RED));
 #endif
                 /* after a while, repeated uses become less effective */
                 if (u.umconf >= 40)
@@ -1426,12 +1620,13 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             }
         }
         if (otyp == SCR_SCARE_MONSTER || !ct)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             You_hear("%s %s.", (confused || scursed) ? "sad wailing"
                                                      : "maniacal laughter",
                      !ct ? "in the distance" : "close by");
 #else
-            You_hear("\89\93\82­\82Å%s\82ð\95·\82¢\82½\81D",
+            You_hear("%s\82­\82Å%s\82ð\95·\82¢\82½\81D",
+                     !ct ? "\89\93" : "\8bß",
                      (confused || sobj->cursed) ? "\94ß\82µ\82­\8b\83\82«\8b©\82Ô\90º"
                                                 : "\8b\82Á\82½\82æ\82¤\82É\8fÎ\82¤\90º");
 #endif
@@ -1454,7 +1649,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
     case SPE_REMOVE_CURSE: {
         register struct obj *obj;
 
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         You_feel(!Hallucination
                      ? (!confused ? "like someone is helping you."
                                   : "like you need some help.")
@@ -1476,9 +1671,14 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
         } else {
             for (obj = invent; obj; obj = obj->nobj) {
                 long wornmask;
+
                 /* gold isn't subject to cursing and blessing */
                 if (obj->oclass == COIN_CLASS)
                     continue;
+                /* hide current scroll from itself so that perm_invent won't
+                   show known blessed scroll losing bknown when confused */
+                if (obj == sobj && obj->quan == 1L)
+                    continue;
                 wornmask = (obj->owornmask & ~(W_BALL | W_ART | W_ARTI));
                 if (wornmask && !sblessed) {
                     /* handle a couple of special cases; we don't
@@ -1508,8 +1708,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                 if (sblessed || wornmask || obj->otyp == LOADSTONE
                     || (obj->otyp == LEASH && obj->leashmon)) {
                     /* water price varies by curse/bless status */
-                    boolean shop_h2o =
-                        (obj->unpaid && obj->otyp == POT_WATER);
+                    boolean shop_h2o = (obj->unpaid && obj->otyp == POT_WATER);
 
                     if (confused) {
                         blessorcurse(obj, 2);
@@ -1554,8 +1753,11 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
          */
         break;
     case SCR_ENCHANT_WEAPON:
+        /* [What about twoweapon mode?  Proofing/repairing/enchanting both
+           would be too powerful, but shouldn't we choose randomly between
+           primary and secondary instead of always acting on primary?] */
         if (confused && uwep
-            && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) {
+            && erosion_matters(uwep) && uwep->oclass != ARMOR_CLASS) {
             old_erodeproof = (uwep->oerodeproof != 0);
             new_erodeproof = !scursed;
             uwep->oerodeproof = 0; /* for messages */
@@ -1567,21 +1769,21 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                 pline("\95\90\8aí\82ª\88ê\8fu\92g\82©\82­\82È\82Á\82½\82æ\82¤\82È\8bC\82ª\82µ\82½\81D");
             } else {
                 uwep->rknown = TRUE;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("%s covered by a %s %s %s!", Yobjnam2(uwep, "are"),
                       scursed ? "mottled" : "shimmering",
                       hcolor(scursed ? NH_PURPLE : NH_GOLDEN),
                       scursed ? "glow" : "shield");
 #else
                 Your("%s\82Í%s%s%s\82Å\95¢\82í\82ê\82½\81I", xname(uwep),
-                     jconj_adj(hcolor(scursed ? NH_PURPLE : NH_GOLDEN)),
+                     hcolor_adv(scursed ? NH_PURPLE : NH_GOLDEN),
                      scursed ? "\8cõ\82é\82Ü\82¾\82ç\82Ì" : "\82ä\82ç\82ß\82­",
                      scursed ? "\8bP\82«" : "\83o\83\8a\83A");
 #endif
             }
             if (new_erodeproof && (uwep->oeroded || uwep->oeroded2)) {
                 uwep->oeroded = uwep->oeroded2 = 0;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("%s as good as new!",
                       Yobjnam2(uwep, Blind ? "feel" : "look"));
 #else
@@ -1596,13 +1798,11 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             uwep->oerodeproof = new_erodeproof ? 1 : 0;
             break;
         }
-        if (!chwepon(sobj,
-                     scursed
-                         ? -1
-                         : !uwep ? 1 : (uwep->spe >= 9)
-                                           ? !rn2(uwep->spe)
-                                           : sblessed ? rnd(3 - uwep->spe / 3)
-                                                      : 1))
+        if (!chwepon(sobj, scursed ? -1
+                             : !uwep ? 1
+                               : (uwep->spe >= 9) ? !rn2(uwep->spe)
+                                 : sblessed ? rnd(3 - uwep->spe / 3)
+                                   : 1))
             sobj = 0; /* nothing enchanted: strange_feeling -> useup */
         break;
     case SCR_TAMING:
@@ -1634,16 +1834,28 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
                 }
         }
         if (!results) {
+#if 0 /*JP:T*/
             pline("Nothing interesting %s.",
                   !candidates ? "happens" : "seems to happen");
+#else
+            pline("\89½\82à\96Ê\94\92\82¢\82±\82Æ\82Í\82¨\82±\82ç\82È\82©\82Á\82½%s\81D",
+                  !candidates ? "" : "\82æ\82¤\82¾");
+#endif
         } else {
+#if 0 /*JP:T*/
             pline_The("neighborhood %s %sfriendlier.",
                       vis_results ? "is" : "seems",
                       (results < 0) ? "un" : "");
+#else
+            pline_The("\82¨\97×\82Æ\82Ì\92\87\82ª%s\82­\82È\82Á\82½%s\81D",
+                      (results < 0) ? "\88«" : "\97Ç",
+                      vis_results ? "" : "\82æ\82¤\82¾");
+#endif
             if (vis_results > 0)
                 known = TRUE;
         }
-    } break;
+        break;
+    }
     case SCR_GENOCIDE:
         if (!already_known)
 /*JP
@@ -1654,7 +1866,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
         if (sblessed)
             do_class_genocide();
         else
-            do_genocide(!scursed | (2 * !!Confusion));
+            do_genocide((!scursed) | (2 * !!Confusion));
         break;
     case SCR_LIGHT:
         if (!confused || rn2(5)) {
@@ -1670,8 +1882,6 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             (void) create_critters(1, !scursed ? &mons[PM_YELLOW_LIGHT]
                                                : &mons[PM_BLACK_LIGHT],
                                    TRUE);
-            if (!objects[sobj->otyp].oc_uname)
-                docall(sobj);
         }
         break;
     case SCR_TELEPORTATION:
@@ -1725,7 +1935,10 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             /* when casting a spell we know we're not confused,
                so inventory must be empty (another message has
                already been given above if reading a scroll) */
+/*JP
             pline("You're not carrying anything to be identified.");
+*/
+            pline("\82 \82È\82½\82Í\8e¯\95Ê\82Å\82«\82é\82à\82Ì\82ð\82È\82É\82à\8e\9d\82Á\82Ä\82¢\82È\82¢\81D");
         }
         break;
     case SCR_CHARGING:
@@ -1796,9 +2009,10 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             /* do_mapping() already reveals secret passages */
         }
         known = TRUE;
+        /*FALLTHRU*/
     case SPE_MAGIC_MAPPING:
         if (level.flags.nommap) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             Your("%s spins as %s blocks the spell!", body_part(HEAD),
                  something);
 #else
@@ -1850,8 +2064,14 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             pline("Maud\82ð\8dl\82¦\82é\82±\82Æ\88È\8aO\81C\82 \82È\82½\82Í\91S\82Ä\82ð\96Y\82ê\82Ä\82µ\82Ü\82Á\82½\81D");
         exercise(A_WIS, FALSE);
         break;
-    case SCR_FIRE:
+    case SCR_FIRE: {
+        coord cc;
+        int dam;
+
+        cc.x = u.ux;
+        cc.y = u.uy;
         cval = bcsign(sobj);
+        dam = (2 * (rn1(3, 3) + 2 * cval) + 1) / 3;
         useup(sobj);
         sobj = 0; /* it's gone */
         if (!already_known)
@@ -1886,20 +2106,45 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
         }
         if (Underwater) {
 /*JP
-            pline_The("water around you vaporizes violently!");
+            pline_The("%s around you vaporizes violently!", hliquid("water"));
 */
-            pline("\82 \82È\82½\82Ì\89ñ\82è\82Ì\90\85\82Í\95¦\93«\82µ\82½\81I");
+            pline_The("\82 \82È\82½\82Ì\89ñ\82è\82Ì%s\82Í\82Í\82°\82µ\82­\95¦\93«\82µ\82½\81I", hliquid("\90\85"));
         } else {
+            if (sblessed) {
+                if (!already_known)
+/*JP
+                    pline("This is a scroll of fire!");
+*/
+                    pline("\82±\82ê\82Í\89Î\82Ì\8aª\95¨\82¾\81I");
+                dam *= 5;
+/*JP
+                pline("Where do you want to center the explosion?");
+*/
+                pline("\82Ç\82±\82ð\94\9a\94­\82Ì\92\86\90S\82É\82µ\82Ü\82·\82©\81H");
+                getpos_sethilite(display_stinking_cloud_positions,
+                                 get_valid_stinking_cloud_pos);
 /*JP
-            pline_The("scroll erupts in a tower of flame!");
+                (void) getpos(&cc, TRUE, "the desired position");
 */
-            pline("\8aª\95¨\82©\82ç\89Î\92\8c\82ª\97§\82¿\8f¸\82Á\82½\81I");
-            iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */
-            burn_away_slime();
+                (void) getpos(&cc, TRUE, "\91_\82¢\82Ì\8fê\8f\8a");
+                if (!is_valid_stinking_cloud_pos(cc.x, cc.y, FALSE)) {
+                    /* try to reach too far, get burned */
+                    cc.x = u.ux;
+                    cc.y = u.uy;
+                }
+            }
+            if (cc.x == u.ux && cc.y == u.uy) {
+/*JP
+                pline_The("scroll erupts in a tower of flame!");
+*/
+                pline("\8aª\95¨\82©\82ç\89Î\92\8c\82ª\97§\82¿\8f¸\82Á\82½\81I");
+                iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */
+                burn_away_slime();
+            }
         }
-        explode(u.ux, u.uy, 11, (2 * (rn1(3, 3) + 2 * cval) + 1) / 3,
-                SCROLL_CLASS, EXPL_FIERY);
+        explode(cc.x, cc.y, 11, dam, SCROLL_CLASS, EXPL_FIERY);
         break;
+    }
     case SCR_EARTH:
         /* TODO: handle steeds */
         if (!Is_rogue_level(&u.uz) && has_ceiling(&u.uz)
@@ -1914,7 +2159,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
 */
                 You_hear("\83S\83\8d\83S\83\8d\82Æ\82¢\82¤\89¹\82ð\95·\82¢\82½\81D");
             else
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline_The("%s rumbles %s you!", ceiling(u.ux, u.uy),
                           sblessed ? "around" : "above");
 #else
@@ -1942,7 +2187,10 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
             if (!sblessed) {
                 drop_boulder_on_player(confused, !scursed, TRUE, FALSE);
             } else if (!nboulders)
+/*JP
                 pline("But nothing else happens.");
+*/
+                pline("\82µ\82©\82µ\91¼\82É\89½\82à\82¨\82±\82ç\82È\82©\82Á\82½\81D");
         }
         break;
     case SCR_PUNISHMENT:
@@ -1965,15 +2213,17 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
 */
             You("\88«\8fL\89_\82Ì\8aª\95¨\82ð\94­\8c©\82µ\82½\81I");
         known = TRUE;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         pline("Where do you want to center the %scloud?",
               already_known ? "stinking " : "");
 #else
-        pline("\89_\82Ì\92\86\90S\82ð\82Ç\82±\82É\82µ\82Ü\82·\82©\81H");
+        pline("%s\89_\82Ì\92\86\90S\82ð\82Ç\82±\82É\82µ\82Ü\82·\82©\81H",
+              already_known ? "\88«\8fL" : "");
 #endif
         cc.x = u.ux;
         cc.y = u.uy;
-        getpos_sethilite(display_stinking_cloud_positions);
+        getpos_sethilite(display_stinking_cloud_positions,
+                         get_valid_stinking_cloud_pos);
 /*JP
         if (getpos(&cc, TRUE, "the desired position") < 0) {
 */
@@ -1990,6 +2240,11 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
     default:
         impossible("What weird effect is this? (%u)", otyp);
     }
+    /* if sobj is gone, we've already called useup() above and the
+       update_inventory() that it performs might have come too soon
+       (before charging an item, for instance) */
+    if (!sobj)
+        update_inventory();
     return sobj ? 0 : 1;
 }
 
@@ -2035,6 +2290,7 @@ boolean confused, helmet_protects, byu, skip_uswallow;
         }
     } else
         dmg = 0;
+    wake_nearto(u.ux, u.uy, 4 * 4);
     /* Must be before the losehp(), for bones files */
 /*JP
     if (!flooreffects(otmp2, u.ux, u.uy, "fall")) {
@@ -2081,9 +2337,15 @@ boolean confused, byu;
             if (mtmp->minvis && !canspotmon(mtmp))
                 map_invisible(mtmp->mx, mtmp->my);
         } else if (u.uswallow && mtmp == u.ustuck)
+#if 0 /*JP:T*/
             You_hear("something hit %s %s over your %s!",
                      s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH),
                      body_part(HEAD));
+#else
+            You_hear("\89½\82©\82ª\82 \82È\82½\82Ì%s\82Ì\8fã\82Ì%s\82Ì%s\82É\93\96\82½\82Á\82½\89¹\82ð\95·\82¢\82½\81I",
+                     body_part(HEAD),
+                     mon_nam(mtmp), mbodypart(mtmp, STOMACH));
+#endif
 
         mdmg = dmgval(otmp2, mtmp) * otmp2->quan;
         if (helmet) {
@@ -2103,7 +2365,7 @@ boolean confused, byu;
                     mdmg = 2;
             } else {
                 if (canspotmon(mtmp))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                     pline("%s's %s does not protect %s.", Monnam(mtmp),
                           xname(helmet), mhim(mtmp));
 #else
@@ -2113,14 +2375,20 @@ boolean confused, byu;
             }
         }
         mtmp->mhp -= mdmg;
-        if (mtmp->mhp <= 0) {
-            if (byu)
-                xkilled(mtmp, 1);
-            else {
+        if (DEADMONSTER(mtmp)) {
+            if (byu) {
+                killed(mtmp);
+            } else {
+/*JP
                 pline("%s is killed.", Monnam(mtmp));
+*/
+                pline("%s\82Í\8e\80\82ñ\82¾\81D", Monnam(mtmp));
                 mondied(mtmp);
             }
+        } else {
+            wakeup(mtmp, byu);
         }
+        wake_nearto(x, y, 4 * 4);
     } else if (u.uswallow && mtmp == u.ustuck) {
         obfree(otmp2, (struct obj *) 0);
         /* fall through to player */
@@ -2184,7 +2452,7 @@ int chg; /* recharging */
     /* inflict damage and destroy the wand */
     dmg = d(n, k);
     obj->in_use = TRUE; /* in case losehp() is fatal (or --More--^C) */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
     pline("%s %s explodes!", Yname2(obj), expl);
 #else
     pline("%s\82Í%s\94\9a\94­\82µ\82½\81I", xname(obj), expl);
@@ -2273,7 +2541,7 @@ struct obj *obj;
             if (Blind)
                 ; /* no feedback */
             else if (is_animal(u.ustuck->data))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("%s %s is lit.", s_suffix(Monnam(u.ustuck)),
                       mbodypart(u.ustuck, STOMACH));
 #else
@@ -2363,7 +2631,7 @@ STATIC_OVL void
 do_class_genocide()
 {
     int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0;
-    char buf[BUFSZ];
+    char buf[BUFSZ] = DUMMY;
     boolean gameover = FALSE; /* true iff killed self */
 
     for (j = 0;; j++) {
@@ -2379,7 +2647,7 @@ do_class_genocide()
             (void) mungspaces(buf);
         } while (!*buf);
         /* choosing "none" preserves genocideless conduct */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         if (*buf == '\033' || !strcmpi(buf, "none")
             || !strcmpi(buf, "nothing"))
 #else
@@ -2484,9 +2752,9 @@ do_class_genocide()
                         if (Upolyd) {
                             if (!feel_dead++)
 /*JP
-                                You_feel("dead inside.");
+                                You_feel("%s inside.", udeadinside());
 */
-                                You("\8d°\82ª\8e\80\82ñ\82¾\82æ\82¤\82È\8bC\82ª\82µ\82½\81D");
+                                You("\8d°\82ª%s\82æ\82¤\82È\8bC\82ª\82µ\82½\81D", udeadinside());
                         } else {
                             if (!feel_dead++)
 /*JP
@@ -2559,7 +2827,7 @@ int how;
 /* 3 = forced genocide of player */
 /* 5 (4 | 1) = normal genocide from throne */
 {
-    char buf[BUFSZ];
+    char buf[BUFSZ] = DUMMY;
     register int i, killplayer = 0;
     register int mndx;
     register struct permonst *ptr;
@@ -2573,29 +2841,32 @@ int how;
     } else {
         for (i = 0;; i++) {
             if (i >= 5) {
+                /* cursed effect => no free pass (unless rndmonst() fails) */
+                if (!(how & REALLY) && (ptr = rndmonst()) != 0)
+                    break;
+
                 pline1(thats_enough_tries);
                 return;
             }
 /*JP
             getlin("What monster do you want to genocide? [type the name]",
 */
-            getlin("\82Ç\82Ì\89ö\95¨\82ð\8bs\8eE\82µ\82Ü\82·\82©\81H[\96¼\91O\82ð\93ü\82ê\82Ä\82Ë]",
+            getlin("\82Ç\82Ì\89ö\95¨\82ð\8bs\8eE\82µ\82Ü\82·\82©\81H[\96¼\91O\82ð\93ú\96{\8cê\82Å\93ü\82ê\82Ä\82Ë]",
                    buf);
             (void) mungspaces(buf);
             /* choosing "none" preserves genocideless conduct */
-/*JP
-            if (!strcmpi(buf, "none") || !strcmpi(buf, "nothing")) {
-*/
-            if (!strcmpi(buf, "\82È\82µ") || !strcmpi(buf, "\96³\82µ")) {
+#if 0 /*JP:T*/
+            if (*buf == '\033' || !strcmpi(buf, "none")
+                || !strcmpi(buf, "nothing")) {
+#else
+            if (*buf == '\033' || !strcmpi(buf, "\82È\82µ")
+                || !strcmpi(buf, "\96³\82µ")) {
+#endif
                 /* ... but no free pass if cursed */
-                if (!(how & REALLY)) {
-                    ptr = rndmonst();
-                    if (!ptr)
-                        return; /* no message, like normal case */
-                    mndx = monsndx(ptr);
+                if (!(how & REALLY) && (ptr = rndmonst()) != 0)
                     break; /* remaining checks don't apply */
-                } else
-                    return;
+
+                return;
             }
 
             mndx = name_to_mon(buf);
@@ -2624,14 +2895,15 @@ int how;
 
             if (!(ptr->geno & G_GENO)) {
                 if (!Deaf) {
-                    /* fixme: unconditional "caverns" will be silly in some
-                     * circumstances */
+                    /* FIXME: unconditional "caverns" will be silly in some
+                     * circumstances.  Who's speaking?  Divine pronouncements
+                     * aren't supposed to be hampered by deafness....
+                     */
                     if (flags.verbose)
-                        pline(
 /*JP
-                            "A thunderous voice booms through the caverns:");
+                        pline("A thunderous voice booms through the caverns:");
 */
-                            "\97\8b\82Ì\82æ\82¤\82È\90º\82ª\93´\8cA\82É\8b¿\82¢\82½\81F");
+                        pline("\97\8b\82Ì\82æ\82¤\82È\90º\82ª\93´\8cA\82É\8b¿\82¢\82½\81F");
 /*JP
                     verbalize("No, mortal!  That will not be done.");
 */
@@ -2644,6 +2916,7 @@ int how;
                 killplayer++;
             break;
         }
+        mndx = monsndx(ptr); /* needed for the 'no free pass' cases */
     }
 
 /*JP
@@ -2661,15 +2934,16 @@ int how;
     } else {
         Strcpy(buf, ptr->mname); /* make sure we have standard singular */
         if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_PRIEST])
-/*JP
+#if 0 /*JP*/
             which = !type_is_pname(ptr) ? "the " : "";
-*/
-            which = !type_is_pname(ptr) ? "" : "";
+#else
+            which = "";
+#endif
     }
     if (how & REALLY) {
         /* setting no-corpse affects wishing and random tin generation */
         mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
         pline("Wiped out %s%s.", which,
               (*which != 'a') ? buf : makeplural(buf));
 #else
@@ -2715,9 +2989,9 @@ int how;
             if (Upolyd && ptr != youmonst.data) {
                 delayed_killer(POLYMORPH, killer.format, killer.name);
 /*JP
-                You_feel("dead inside.");
+                You_feel("%s inside.", udeadinside());
 */
-                You("\8d°\82ª\8e\80\82ñ\82¾\82æ\82¤\82È\8bC\82ª\82µ\82½\81D");
+                You_feel("\8d°\82ª%s\82æ\82¤\82È\8bC\82ª\82µ\82½\81D", udeadinside());
             } else
                 done(GENOCIDED);
         } else if (ptr == youmonst.data) {
@@ -2742,7 +3016,7 @@ int how;
             /* accumulated 'cnt' doesn't take groups into account;
                assume bringing in new mon(s) didn't remove any old ones */
             cnt = monster_census(FALSE) - census;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("Sent in %s%s.", (cnt > 1) ? "some " : "",
                   (cnt > 1) ? makeplural(buf) : an(buf));
 #else
@@ -2771,7 +3045,7 @@ struct obj *sobj;
         Your("iron ball gets heavier.");
 */
         Your("\93S\8b\85\82Í\82³\82ç\82É\8fd\82­\82È\82Á\82½\81D");
-        uball->owt += 160 * (1 + sobj->cursed);
+        uball->owt += IRON_BALL_W_INCR * (1 + sobj->cursed);
         return;
     }
     if (amorphous(youmonst.data) || is_whirly(youmonst.data)
@@ -2795,8 +3069,8 @@ struct obj *sobj;
     uball->spe = 1; /* special ball (see save) */
 
     /*
-     *  Place ball & chain if not swallowed.  If swallowed, the ball &
-     *  chain variables will be set at the next call to placebc().
+     *  Place ball & chain if not swallowed.  If swallowed, the ball & chain
+     *  variables will be set at the next call to placebc().
      */
     if (!u.uswallow) {
         placebc();
@@ -2812,12 +3086,14 @@ unpunish()
 {
     struct obj *savechain = uchain;
 
+    /* chain goes away */
     obj_extract_self(uchain);
     newsym(uchain->ox, uchain->oy);
-    setworn((struct obj *) 0, W_CHAIN);
+    setworn((struct obj *) 0, W_CHAIN); /* sets 'uchain' to Null */
     dealloc_obj(savechain);
+    /* ball persists */
     uball->spe = 0;
-    setworn((struct obj *) 0, W_BALL);
+    setworn((struct obj *) 0, W_BALL); /* sets 'uball' to Null */
 }
 
 /* some creatures have special data structures that only make sense in their
@@ -2849,6 +3125,208 @@ struct obj *from_obj;
     return FALSE;
 }
 
+struct _create_particular_data {
+    int which;
+    int fem;
+    char monclass;
+    boolean randmonst;
+    boolean maketame, makepeaceful, makehostile;
+    boolean sleeping, saddled, invisible, hidden;
+};
+
+boolean
+create_particular_parse(str, d)
+char *str;
+struct _create_particular_data *d;
+{
+    char *bufp = str;
+    char *tmpp;
+
+    d->monclass = MAXMCLASSES;
+    d->which = urole.malenum; /* an arbitrary index into mons[] */
+    d->fem = -1; /* gender not specified */
+    d->randmonst = FALSE;
+    d->maketame = d->makepeaceful = d->makehostile = FALSE;
+    d->sleeping = d->saddled = d->invisible = d->hidden = FALSE;
+
+    if ((tmpp = strstri(bufp, "saddled ")) != 0) {
+        d->saddled = TRUE;
+        (void) memset(tmpp, ' ', sizeof "saddled " - 1);
+    }
+    if ((tmpp = strstri(bufp, "sleeping ")) != 0) {
+        d->sleeping = TRUE;
+        (void) memset(tmpp, ' ', sizeof "sleeping " - 1);
+    }
+    if ((tmpp = strstri(bufp, "invisible ")) != 0) {
+        d->invisible = TRUE;
+        (void) memset(tmpp, ' ', sizeof "invisible " - 1);
+    }
+    if ((tmpp = strstri(bufp, "hidden ")) != 0) {
+        d->hidden = TRUE;
+        (void) memset(tmpp, ' ', sizeof "hidden " - 1);
+    }
+    /* check "female" before "male" to avoid false hit mid-word */
+    if ((tmpp = strstri(bufp, "female ")) != 0) {
+        d->fem = 1;
+        (void) memset(tmpp, ' ', sizeof "female " - 1);
+    }
+    if ((tmpp = strstri(bufp, "male ")) != 0) {
+        d->fem = 0;
+        (void) memset(tmpp, ' ', sizeof "male " - 1);
+    }
+    bufp = mungspaces(bufp); /* after potential memset(' ') */
+    /* allow the initial disposition to be specified */
+#if 0 /*JP:T*/
+    if (!strncmpi(bufp, "tame ", 5)) {
+        bufp += 5;
+#else
+    if (!STRNCMP2(bufp, "\8eè\82È\82¸\82¯\82ç\82ê\82½")) {
+        bufp += 14;
+#endif
+        d->maketame = TRUE;
+#if 0 /*JP:T*/
+    } else if (!strncmpi(bufp, "peaceful ", 9)) {
+        bufp += 9;
+#else
+    } else if (!STRNCMP2(bufp, "\97F\8dD\93I\82È")) {
+        bufp += 8;
+#endif
+        d->makepeaceful = TRUE;
+#if 0 /*JP:T*/
+    } else if (!strncmpi(bufp, "hostile ", 8)) {
+        bufp += 8;
+#else
+    } else if (!STRNCMP2(bufp, "\93G\91Î\93I\82È")) {
+        bufp += 8;
+#endif
+        d->makehostile = TRUE;
+    }
+    /* decide whether a valid monster was chosen */
+/*JP
+    if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) {
+*/
+    if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "\83\89\83\93\83_\83\80"))) {
+        d->randmonst = TRUE;
+        return TRUE;
+    }
+    d->which = name_to_mon(bufp);
+    if (d->which >= LOW_PM)
+        return TRUE; /* got one */
+    d->monclass = name_to_monclass(bufp, &d->which);
+
+    if (d->which >= LOW_PM) {
+        d->monclass = MAXMCLASSES; /* matters below */
+        return TRUE;
+    } else if (d->monclass == S_invisible) { /* not an actual monster class */
+        d->which = PM_STALKER;
+        d->monclass = MAXMCLASSES;
+        return TRUE;
+    } else if (d->monclass == S_WORM_TAIL) { /* empty monster class */
+        d->which = PM_LONG_WORM;
+        d->monclass = MAXMCLASSES;
+        return TRUE;
+    } else if (d->monclass > 0) {
+        d->which = urole.malenum; /* reset from NON_PM */
+        return TRUE;
+    }
+    return FALSE;
+}
+
+boolean
+create_particular_creation(d)
+struct _create_particular_data *d;
+{
+    struct permonst *whichpm = NULL;
+    int i, mx, my, firstchoice = NON_PM;
+    struct monst *mtmp;
+    boolean madeany = FALSE;
+
+    if (!d->randmonst) {
+        firstchoice = d->which;
+        if (cant_revive(&d->which, FALSE, (struct obj *) 0)
+            && firstchoice != PM_LONG_WORM_TAIL) {
+            /* wizard mode can override handling of special monsters */
+            char buf[BUFSZ];
+
+#if 0 /*JP:T*/
+            Sprintf(buf, "Creating %s instead; force %s?",
+                    mons[d->which].mname, mons[firstchoice].mname);
+#else
+            Sprintf(buf, "\91ã\82í\82è\82É%s\82ª\8dì\82ç\82ê\82Ü\82·\81G%s\82É\82·\82é\81H",
+                    mons[d->which].mname, mons[firstchoice].mname);
+#endif
+            if (yn(buf) == 'y')
+                d->which = firstchoice;
+        }
+        whichpm = &mons[d->which];
+    }
+    for (i = 0; i <= multi; i++) {
+        if (d->monclass != MAXMCLASSES)
+            whichpm = mkclass(d->monclass, 0);
+        else if (d->randmonst)
+            whichpm = rndmonst();
+        mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS);
+        if (!mtmp) {
+            /* quit trying if creation failed and is going to repeat */
+            if (d->monclass == MAXMCLASSES && !d->randmonst)
+                break;
+            /* otherwise try again */
+            continue;
+        }
+        mx = mtmp->mx, my = mtmp->my;
+        /* 'is_FOO()' ought to be called 'always_FOO()' */
+        if (d->fem != -1 && !is_male(mtmp->data) && !is_female(mtmp->data))
+            mtmp->female = d->fem; /* ignored for is_neuter() */
+        if (d->maketame) {
+            (void) tamedog(mtmp, (struct obj *) 0);
+        } else if (d->makepeaceful || d->makehostile) {
+            mtmp->mtame = 0; /* sanity precaution */
+            mtmp->mpeaceful = d->makepeaceful ? 1 : 0;
+            set_malign(mtmp);
+        }
+        if (d->saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) {
+            struct obj *otmp = mksobj(SADDLE, TRUE, FALSE);
+
+            put_saddle_on_mon(otmp, mtmp);
+        }
+        if (d->invisible) {
+            mon_set_minvis(mtmp);
+            if (does_block(mx, my, &levl[mx][my]))
+                block_point(mx, my);
+            else
+                unblock_point(mx, my);
+        }
+       if (d->hidden
+           && ((is_hider(mtmp->data) && mtmp->data->mlet != S_MIMIC)
+               || (hides_under(mtmp->data) && OBJ_AT(mx, my))
+               || (mtmp->data->mlet == S_EEL && is_pool(mx, my))))
+            mtmp->mundetected = 1;
+        if (d->sleeping)
+            mtmp->msleeping = 1;
+        /* iff asking for 'hidden', show locaton of every created monster
+           that can't be seen--whether that's due to successfully hiding
+           or vision issues (line-of-sight, invisibility, blindness) */
+        if (d->hidden && !canspotmon(mtmp)) {
+            int count = couldsee(mx, my) ? 8 : 4;
+            char saveviz = viz_array[my][mx];
+
+            if (!flags.sparkle)
+                count /= 2;
+            viz_array[my][mx] |= (IN_SIGHT | COULD_SEE);
+            flash_glyph_at(mx, my, mon_to_glyph(mtmp, newsym_rn2), count);
+            viz_array[my][mx] = saveviz;
+            newsym(mx, my);
+        }
+        madeany = TRUE;
+        /* in case we got a doppelganger instead of what was asked
+           for, make it start out looking like what was asked for */
+        if (mtmp->cham != NON_PM && firstchoice != NON_PM
+            && mtmp->cham != firstchoice)
+            (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE);
+    }
+    return madeany;
+}
+
 /*
  * Make a new monster with the type controlled by the user.
  *
@@ -2864,19 +3342,11 @@ struct obj *from_obj;
 boolean
 create_particular()
 {
-    char buf[BUFSZ], *bufp, monclass;
-    int which, tryct, i, firstchoice = NON_PM;
-    struct permonst *whichpm = NULL;
-    struct monst *mtmp;
-    boolean madeany = FALSE;
-    boolean maketame, makepeaceful, makehostile;
-    boolean randmonst = FALSE;
+    char buf[BUFSZ] = DUMMY, *bufp;
+    int  tryct = 5;
+    struct _create_particular_data d;
 
-    tryct = 5;
     do {
-        monclass = MAXMCLASSES;
-        which = urole.malenum; /* an arbitrary index into mons[] */
-        maketame = makepeaceful = makehostile = FALSE;
 /*JP
         getlin("Create what kind of monster? [type the name or symbol]", buf);
 */
@@ -2884,51 +3354,10 @@ create_particular()
         bufp = mungspaces(buf);
         if (*bufp == '\033')
             return FALSE;
-        /* allow the initial disposition to be specified */
-#if 0 /*JP*/
-        if (!strncmpi(bufp, "tame ", 5)) {
-            bufp += 5;
-#else
-        if (!strncmpi(bufp, "\8eè\82È\82¸\82¯\82ç\82ê\82½", 14)) {
-            bufp += 14;
-#endif
-            maketame = TRUE;
-#if 0 /*JP*/
-        } else if (!strncmpi(bufp, "peaceful ", 9)) {
-            bufp += 9;
-#else
-        } else if (!strncmpi(bufp, "\97F\8dD\93I\82È", 8)) {
-            bufp += 8;
-#endif
-            makepeaceful = TRUE;
-#if 0 /*JP*/
-        } else if (!strncmpi(bufp, "hostile ", 8)) {
-            bufp += 8;
-#else
-        } else if (!strncmpi(bufp, "\93G\91Î\93I\82È", 8)) {
-            bufp += 8;
-#endif
-            makehostile = TRUE;
-        }
-        /* decide whether a valid monster was chosen */
-/*JP
-        if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) {
-*/
-        if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "\83\89\83\93\83_\83\80"))) {
-            randmonst = TRUE;
-            break;
-        }
-        which = name_to_mon(bufp);
-        if (which >= LOW_PM)
-            break; /* got one */
-        monclass = name_to_monclass(bufp, &which);
-        if (which >= LOW_PM) {
-            monclass = MAXMCLASSES; /* matters below */
-            break;
-        } else if (monclass > 0) {
-            which = urole.malenum; /* reset from NON_PM */
+
+        if (create_particular_parse(bufp, &d))
             break;
-        }
+
         /* no good; try again... */
 /*JP
         pline("I've never heard of such monsters.");
@@ -2936,54 +3365,12 @@ create_particular()
         pline("\82»\82Ì\82æ\82¤\82È\89ö\95¨\82Í\95·\82¢\82½\82±\82Æ\82ª\82È\82¢\81D");
     } while (--tryct > 0);
 
-    if (!tryct) {
+    if (!tryct)
         pline1(thats_enough_tries);
-    } else {
-        if (!randmonst) {
-            firstchoice = which;
-            if (cant_revive(&which, FALSE, (struct obj *) 0)) {
-                /* wizard mode can override handling of special monsters */
-#if 0 /*JP*/
-                Sprintf(buf, "Creating %s instead; force %s?",
-                        mons[which].mname, mons[firstchoice].mname);
-#else
-                Sprintf(buf, "\91ã\82í\82è\82É%s\82ª\8dì\82ç\82ê\82Ü\82·\81G%s\82É\82·\82é\81H",
-                        mons[which].mname, mons[firstchoice].mname);
-#endif
-                if (yn(buf) == 'y')
-                    which = firstchoice;
-            }
-            whichpm = &mons[which];
-        }
-        for (i = 0; i <= multi; i++) {
-            if (monclass != MAXMCLASSES)
-                whichpm = mkclass(monclass, 0);
-            else if (randmonst)
-                whichpm = rndmonst();
-            mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS);
-            if (!mtmp) {
-                /* quit trying if creation failed and is going to repeat */
-                if (monclass == MAXMCLASSES && !randmonst)
-                    break;
-                /* otherwise try again */
-                continue;
-            }
-            if (maketame) {
-                (void) tamedog(mtmp, (struct obj *) 0);
-            } else if (makepeaceful || makehostile) {
-                mtmp->mtame = 0; /* sanity precaution */
-                mtmp->mpeaceful = makepeaceful ? 1 : 0;
-                set_malign(mtmp);
-            }
-            madeany = TRUE;
-            /* in case we got a doppelganger instead of what was asked
-               for, make it start out looking like what was asked for */
-            if (mtmp->cham != NON_PM && firstchoice != NON_PM
-                && mtmp->cham != firstchoice)
-                (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE);
-        }
-    }
-    return madeany;
+    else
+        return create_particular_creation(&d);
+
+    return FALSE;
 }
 
 /*read.c*/