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
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 ### */
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 *));
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));
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));
#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)
#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 */
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 &&
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;
-/* 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. */
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);
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))
-/* 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. */
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) {
-/* 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. */
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:
-/* 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. */
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;
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) {
/* 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 */
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 */
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
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 */
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
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;
!((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;
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)
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)
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;
-/* 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. */
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)));
}
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;
-/* 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. */
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)
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;
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] ||
|| ((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:
}
#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;
}
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) &&
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*/
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),
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),
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
-/* 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. */
}
}
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!");
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 &&
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 */
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:
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;
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) {
}
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);
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 */
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()
{
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");
-/* 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. */
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;
-/* 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. */
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);
-/* 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. */
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:
-/* 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. */
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)
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),
-/* 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. */
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.
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;
}
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);
hittxt = TRUE;
}
if (objects[obj->otyp].oc_material == SILVER
- && hates_silver(mdat)) {
+ && mon_hates_silver(mon)) {
silvermsg = TRUE; silverobj = TRUE;
}
#ifdef STEED
#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;
* 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;
}
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);
}
-/* 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. */
/* 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;
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
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;
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]);
}
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);
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;
}