OSDN Git Service

update year to 2019
[jnethack/source.git] / src / mthrowu.c
index b63a479..7f389b2 100644 (file)
-/* NetHack 3.6 mthrowu.c       $NHDT-Date: 1446887531 2015/11/07 09:12:11 $  $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */
+/* NetHack 3.6 mthrowu.c       $NHDT-Date: 1514152830 2017/12/24 22:00:30 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.73 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Pasi Kallinen, 2016. */
 /* NetHack may be freely redistributed.  See license for details. */
 
+/* JNetHack Copyright */
+/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019            */
+/* JNetHack may be freely redistributed.  See license for details. */
+
 #include "hack.h"
 
+STATIC_DCL int FDECL(monmulti, (struct monst *, struct obj *, struct obj *));
+STATIC_DCL void FDECL(monshoot, (struct monst *, struct obj *, struct obj *));
 STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
+STATIC_DCL boolean FDECL(m_lined_up, (struct monst *, struct monst *));
 
 #define URETREATING(x, y) \
     (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
 
 #define POLE_LIM 5 /* How far monsters can use pole-weapons */
 
+#define PET_MISSILE_RANGE2 36 /* Square of distance within which pets shoot */
+
 /*
  * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
  */
 STATIC_OVL NEARDATA const char *breathwep[] = {
+#if 0 /*JP*/
     "fragments", "fire", "frost", "sleep gas", "a disintegration blast",
     "lightning", "poison gas", "acid", "strange breath #8",
     "strange breath #9"
+#else
+    "\94j\95Ð", "\89\8a", "\97â\8bC", "\90\87\96°\83K\83X", "\95ª\89ð\82Ì\91§",
+    "\88î\8dÈ", "\93Å\82Ì\91§", "\8e_", "strange breath #8",
+    "strange breath #9"
+#endif
 };
 
 extern boolean notonhead; /* for long worms */
+STATIC_VAR int mesg_given; /* for m_throw()/thitu() 'miss' message */
 
 /* hero is hit by something other than a monster */
 int
-thitu(tlev, dam, obj, name)
+thitu(tlev, dam, objp, name)
 int tlev, dam;
-struct obj *obj;
-const char *name; /* if null, then format `obj' */
+struct obj **objp;
+const char *name; /* if null, then format `*objp' */
 {
+    struct obj *obj = objp ? *objp : 0;
     const char *onm, *knm;
     boolean is_acid;
-    int kprefix = KILLED_BY_AN;
+    int kprefix = KILLED_BY_AN, dieroll;
     char onmbuf[BUFSZ], knmbuf[BUFSZ];
 
     if (!name) {
         if (!obj)
             panic("thitu: name & obj both null?");
-        name =
-            strcpy(onmbuf, (obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
+        name = strcpy(onmbuf,
+                      (obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
         knm = strcpy(knmbuf, killer_xname(obj));
         kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */
     } else {
         knm = name;
+#if 0 /*JP*/
         /* [perhaps ought to check for plural here to] */
         if (!strncmpi(name, "the ", 4) || !strncmpi(name, "an ", 3)
             || !strncmpi(name, "a ", 2))
             kprefix = KILLED_BY;
+#else /* \93ú\96{\8cê\82Å\82Í\82»\82Ì\82Ü\82Ü */
+        knm = strcpy(knmbuf, name);
+#endif
     }
-    onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L)
-                                                       ? name
-                                                       : an(name);
+#if 1 /*JP*/
+    strcat(knmbuf, "\82É\93\96\82½\82Á\82Ä");
+#endif
+    onm = (obj && obj_is_pname(obj)) ? the(name)
+          : (obj && obj->quan > 1L) ? name
+            : an(name);
     is_acid = (obj && obj->otyp == ACID_VENOM);
 
-    if (u.uac + tlev <= rnd(20)) {
-        if (Blind || !flags.verbose)
+    if (u.uac + tlev <= (dieroll = rnd(20))) {
+        ++mesg_given;
+        if (Blind || !flags.verbose) {
+/*JP
             pline("It misses.");
-        else
+*/
+            pline("\82»\82ê\82Í\82Í\82¸\82ê\82½\81D");
+        } else if (u.uac + tlev <= dieroll - 2) {
+            if (onm != onmbuf)
+                Strcpy(onmbuf, onm); /* [modifiable buffer for upstart()] */
+/*JP
+            pline("%s %s you.", upstart(onmbuf), vtense(onmbuf, "miss"));
+*/
+            pline("%s\82Í\8dU\8c\82\82ð\82Í\82¸\82µ\82½\81D", upstart(onmbuf));
+        } else
+/*JP
             You("are almost hit by %s.", onm);
+*/
+            pline("\82à\82¤\8f­\82µ\82Å%s\82É\96½\92\86\82·\82é\82Æ\82±\82ë\82¾\82Á\82½\81I",onm);
         return 0;
     } else {
         if (Blind || !flags.verbose)
+/*JP
             You("are hit%s", exclam(dam));
+*/
+            pline("\89½\82©\82ª\82 \82È\82½\82É\96½\92\86\82µ\82½\81I");
         else
+/*JP
             You("are hit by %s%s", onm, exclam(dam));
+*/
+            pline("%s\82ª\82 \82È\82½\82É\96½\92\86\82µ\82½\81I", onm);
 
-        if (obj && objects[obj->otyp].oc_material == SILVER && Hate_silver) {
-            /* extra damage already applied by dmgval() */
-            pline_The("silver sears your flesh!");
-            exercise(A_CON, FALSE);
-        }
-        if (is_acid && Acid_resistance)
+        if (is_acid && Acid_resistance) {
+/*JP
             pline("It doesn't seem to hurt you.");
-        else {
+*/
+            pline("\82 \82È\82½\82Í\8f\9d\82Â\82©\82È\82©\82Á\82½\81D");
+        } else if (obj && obj->oclass == POTION_CLASS) {
+            /* an explosion which scatters objects might hit hero with one
+               (potions deliberately thrown at hero are handled by m_throw) */
+            potionhit(&youmonst, obj, POTHIT_OTHER_THROW);
+            *objp = obj = 0; /* potionhit() uses up the potion */
+        } else {
+            if (obj && objects[obj->otyp].oc_material == SILVER
+                && Hate_silver) {
+                /* extra damage already applied by dmgval() */
+/*JP
+            pline_The("silver sears your flesh!");
+*/
+            pline("\82 \82È\82½\82Ì\91Ì\82Í\8bâ\82Å\8fÄ\82©\82ê\82½\81I");
+                exercise(A_CON, FALSE);
+            }
             if (is_acid)
+/*JP
                 pline("It burns!");
+*/
+                pline("\8e_\82Å\8fÄ\82©\82ê\82½\81I");
             losehp(dam, knm, kprefix); /* acid damage */
             exercise(A_STR, FALSE);
         }
@@ -105,16 +166,19 @@ int x, y;
     else
         create = 1;
 
-    if (create
-        && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && (t = t_at(x, y))
-             && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))) {
+    if (create && !((mtmp = m_at(x, y)) != 0 && mtmp->mtrapped
+                    && (t = t_at(x, y)) != 0
+                    && (t->ttyp == PIT || t->ttyp == SPIKED_PIT))) {
         int objgone = 0;
 
         if (down_gate(x, y) != -1)
             objgone = ship_object(obj, x, y, FALSE);
         if (!objgone) {
-            if (!flooreffects(obj, x, y,
-                              "fall")) { /* don't double-dip on damage */
+#if 0 /*JP:T*/
+            if (!flooreffects(obj, x, y, "fall")) {
+#else
+            if (!flooreffects(obj, x, y, "\97\8e\82¿\82é")) {
+#endif
                 place_object(obj, x, y);
                 if (!mtmp && x == u.ux && y == u.uy)
                     mtmp = &youmonst;
@@ -129,6 +193,167 @@ int x, y;
     return retvalu;
 }
 
+/* The monster that's being shot at when one monster shoots at another */
+STATIC_OVL struct monst *target = 0;
+/* The monster that's doing the shooting/throwing */
+STATIC_OVL struct monst *archer = 0;
+
+/* calculate multishot volley count for mtmp throwing otmp (if not ammo) or
+   shooting otmp with mwep (if otmp is ammo and mwep appropriate launcher) */
+STATIC_OVL int
+monmulti(mtmp, otmp, mwep)
+struct monst *mtmp;
+struct obj *otmp, *mwep;
+{
+    int skill = (int) objects[otmp->otyp].oc_skill;
+    int multishot = 1;
+
+    if (otmp->quan > 1L /* no point checking if there's only 1 */
+        /* ammo requires corresponding launcher be wielded */
+        && (is_ammo(otmp)
+               ? matching_launcher(otmp, mwep)
+               /* otherwise any stackable (non-ammo) weapon */
+               : otmp->oclass == WEAPON_CLASS)
+        && !mtmp->mconf) {
+        /* Assumes lords are skilled, princes are expert */
+        if (is_prince(mtmp->data))
+            multishot += 2;
+        else if (is_lord(mtmp->data))
+            multishot++;
+        /* fake players treated as skilled (regardless of role limits) */
+        else if (is_mplayer(mtmp->data))
+            multishot++;
+
+        /* this portion is different from hero multishot; from slash'em?
+         */
+        /* Elven Craftsmanship makes for light, quick bows */
+        if (otmp->otyp == ELVEN_ARROW && !otmp->cursed)
+            multishot++;
+        if (ammo_and_launcher(otmp, uwep) && mwep->otyp == ELVEN_BOW
+            && !mwep->cursed)
+            multishot++;
+        /* 1/3 of launcher enchantment */
+        if (ammo_and_launcher(otmp, mwep) && mwep->spe > 1)
+            multishot += (long) rounddiv(mwep->spe, 3);
+        /* Some randomness */
+        multishot = (long) rnd((int) multishot);
+
+        /* class bonus */
+        switch (monsndx(mtmp->data)) {
+        case PM_CAVEMAN: /* give bonus for low-tech gear */
+            if (skill == -P_SLING || skill == P_SPEAR)
+                multishot++;
+            break;
+        case PM_MONK: /* allow higher volley count */
+            if (skill == -P_SHURIKEN)
+                multishot++;
+            break;
+        case PM_RANGER:
+            if (skill != P_DAGGER)
+                multishot++;
+            break;
+        case PM_ROGUE:
+            if (skill == P_DAGGER)
+                multishot++;
+            break;
+        case PM_NINJA:
+            if (skill == -P_SHURIKEN || skill == -P_DART)
+                multishot++;
+            /*FALLTHRU*/
+        case PM_SAMURAI:
+            if (otmp->otyp == YA && mwep->otyp == YUMI)
+                multishot++;
+            break;
+        default:
+            break;
+        }
+        /* racial bonus */
+        if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW
+            && mwep->otyp == ELVEN_BOW)
+            || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW
+                && mwep->otyp == ORCISH_BOW)
+            || (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT
+                && mwep->otyp == CROSSBOW))
+            multishot++;
+    }
+
+    if (otmp->quan < multishot)
+        multishot = (int) otmp->quan;
+    if (multishot < 1)
+        multishot = 1;
+    return multishot;
+}
+
+/* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
+STATIC_OVL void
+monshoot(mtmp, otmp, mwep)
+struct monst *mtmp;
+struct obj *otmp, *mwep;
+{
+    struct monst *mtarg = target;
+    int dm = distmin(mtmp->mx, mtmp->my,
+                     mtarg ? mtarg->mx : mtmp->mux,
+                     mtarg ? mtarg->my : mtmp->muy),
+        multishot = monmulti(mtmp, otmp, mwep);
+        /*
+         * Caller must have called linedup() to set up tbx, tby.
+         */
+
+    if (canseemon(mtmp)) {
+        const char *onm;
+        char onmbuf[BUFSZ], trgbuf[BUFSZ];
+
+        if (multishot > 1) {
+            /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
+               xname()'s result will already be pluralized */
+/*JP
+            Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
+*/
+            Sprintf(onmbuf, "%d%s\82Ì%s", multishot, numeral(otmp), xname(otmp));
+            onm = onmbuf;
+        } else {
+            /* "an arrow" */
+            onm = singular(otmp, xname);
+            onm = obj_is_pname(otmp) ? the(onm) : an(onm);
+        }
+        m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
+        Strcpy(trgbuf, mtarg ? mon_nam(mtarg) : "");
+#if 0 /*JP*//*\93ú\96{\8cê\82Å\82Ímon_nam\82Í\81u\89½\8eÒ\82©\81v\82ð\95Ô\82·\82Ì\82Å\95Ï\8dX\95s\97v*/
+        if (!strcmp(trgbuf, "it"))
+            Strcpy(trgbuf, humanoid(mtmp->data) ? "someone" : something);
+#endif
+#if 0 /*JP*/
+        pline("%s %s %s%s%s!", Monnam(mtmp),
+              m_shot.s ? "shoots" : "throws", onm,
+              mtarg ? " at " : "", trgbuf);
+#else
+        pline("%s\82Í%s\82ð%s\82É%s\81I", Monnam(mtmp),
+              onm,
+              trgbuf,
+              m_shot.s ? "\8c\82\82Á\82½" : "\93\8a\82°\82½");
+#endif
+        m_shot.o = otmp->otyp;
+    } else {
+        m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
+    }
+    m_shot.n = multishot;
+    for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
+        m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
+        /* conceptually all N missiles are in flight at once, but
+           if mtmp gets killed (shot kills adjacent gas spore and
+           triggers explosion, perhaps), inventory will be dropped
+           and otmp might go away via merging into another stack */
+        if (mtmp->mhp <= 0 && m_shot.i < m_shot.n)
+            /* cancel pending shots (perhaps ought to give a message here
+               since we gave one above about throwing/shooting N missiles) */
+            break; /* endmultishot(FALSE); */
+    }
+    /* reset 'm_shot' */
+    m_shot.n = m_shot.i = 0;
+    m_shot.o = STRANGE_OBJECT;
+    m_shot.s = FALSE;
+}
+
 /* an object launched by someone/thing other than player attacks a monster;
    return 1 if the object has stopped moving (hit or its range used up) */
 int
@@ -143,18 +368,31 @@ boolean verbose;    /* give message(s) even when you can't see what happened */
     int damage, tmp;
     boolean vis, ismimic;
     int objgone = 1;
+    struct obj *mon_launcher = archer ? MON_WEP(archer) : NULL;
 
     notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
     ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER;
     vis = cansee(bhitpos.x, bhitpos.y);
 
     tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
+    /* High level monsters will be more likely to hit */
+    /* This check applies only if this monster is the target
+     * the archer was aiming at. */
+    if (archer && target == mtmp) {
+        if (archer->m_lev > 5)
+            tmp += archer->m_lev - 5;
+        if (mon_launcher && mon_launcher->oartifact)
+            tmp += spec_abon(mon_launcher, mtmp);
+    }
     if (tmp < rnd(20)) {
         if (!ismimic) {
             if (vis)
                 miss(distant_name(otmp, mshot_xname), mtmp);
-            else if (verbose)
+            else if (verbose && !target)
+/*JP
                 pline("It is missed.");
+*/
+                pline("\89½\82©\82ª\82©\82·\82ß\82½\81D");
         }
         if (!range) { /* Last position; object drops */
             (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
@@ -166,7 +404,9 @@ boolean verbose;    /* give message(s) even when you can't see what happened */
         mtmp->msleeping = 0;
         if (vis)
             otmp->dknown = 1;
-        potionhit(mtmp, otmp, FALSE);
+        /* probably thrown by a monster rather than 'other', but the
+           distinction only matters when hitting the hero */
+        potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
         return 1;
     } else {
         damage = dmgval(otmp, mtmp);
@@ -175,22 +415,43 @@ boolean verbose;    /* give message(s) even when you can't see what happened */
         if (ismimic)
             seemimic(mtmp);
         mtmp->msleeping = 0;
-        if (vis)
-            hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
-        else if (verbose)
-            pline("%s is hit%s", Monnam(mtmp), exclam(damage));
+        if (vis) {
+            if (otmp->otyp == EGG)
+#if 0 /*JP*/
+                pline("Splat! %s is hit with %s egg!", Monnam(mtmp),
+                      otmp->known ? an(mons[otmp->corpsenm].mname) : "an");
+#else
+                pline("\83r\83`\83\83\83b\81I%s\82Í%s\97\91\82É\93\96\82½\82Á\82½\81I", Monnam(mtmp),
+                      otmp->known ? s_suffix(mons[otmp->corpsenm].mname) : "");
+#endif
+            else
+                hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
+        } else if (verbose && !target)
+#if 0 /*JP:T*/
+            pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat! " : "",
+                  Monnam(mtmp), exclam(damage));
+#else
+            pline("%s%s\82É\96½\92\86\82µ\82½%s", (otmp->otyp == EGG) ? "\83r\83`\83\83\83b\81I" : "",
+                  Monnam(mtmp), exclam(damage));
+#endif
 
         if (otmp->opoisoned && is_poisonable(otmp)) {
             if (resists_poison(mtmp)) {
                 if (vis)
+/*JP
                     pline_The("poison doesn't seem to affect %s.",
+*/
+                    pline("%s\82Í\93Å\82Ì\89e\8b¿\82ð\8eó\82¯\82È\82¢\82æ\82¤\82¾\81D",
                               mon_nam(mtmp));
             } else {
                 if (rn2(30)) {
                     damage += rnd(6);
                 } else {
                     if (vis)
+/*JP
                         pline_The("poison was deadly...");
+*/
+                        pline("\93Å\82Í\92v\8e\80\97Ê\82¾\82Á\82½\81D\81D\81D");
                     damage = mtmp->mhp;
                 }
             }
@@ -198,44 +459,77 @@ boolean verbose;    /* give message(s) even when you can't see what happened */
         if (objects[otmp->otyp].oc_material == SILVER
             && mon_hates_silver(mtmp)) {
             if (vis)
+/*JP
                 pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
-            else if (verbose)
+*/
+                pline("%s\82Ì\91Ì\82Í\8bâ\82Å\8fÄ\82©\82ê\82½\81I", mon_nam(mtmp));
+            else if (verbose && !target)
+/*JP
                 pline("Its flesh is seared!");
+*/
+                pline("\89½\8eÒ\82©\82Ì\91Ì\82Í\8fÄ\82©\82ê\82½\81I");
         }
         if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
             if (resists_acid(mtmp)) {
-                if (vis || verbose)
+                if (vis || (verbose && !target))
+/*JP
                     pline("%s is unaffected.", Monnam(mtmp));
-                damage = 0;
+*/
+                    pline("%s\82Í\89e\8b¿\82ð\8eó\82¯\82È\82¢\81D", Monnam(mtmp));
             } else {
                 if (vis)
-                    pline_The("acid burns %s!", mon_nam(mtmp));
-                else if (verbose)
+/*JP
+                    pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp));
+*/
+                    pline_The("%s\82Í%s\82Å\8fÄ\82©\82ê\82½\81I", mon_nam(mtmp), hliquid("\8e_"));
+                else if (verbose && !target)
+/*JP
                     pline("It is burned!");
+*/
+                    pline("\89½\82©\82Í\8fÄ\82©\82ê\82½\81I");
             }
         }
-        mtmp->mhp -= damage;
-        if (mtmp->mhp < 1) {
-            if (vis || verbose)
-                pline("%s is %s!", Monnam(mtmp),
-                      (nonliving(mtmp->data) || is_vampshifter(mtmp)
-                       || !canspotmon(mtmp))
-                          ? "destroyed"
-                          : "killed");
-            /* don't blame hero for unknown rolling boulder trap */
-            if (!context.mon_moving
-                && (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped))
-                xkilled(mtmp, 0);
-            else
-                mondied(mtmp);
+        if (otmp->otyp == EGG && touch_petrifies(&mons[otmp->corpsenm])) {
+            if (!munstone(mtmp, TRUE))
+                minstapetrify(mtmp, TRUE);
+            if (resists_ston(mtmp))
+                damage = 0;
         }
 
-        if (can_blnd((struct monst *) 0, mtmp,
-                     (uchar) (otmp->otyp == BLINDING_VENOM ? AT_SPIT
-                                                           : AT_WEAP),
-                     otmp)) {
+        if (mtmp->mhp > 0) { /* might already be dead (if petrified) */
+            mtmp->mhp -= damage;
+            if (mtmp->mhp < 1) {
+                if (vis || (verbose && !target))
+#if 0 /*JP:T*/
+                    pline("%s is %s!", Monnam(mtmp),
+                          (nonliving(mtmp->data) || is_vampshifter(mtmp)
+                           || !canspotmon(mtmp)) ? "destroyed" : "killed");
+#else
+                    pline("%s\82Í%s\81I", Monnam(mtmp),
+                          (nonliving(mtmp->data) || is_vampshifter(mtmp)
+                           || !canspotmon(mtmp)) ? "\93|\82³\82ê\82½" : "\8e\80\82ñ\82¾");
+#endif
+                /* don't blame hero for unknown rolling boulder trap */
+                if (!context.mon_moving && (otmp->otyp != BOULDER
+                                            || range >= 0 || otmp->otrapped))
+                    xkilled(mtmp, XKILL_NOMSG);
+                else
+                    mondied(mtmp);
+            }
+        }
+
+        /* blinding venom and cream pie do 0 damage, but verify
+           that the target is still alive anyway */
+        if (mtmp->mhp > 0
+            && can_blnd((struct monst *) 0, mtmp,
+                        (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
+                                                                : AT_WEAP),
+                        otmp)) {
             if (vis && mtmp->mcansee)
+/*JP
                 pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
+*/
+                pline("%s\82Í%s\82É\82æ\82Á\82Ä\96Ú\82ª\8c©\82¦\82È\82­\82È\82Á\82½\81D", Monnam(mtmp), the(xname(otmp)));
             mtmp->mcansee = 0;
             tmp = (int) mtmp->mblinded + rnd(25) + 20;
             if (tmp > 127)
@@ -253,6 +547,24 @@ boolean verbose;    /* give message(s) even when you can't see what happened */
     return 0;
 }
 
+#define MT_FLIGHTCHECK(pre)                                             \
+    (/* missile hits edge of screen */                                  \
+     !isok(bhitpos.x + dx, bhitpos.y + dy)                              \
+     /* missile hits the wall */                                        \
+     || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)               \
+     /* missile hit closed door */                                      \
+     || closed_door(bhitpos.x + dx, bhitpos.y + dy)                     \
+     /* missile might hit iron bars */                                  \
+     /* the random chance for small objects hitting bars is */          \
+     /* skipped when reaching them at point blank range */              \
+     || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS           \
+         && hits_bars(&singleobj,                                       \
+                      bhitpos.x, bhitpos.y,                             \
+                      bhitpos.x + dx, bhitpos.y + dy,                   \
+                      ((pre) ? 0 : !rn2(5)), 0))                        \
+     /* Thrown objects "sink" */                                        \
+     || (!(pre) && IS_SINK(levl[bhitpos.x][bhitpos.y].typ)))
+
 void
 m_throw(mon, x, y, dx, dy, range, obj)
 struct monst *mon;       /* launching monster */
@@ -262,7 +574,7 @@ struct obj *obj;         /* missile (or stack providing it) */
     struct monst *mtmp;
     struct obj *singleobj;
     char sym = obj->oclass;
-    int hitu, oldumort, blindinc = 0;
+    int hitu = 0, oldumort, blindinc = 0;
 
     bhitpos.x = x;
     bhitpos.y = y;
@@ -296,10 +608,18 @@ struct obj *obj;         /* missile (or stack providing it) */
     if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) {
         if (canseemon(mon) && flags.verbose) {
             if (is_ammo(singleobj))
+/*JP
                 pline("%s misfires!", Monnam(mon));
+*/
+                pline("%s\82Í\82Í\82¸\82µ\82½\81I", Monnam(mon));
             else
+#if 0 /*JP*/
                 pline("%s as %s throws it!", Tobjnam(singleobj, "slip"),
                       mon_nam(mon));
+#else
+                pline("%s\82ª\93\8a\82°\82æ\82¤\82Æ\82µ\82½\82Æ\82½\82ñ%s\82ª\8a\8a\82Á\82½\81I",
+                          mon_nam(mon), xname(singleobj));
+#endif
         }
         dx = rn2(3) - 1;
         dy = rn2(3) - 1;
@@ -310,18 +630,11 @@ struct obj *obj;         /* missile (or stack providing it) */
         }
     }
 
-    /* pre-check for doors, walls and boundaries.
-       Also need to pre-check for bars regardless of direction;
-       the random chance for small objects hitting bars is
-       skipped when reaching them at point blank range */
-    if (!isok(bhitpos.x + dx, bhitpos.y + dy)
-        || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)
-        || closed_door(bhitpos.x + dx, bhitpos.y + dy)
-        || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS
-            && hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) {
+    if (MT_FLIGHTCHECK(TRUE)) {
         (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
         return;
     }
+    mesg_given = 0; /* a 'missile misses' message has not yet been shown */
 
     /* Note: drop_throw may destroy singleobj.  Since obj must be destroyed
      * early to avoid the dagger bug, anyone who modifies this code should
@@ -343,25 +656,44 @@ struct obj *obj;         /* missile (or stack providing it) */
                 && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */
                 && is_unicorn(youmonst.data)) {
                 if (singleobj->otyp > LAST_GEM) {
+/*JP
                     You("catch the %s.", xname(singleobj));
+*/
+                    You("%s\82ð\82Â\82©\82Ü\82¦\82½\81D", xname(singleobj));
+#if 0 /*JP*/
                     You("are not interested in %s junk.",
                         s_suffix(mon_nam(mon)));
+#else
+                    You("%s\82Ì\83K\83\89\83N\83^\82É\8b»\96¡\82Í\82È\82¢\81D",
+                        mon_nam(mon));
+#endif
                     makeknown(singleobj->otyp);
                     dropy(singleobj);
                 } else {
                     You(
+/*JP
                      "accept %s gift in the spirit in which it was intended.",
+*/
+                     "\82±\82ê\82ª\97~\82µ\82©\82Á\82½\82ñ\82¾\82Æ\8ev\82¢\82È\82ª\82ç%s\82Ì\91¡\82è\95¨\82ð\8eó\82¯\82Æ\82Á\82½\81D",
                         s_suffix(mon_nam(mon)));
-                    (void) hold_another_object(
-                        singleobj, "You catch, but drop, %s.",
-                        xname(singleobj), "You catch:");
+#if 0 /*JP*/
+                    (void) hold_another_object(singleobj,
+                                               "You catch, but drop, %s.",
+                                               xname(singleobj),
+                                               "You catch:");
+#else
+                    (void) hold_another_object(singleobj,
+                                     "\82 \82È\82½\82Í%s\82ð\82Â\82©\82Ü\82¦\82½\82ª\81C\97\8e\82µ\82½\81D",
+                                               xname(singleobj),
+                                               "\82ð\82Â\82©\82Ü\82¦\82½\81D");
+#endif
                 }
                 break;
             }
             if (singleobj->oclass == POTION_CLASS) {
                 if (!Blind)
                     singleobj->dknown = 1;
-                potionhit(&youmonst, singleobj, FALSE);
+                potionhit(&youmonst, singleobj, POTHIT_MONST_THROW);
                 break;
             }
             oldumort = u.umortality;
@@ -377,7 +709,7 @@ struct obj *obj;         /* missile (or stack providing it) */
             /* fall through */
             case CREAM_PIE:
             case BLINDING_VENOM:
-                hitu = thitu(8, 0, singleobj, (char *) 0);
+                hitu = thitu(8, 0, &singleobj, (char *) 0);
                 break;
             default:
                 dam = dmgval(singleobj, &youmonst);
@@ -397,7 +729,7 @@ struct obj *obj;         /* missile (or stack providing it) */
                 hitv += 8 + singleobj->spe;
                 if (dam < 1)
                     dam = 1;
-                hitu = thitu(hitv, dam, singleobj, (char *) 0);
+                hitu = thitu(hitv, dam, &singleobj, (char *) 0);
             }
             if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
                 char onmbuf[BUFSZ], knmbuf[BUFSZ];
@@ -410,18 +742,27 @@ struct obj *obj;         /* missile (or stack providing it) */
                          (u.umortality > oldumort) ? 0 : 10, TRUE);
             }
             if (hitu && can_blnd((struct monst *) 0, &youmonst,
-                                 (uchar) (singleobj->otyp == BLINDING_VENOM
+                                 (uchar) ((singleobj->otyp == BLINDING_VENOM)
                                              ? AT_SPIT
                                              : AT_WEAP),
                                  singleobj)) {
                 blindinc = rnd(25);
                 if (singleobj->otyp == CREAM_PIE) {
                     if (!Blind)
+/*JP
                         pline("Yecch!  You've been creamed.");
+*/
+                        pline("\83E\83F\81[\81D\83N\83\8a\81[\83\80\82ð\82©\82Ô\82Á\82½\81D");
                     else
+#if 0 /*JP*/
                         pline("There's %s sticky all over your %s.",
                               something, body_part(FACE));
+#else
+                        pline("\82 \82È\82½\82Í%s\82É\82×\82Æ\82Â\82­\82à\82Ì\82ð\8a´\82\82½\81D",
+                              body_part(FACE));
+#endif
                 } else if (singleobj->otyp == BLINDING_VENOM) {
+#if 0 /*JP*/
                     const char *eyes = body_part(EYE);
 
                     if (eyecount(youmonst.data) != 1)
@@ -431,6 +772,12 @@ struct obj *obj;         /* missile (or stack providing it) */
                         pline_The("venom blinds you.");
                     else
                         Your("%s %s.", eyes, vtense(eyes, "sting"));
+#else
+                    if(!Blind)
+                        pline("\93Å\82Å\96Ú\82ª\8c©\82¦\82È\82­\82È\82Á\82½\81D");
+                    else
+                        Your("%s\82Í\82¿\82­\82¿\82­\82µ\82½\81D", body_part(EYE));
+#endif
                 }
             }
             if (hitu && singleobj->otyp == EGG) {
@@ -441,25 +788,24 @@ struct obj *obj;         /* missile (or stack providing it) */
                 }
             }
             stop_occupation();
-            if (hitu || !range) {
+            if (hitu) {
                 (void) drop_throw(singleobj, hitu, u.ux, u.uy);
                 break;
             }
         }
         if (!range /* reached end of path */
-            /* missile hits edge of screen */
-            || !isok(bhitpos.x + dx, bhitpos.y + dy)
-            /* missile hits the wall */
-            || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)
-            /* missile hit closed door */
-            || closed_door(bhitpos.x + dx, bhitpos.y + dy)
-            /* missile might hit iron bars */
-            || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS
-                && hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0))
-            /* Thrown objects "sink" */
-            || IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
-            if (singleobj) /* hits_bars might have destroyed it */
+            || MT_FLIGHTCHECK(FALSE)) {
+            if (singleobj) { /* hits_bars might have destroyed it */
+                if (m_shot.n > 1
+                    && (!mesg_given || bhitpos.x != u.ux || bhitpos.y != u.uy)
+                    && (cansee(bhitpos.x, bhitpos.y)
+                        || (archer && canseemon(archer))))
+/*JP
+                    pline("%s misses.", The(mshot_xname(singleobj)));
+*/
+                    pline("%s\82Í\82Í\82¸\82ê\82½\81D", mshot_xname(singleobj));
                 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
+            }
             break;
         }
         tmp_at(bhitpos.x, bhitpos.y);
