OSDN Git Service

update year to 2020
[jnethack/source.git] / src / monmove.c
index bf15359..9ca11e1 100644 (file)
@@ -1,11 +1,11 @@
-/* NetHack 3.6 monmove.c       $NHDT-Date: 1517877380 2018/02/06 00:36:20 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.96 $ */
+/* NetHack 3.6 monmove.c       $NHDT-Date: 1575245074 2019/12/02 00:04:34 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.116 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Michael Allison, 2006. */
 /* 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-2020            */
 /* JNetHack may be freely redistributed.  See license for details. */
 
 #include "hack.h"
@@ -20,7 +20,8 @@ STATIC_DCL void FDECL(release_hero, (struct monst *));
 STATIC_DCL void FDECL(distfleeck, (struct monst *, int *, int *, int *));
 STATIC_DCL int FDECL(m_arrival, (struct monst *));
 STATIC_DCL boolean FDECL(stuff_prevents_passage, (struct monst *));
-STATIC_DCL int FDECL(vamp_shift, (struct monst *, struct permonst *, BOOLEAN_P));
+STATIC_DCL int FDECL(vamp_shift, (struct monst *, struct permonst *,
+                                  BOOLEAN_P));
 
 /* True if mtmp died */
 boolean
@@ -42,9 +43,9 @@ struct monst *mtmp;
     wake_nearto(mtmp->mx, mtmp->my, 7 * 7);
     mtmp->mstun = 1;
     mtmp->mhp -= rnd(15);
-    if (mtmp->mhp <= 0) {
+    if (DEADMONSTER(mtmp)) {
         mondied(mtmp);
-        if (mtmp->mhp > 0) /* lifesaved */
+        if (!DEADMONSTER(mtmp)) /* lifesaved */
             return FALSE;
         else
             return TRUE;
@@ -73,23 +74,30 @@ const char *shout;
             /* Sidenote on "A watchman angrily waves her arms!"
              * Female being called watchman is correct (career name).
              */
+#if 0 /*JP:T*/
             pline("%s angrily %s %s %s!",
                 Amonnam(mon),
                 nolimbs(mon->data) ? "shakes" : "waves",
                 mhis(mon),
                 nolimbs(mon->data) ? mbodypart(mon, HEAD)
                                    : makeplural(mbodypart(mon, ARM)));
+#else
+            pline("%s\82Í\93{\82Á\82Ä%s\82ð\90U\82Á\82½\81I",
+                Amonnam(mon),
+                nolimbs(mon->data) ? mbodypart(mon, HEAD)
+                                   : makeplural(mbodypart(mon, ARM)));
+#endif
     } else {
         if (canspotmon(mon))
 /*JP
-        pline("%s yells:", Amonnam(mon));
+            pline("%s yells:", Amonnam(mon));
 */
-        pline("%s\82Í\8b©\82ñ\82¾\81F", Amonnam(mon));
+            pline("%s\82Í\8b©\82ñ\82¾\81F", Amonnam(mon));
         else
 /*JP
-        You_hear("someone yell:");
+            You_hear("someone yell:");
 */
-        pline("\89½\8eÒ\82©\82Í\8b©\82ñ\82¾\81F");
+            pline("\89½\8eÒ\82©\82Í\8b©\82ñ\82¾\81F");
         verbalize1(shout);
     }
 }
@@ -253,8 +261,8 @@ register struct monst *mtmp;
               || mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50))
         && (Aggravate_monster
             || (mtmp->data->mlet == S_DOG || mtmp->data->mlet == S_HUMAN)
-            || (!rn2(7) && mtmp->m_ap_type != M_AP_FURNITURE
-                && mtmp->m_ap_type != M_AP_OBJECT))) {
+            || (!rn2(7) && M_AP_TYPE(mtmp) != M_AP_FURNITURE
+                && M_AP_TYPE(mtmp) != M_AP_OBJECT))) {
         mtmp->msleeping = 0;
         return 1;
     }
@@ -279,6 +287,12 @@ struct monst *mon;
     }
 }
 
