]> granicus.if.org Git - nethack/commitdiff
vampires now shapeshift [trunk only]
authornethack.allison <nethack.allison>
Tue, 15 Jun 2004 11:52:04 +0000 (11:52 +0000)
committernethack.allison <nethack.allison>
Tue, 15 Jun 2004 11:52:04 +0000 (11:52 +0000)
- can shift into fog clouds, vampire bats, and vampire lords into wolves
- after being "killed" in shifted form, they transform back rather than get
  destroyed, and you must take them on in vampire form to defeat them
- can deliberately shift into fog clouds to pass under closed doors

27 files changed:
doc/fixes35.0
include/extern.h
include/hack.h
include/monst.h
src/apply.c
src/cmd.c
src/dog.c
src/dokick.c
src/explode.c
src/makemon.c
src/mhitu.c
src/mon.c
src/mondata.c
src/monmove.c
src/monst.c
src/mthrowu.c
src/muse.c
src/polyself.c
src/potion.c
src/pray.c
src/region.c
src/sounds.c
src/spell.c
src/trap.c
src/uhitm.c
src/weapon.c
src/zap.c

index f9660cd5362071200ce1ec4dbe3d7ccd8a8b66e7..2cfc8611a70d586221074bc1a7ec1dec1928b0fc 100644 (file)
@@ -109,6 +109,10 @@ health-food store that stocks monk-appropriate foods in mine town when monk
 give more information about your attributes in debug mode
 polywarn to give intrinsic monster detection of limited species while polymorphed
 rocks can skip on the water sometimes allowing them to pass over water creatures
+vampires can now shapeshift into bats and fog clouds; the latter can be done at 
+       will to slip through locked doors
+shapeshifted vampire will transform back to vampire form after you defeat it and
+       continue to fight in its native form
 
 
 Platform- and/or Interface-Specific New Features
index 6d0ebf8060db539881076888cd06cafdfba334aa..3e0c4da9b96f83a7d094f68bacdf5eabec47853f 100644 (file)
@@ -1196,6 +1196,7 @@ E void NDECL(kill_genocided_monsters);
 E void FDECL(golemeffects, (struct monst *,int,int));
 E boolean FDECL(angry_guards, (BOOLEAN_P));
 E void NDECL(pacify_guards);
+E void FDECL(decide_to_shapeshift, (struct monst *,int));
 
 /* ### mondata.c ### */
 
@@ -1209,6 +1210,7 @@ E boolean FDECL(resists_blnd, (struct monst *));
 E boolean FDECL(can_blnd, (struct monst *,struct monst *,UCHAR_P,struct obj *));
 E boolean FDECL(ranged_attk, (struct permonst *));
 E boolean FDECL(hates_silver, (struct permonst *));
+E boolean FDECL(mon_hates_silver, (struct monst *));
 E boolean FDECL(passes_bars, (struct permonst *));
 E boolean FDECL(can_blow, (struct monst *));
 E boolean FDECL(can_track, (struct permonst *));
@@ -1247,6 +1249,7 @@ E boolean FDECL(closed_door, (int,int));
 E boolean FDECL(accessible, (int,int));
 E void FDECL(set_apparxy, (struct monst *));
 E boolean FDECL(can_ooze, (struct monst *));
+E boolean FDECL(can_fog, (struct monst *));
 #ifdef BARGETHROUGH
 E boolean FDECL(should_displace, (struct monst *,coord *,long *,int,
                                        XCHAR_P,XCHAR_P));
@@ -1591,6 +1594,7 @@ E int NDECL(dospinweb);
 E int NDECL(dosummon);
 E int NDECL(dogaze);
 E int NDECL(dohide);
+E int NDECL(dopoly);
 E int NDECL(domindblast);
 E void FDECL(skinback, (BOOLEAN_P));
 E const char *FDECL(mbodypart, (struct monst *,int));
index ba77608c15e44900419adc8ea2652cd7698248fd..d0a02f07c26f9115dda4c5ffbe86b3d9a33e62db 100644 (file)
@@ -153,6 +153,10 @@ NEARDATA extern coord bhitpos;     /* place where throw or zap hits or stops */
 #define CORPSTAT_INIT    0x01  /* pass init flag to mkcorpstat */
 #define CORPSTAT_BURIED          0x02  /* bury the corpse or statue */
 
+/* flags for decide_to_shift() */
+#define SHIFT_SEENMSG    0x01  /* put out a message if in sight */
+#define SHIFT_MSG        0x02  /* always put out a message */
 /* special mhpmax value when loading bones monster to flag as extinct or genocided */
 #define DEFUNCT_MONSTER        (-100)
 
index c98239905452a371187266fc115c5faa85cb9bc1..a1ba25f0f9b1c260c43e95c6cd423949a4842ab5 100644 (file)
@@ -176,5 +176,7 @@ struct monst {
 
 #define DEADMONSTER(mon)       ((mon)->mhp < 1)
 #define is_starting_pet(mon)   ((mon)->m_id == context.startingpet_mid)
-
+#define is_vampshifter(mon)    ((mon)->cham == PM_VAMPIRE || \
+                                (mon)->cham == PM_VAMPIRE_LORD || \
+                                (mon)->cham == PM_VLAD_THE_IMPALER)
 #endif /* MONST_H */
index c2138aa20f947e165f853a8ec77fab34bad2e3ea..45df4545d4e669b1860244221bd7476cd5af9ceb 100644 (file)
@@ -763,7 +763,7 @@ struct obj *obj;
            if (vis)
                pline("%s can't see anything right now.", Monnam(mtmp));
        /* some monsters do special things */
