]> granicus.if.org Git - nethack/commitdiff
fix #U782 - undead turning in a shop [trunk only]
authornethack.rankin <nethack.rankin>
Fri, 22 Oct 2004 01:04:34 +0000 (01:04 +0000)
committernethack.rankin <nethack.rankin>
Fri, 22 Oct 2004 01:04:34 +0000 (01:04 +0000)
     Reported last December by <email deleted>.  Using
a wand or spell of undead turning inside a shop used up corpses without
checking whether they were owned by the shop.  Although the report didn't
mention it, using stone-to-flesh on statues had the same problem.

     I'm not completely satisfied by some aspects of this code, but if I
don't commit what I've got now I probably never would.  My original notes
are lost; I thought that there were some additional fixes present, but
looking at these diffs I don't see anything else significant enough to
warrant mention in the fixes file.

doc/fixes34.4
include/extern.h
src/do.c
src/mkroom.c
src/trap.c
src/zap.c

index ace4cfb2512cac9109e9325f8894105715bde921..5314a755b3e36d9c5515500a9c95e3505ae09278 100644 (file)
@@ -56,6 +56,7 @@ destroying a worn item via dipping in burning oil would not unwear/unwield
        the item properly, possibly leading to various strange behaviors
 avoid a panic splitbill when shopkeeper is trapped by the door
 grammar tidbit for message given when eating tainted meat is also cannibalism
+charge for reviving a shop owned corpse or reanimating a shop owned statue
 
 
 Platform- and/or Interface-Specific Fixes
index d88ffcd09b706bf209e19309562898b329176c17..7c53e4ab0e59dcc64c71f0d5e7a429a38d607996 100644 (file)
@@ -2422,7 +2422,7 @@ E boolean FDECL(get_obj_location, (struct obj *,xchar *,xchar *,int));
 E boolean FDECL(get_mon_location, (struct monst *,xchar *,xchar *,int));
 E struct monst *FDECL(get_container_location, (struct obj *obj, int *, int *));
 E struct monst *FDECL(montraits, (struct obj *,coord *));
-E struct monst *FDECL(revive, (struct obj *));
+E struct monst *FDECL(revive, (struct obj *,BOOLEAN_P));
 E int FDECL(unturn_dead, (struct monst *));
 E void FDECL(cancel_item, (struct obj *));
 E boolean FDECL(drain_item, (struct obj *));
index 927c3f7b027f04e8d858562e532e0e5d79911bf5..0e230ff3623548f2eb4b39bac2921e7bae4c4e62 100644 (file)
--- a/src/do.c
+++ b/src/do.c
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)do.c       3.4     2003/12/17      */
+/*     SCCS Id: @(#)do.c       3.4     2004/09/10      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1511,7 +1511,7 @@ struct obj *corpse;
        /* container_where is the outermost container's location even if nested */
        if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2;
     }
-    mtmp = revive(corpse);     /* corpse is gone if successful */
+    mtmp = revive(corpse, FALSE);      /* corpse is gone if successful */
 
     if (mtmp) {
        chewed = (mtmp->mhp < mtmp->mhpmax);
index 3e0f78827caa29e30c6f8d92d6804abdd9b73dea..419eae0892284d42d705ade43acef5d3ae39a6f0 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)mkroom.c   3.4     2001/09/06      */
+/*     SCCS Id: @(#)mkroom.c   3.4     2004/06/10      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -403,7 +403,7 @@ int mm_flags;
            if (enexto(&cc, mm->x, mm->y, mdat) &&
                    (!revive_corpses ||
                     !(otmp = sobj_at(CORPSE, cc.x, cc.y)) ||
-                    !revive(otmp)))
+                    !revive(otmp, FALSE)))
                (void) makemon(mdat, cc.x, cc.y, mm_flags);
        }
        level.flags.graveyard = TRUE;   /* reduced chance for undead corpse */
index 950b4c793285dc7a59c65bc09e374f76cb943b43..1ea19350b60d06c387f70f969ef7576c49541416 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)trap.c     3.4     2004/08/23      */
+/*     SCCS Id: @(#)trap.c     3.4     2004/09/10      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -382,6 +382,18 @@ boolean td;        /* td == TRUE : trap door or hole */
  *
  * Perhaps x, y is not needed if we can use get_obj_location() to find
  * the statue's location... ???