+#define flees_light(mon) ((mon)->data == &mons[PM_GREMLIN]     \
+                          && (uwep && artifact_light(uwep) && uwep->lamplit))
+/* we could include this in the above macro, but probably overkill/overhead */
+/*      && (!(which_armor((mon), W_ARMC) != 0                               */
+/*            && which_armor((mon), W_ARMH) != 0))                          */
+
 /* monster begins fleeing for the specified time, 0 means untimed flee
  * if first, only adds fleetime if monster isn't already fleeing
  * if fleemsg, prints a message about new flight, otherwise, caller should */
@@ -308,17 +322,31 @@ boolean fleemsg;
             mtmp->mfleetim = (unsigned) min(fleetime, 127);
         }
         if (!mtmp->mflee && fleemsg && canseemon(mtmp)
-            && mtmp->m_ap_type != M_AP_FURNITURE
-            && mtmp->m_ap_type != M_AP_OBJECT) {
+            && M_AP_TYPE(mtmp) != M_AP_FURNITURE
+            && M_AP_TYPE(mtmp) != M_AP_OBJECT) {
             /* unfortunately we can't distinguish between temporary
                sleep and temporary paralysis, so both conditions
                receive the same alternate message */
-            if (!mtmp->mcanmove || !mtmp->data->mmove)
+            if (!mtmp->mcanmove || !mtmp->data->mmove) {
 /*JP
                 pline("%s seems to flinch.", Adjmonnam(mtmp, "immobile"));
 */
                 pline("%s\82Í\82µ\82è\82²\82Ý\82µ\82Ä\82¢\82é\82æ\82¤\82¾\81D", Monnam(mtmp));
-            else
+            } else if (flees_light(mtmp)) {
+                if (rn2(10) || Deaf)
+#if 0 /*JP*/
+                    pline("%s flees from the painful light of %s.",
+                          Monnam(mtmp), bare_artifactname(uwep));
+#else
+                    pline("%s\82Í%s\82Ì\8cõ\82É\82¨\82Ñ\82¦\82½\81D",
+                          Monnam(mtmp), bare_artifactname(uwep));
+#endif
+                else
+/*JP
+                    verbalize("Bright light!");
+*/
+                    verbalize("\8bP\82­\8cõ\81I");
+            } else
 /*JP
                 pline("%s turns to flee.", Monnam(mtmp));
 */
@@ -336,7 +364,7 @@ register struct monst *mtmp;
 int *inrange, *nearby, *scared;
 {
     int seescaryx, seescaryy;
-    boolean sawscary = FALSE;
+    boolean sawscary = FALSE, bravegremlin = (rn2(5) == 0);
 
     *inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy)
                 <= (BOLT_LIM * BOLT_LIM));
@@ -359,6 +387,7 @@ int *inrange, *nearby, *scared;
 
     sawscary = onscary(seescaryx, seescaryy, mtmp);
     if (*nearby && (sawscary
+                    || (flees_light(mtmp) && !bravegremlin)
                     || (!mtmp->mpeaceful && in_your_sanctuary(mtmp, 0, 0)))) {
         *scared = 1;
         monflee(mtmp, rnd(rn2(7) ? 10 : 100), TRUE, TRUE);
@@ -366,6 +395,8 @@ int *inrange, *nearby, *scared;
         *scared = 0;
 }
 
+#undef flees_light
+
 /* perform a special one-time action for a monster; returns -1 if nothing
    special happened, 0 if monster uses up its turn, 1 if monster is killed */
 STATIC_OVL int
@@ -445,7 +476,7 @@ register struct monst *mtmp;
         m_respond(mtmp);
     if (mdat == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my))
         m_respond(mtmp);
-    if (mtmp->mhp <= 0)
+    if (DEADMONSTER(mtmp))
         return 1; /* m_respond gaze can kill medusa */
 
     /* fleeing monsters might regain courage */