-       } else if (mlet == S_VAMPIRE || mlet == S_GHOST) {
+       } else if (mlet == S_VAMPIRE || mlet == S_GHOST || is_vampshifter(mtmp)) {
            if (vis)
                pline ("%s doesn't have a reflection.", Monnam(mtmp));
        } else if(!mtmp->mcan && !mtmp->minvis &&
index c434f0ed20378e227c11d211fb75ca8a69993a7e..301fb87c99691c964a660e06934f50074399a0e6 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -464,7 +464,8 @@ domonability()
            if(u.uburied)
                pline("Unfortunately sound does not carry well through rock.");
            else aggravate();
-       } else if (Upolyd)
+       } else if (youmonst.data->mlet == S_VAMPIRE) return dopoly();
+       else if (Upolyd)
                pline("Any special ability you may have is purely reflexive.");
        else You("don't have a special ability in your normal form!");
        return 0;
index 98301e8f76502a563bf4c24d0787aa124c2387f5..a6a94d433d9943c36a243f80e30f8c629474095e 100644 (file)
--- a/src/dog.c
+++ b/src/dog.c
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)dog.c      3.4     2002/09/08      */
+/*     SCCS Id: @(#)dog.c      3.4     2004/06/12      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -689,7 +689,7 @@ register struct obj *obj;
                        return (herbi ? CADAVER : MANFOOD);
                    else return (carni ? CADAVER : MANFOOD);
                case CLOVE_OF_GARLIC:
-                   return (is_undead(mon->data) ? TABU :
+                   return ((is_undead(mon->data) || is_vampshifter(mon)) ? TABU :
                            ((herbi || starving) ? ACCFOOD : MANFOOD));
                case TIN:
                    return (metallivorous(mon->data) ? ACCFOOD : MANFOOD);
@@ -709,7 +709,7 @@ register struct obj *obj;
            if (obj->otyp == AMULET_OF_STRANGULATION ||
                        obj->otyp == RIN_SLOW_DIGESTION)
                return TABU;
-           if (hates_silver(mon->data) &&
+           if (mon_hates_silver(mon) &&
                objects[obj->otyp].oc_material == SILVER)
                return(TABU);
            if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj))
index 15265e13bd5f124802a84e4f820ee16e59e579ea..5f81348f6748d5987b619c8c14cae6af2f4d5472 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)dokick.c   3.4     2003/12/04      */
+/*     SCCS Id: @(#)dokick.c   3.4     2004/06/12      */
 /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -49,8 +49,8 @@ register boolean clumsy;
        if (mon->data == &mons[PM_SHADE])
            dmg = 0;
 
-       if ((is_undead(mon->data) || is_demon(mon->data)) && uarmf &&
-               uarmf->blessed)
+       if ((is_undead(mon->data) || is_demon(mon->data) || is_vampshifter(mon))
+                && uarmf && uarmf->blessed)
            blessed_foot_damage = 1;
 
        if (mon->data == &mons[PM_SHADE] && !blessed_foot_damage) {
index c0d707bec0c358925e623f19d1124829d6e9a7a2..6885a3489df18c33a7323d1d382933b0071beb74 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)explode.c  3.4     2003/10/21      */
+/*     SCCS Id: @(#)explode.c  3.4     2004/06/12      */
 /*     Copyright (C) 1990 by Ken Arromdee */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -157,7 +157,7 @@ int expltype;
                                break;
                        case AD_DISN:
                                explmask[i][j] |= (olet == WAND_CLASS) ?
-                                       (nonliving(mtmp->data) || is_demon(mtmp->data)) :
+       (nonliving(mtmp->data) || is_demon(mtmp->data) || is_vampshifter(mtmp)) :
                                        resists_disint(mtmp);
                                break;
                        case AD_ELEC:
index cfacb34eaf41091b5ce6790e8e6a6c49cd70bf2d..f1ca79d92a935a18f4218aaf7b8b65e316965de6 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)makemon.c  3.4     2004/05/21      */
+/*     SCCS Id: @(#)makemon.c  3.4     2004/06/12      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1001,18 +1001,28 @@ register int    mmflags;
                                 LS_MONSTER, (genericptr_t)mtmp);
        mitem = 0;      /* extra inventory item for this monster */
 