+ *
+ * Sequencing matters:
+ *     create monster; if it fails, give up with statue intact;
+ *     give "statue comes to life" message;
+ *     if statue belongs to shop, have shk give "you owe" message;
+ *     transfer statue contents to monster (after stolen_value());
+ *     delete statue.
+ *     [This ordering means that if the statue ends up wearing a cloak of
+ *      invisibility or a mummy wrapping, the visibility checks might be
+ *      wrong, but to avoid that we'd have to clone the statue contents
+ *      first in order to give them to the monster before checking their
+ *      shop status--it's not worth the hassle.]
  */
 struct monst *
 animate_statue(statue, x, y, cause, fail_reason)
@@ -392,15 +404,16 @@ int *fail_reason;
 {
        int mnum = statue->corpsenm;
        struct permonst *mptr = &mons[mnum];
-       struct monst *mon = 0;
+       struct monst *mon = 0, *shkp;
        struct obj *item;
        coord cc;
-       boolean historic = (Role_if(PM_ARCHEOLOGIST) && !context.mon_moving &&
-                           (statue->spe & STATUE_HISTORIC)),
+       boolean historic = (Role_if(PM_ARCHEOLOGIST) &&
+                               (statue->spe & STATUE_HISTORIC) != 0),
                use_saved_traits;
-       char statuename[BUFSZ];
-
-       Strcpy(statuename,the(xname(statue)));
+       const char *comes_to_life;
+       char statuename[BUFSZ], tmpbuf[BUFSZ];
+       static const char historic_statue_is_gone[] =
+                               "that the historic statue is now gone";
 
        if (cant_revive(&mnum, TRUE, statue)) {
            /* mnum has changed; we won't be animating this statue as itself */
@@ -449,10 +462,7 @@ int *fail_reason;
            return (struct monst *)0;
        }
 
-       /* in case statue is wielded and hero zaps stone-to-flesh at self */
-       if (statue->owornmask) remove_worn_item(statue, TRUE);
-
-       /* allow statues to be of a specific gender */
+       /* a non-montraits() statue might specify gender */
        if (statue->spe & STATUE_MALE)
            mon->female = FALSE;
        else if (statue->spe & STATUE_FEMALE)
@@ -460,40 +470,65 @@ int *fail_reason;
        /* if statue has been named, give same name to the monster */
        if (statue->onamelth)
            mon = christen_monst(mon, ONAME(statue));
-       /* transfer any statue contents to monster's inventory */
-       while ((item = statue->cobj) != 0) {
-           obj_extract_self(item);
-           (void) add_to_minv(mon, item);
-       }
-       m_dowear(mon, TRUE);
-       delobj(statue);
-
        /* mimic statue becomes seen mimic; other hiders won't be hidden */
        if (mon->m_ap_type) seemimic(mon);
        else mon->mundetected = FALSE;
 
+       comes_to_life = !canspotmon(mon) ? "disappears" :
+                       (nonliving(mon->data) || is_vampshifter(mon)) ?
+                               "moves" : "comes to life";
        if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) {
-           const char *comes_to_life = (nonliving(mon->data) ||
-                                        is_vampshifter(mon)) ?
-                                       "moves" : "comes to life"; 
-           if (cause == ANIMATE_SPELL)
-               pline("%s %s!", upstart(statuename),
-                       canspotmon(mon) ? comes_to_life : "disappears");
+           /* "the|your|Manlobbi's statue [of a wombat]" */
+           Sprintf(statuename, "%s%s", shk_your(tmpbuf, statue),
+                   (cause == ANIMATE_SPELL) ? xname(statue) : "statue");
+           pline("%s %s!", upstart(statuename), comes_to_life);
+       } else if (cause == ANIMATE_SHATTER) {
+           if (cansee(x, y))
+               Sprintf(statuename, "%s%s", shk_your(tmpbuf, statue),
+                         xname(statue));
            else
-               pline_The("statue %s!",
-                       canspotmon(mon) ? comes_to_life : "disappears");
-           if (historic) {
-                   You_feel("guilty that the historic statue is now gone.");
-                   adjalign(-1);
-           }
-       } else if (cause == ANIMATE_SHATTER)
-           pline("Instead of shattering, the statue suddenly %s!",
-               canspotmon(mon) ? "comes to life" : "disappears");
-       else { /* cause == ANIMATE_NORMAL */
+               Strcpy(statuename, "a statue");
+           pline("Instead of shattering, %s suddenly %s!",
+                 statuename, comes_to_life);
+       } else { /* cause == ANIMATE_NORMAL */
            You("find %s posing as a statue.",
                canspotmon(mon) ? a_monnam(mon) : something);
            stop_occupation();
        }
+
+       /* if this isn't caused by a monster using a wand of striking,
+          there might be consequences for the hero */
+       if (!context.mon_moving) {
+           /* if statue is owned by a shop, hero will have to pay for it;
+              stolen_value gives a message (about debt or use of credit)
+              which refers to "it" so needs to follow a message describing
+              the object ("the statue comes to life" one above) */
+           if (cause != ANIMATE_NORMAL && costly_spot(x, y) &&
+                   (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0)
+               (void) stolen_value(statue, x, y,
+                                   (boolean)shkp->mpeaceful, FALSE);
+
+           if (historic) {
+               You_feel("guilty %s.", historic_statue_is_gone);
+               adjalign(-1);
+           }
+       } else {   
+           if (historic && cansee(x, y))
+               You_feel("regret %s.", historic_statue_is_gone);
+               /* no alignment penalty */
+       }
+
+       /* transfer any statue contents to monster's inventory */
+       while ((item = statue->cobj) != 0) {
+           obj_extract_self(item);
+           (void) add_to_minv(mon, item);
+       }
+       m_dowear(mon, TRUE);
+       /* in case statue is wielded and hero zaps stone-to-flesh at self */
+       if (statue->owornmask) remove_worn_item(statue, TRUE);
+       /* statue no longer exists */
+       delobj(statue);
+
        /* avoid hiding under nothing */
        if (x == u.ux && y == u.uy &&
                Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y))
index f5f56dba8d26bac7cef2d1862dc38d0c766e13ac..4cac707a365d01e6d66826ed76e32bce5f5b5d4e 100644 (file)
--- a/src/zap.c
+++ b/src/zap.c
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)zap.c      3.4     2004/08/02      */
+/*     SCCS Id: @(#)zap.c      3.4     2004/09/10      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -563,168 +563,194 @@ int *container_nesting;
  * successful.  Note: this does NOT use up the corpse if it fails.
  */
 struct monst *