@@ -485,7 +516,7 @@ register struct monst *mtmp;
     if (nearby && mdat->msound == MS_BRIBE && mtmp->mpeaceful && !mtmp->mtame
         && !u.uswallow) {
         if (mtmp->mux != u.ux || mtmp->muy != u.uy) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
             pline("%s whispers at thin air.",
                   cansee(mtmp->mux, mtmp->muy) ? Monnam(mtmp) : "It");
 #else
@@ -546,7 +577,7 @@ register struct monst *mtmp;
 
             if (m_sen || (Blind_telepat && rn2(2)) || !rn2(10)) {
                 int dmg;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                 pline("It locks on to your %s!",
                       m_sen ? "telepathy" : Blind_telepat ? "latent telepathy"
                                                           : "mind");
@@ -582,14 +613,14 @@ register struct monst *mtmp;
 */
                     pline("%s\82ð\92¼\8c\82\82µ\82½\81D", mon_nam(m2));
                 m2->mhp -= rnd(15);
-                if (m2->mhp <= 0)
+                if (DEADMONSTER(m2))
                     monkilled(m2, "", AD_DRIN);
                 else
                     m2->msleeping = 0;
             }
         }
     }
-toofar:
+ toofar:
 
     /* If monster is nearby you, and has to wield a weapon, do so.   This
      * costs the monster a move, of course.
@@ -654,7 +685,7 @@ toofar:
         case 0: /* no movement, but it can still attack you */
         case 3: /* absolutely no movement */
             /* vault guard might have vanished */
-            if (mtmp->isgd && (mtmp->mhp < 1 || mtmp->mx == 0))
+            if (mtmp->isgd && (DEADMONSTER(mtmp) || mtmp->mx == 0))
                 return 1; /* behave as if it died */
             /* During hallucination, monster appearance should
              * still change - even if it doesn't move.
@@ -783,25 +814,25 @@ struct monst *mtmp;
 xchar nix,niy;
 {
     boolean can_tunnel = 0;
-    struct obj *mw_tmp;
+    struct obj *mw_tmp = MON_WEP(mtmp);
 
     if (!Is_rogue_level(&u.uz))
         can_tunnel = tunnels(mtmp->data);
 
-    if (can_tunnel && needspick(mtmp->data)
-        && mtmp->weapon_check != NO_WEAPON_WANTED
-        && ((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy))
-            || closed_door(nix, niy))) {
+    if (can_tunnel && needspick(mtmp->data) && !mwelded(mw_tmp)
+        && (may_dig(nix, niy) || closed_door(nix, niy))) {
+        /* may_dig() is either IS_STWALL or IS_TREE */
         if (closed_door(nix, niy)) {
-            if (!(mw_tmp = MON_WEP(mtmp))
+            if (!mw_tmp
                 || !is_pick(mw_tmp)
                 || !is_axe(mw_tmp))
                 mtmp->weapon_check = NEED_PICK_OR_AXE;
         } else if (IS_TREE(levl[nix][niy].typ)) {
             if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
                 mtmp->weapon_check = NEED_AXE;
-        } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
-            mtmp->weapon_check = NEED_PICK_AXE;
+        } else if (IS_STWALL(levl[nix][niy].typ)) {
+            if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp))
+                mtmp->weapon_check = NEED_PICK_AXE;
         }
         if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
             return TRUE;
@@ -950,7 +981,7 @@ register int after;
         mmoved = 1;
         goto postmov;
     }
-not_special:
+ not_special:
     if (u.uswallow && !mtmp->mflee && u.ustuck != mtmp)
         return 1;
     omx = mtmp->mx;
@@ -1036,7 +1067,7 @@ not_special:
         if ((likegold || likegems || likeobjs || likemagic || likerock
              || conceals) && (!*in_rooms(omx, omy, SHOPBASE)
                               || (!rn2(25) && !mtmp->isshk))) {
       look_for_obj:
+ look_for_obj:
             oomx = min(COLNO - 1, omx + minr);
             oomy = min(ROWNO - 1, omy + minr);
             lmx = max(1, omx - minr);
@@ -1211,7 +1242,7 @@ not_special:
                 chi = i;
                 mmoved = 1;
             }
       nxti:
+ nxti:
             ;
         }
     }