+       if (mndx == PM_VLAD_THE_IMPALER)
+               mitem = CANDELABRUM_OF_INVOCATION;
        mtmp->cham = CHAM_ORDINARY;     /* default is "not a shapechanger" */
        if ((mcham = pm_to_cham(mndx)) != CHAM_ORDINARY) {
                /* this is a shapechanger after all */
                if (Protection_from_shape_changers) {
                        ;       /* stuck in its natural form (CHAM_ORDINARY) */
                } else {
-                       /* new shapechanger starts out with random form
+                       /* General shapechangers start out with random form
                           (this explicitly picks something from the normal
                           selection for current difficulty level rather
-                          than from among shapechanger's preferred forms) */
+                          than from among shapechanger's preferred forms).
+                          Vampires are the exception. */
+                       struct permonst *tmpcham = rndmonst();
                        mtmp->cham = mcham;
-                       (void) newcham(mtmp, rndmonst(), FALSE, FALSE);
+                       if (is_vampshifter(mtmp)){
+                           int chamidx = select_newcham_form(mtmp);
+                           if (chamidx != NON_PM)
+                               tmpcham = &mons[chamidx];
+                       }
+                       if (mtmp->cham != PM_VLAD_THE_IMPALER)
+                           (void) newcham(mtmp,tmpcham,FALSE, FALSE);
                }
        } else if (mndx == PM_WIZARD_OF_YENDOR) {
                mtmp->iswiz = TRUE;
@@ -1021,8 +1031,6 @@ register int      mmflags;
                        mitem = SPE_DIG;
        } else if (mndx == PM_GHOST && !(mmflags & MM_NONAME)) {
                mtmp = christen_monst(mtmp, rndghostname());
-       } else if (mndx == PM_VLAD_THE_IMPALER) {
-               mitem = CANDELABRUM_OF_INVOCATION;
        } else if (mndx == PM_CROESUS) {
                mitem = TWO_HANDED_SWORD;
        } else if (ptr->msound == MS_NEMESIS) {
index ff0b6bc04cbcebb45f6fe672c3433a3e91ec35a3..bed5b1bc24d9b2a8b5632b07059cec98923d52b1 100644 (file)
@@ -890,7 +890,7 @@ hitmu(mtmp, mattk)
 
 /*     First determine the base damage done */
        dmg = d((int)mattk->damn, (int)mattk->damd);
-       if(is_undead(mdat) && midnight())
+       if((is_undead(mdat) || is_vampshifter(mtmp)) && midnight())
                dmg += d((int)mattk->damn, (int)mattk->damd); /* extra damage */
 
 /*     Next a cancellation factor      */
@@ -1550,7 +1550,8 @@ dopois:
            if (Half_physical_damage
                                        /* Mitre of Holiness */
                || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh) &&
-                   (is_undead(mtmp->data) || is_demon(mtmp->data))))
+                   (is_undead(mtmp->data) ||
+                       is_demon(mtmp->data) || is_vampshifter(mtmp))))
                dmg = (dmg+1) / 2;
 
            if (permdmg) {      /* Death's life force drain */
index 2355b857f66e4414c9a28bd98c88298392f43eaa..c0bbdecb97b1b38f469869c55e8ab18839fe3fb2 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -18,7 +18,6 @@ STATIC_DCL long FDECL(mm_aggression, (struct monst *,struct monst *));
 STATIC_DCL long FDECL(mm_displacement, (struct monst *,struct monst *));
 #endif
 STATIC_DCL int NDECL(pick_animal);
-STATIC_DCL int FDECL(select_newcham_form, (struct monst *));
 STATIC_DCL void FDECL(kill_eggs, (struct obj *));
 
 #ifdef REINCARNATION
@@ -530,8 +529,12 @@ mcalcdistress()
        mon_regen(mtmp, FALSE);
 
        /* possibly polymorph shapechangers and lycanthropes */
-       if (mtmp->cham && !rn2(6))
-           (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
+       if (mtmp->cham != CHAM_ORDINARY) {
+           if (is_vampshifter(mtmp) || mtmp->data->mlet == S_VAMPIRE)
+               decide_to_shapeshift(mtmp,0);
+           else if (!rn2(6))
+               (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
+       }
        were_change(mtmp);
 
        /* gradually time out temporary problems */
@@ -917,7 +920,6 @@ max_mon_load(mtmp)
 register struct monst *mtmp;
 {
        register long maxload;
-
        /* Base monster carrying capacity is equal to human maximum
         * carrying capacity, or half human maximum if not strong.
         * (for a polymorphed player, the value used would be the
@@ -956,7 +958,7 @@ struct obj *otmp;
            return FALSE;
        if (otyp == CORPSE && is_rider(&mons[otmp->corpsenm]))
            return FALSE;
-       if (objects[otyp].oc_material == SILVER && hates_silver(mdat) &&
+       if (objects[otyp].oc_material == SILVER && mon_hates_silver(mtmp) &&
                (otyp != BELL_OF_OPENING || !is_covetous(mdat)))
            return FALSE;
 
@@ -1049,7 +1051,8 @@ nexttry:  /* eels prefer the water, but if there is no water nearby,
               !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue;
            /* KMH -- Added iron bars */
            if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue;
-           if(IS_DOOR(ntyp) && !amorphous(mdat) &&
+           if(IS_DOOR(ntyp) && 
+               !(amorphous(mdat) || (!amorphous(mdat) && can_fog(mon))) &&
               ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) ||
                (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))) &&
               !thrudoor) continue;
@@ -1373,7 +1376,7 @@ struct obj *
 mlifesaver(mon)
 struct monst *mon;
 {
-       if (!nonliving(mon->data)) {
+       if (!nonliving(mon->data) || is_vampshifter(mon)) {
            struct obj *otmp = which_armor(mon, W_AMUL);
 
            if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING)
@@ -1441,6 +1444,52 @@ register struct monst *mtmp;
        lifesaved_monster(mtmp);
        if (mtmp->mhp > 0) return;
 
+       if (is_vampshifter(mtmp)) {
+               int mndx = mtmp->cham;
+               int x = mtmp->mx, y = mtmp->my;
+               /* this only happens if shapeshifted */
+               if (mndx != CHAM_ORDINARY && mndx != monsndx(mtmp->data)) {
+                       char buf[BUFSZ];
+                       boolean in_door = amorphous(mtmp->data) &&
+                                        closed_door(mtmp->mx,mtmp->my);
+                       Sprintf(buf,
+                               "The %s%s suddenly %s and rises as %%s!",
+                               (nonliving(mtmp->data) ||
+                                noncorporeal(mtmp->data) ||
+                                amorphous(mtmp->data)) ? "" : "seemingly dead ",
+                               x_monnam(mtmp, ARTICLE_NONE, (char *)0, 
+                                   SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION |
+                                   SUPPRESS_INVISIBLE | SUPPRESS_IT, FALSE),
+                               (nonliving(mtmp->data) ||
+                                noncorporeal(mtmp->data) ||
+                                amorphous(mtmp->data)) ?
+                               "reconstitutes" : "transforms");
+                       mtmp->mcanmove = 1;
+                       mtmp->mfrozen = 0;
+                       if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10;
+                       mtmp->mhp = mtmp->mhpmax;
+                       /* this can happen if previously a fog cloud */
+                       if (u.uswallow && (mtmp == u.ustuck))
+                               expels(mtmp, mtmp->data, FALSE);
+                       if (in_door) {
+                               coord new_xy;
+                               if (enexto(&new_xy,
+                                           mtmp->mx, mtmp->my, &mons[mndx])) {
+                                       rloc_to(mtmp, new_xy.x, new_xy.y);
+                               }
+                       }
+                       newcham(mtmp, &mons[mndx], FALSE, FALSE);
+                       if (mtmp->data == &mons[mndx])
+                               mtmp->cham = CHAM_ORDINARY;
+                       else
+                               mtmp->cham = mndx;
+                       if ((!Blind && canseemon(mtmp)) || sensemon(mtmp))
+                               pline(buf, a_monnam(mtmp));
+                       newsym(x,y);
+                       return;
+               }
+       }
+
 #ifdef STEED
        /* Player is thrown from his steed when it dies */
        if (mtmp == u.usteed)
@@ -2306,6 +2355,31 @@ pick_animal()
        return animal_list[rn2(animal_list_count)];
 }
 
+void
+decide_to_shapeshift(mon, shiftflags)
+struct monst *mon;
+int shiftflags;
+{
+       boolean msg = FALSE;
+
+       if ((shiftflags & SHIFT_MSG) ||
+           ((shiftflags & SHIFT_SEENMSG) && sensemon(mon))) msg = TRUE;
+
+       if (is_vampshifter(mon)) {
+           /* The vampire has to be in good health (mhp) to maintain
+            * its shifted form.
+             *
+            * If we're shifted and getting low on hp, maybe shift back.
+            * If we're not already shifted and in good health, maybe shift.
+            */
+               if ((mon->mhp <= mon->mhpmax / 6) && rn2(4))
+                       (void) newcham(mon, &mons[mon->cham], FALSE, msg);
+       } else if (mon->data->mlet == S_VAMPIRE && mon->cham == CHAM_ORDINARY
+                  && !rn2(6) && (mon->mhp > mon->mhpmax - ((mon->mhpmax / 10) + 1))) {
+                       (void) newcham(mon, (struct permonst *)0, FALSE, msg);
+       }
+}
+
 int
 select_newcham_form(mon)
 struct monst *mon;
index b580c4d832114e610e67dd292b3034999cd0d4ad..33d0bd0f75dd6460287af3a4ec9f86d1c8e573c1 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)mondata.c  3.4     2003/06/02      */
+/*     SCCS Id: @(#)mondata.c  3.4     2004/06/12      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -63,7 +63,7 @@ struct monst *mon;
        struct obj *wep = ((mon == &youmonst) ? uwep : MON_WEP(mon));
 
        return (boolean)(is_undead(ptr) || is_demon(ptr) || is_were(ptr) ||
-                        ptr == &mons[PM_DEATH] ||
+                        ptr == &mons[PM_DEATH] || is_vampshifter(mon) ||
                         (wep && wep->oartifact && defends(AD_DRLI, wep)));
 }
 
@@ -226,6 +226,13 @@ struct permonst *ptr;
        return FALSE;
 }
 
+boolean
+mon_hates_silver(mon)
+struct monst *mon;
+{
+       return (is_vampshifter(mon) || hates_silver(mon->data));
+}
+
 boolean
 hates_silver(ptr)
 register struct permonst *ptr;
index d63481acf583ecdd2fa718dadd06e430fc6299e4..10fcc72077587ff9df48c2186b76650f770bda05 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)monmove.c  3.4     2002/04/06      */
+/*     SCCS Id: @(#)monmove.c  3.4     2004/06/12      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -13,6 +13,9 @@ STATIC_DCL int FDECL(disturb,(struct monst *));
 STATIC_DCL void FDECL(distfleeck,(struct monst *,int *,int *,int *));
 STATIC_DCL int FDECL(m_arrival, (struct monst *));
 STATIC_DCL void FDECL(watch_on_duty,(struct monst *));
+STATIC_DCL boolean FDECL(stuff_prevents_passage, (struct monst *));
+STATIC_OVL int FDECL(vamp_shift, (struct monst *,struct permonst *));
+
 
 boolean /* TRUE : mtmp died */
 mb_trapped(mtmp)
@@ -936,6 +939,7 @@ not_special:
        if (can_tunnel) flag |= ALLOW_DIG;
        if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM;
        if (is_undead(ptr) && ptr->mlet != S_GHOST) flag |= NOGARLIC;
+       if (is_vampshifter(mtmp)) flag |= NOGARLIC;
        if (throws_rocks(ptr)) flag |= ALLOW_ROCK;
        if (can_open) flag |= OPENDOOR;
        if (can_unlock) flag |= UNLOCKDOOR;
@@ -1118,7 +1122,9 @@ postmov:
                    struct rm *here = &levl[mtmp->mx][mtmp->my];
                    boolean btrapped = (here->doormask & D_TRAPPED);
 
-                   if(here->doormask & (D_LOCKED|D_CLOSED) && amorphous(ptr)) {
+                   if(here->doormask & (D_LOCKED|D_CLOSED) &&
+                       (amorphous(ptr) || (!amorphous(ptr) && can_fog(mtmp) &&
+                          vamp_shift(mtmp, &mons[PM_FOG_CLOUD])))) {
                        if (flags.verbose && canseemon(mtmp))
                            pline("%s %s under the door.", Monnam(mtmp),
                                  (ptr == &mons[PM_FOG_CLOUD] ||
@@ -1346,7 +1352,8 @@ register struct monst *mtmp;
                  || ((mx != u.ux || my != u.uy) &&
                      !passes_walls(mtmp->data) &&
                      (!ACCESSIBLE(levl[mx][my].typ) ||
-                      (closed_door(mx, my) && !can_ooze(mtmp))))
+                      (closed_door(mx, my) &&
+                       !(can_ooze(mtmp) || can_fog(mtmp)))))
                  || !couldsee(mx, my));
        } else {
 found_you:
@@ -1392,21 +1399,24 @@ xchar x,y;
 }
 #endif /* BARGETHROUGH */
 
-boolean
-can_ooze(mtmp)
+/*
+ * Inventory prevents passage under door.
+ * Used by can_ooze() and can_fog().
+ */
+STATIC_OVL boolean
+stuff_prevents_passage(mtmp)
 struct monst *mtmp;
 {
        struct obj *chain, *obj;
 
-       if (!amorphous(mtmp->data)) return FALSE;
        if (mtmp == &youmonst) {
 #ifndef GOLDOBJ
-               if (u.ugold > 100L) return FALSE;
+               if (u.ugold > 100L) return TRUE;
 #endif
                chain = invent;
        } else {
 #ifndef GOLDOBJ
-               if (mtmp->mgold > 100L) return FALSE;
+               if (mtmp->mgold > 100L) return TRUE;
 #endif
                chain = mtmp->minvent;
        }
@@ -1414,7 +1424,7 @@ struct monst *mtmp;
                int typ = obj->otyp;
 
 #ifdef GOLDOBJ
-                if (typ == COIN_CLASS && obj->quan > 100L) return FALSE;
+                if (typ == COIN_CLASS && obj->quan > 100L) return TRUE;
 #endif
                if (obj->oclass != GEM_CLASS &&
                    !(typ >= ARROW && typ <= BOOMERANG) &&
@@ -1441,11 +1451,47 @@ struct monst *mtmp;
                    typ != TIN_WHISTLE && typ != MAGIC_WHISTLE &&
                    typ != MAGIC_MARKER && typ != TIN_OPENER &&
                    typ != SKELETON_KEY && typ != LOCK_PICK
-               ) return FALSE;
-               if (Is_container(obj) && obj->cobj) return FALSE;
-                   
+               ) return TRUE;
+               if (Is_container(obj) && obj->cobj) return TRUE;                    
        }
+       return FALSE;
+}
+
+boolean
+can_ooze(mtmp)
+struct monst *mtmp;
+{
+       if (!amorphous(mtmp->data) ||
+               stuff_prevents_passage(mtmp))
+               return FALSE;
        return TRUE;
 }
 
