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
+4
View 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
+4
View 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));
+4
View 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)
+3 -1
View 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 */
+1 -1
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 &&
+2 -1
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;
+3 -3
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))
+3 -3
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) {
+2 -2
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:
+14 -6
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) {
+3 -2
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 */
+81 -7
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;
+9 -2
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;
+58 -12
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*/
+6 -6
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
+4 -3
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 &&
+4 -3
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;
+33 -6
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()
{
+1 -1
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");
+2 -1
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;
+3 -2
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);
+2 -2
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:
+3 -2
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)
+2 -1
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),
+9 -8
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);
}
+7 -6
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]);
}
+3 -2
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;
}