@@ -1255,6 +1286,7 @@ not_special:
         if ((info[chi] & ALLOW_M) || (nix == mtmp->mux && niy == mtmp->muy)) {
             struct monst *mtmp2;
             int mstatus;
+
             mtmp2 = m_at(nix, niy);
 
             notonhead = mtmp2 && (nix != mtmp2->mx || niy != mtmp2->my);
@@ -1278,6 +1310,7 @@ not_special:
         if ((info[chi] & ALLOW_MDISP)) {
             struct monst *mtmp2;
             int mstatus;
+
             mtmp2 = m_at(nix, niy);
             mstatus = mdisplacem(mtmp, mtmp2, FALSE);
             if ((mstatus & MM_AGR_DIED) || (mstatus & MM_DEF_DIED))
@@ -1289,6 +1322,7 @@ not_special:
 
         if (!m_in_out_region(mtmp, nix, niy))
             return 3;
+
         remove_monster(omx, omy);
         place_monster(mtmp, nix, niy);
         for (j = MTSZ - 1; j > 0; j--)
@@ -1306,18 +1340,51 @@ not_special:
         if (mtmp->wormno)
             worm_nomove(mtmp);
     }
-postmov:
+ postmov:
     if (mmoved == 1 || mmoved == 3) {
         boolean canseeit = cansee(mtmp->mx, mtmp->my);
 
         if (mmoved == 1) {
+            /* normal monster move will already have <nix,niy>,
+               but pet dog_move() with 'goto postmov' won't */
+            nix = mtmp->mx, niy = mtmp->my;
+            /* sequencing issue:  when monster movement decides that a
+               monster can move to a door location, it moves the monster
+               there before dealing with the door rather than after;
+               so a vampire/bat that is going to shift to fog cloud and
+               pass under the door is already there but transformation
+               into fog form--and its message, when in sight--has not
+               happened yet; we have to move monster back to previous
+               location before performing the vamp_shift() to make the
+               message happen at right time, then back to the door again
+               [if we did the shift above, before moving the monster,
+               we would need to duplicate it in dog_move()...] */
+            if (is_vampshifter(mtmp) && !amorphous(mtmp->data)
+                && IS_DOOR(levl[nix][niy].typ)
+                && ((levl[nix][niy].doormask & (D_LOCKED | D_CLOSED)) != 0)
+                && can_fog(mtmp)) {
+                if (sawmon) {
+                    remove_monster(nix, niy);
+                    place_monster(mtmp, omx, omy);
+                    newsym(nix, niy), newsym(omx, omy);
+                }
+                if (vamp_shift(mtmp, &mons[PM_FOG_CLOUD], sawmon)) {
+                    ptr = mtmp->data; /* update cached value */
+                }
+                if (sawmon) {
+                    remove_monster(omx, omy);
+                    place_monster(mtmp, nix, niy);
+                    newsym(omx, omy), newsym(nix, niy);
+                }
+            }
+
             newsym(omx, omy); /* update the old position */
             if (mintrap(mtmp) >= 2) {
                 if (mtmp->mx)
                     newsym(mtmp->mx, mtmp->my);
                 return 2; /* it died */
             }
-            ptr = mtmp->data;
+            ptr = mtmp->data; /* in case mintrap() caused polymorph */
 
             /* open a door, or crash through it, if 'mtmp' can */
             if (IS_DOOR(levl[mtmp->mx][mtmp->my].typ)
@@ -1338,25 +1405,16 @@ postmov:
                     btrapped = FALSE;
                 }
                 if ((here->doormask & (D_LOCKED | D_CLOSED)) != 0
-                    && (amorphous(ptr)
-                        || (can_fog(mtmp)
-                            && vamp_shift(mtmp, &mons[PM_FOG_CLOUD],
-                                          sawmon)))) {
-                    /* update cached value for vamp_shift() case */
-                    ptr = mtmp->data;
+                    && amorphous(ptr)) {
                     if (flags.verbose && canseemon(mtmp))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
                         pline("%s %s under the door.", Monnam(mtmp),
                               (ptr == &mons[PM_FOG_CLOUD]
-                               || ptr->mlet == S_LIGHT)
-                                  ? "flows"
-                                  : "oozes");
+                               || ptr->mlet == S_LIGHT) ? "flows" : "oozes");
 #else
-                        pline("%s\82Í\94à\82Ì\89º\82©\82ç%s\81D", Monnam(mtmp),
+                        pline("%s\82Í\94à\82Ì\89º\82©\82ç%s\82Å\82½\81D", Monnam(mtmp),
                               (ptr == &mons[PM_FOG_CLOUD]
-                               || ptr->mlet == S_LIGHT)
-                                  ? "\97¬\82ê\82Å\82½"
-                                  : "\82É\82\82Ý\82Å\82½");
+                               || ptr->mlet == S_LIGHT) ? "\97¬\82ê" : "\82É\82\82Ý");
 #endif
                 } else if (here->doormask & D_LOCKED && can_unlock) {
                     if (btrapped) {
@@ -1456,7 +1514,8 @@ postmov:
                         add_damage(mtmp->mx, mtmp->my, 0L);
                 }
             } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) {
-                if (may_dig(mtmp->mx, mtmp->my)
+                /* As of 3.6.2: was using may_dig() but it doesn't handle bars */
+                if (!(levl[mtmp->mx][mtmp->my].wall_info & W_NONDIGGABLE)
                     && (dmgtype(ptr, AD_RUST) || dmgtype(ptr, AD_CORR))) {
                     if (canseemon(mtmp))
 /*JP
@@ -1570,6 +1629,7 @@ dissolve_bars(x, y)
 register int x, y;
 {
     levl[x][y].typ = (Is_special(&u.uz) || *in_rooms(x, y, 0)) ? ROOM : CORR;
+    levl[x][y].flags = 0;
     newsym(x, y);
 }
 
@@ -1638,6 +1698,7 @@ register struct monst *mtmp;
 
     if (!gotu) {
         register int try_cnt = 0;
+
         do {
             if (++try_cnt > 200)
                 goto found_you; /* punt */
@@ -1651,7 +1712,7 @@ register struct monst *mtmp;
                               && (can_ooze(mtmp) || can_fog(mtmp)))))
                  || !couldsee(mx, my));
     } else {
   found_you:
+ found_you:
         mx = u.ux;
         my = u.uy;
     }