+/* monster can change form into a fog if necessary */
+boolean
+can_fog(mtmp)
+struct monst *mtmp;
+{
+       if ((is_vampshifter(mtmp) || mtmp->data->mlet == S_VAMPIRE) &&
+               !Protection_from_shape_changers && !stuff_prevents_passage(mtmp))
+               return TRUE;
+       return FALSE;
+}
+
+STATIC_OVL int
+vamp_shift(mon,ptr)
+struct monst *mon;
+struct permonst *ptr;
+{
+       int reslt = 0;
+       if (mon->cham != CHAM_ORDINARY) {
+               if (ptr == &mons[mon->cham])
+                       mon->cham = CHAM_ORDINARY;
+               reslt = newcham(mon, ptr, FALSE, FALSE);
+       } else if (mon->cham == CHAM_ORDINARY && ptr != mon->data) {
+               mon->cham = monsndx(mon->data);
+               reslt = newcham(mon, ptr, FALSE, FALSE);
+       }
+       return reslt;
+}
 /*monmove.c*/
index c7ba3353a87a69f3120cc91fd3805f3b92b8d9b1..03356569c782ad022474e1c2b811f5dca9e4592d 100644 (file)
@@ -1997,16 +1997,16 @@ struct permonst _mons2[] = {
          NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
        SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
        M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
-       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE,
-       CLR_RED),
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_SHAPESHIFTER,
+       M3_INFRAVISIBLE, CLR_RED),
     MON("vampire lord", S_VAMPIRE,
        LVL(12, 14, 0, 50, -9), (G_GENO|G_NOCORPSE|1),
        A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_DRLI, 1, 8),
          NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
        SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
        M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
-       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_LORD|M2_MALE,
-       M3_INFRAVISIBLE, CLR_BLUE),
+       M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_LORD|M2_MALE|
+         M2_SHAPESHIFTER, M3_INFRAVISIBLE, CLR_BLUE),
 #if 0  /* DEFERRED */
     MON("vampire mage", S_VAMPIRE,
        LVL(20, 14, -4, 50, -9), (G_GENO|G_NOCORPSE|1),
@@ -2015,7 +2015,7 @@ struct permonst _mons2[] = {
        SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
        M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
        M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_LORD|M2_MALE|
-       M2_MAGIC, M3_INFRAVISIBLE, HI_ZAP),
+         M2_MAGIC|M2_SHAPESHIFTER, M3_INFRAVISIBLE, HI_ZAP),
 #endif
     MON("Vlad the Impaler", S_VAMPIRE,
        LVL(14, 18, -3, 80, -10), (G_NOGEN|G_NOCORPSE|G_UNIQ),
@@ -2024,7 +2024,7 @@ struct permonst _mons2[] = {
        SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0,
        M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN,
        M2_NOPOLY|M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|
-         M2_NASTY|M2_PRINCE|M2_MALE,
+         M2_NASTY|M2_PRINCE|M2_MALE|M2_SHAPESHIFTER,
        M3_WAITFORU|M3_WANTSCAND|M3_INFRAVISIBLE, HI_LORD),
 /*
  * Wraiths
index f965df824122e6f1b005f6526a89252d03d3a4ce..3fbc6c862f72969f2d44d09679feca2c7e4a7169 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)mthrowu.c  3.4     2003/11/26      */
+/*     SCCS Id: @(#)mthrowu.c  3.4     2004/06/12      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -182,7 +182,7 @@ boolean verbose;  /* give message(s) even when you can't see what happened */
                }
            }
            if (objects[otmp->otyp].oc_material == SILVER &&
-                   hates_silver(mtmp->data)) {
+                   mon_hates_silver(mtmp)) {
                if (vis) pline_The("silver sears %s flesh!",
                                s_suffix(mon_nam(mtmp)));
                else if (verbose) pline("Its flesh is seared!");
@@ -201,7 +201,8 @@ boolean verbose;  /* give message(s) even when you can't see what happened */
            if (mtmp->mhp < 1) {
                if (vis || verbose)
                    pline("%s is %s!", Monnam(mtmp),
-                       (nonliving(mtmp->data) || !canspotmon(mtmp))
+                       (nonliving(mtmp->data) ||
+                               is_vampshifter(mtmp) || !canspotmon(mtmp))
                        ? "destroyed" : "killed");
                /* don't blame hero for unknown rolling boulder trap */
                if (!context.mon_moving &&
index 107f432fdfc2df268ab567b62f4ec0ab38931498..59072edd59df8448a33fcda8ed2c7d21310e689d 100644 (file)
@@ -1848,7 +1848,7 @@ skipmsg:
                    if (!where_to) {
                        pline_The("whip slips free.");  /* not `The_whip' */
                        return 1;
-                   } else if (where_to == 3 && hates_silver(mtmp->data) &&
+                   } else if (where_to == 3 && mon_hates_silver(mtmp) &&
                            objects[obj->otyp].oc_material == SILVER) {
                        /* this monster won't want to catch a silver
                           weapon; drop it at hero's feet instead */
@@ -1929,7 +1929,8 @@ struct monst *mtmp;
        if (difficulty < 6 && !rn2(30))
            return rn2(6) ? POT_POLYMORPH : WAN_POLYMORPH;
 
-       if (!rn2(40) && !nonliving(pm)) return AMULET_OF_LIFE_SAVING;
+       if (!rn2(40) && !nonliving(pm) && !is_vampshifter(mtmp))
+           return AMULET_OF_LIFE_SAVING;
 
        switch (rn2(3)) {
                case 0:
@@ -1997,7 +1998,7 @@ struct obj *obj;
            break;
        case AMULET_CLASS:
            if (typ == AMULET_OF_LIFE_SAVING)
-               return (boolean)(!nonliving(mon->data));
+               return (boolean)(!(nonliving(mon->data) || is_vampshifter(mon)));
            if (typ == AMULET_OF_REFLECTION)
                return TRUE;
            break;
index 948de3fdee90036c67a6f430531516582bc7365c..7c76e4da9c03be5c585bc0d10d56c476c543b8e0 100644 (file)
@@ -233,11 +233,12 @@ int psflags;
        int mntmp = NON_PM;
        int tries=0;
        boolean forcecontrol = (psflags == 1);
+       boolean monsterpoly = (psflags == 2);
        boolean draconian = (uarm &&
                                uarm->otyp >= GRAY_DRAGON_SCALE_MAIL &&
                                uarm->otyp <= YELLOW_DRAGON_SCALES);
        boolean iswere = (u.ulycn >= LOW_PM || is_were(youmonst.data));
-       boolean isvamp = (youmonst.data->mlet == S_VAMPIRE || u.umonnum == PM_VAMPIRE_BAT);
+       boolean isvamp = (youmonst.data->mlet == S_VAMPIRE);
        boolean was_floating = (Levitation || Flying);
 
         if(!Polymorph_control && !forcecontrol && !draconian && !iswere && !isvamp) {
@@ -250,7 +251,7 @@ int psflags;
        }
        old_light = Upolyd ? emits_light(youmonst.data) : 0;
 
-       if (Polymorph_control || forcecontrol) {
+       if ((Polymorph_control || forcecontrol) && !monsterpoly) {
                do {
                        getlin("Become what kind of monster? [type the name]",
                                buf);
@@ -288,10 +289,21 @@ int psflags;
                        else
                                mntmp = u.ulycn;
                } else {
-                       if (youmonst.data->mlet == S_VAMPIRE)
-                               mntmp = PM_VAMPIRE_BAT;
-                       else
-                               mntmp = PM_VAMPIRE;
+                       if (youmonst.data->mlet == S_VAMPIRE) {
+                               mntmp = (youmonst.data != &mons[PM_VAMPIRE] &&
+                                        !rn2(10)) ? PM_WOLF :
+                                       !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT;
+                               if (Polymorph_control) {
+                                       char buf[BUFSZ];
+                                       Sprintf(buf, "Become %s?",
+                                               an(mons[mntmp].mname));
+                                       if (yn(buf) != 'y') return;
+                               }
+                               if (Unchanging) {
+                                       pline("You fail to transform!");
+                                       return;
+                               }
+                       }
                }
                /* if polymon fails, "you feel" message has been given
                   so don't follow up with another polymon or newman */
@@ -1077,6 +1089,21 @@ dohide()
        return(1);
 }
 
+int
+dopoly()
+{
+       boolean isvampire = youmonst.data->mlet == S_VAMPIRE;
+       struct permonst *savedat = youmonst.data;
+       if (isvampire) {
+               polyself(2);
+               if (savedat != youmonst.data) {
+                       You("transform into %s.", an(youmonst.data->mname));
+                       newsym(u.ux,u.uy);
+               }
+       }
+       return(1);
+}
+
 int
 domindblast()
 {
index 79b1ba73c96fe7e88599e7750612b35c6ddda933..e08605f2cc29149d8194106217b7e570f3231b8c 100644 (file)
@@ -1211,7 +1211,7 @@ boolean your_fault;
                break;
        case POT_WATER:
                if (is_undead(mon->data) || is_demon(mon->data) ||
-                       is_were(mon->data)) {
+                       is_were(mon->data) || is_vampshifter(mon)) {
                    if (obj->blessed) {
                        pline("%s %s in pain!", Monnam(mon),
                              is_silent(mon->data) ? "writhes" : "shrieks");
index d1d9c90527e9bf59ecdc4407d76e4225329c935a..b5fd74e8e49ec2e99027c5cd1f88e78671e264fc 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)pray.c     3.4     2003/10/26      */
+/*     SCCS Id: @(#)pray.c     3.4     2004/06/12      */
 /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1697,6 +1697,7 @@ doturn()
                distu(mtmp->mx,mtmp->my) > range) continue;
 
            if (!mtmp->mpeaceful && (is_undead(mtmp->data) ||
+                  is_vampshifter(mtmp) ||
                   (is_demon(mtmp->data) && (u.ulevel > (MAXULEV/2))))) {
 
                    mtmp->msleeping = 0;
index ddbbcf48dbf7d2500557e8e7ead09df3670b24fe..302a4599bdd945909ca6a597605c3e9040e9318c 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)region.c   3.4     2002/10/15      */
+/*     SCCS Id: @(#)region.c   3.4     2004/06/12      */
 /* Copyright (c) 1996 by Jean-Christophe Collet         */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -922,7 +922,8 @@ genericptr_t p2;
        mtmp = (struct monst *) p2;
 
        /* Non living and non breathing monsters are not concerned */
-       if (!nonliving(mtmp->data) && !breathless(mtmp->data)) {
+       if (!(nonliving(mtmp->data) || is_vampshifter(mtmp))
+                        && !breathless(mtmp->data)) {
            if (cansee(mtmp->mx, mtmp->my))
                pline("%s coughs!", Monnam(mtmp));
            if (heros_fault(reg)) setmangry(mtmp);
index 8ae8db5506351c0bc29096ca61a4eba6ffa5ad75..bb0095c3623672e82a74c0c9f8a3fd10a69b711c 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)sounds.c   3.4     2002/05/06      */
+/*     SCCS Id: @(#)sounds.c   3.4     2004/06/12      */
 /*     Copyright (c) 1989 Janet Walz, Mike Threepoint */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -157,7 +157,7 @@ dosounds()
     if (level.flags.has_morgue && !rn2(200)) {
        for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
            if (DEADMONSTER(mtmp)) continue;
-           if (is_undead(mtmp->data) &&
+           if ((is_undead(mtmp->data) || is_vampshifter(mtmp)) &&
                mon_in_room(mtmp, MORGUE)) {
                switch (rn2(2)+hallu) {
                    case 0:
index 5828b8532a4fb1e230c12836aa8bb9c2869e80ad..6900addaec55675894dc515a58e895b817fa0832 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)spell.c    3.4     2003/01/17      */
+/*     SCCS Id: @(#)spell.c    3.4     2004/06/12      */
 /*     Copyright (c) M. Stephenson 1988                          */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -284,7 +284,8 @@ raise_dead:
            mtmp2 = mtmp->nmon;         /* tamedog() changes chain */
            if (DEADMONSTER(mtmp)) continue;
 
-           if (is_undead(mtmp->data) && cansee(mtmp->mx, mtmp->my)) {
+           if ((is_undead(mtmp->data) || is_vampshifter(mtmp)) &&
+                       cansee(mtmp->mx, mtmp->my)) {
                mtmp->mpeaceful = TRUE;
                if(sgn(mtmp->data->maligntyp) == sgn(u.ualign.type)
                   && distu(mtmp->mx, mtmp->my) < 4)
index 689420f15b2a9801dd87e5484e2ad3161514327a..63c3d4cc35e8639f4e30edae8daeb57fe59113a4 100644 (file)
@@ -472,7 +472,8 @@ int *fail_reason;
        else mon->mundetected = FALSE;
 
        if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) {
-           const char *comes_to_life = nonliving(mon->data) ?
+           const char *comes_to_life = (nonliving(mon->data) ||
+                                        is_vampshifter(mon)) ?
                                        "moves" : "comes to life"; 
            if (cause == ANIMATE_SPELL)
                pline("%s %s!", upstart(statuename),
index 8db83f292e888c38e2c0e130a15c79cb4418328e..d1a7f4d31f4788d4af5ff9201fe14ff4197c0fd5 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)uhitm.c    3.4     2003/03/14      */
+/*     SCCS Id: @(#)uhitm.c    3.4     2004/06/12      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -570,7 +570,8 @@ int thrown;
                tmp = rnd(2);
            valid_weapon_attack = (tmp > 1);
            /* blessed gloves give bonuses when fighting 'bare-handed' */
-           if (uarmg && uarmg->blessed && (is_undead(mdat) || is_demon(mdat)))
+           if (uarmg && uarmg->blessed &&
+                   (is_undead(mdat) || is_demon(mdat) || is_vampshifter(mon)))
                tmp += rnd(4);
            /* So do silver rings.  Note: rings are worn under gloves, so you
             * don't get both bonuses.
@@ -580,7 +581,7 @@ int thrown;
                    barehand_silver_rings++;
                if (uright && objects[uright->otyp].oc_material == SILVER)
                    barehand_silver_rings++;
-               if (barehand_silver_rings && hates_silver(mdat)) {
+               if (barehand_silver_rings && mon_hates_silver(mon)) {
                    tmp += rnd(20);
                    silvermsg = TRUE;
                }
@@ -609,7 +610,7 @@ int thrown;
                    else
                        tmp = rnd(2);
                    if (objects[obj->otyp].oc_material == SILVER
-                               && hates_silver(mdat)) {
+                               && mon_hates_silver(mon)) {
                        silvermsg = TRUE; silverobj = TRUE;
                        /* if it will already inflict dmg, make it worse */
                        tmp += rnd((tmp) ? 20 : 10);
@@ -676,7 +677,7 @@ int thrown;
                        hittxt = TRUE;
                    }
                    if (objects[obj->otyp].oc_material == SILVER
-                               && hates_silver(mdat)) {
+                               && mon_hates_silver(mon)) {
                        silvermsg = TRUE; silverobj = TRUE;
                    }
 #ifdef STEED
@@ -833,7 +834,7 @@ int thrown;
 #undef useup_eggs
                      }
                    case CLOVE_OF_GARLIC:       /* no effect against demons */
-                       if (is_undead(mdat)) {
+                       if (is_undead(mdat) || is_vampshifter(mon)) {
                            monflee(mon, d(2, 4), FALSE, TRUE);
                        }
                        tmp = 1;
@@ -905,7 +906,7 @@ int thrown;
                         * so we need another silver check.
                         */
                        if (objects[obj->otyp].oc_material == SILVER
-                                               && hates_silver(mdat)) {
+                                               && mon_hates_silver(mon)) {
                                tmp += rnd(20);
                                silvermsg = TRUE; silverobj = TRUE;
                        }
@@ -1067,7 +1068,7 @@ int thrown;
                    fmt = "%s is seared!";
                }
                /* note: s_suffix returns a modifiable buffer */
-               if (!noncorporeal(mdat))
+               if (!noncorporeal(mdat) && !amorphous(mdat))
                    whom = strcat(s_suffix(whom), " flesh");
                pline(fmt, whom);
        }
index e986d70870cc86ecb84534a6529ed8cddd561e73..9275fb38a139f9670e5ff849317775adb0c64ba2 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)weapon.c   3.4     2002/11/07      */
+/*     SCCS Id: @(#)weapon.c   3.4     2004/06/12      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -124,7 +124,7 @@ struct monst *mon;
 
        /* Blessed weapons used against undead or demons */
        if (Is_weapon && otmp->blessed &&
-          (is_demon(ptr) || is_undead(ptr))) tmp += 2;
+          (is_demon(ptr) || is_undead(ptr) || is_vampshifter(mon))) tmp += 2;
 
        if (is_spear(otmp) &&
           index(kebabable, ptr->mlet)) tmp += 2;
@@ -270,11 +270,12 @@ struct monst *mon;
                otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) {
            int bonus = 0;
 
-           if (otmp->blessed && (is_undead(ptr) || is_demon(ptr)))
+           if (otmp->blessed &&
+               (is_undead(ptr) || is_demon(ptr) || is_vampshifter(mon)))
                bonus += rnd(4);
            if (is_axe(otmp) && is_wooden(ptr))
                bonus += rnd(4);
-           if (objects[otyp].oc_material == SILVER && hates_silver(ptr))
+           if (objects[otyp].oc_material == SILVER && mon_hates_silver(mon))
                bonus += rnd(20);
 
            /* if the weapon is going to get a double damage bonus, adjust
@@ -370,7 +371,7 @@ register struct monst *mtmp;
                if (((strongmonst(mtmp->data) && (mtmp->misc_worn_check & W_ARMS) == 0)
                        || !objects[pwep[i]].oc_bimanual) &&
                    (objects[pwep[i]].oc_material != SILVER
-                       || !hates_silver(mtmp->data))) {
+                       || !mon_hates_silver(mtmp))) {
                    if ((otmp = oselect(mtmp, pwep[i])) != 0) {
                        propellor = otmp; /* force the monster to wield it */
                        return otmp;
@@ -492,7 +493,7 @@ register struct monst *mtmp;
            if (((strong && !wearing_shield)
                        || !objects[hwep[i]].oc_bimanual) &&
                    (objects[hwep[i]].oc_material != SILVER
-                       || !hates_silver(mtmp->data)))
+                       || !mon_hates_silver(mtmp)))
                Oselect(hwep[i]);
        }
 
index 7610ec10134e7e3d2e0d9977661ab08e78dd124f..41f2f730542bedf087b8d0d92e1196c0992b17b3 100644 (file)
--- a/src/zap.c
+++ b/src/zap.c
@@ -153,7 +153,7 @@ struct obj *otmp;
        case SPE_TURN_UNDEAD:
                wake = FALSE;
                if (unturn_dead(mtmp)) wake = TRUE;
-               if (is_undead(mtmp->data)) {
+               if (is_undead(mtmp->data) || is_vampshifter(mtmp)) {
                        reveal_invis = TRUE;
                        wake = TRUE;
                        dmg = rnd(8);
@@ -3034,7 +3034,8 @@ struct obj **ootmp;       /* to return worn armor for caller to disintegrate */
                        break;
                    }
                    if (nonliving(mon->data) || is_demon(mon->data) ||
-                           resists_magm(mon)) {        /* similar to player */
+                           is_vampshifter(mon) || resists_magm(mon)) {
+                       /* similar to player */
                        sho_shieldeff = TRUE;
                        break;
                    }