-revive(obj)
-register struct obj *obj;
+revive(corpse, by_hero)
+struct obj *corpse;
+boolean by_hero;
 {
-       register struct monst *mtmp = (struct monst *)0;
-       struct permonst *mptr;
-       struct obj *container = (struct obj *)0;
-       int container_nesting = 0;
-       schar savetame = 0;
-       boolean recorporealization = FALSE;
-       boolean in_container = FALSE;
-
-       if(obj->otyp == CORPSE) {
-               int montype = obj->corpsenm;
-               xchar x, y;
-
-               if (obj->where == OBJ_CONTAINED) {
-                       /* deal with corpses in [possibly nested] containers */
-                       struct monst *carrier;
-                       int holder = 0;
-
-                       container = obj->ocontainer;
-                       carrier = get_container_location(container, &holder,
-                                                       &container_nesting);
-                       switch(holder) {
-                           case OBJ_MINVENT:
-                               x = carrier->mx; y = carrier->my;
-                               in_container = TRUE;
-                               break;
-                           case OBJ_INVENT:
-                               x = u.ux; y = u.uy;
-                               in_container = TRUE;
-                               break;
-                           case OBJ_FLOOR:
-                               if (!get_obj_location(obj, &x, &y, CONTAINED_TOO))
-                                       return (struct monst *) 0;
-                               in_container = TRUE;
-                               break;
-                           default:
-                               return (struct monst *)0;
-                       }
-               } else {
-                       /* only for invent, minvent, or floor */
-                       if (!get_obj_location(obj, &x, &y, 0))
-                           return (struct monst *) 0;
-               }
-               if (in_container) {
-                       /* Rules for revival from containers:
-                          - the container cannot be locked
-                          - the container cannot be heavily nested (>2 is arbitrary)
-                          - the container cannot be a statue or bag of holding
-                            (except in very rare cases for the latter)
-                       */
-                       if (!x || !y || container->olocked || container_nesting > 2 ||
-                           container->otyp == STATUE ||
-                           (container->otyp == BAG_OF_HOLDING && rn2(40)))
-                               return (struct monst *)0;
-               }
+    struct monst *mtmp = 0;
+    struct permonst *mptr;
+    struct obj *container;
+    coord xy;
+    xchar x, y;
+    int montype, container_nesting = 0;
+
+    if (corpse->otyp != CORPSE) {
+       impossible("Attempting to revive %s?", xname(corpse));
+       return (struct monst *)0;
+    }
 
-               if (MON_AT(x,y)) {
-                   coord new_xy;
+    x = y = 0;
+    if (corpse->where != OBJ_CONTAINED) {
+       /* only for invent, minvent, or floor */
+       container = 0;
+       (void) get_obj_location(corpse, &x, &y, 0);
+    } else {
+       /* deal with corpses in [possibly nested] containers */
+       struct monst *carrier;
+       int holder = OBJ_FREE;
+
+       container = corpse->ocontainer;
+       carrier = get_container_location(container, &holder,
+                                        &container_nesting);
+       switch (holder) {
+       case OBJ_MINVENT:
+           x = carrier->mx,  y = carrier->my;
+           break;
+       case OBJ_INVENT:
+           x = u.ux,  y = u.uy;
+           break;
+       case OBJ_FLOOR:
+           (void) get_obj_location(corpse, &x, &y, CONTAINED_TOO);
+           break;
+       default:
+           break;              /* x,y are 0 */
+       }
+    }
+    if (!x || !y ||
+           /* Rules for revival from containers:
+              - the container cannot be locked
+              - the container cannot be heavily nested (>2 is arbitrary)
+              - the container cannot be a statue or bag of holding
+              (except in very rare cases for the latter)
+           */
+           (container &&
+               (container->olocked || container_nesting > 2 ||
+                container->otyp == STATUE ||
+                (container->otyp == BAG_OF_HOLDING && rn2(40)))))
+       return (struct monst *)0;
 
-                   if (enexto(&new_xy, x, y, &mons[montype]))
-                       x = new_xy.x,  y = new_xy.y;
-               }
+    /* record the object's location now that we're sure where it is */
+    corpse->ox = x,  corpse->oy = y;
+
+    /* prepare for the monster */
+    montype = corpse->corpsenm;
+    mptr = &mons[montype];
+    /* [should probably handle recorporealization first; if corpse and
+       ghost are at same location, revived creature shouldn't be bumped
+       to an adjacent spot by ghost which joins with it] */
+    if (MON_AT(x,y)) {
+       if (enexto(&xy, x, y, mptr))
+           x = xy.x,  y = xy.y;
+    }
 
-               mptr = &mons[montype];
-               if (cant_revive(&montype, TRUE, obj)) {
-                   /* make a zombie or doppelganger instead */
-                   mtmp = makemon(&mons[montype], x, y,
-                                  NO_MINVENT | MM_NOWAIT);
-                   if (mtmp) {
-                       if (mtmp->cham == PM_DOPPELGANGER) {
-                           /* change shape to match the corpse */
-                           (void) newcham(mtmp, mptr, FALSE, FALSE);
-                       } else if (mtmp->data->mlet == S_ZOMBIE) {
-                           mtmp->mhp = mtmp->mhpmax = 100;
-                           mon_adjust_speed(mtmp, 2, (struct obj *)0); /* MFAST */
-                       }
-                   }
-               } else {
-                   if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) {
-                       coord xy;
+    if (cant_revive(&montype, TRUE, corpse)) {
+       /* make a zombie or doppelganger instead */
+       /* note: montype has changed; mptr keeps old value for newcham() */
+       mtmp = makemon(&mons[montype], x, y, NO_MINVENT|MM_NOWAIT);
+       if (mtmp) {
+           corpse->oattached = OATTACHED_NOTHING;  /* skip ghost handling */
+           if (mtmp->cham == PM_DOPPELGANGER) {
+               /* change shape to match the corpse */
+               (void) newcham(mtmp, mptr, FALSE, FALSE);
+           } else if (mtmp->data->mlet == S_ZOMBIE) {
+               mtmp->mhp = mtmp->mhpmax = 100;
+               mon_adjust_speed(mtmp, 2, (struct obj *)0); /* MFAST */
+           }
+       }
+    } else if (corpse->oxlth && corpse->oattached == OATTACHED_MONST) {
+       /* use saved traits */
+       xy.x = x,  xy.y = y;
+       mtmp = montraits(corpse, &xy);
+       if (mtmp && mtmp->mtame && !mtmp->isminion)
+           wary_dog(mtmp, TRUE);
+    } else {
+       /* make a new monster */
+       mtmp = makemon(mptr, x, y, NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
+    }
+    if (!mtmp) return (struct monst *)0;
 
-                       xy.x = x; xy.y = y;
-                       mtmp = montraits(obj, &xy);
-                       if (mtmp && mtmp->mtame && !mtmp->isminion)
-                           wary_dog(mtmp, TRUE);
-                   } else
-                       mtmp = makemon(&mons[montype], x, y,
-                                      NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
-                   if (mtmp) {
-                       if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) {
-                           unsigned m_id;
-                           struct monst *ghost;
-                           (void) memcpy((genericptr_t)&m_id,
-                                   (genericptr_t)obj->oextra, sizeof(m_id));
-                           ghost = find_mid(m_id, FM_FMON);
-                           if (ghost && ghost->data == &mons[PM_GHOST]) {
-                                   int x2, y2;
-                                   x2 = ghost->mx; y2 = ghost->my;
-                                   if (ghost->mtame)
-                                       savetame = ghost->mtame;
-                                   if (canseemon(ghost))
-                                       pline("%s is suddenly drawn into its former body!",
-                                               Monnam(ghost));
-                                   mondead(ghost);
-                                   recorporealization = TRUE;
-                                   newsym(x2, y2);
-                           }
-                           /* don't mess with obj->oxlth here */
-                           obj->oattached = OATTACHED_NOTHING;
-                       }
-                       /* Monster retains its name */
-                       if (obj->onamelth)
-                           mtmp = christen_monst(mtmp, ONAME(obj));
-                   }
-               }
-               if (mtmp) {
-                       if (obj->oeaten)
-                               mtmp->mhp = eaten_stat(mtmp->mhp, obj);
-                       /* track that this monster was revived at least once */
-                       mtmp->mrevived = 1;
-
-                       if (recorporealization) {
-                               /* If mtmp is revivification of former tame ghost*/
-                               if (savetame) {
-                                   struct monst *mtmp2 = tamedog(mtmp, (struct obj *)0);
-                                   if (mtmp2) {
-                                       mtmp2->mtame = savetame;
-                                       mtmp = mtmp2;
-                                   }
-                               }
-                               /* was ghost, now alive, it's all very confusing */
-                               mtmp->mconf = 1;
-                       }
+    /* if this is caused by the hero there might be a shop charge */
+    if (by_hero) {
+       struct monst *shkp = 0;
 
-                       switch (obj->where) {
-                           case OBJ_INVENT:
-                               useup(obj);
-                               break;
-                           case OBJ_FLOOR:
-                               /* in case MON_AT+enexto for invisible mon */
-                               x = obj->ox,  y = obj->oy;
-                               /* not useupf(), which charges */
-                               if (obj->quan > 1L)
-                                   obj = splitobj(obj, 1L);
-                               delobj(obj);
-                               newsym(x, y);
-                               break;
-                           case OBJ_MINVENT:
-                               m_useup(obj->ocarry, obj);
-                               break;
-                           case OBJ_CONTAINED:
-                               obj_extract_self(obj);
-                               obfree(obj, (struct obj *) 0);
-                               break;
-                           default:
-                               panic("revive");
-                       }
+       x = corpse->ox,  y = corpse->oy;
+       if (costly_spot(x, y))
+           shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
+
+       if (cansee(x, y))
+           pline_The("%s glows iridescently.", cxname(corpse));
+       else if (shkp)
+           /* need some prior description of the corpse since
+              stolen_value() will refer to the object as "it" */
+           pline("A corpse is resuscitated.");
+
+       if (shkp)
+           (void) stolen_value(corpse, x, y, (boolean)shkp->mpeaceful, FALSE);
+
+       /* [we don't give any comparable message about the corpse for
+          the !by_hero case because caller might have already done so] */
+    }
+
+    /* handle recorporealization of an active ghost */
+    if (corpse->oxlth && corpse->oattached == OATTACHED_M_ID) {
+       unsigned m_id;
+       struct monst *ghost, *mtmp2;
+       struct obj *otmp;
+
+       (void) memcpy((genericptr_t)&m_id,
+                     (genericptr_t)corpse->oextra, sizeof m_id);
+       ghost = find_mid(m_id, FM_FMON);
+       if (ghost && ghost->data == &mons[PM_GHOST]) {
+           if (canseemon(ghost))
+               pline("%s is suddenly drawn into its former body!",
+                     Monnam(ghost));
+           /* transfer the ghost's inventory along with it */
+           while ((otmp = ghost->minvent) != 0) {
+               obj_extract_self(otmp);
+               add_to_minv(mtmp, otmp);
+           }
+           /* tame the revived monster if its ghost was tame */
+           if (ghost->mtame && !mtmp->mtame) {
+               mtmp2 = tamedog(mtmp, (struct obj *)0);
+               if (mtmp2) {
+                   /* ghost's edog data is ignored */
+                   mtmp2->mtame = ghost->mtame;
+                   mtmp = mtmp2;
                }
+           }
+           /* was ghost, now alive, it's all very confusing */
+           mtmp->mconf = 1;
+           /* separate ghost monster no longer exists */
+           mongone(ghost);
        }
-       return mtmp;
+       corpse->oattached = OATTACHED_NOTHING;
+    }
+
+    /* monster retains its name */
+    if (corpse->onamelth)
+       mtmp = christen_monst(mtmp, ONAME(corpse));
+    /* partially eaten corpse yields wounded monster */
+    if (corpse->oeaten)
+       mtmp->mhp = eaten_stat(mtmp->mhp, corpse);
+    /* track that this monster was revived at least once */
+    mtmp->mrevived = 1;
+
+    /* finally, get rid of the corpse--it's gone now */
+    switch (corpse->where) {
+    case OBJ_INVENT:
+       useup(corpse);
+       break;
+    case OBJ_FLOOR:
+       /* in case MON_AT+enexto for invisible mon */
+       x = corpse->ox,  y = corpse->oy;
+       /* not useupf(), which charges */
+       if (corpse->quan > 1L)
+           corpse = splitobj(corpse, 1L);
+       delobj(corpse);
+       newsym(x, y);
+       break;
+    case OBJ_MINVENT:
+       m_useup(corpse->ocarry, corpse);
+       break;
+    case OBJ_CONTAINED:
+       obj_extract_self(corpse);
+       obfree(corpse, (struct obj *)0);
+       break;
+    default:
+       panic("revive");
+    }
+
+    return mtmp;
 }
 
 STATIC_OVL void
@@ -762,7 +788,7 @@ struct monst *mon;
            if (youseeit) Strcpy(corpse, corpse_xname(otmp, TRUE));
 
            /* for a merged group, only one is revived; should this be fixed? */
-           if ((mtmp2 = revive(otmp)) != 0) {
+           if ((mtmp2 = revive(otmp, !context.mon_moving)) != 0) {
                ++res;
                if (youseeit) {
                    if (!once++) Strcpy(owner,
@@ -1577,29 +1603,30 @@ struct obj *obj, *otmp;
                break;
        case WAN_UNDEAD_TURNING:
        case SPE_TURN_UNDEAD:
-               if (obj->otyp == EGG)
-                       revive_egg(obj);
-               else {
-                       int corpsenm = (obj->otyp == CORPSE) ?
-                                       corpse_revive_type(obj) : 0;
-                       res = !!revive(obj);
-                       if (res && corpsenm && Role_if(PM_HEALER)) {
-                           boolean u_noticed = FALSE;
-                           if (Hallucination && !Deaf) {
-                               You_hear("the sound of a defibrillator.");
-                               u_noticed = TRUE;
-                           } else if (!Blind) {
-                               You("observe %s %s change dramatically.",
-                                       s_suffix(an(mons[corpsenm].mname)),
-                                       nonliving(&mons[corpsenm]) ?
+               if (obj->otyp == EGG) {
+                   revive_egg(obj);
+               } else if (obj->otyp == CORPSE) {
+                   int corpsenm = corpse_revive_type(obj);
+
+                   res = !!revive(obj, TRUE);
+                   if (res && Role_if(PM_HEALER)) {
+                       boolean u_noticed = FALSE;
+
+                       if (Hallucination && !Deaf) {
+                           You_hear("the sound of a defibrillator.");
+                           u_noticed = TRUE;
+                       } else if (!Blind) {
+                           You("observe %s %s change dramatically.",
+                               s_suffix(an(mons[corpsenm].mname)),
+                               nonliving(&mons[corpsenm]) ?
                                        "motility" : "health");
-                               u_noticed = TRUE;
-                           }
-                           if (u_noticed) {
-                                   makeknown(otmp->otyp);
-                                   exercise(A_WIS, TRUE);
-                           }
+                           u_noticed = TRUE;
+                       }
+                       if (u_noticed) {
+                           makeknown(otmp->otyp);
+                           exercise(A_WIS, TRUE);
                        }
+                   }
                }
                break;
        case WAN_OPENING: