vampires now shapeshift [trunk only]

- 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
This commit is contained in:
nethack.allison
2004-06-15 11:52:04 +00:00
parent c8ef9338f0
commit 9b3521e503
27 changed files with 270 additions and 83 deletions

View 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 &&

View File

@@ -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;

View File

@@ -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))

View 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) {

View 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:

View 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) {

View 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 */

View File

@@ -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;

View 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;

View 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*/

View 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

View 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 &&

View 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;

View 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()
{

View 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");

View 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;

View 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);

View 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:

View 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)

View 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),

View 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);
}

View 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]);
}

View File

@@ -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;
}