@@ -468,6 +814,7 @@ struct obj *obj;         /* missile (or stack providing it) */
     tmp_at(bhitpos.x, bhitpos.y);
     delay_output();
     tmp_at(DISP_END, 0);
+    mesg_given = 0; /* reset */
 
     if (blindinc) {
         u.ucreamed += blindinc;
@@ -477,6 +824,174 @@ struct obj *obj;         /* missile (or stack providing it) */
     }
 }
 
+#undef MT_FLIGHTCHECK
+
+/* Monster throws item at another monster */
+int
+thrwmm(mtmp, mtarg)
+struct monst *mtmp, *mtarg;
+{
+    struct obj *otmp, *mwep;
+    register xchar x, y;
+    boolean ispole;
+
+    /* Polearms won't be applied by monsters against other monsters */
+    if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
+        mtmp->weapon_check = NEED_RANGED_WEAPON;
+        /* mon_wield_item resets weapon_check as appropriate */
+        if (mon_wield_item(mtmp) != 0)
+            return 0;
+    }
+
+    /* Pick a weapon */
+    otmp = select_rwep(mtmp);
+    if (!otmp)
+        return 0;
+    ispole = is_pole(otmp);
+
+    x = mtmp->mx;
+    y = mtmp->my;
+
+    mwep = MON_WEP(mtmp); /* wielded weapon */
+
+    if (!ispole && m_lined_up(mtarg, mtmp)) {
+        int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
+
+        if (!mtarg->mflee || !rn2(chance)) {
+            if (ammo_and_launcher(otmp, mwep)
+                && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
+                   > PET_MISSILE_RANGE2)
+                return 0; /* Out of range */
+            /* Set target monster */
+            target = mtarg;
+            archer = mtmp;
+            monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
+            archer = target = (struct monst *) 0;
+            nomul(0);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+/* monster spits substance at monster */
+int
+spitmm(mtmp, mattk, mtarg)
+struct monst *mtmp, *mtarg;
+struct attack *mattk;
+{
+    struct obj *otmp;
+
+    if (mtmp->mcan) {
+        if (!Deaf)
+#if 0 /*JP:T*/
+            pline("A dry rattle comes from %s throat.",
+                  s_suffix(mon_nam(mtmp)));
+#else
+            pline("%s\82Ì\8dA\82ª\83K\83\89\83K\83\89\82Æ\96Â\82Á\82½\81D",
+                  mon_nam(mtmp));
+#endif
+        return 0;
+    }
+    if (m_lined_up(mtarg, mtmp)) {
+        switch (mattk->adtyp) {
+        case AD_BLND:
+        case AD_DRST:
+            otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
+            break;
+        default:
+            impossible("bad attack type in spitmu");
+            /* fall through */
+        case AD_ACID:
+            otmp = mksobj(ACID_VENOM, TRUE, FALSE);
+            break;
+        }
+        if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) {
+            if (canseemon(mtmp))
+/*JP
+                pline("%s spits venom!", Monnam(mtmp));
+*/
+                pline("%s\82Í\93Å\82ð\93f\82¢\82½\81I", Monnam(mtmp));
+            target = mtarg;
+            m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
+                    distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp);
+            target = (struct monst *)0;
+            nomul(0);
+
+            /* If this is a pet, it'll get hungry. Minions and
+             * spell beings won't hunger */
+            if (mtmp->mtame && !mtmp->isminion) {
+                struct edog *dog = EDOG(mtmp);
+
+                /* Hunger effects will catch up next move */
+                if (dog->hungrytime > 1)
+                    dog->hungrytime -= 5;
+            }
+
+            return 1;
+        }
+    }
+    return 0;
+}
+
+/* monster breathes at monster (ranged) */
+int
+breamm(mtmp, mattk, mtarg)
+struct monst *mtmp, *mtarg;
+struct attack  *mattk;
+{
+    /* if new breath types are added, change AD_ACID to max type */
+    int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
+
+    if (m_lined_up(mtarg, mtmp)) {
+        if (mtmp->mcan) {
+            if (!Deaf) {
+                if (canseemon(mtmp))
+/*JP
+                    pline("%s coughs.", Monnam(mtmp));
+*/
+                    pline("%s\82Í\82¹\82«\82ð\82µ\82½\81D", Monnam(mtmp));
+                else
+/*JP
+                    You_hear("a cough.");
+*/
+                    You_hear("\82¹\82«\82Ì\89¹\82ð\95·\82¢\82½\81D");
+            }
+            return 0;
+        }
+        if (!mtmp->mspec_used && rn2(3)) {
+            if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
+                if (canseemon(mtmp))
+/*JP
+                    pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
+*/
+                    pline("%s\82Í%s\82ð\82Í\82¢\82½\81I", Monnam(mtmp), breathwep[typ - 1]);
+                dobuzz((int) (-20 - (typ - 1)), (int)mattk->damn,
+                       mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
+                nomul(0);
+                /* breath runs out sometimes. Also, give monster some
+                 * cunning; don't breath if the target fell asleep.
+                 */
+                mtmp->mspec_used = 6 + rn2(18);
+
+                /* If this is a pet, it'll get hungry. Minions and
+                 * spell beings won't hunger */
+                if (mtmp->mtame && !mtmp->isminion) {
+                    struct edog *dog = EDOG(mtmp);
+
+                    /* Hunger effects will catch up next move */
+                    if (dog->hungrytime >= 10)
+                        dog->hungrytime -= 10;
+                }
+            } else impossible("Breath weapon %d used", typ-1);
+        } else
+            return 0;
+    }
+    return 1;
+}
+
+
+
 /* remove an entire item from a monster's inventory; destroy that item */
 void
 m_useupall(mon, obj)
@@ -515,7 +1030,6 @@ struct monst *mtmp;
 {
     struct obj *otmp, *mwep;
     xchar x, y;
-    int multishot;
     const char *onm;
 
     /* Rearranged beginning so monsters can use polearms not in a line */
@@ -542,8 +1056,12 @@ struct monst *mtmp;
 
         if (canseemon(mtmp)) {
             onm = xname(otmp);
+#if 0 /*JP*/
             pline("%s thrusts %s.", Monnam(mtmp),
                   obj_is_pname(otmp) ? the(onm) : an(onm));
+#else
+            pline("%s\82Í%s\82ð\93Ë\82«\8eh\82µ\82½\81D", Monnam(mtmp), onm);
+#endif
         }
 
         dam = dmgval(otmp, &youmonst);
@@ -556,7 +1074,7 @@ struct monst *mtmp;
         if (dam < 1)
             dam = 1;
 
-        (void) thitu(hitv, dam, otmp, (char *) 0);
+        (void) thitu(hitv, dam, &otmp, (char *) 0);
         stop_occupation();
         return;
     }
@@ -574,101 +1092,7 @@ struct monst *mtmp;
         return;
 
     mwep = MON_WEP(mtmp); /* wielded weapon */
-
-    /* Multishot calculations */
-    multishot = 1;
-    if (otmp->quan > 1L /* no point checking if there's only 1 */
-        /* ammo requires corresponding launcher be wielded */
-        && (is_ammo(otmp)
-               ? matching_launcher(otmp, mwep)
-               /* otherwise any stackable (non-ammo) weapon */
-               : otmp->oclass == WEAPON_CLASS)
-        && !mtmp->mconf) {
-        int skill = (int) objects[otmp->otyp].oc_skill;
-
-        /* Assumes lords are skilled, princes are expert */
-        if (is_prince(mtmp->data))
-            multishot += 2;
-        else if (is_lord(mtmp->data))
-            multishot++;
-        /* fake players treated as skilled (regardless of role limits) */
-        else if (is_mplayer(mtmp->data))
-            multishot++;
-
-        /* class bonus */
-        switch (monsndx(mtmp->data)) {
-        case PM_MONK:
-            if (skill == -P_SHURIKEN)
-                multishot++;
-            break;
-        case PM_RANGER:
-            multishot++;
-            break;
-        case PM_ROGUE:
-            if (skill == P_DAGGER)
-                multishot++;
-            break;
-        case PM_NINJA:
-            if (skill == -P_SHURIKEN || skill == -P_DART)
-                multishot++;
-            /*FALLTHRU*/
-        case PM_SAMURAI:
-            if (otmp->otyp == YA && mwep && mwep->otyp == YUMI)
-                multishot++;
-            break;
-        default:
-            break;
-        }
-        /* racial bonus */
-        if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep
-             && mwep->otyp == ELVEN_BOW)
-            || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW && mwep
-                && mwep->otyp == ORCISH_BOW))
-            multishot++;
-
-        multishot = rnd(multishot);
-        if ((long) multishot > otmp->quan)
-            multishot = (int) otmp->quan;
-    }
-
-    if (canseemon(mtmp)) {
-        char onmbuf[BUFSZ];
-
-        if (multishot > 1) {
-            /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
-               xname()'s result will already be pluralized */
-            Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
-            onm = onmbuf;
-        } else {
-            /* "an arrow" */
-            onm = singular(otmp, xname);
-            onm = obj_is_pname(otmp) ? the(onm) : an(onm);
-        }
-        m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
-        pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm);
-        m_shot.o = otmp->otyp;
-    } else {
-        m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
-    }
-
-    m_shot.n = multishot;
-    for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
-        m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
-                distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
-        /* conceptually all N missiles are in flight at once, but
-           if mtmp gets killed (shot kills adjacent gas spore and
-           triggers explosion, perhaps), inventory will be dropped
-           and otmp might go away via merging into another stack */
-        if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) {
-            /* cancel pending shots (ought to give a message here since
-               we gave one above about throwing/shooting N missiles) */
-            break; /* endmultishot(FALSE); */
-        }
-    }
-    m_shot.n = m_shot.i = 0;
-    m_shot.o = STRANGE_OBJECT;
-    m_shot.s = FALSE;
-
+    monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
     nomul(0);
 }
 