@@ -1670,8 +1731,8 @@ register struct monst *mtmp;
  */
 boolean
 undesirable_disp(mtmp, x, y)
-struct monst *mtmp;
-xchar x, y;
+struct monst *mtmp; /* barging creature */
+xchar x, y; /* spot 'mtmp' is considering moving to */
 {
     boolean is_pet = (mtmp && mtmp->mtame && !mtmp->isminion);
     struct trap *trap = t_at(x, y);
@@ -1690,6 +1751,18 @@ xchar x, y;
         return TRUE;
     }
 
+    /* oversimplification:  creatures that bargethrough can't swap places
+       when target monster is in rock or closed door or water (in particular,
+       avoid moving to spots where mondied() won't leave a corpse; doesn't
+       matter whether barger is capable of moving to such a target spot if
+       it were unoccupied) */
+    if (!accessible(x, y)
+        /* mondied() allows is_pool() as an exception to !accessible(),
+           but we'll only do that if 'mtmp' is already at a water location
+           so that we don't swap a water critter onto land */
+        && !(is_pool(x, y) && is_pool(mtmp->mx, mtmp->my)))
+        return TRUE;
+
     return FALSE;
 }
 
@@ -1776,9 +1849,18 @@ boolean domsg;
     }
 
     if (reslt && domsg) {
+#if 0 /*JP:T*/
         pline("You %s %s where %s was.",
               !canseemon(mon) ? "now detect" : "observe",
               noname_monnam(mon, ARTICLE_A), oldmtype);
+#else
+        pline("\82 \82È\82½\82Í%s\82ª\82¢\82½\8fê\8f\8a\82É%s\82ð%s\81D",
+              oldmtype, noname_monnam(mon, ARTICLE_A),
+              !canseemon(mon) ? "\8a´\92m\82µ\82½" : "\8c©\82Â\82¯\82½");
+#endif
+        /* this message is given when it turns into a fog cloud
+           in order to move under a closed door */
+        display_nhwindow(WIN_MESSAGE, FALSE);
     }
 
     return reslt;