@@ -682,8 +1106,13 @@ struct attack *mattk;
 
     if (mtmp->mcan) {
         if (!Deaf)
+#if 0 /*JP*/
             pline("A dry rattle comes from %s throat.",
                   s_suffix(mon_nam(mtmp)));
+#else
+            pline("\8a£\82¢\82½\83K\83\89\83K\83\89\89¹\82ª%s\82Ì\82Ì\82Ç\82©\82ç\95·\82±\82¦\82Ä\82«\82½\81D",
+                  mon_nam(mtmp));
+#endif
         return 0;
     }
     if (lined_up(mtmp)) {
@@ -702,7 +1131,10 @@ struct attack *mattk;
         if (!rn2(BOLT_LIM
                  - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
             if (canseemon(mtmp))
+/*JP
                 pline("%s spits venom!", Monnam(mtmp));
+*/
+                pline("%s\82Í\93Å\89t\82ð\93f\82¢\82½\81I", Monnam(mtmp));
             m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
                     distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
             nomul(0);
@@ -728,17 +1160,28 @@ struct attack *mattk;
         if (mtmp->mcan) {
             if (!Deaf) {
                 if (canseemon(mtmp))
+/*JP
                     pline("%s coughs.", Monnam(mtmp));
+*/
+                    pline("%s\82Í\82¹\82«\82ð\82µ\82½\81D", Monnam(mtmp));
                 else
+/*JP
                     You_hear("a cough.");
+*/
+                    You_hear("\82¹\82«\82Ì\89¹\82ð\95·\82¢\82½\81D");
             }
             return 0;
         }
         if (!mtmp->mspec_used && rn2(3)) {
             if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
                 if (canseemon(mtmp))
+#if 0 /*JP*/
                     pline("%s breathes %s!", Monnam(mtmp),
                           breathwep[typ - 1]);
+#else
+                    pline("%s\82Í%s\82ð\93f\82¢\82½\81I", Monnam(mtmp),
+                          breathwep[typ - 1]);
+#endif
                 buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
                      mtmp->my, sgn(tbx), sgn(tby));
                 nomul(0);
@@ -798,6 +1241,14 @@ int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
     return FALSE;
 }
 
+STATIC_OVL boolean
+m_lined_up(mtarg, mtmp)
+struct monst *mtarg, *mtmp;
+{
+    return (linedup(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my, 0));
+}
+
+
 /* is mtmp in position to use ranged attack? */
 boolean
 lined_up(mtmp)
@@ -831,11 +1282,60 @@ int type;
     return (struct obj *) 0;
 }
 
+void
+hit_bars(objp, objx, objy, barsx, barsy, your_fault, from_invent)
+struct obj **objp;      /* *objp will be set to NULL if object breaks */
+int objx, objy, barsx, barsy;
+boolean your_fault, from_invent;
+{
+    struct obj *otmp = *objp;
+    int obj_type = otmp->otyp;
+    boolean unbreakable = (levl[barsx][barsy].wall_info & W_NONDIGGABLE) != 0;
+
+    if (your_fault
+        ? hero_breaks(otmp, objx, objy, from_invent)
+        : breaks(otmp, objx, objy)) {
+        *objp = 0; /* object is now gone */
+        /* breakage makes its own noises */
+        if (obj_type == POT_ACID) {
+            if (cansee(barsx, barsy) && !unbreakable)
+/*JP
+                pline_The("iron bars are dissolved!");
+*/
+                pline_The("\93S\82Ì\96_\82Í\97Z\82¯\82½\81I");
+            else
+/*JP
+                You_hear(Hallucination ? "angry snakes!" : "a hissing noise.");
+*/
+                You_hear(Hallucination ? "\93{\82Á\82½\82Ö\82Ñ\82Ì\90º\82ð\95·\82¢\82½\81I" : "\83V\81[\83b\82Æ\82¢\82¤\89¹\82ð\95·\82¢\82½\81D");
+            if (!unbreakable)
+                dissolve_bars(barsx, barsy);
+        }
+    }
+    else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
+/*JP
+            pline("Whang!");
+*/
+            pline("\82®\82í\81[\82ñ\81I");
+    else if (otmp->oclass == COIN_CLASS
+             || objects[obj_type].oc_material == GOLD
+             || objects[obj_type].oc_material == SILVER)
+/*JP
+            pline("Clink!");
+*/
+            pline("\83`\83\83\83\8a\83\93\81I");
+    else
+/*JP
+            pline("Clonk!");
+*/
+            pline("\83S\83c\83\93\81I");
+}
+
 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
 boolean
-hits_bars(obj_p, x, y, always_hit, whodidit)
+hits_bars(obj_p, x, y, barsx, barsy, always_hit, whodidit)
 struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
-int x, y;
+int x, y, barsx, barsy;
 int always_hit; /* caller can force a hit for items which would fit through */
 int whodidit;   /* 1==hero, 0=other, -1==just check whether it'll pass thru */
 {
@@ -885,17 +1385,7 @@ int whodidit;   /* 1==hero, 0=other, -1==just check whether it'll pass thru */
         }
 
     if (hits && whodidit != -1) {
-        if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y))
-            *obj_p = otmp = 0; /* object is now gone */
-        /* breakage makes its own noises */
-        else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
-            pline("Whang!");
-        else if (otmp->oclass == COIN_CLASS
-                 || objects[obj_type].oc_material == GOLD
-                 || objects[obj_type].oc_material == SILVER)
-            pline("Clink!");
-        else
-            pline("Clonk!");
+        hit_bars(obj_p, x,y, barsx,barsy, whodidit, FALSE);
     }
 
     return hits;