shapechanger hit points (trunk only)

Try to fix the report of a doppelganger (created from using stone-
to-flesh on a fake statue of Demogorgon) having 1700 hit points after
reverting to its native form.  The problem was due to the special monster
level of Demogorgon rather than anything to do with shape changers; the
actual bug was use of `mdat->mlevel' where it should have been using
`mtmp->data->mlevel'.  But the whole section of code was rather suspect
since it didn't attempt to handle other types of monsters (dragons, golems,
elementals) which have non-standard hit points, so I knocked some out.
Monsters who have gained or lost levels prior to changing form will no
longer carry that adjustment along; the new form will always be a brand
new one of its type.  However, if the old form is injured at the time of
change, the new form will be too (same as before).
This commit is contained in:
nethack.rankin
2004-05-22 03:24:23 +00:00
parent 1fbd886068
commit 9620eefd50
4 changed files with 54 additions and 47 deletions

View File

@@ -68,6 +68,7 @@ when blind and levitating > shouldn't say "stairs" if player has not seen them
a slow-moving monster hidden under a rotting corpse was not immediately
displayed when the corpse rotted away
mimic that ends up on the rogue level should not mimic a closed door
polymorphed or shapechanged monster sometimes got erroneous hit points
Platform- and/or Interface-Specific Fixes

View File

@@ -955,6 +955,7 @@ E void FDECL(readmail, (struct obj *));
E boolean FDECL(is_home_elemental, (struct permonst *));
E struct monst *FDECL(clone_mon, (struct monst *,XCHAR_P,XCHAR_P));
E void FDECL(newmonhp, (struct monst *,int));
E struct monst *FDECL(makemon, (struct permonst *,int,int,int));
E boolean FDECL(create_critters, (int,struct permonst *));
E struct permonst *NDECL(rndmonst);

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)makemon.c 3.4 2003/11/30 */
/* SCCS Id: @(#)makemon.c 3.4 2004/05/21 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -802,6 +802,41 @@ boolean ghostly;
return result;
}
/* set up a new monster's initial level and hit points;
used by newcham() as well as by makemon() */
void
newmonhp(mon, mndx)
struct monst *mon;
int mndx;
{
struct permonst *ptr = &mons[mndx];
mon->m_lev = adj_lev(ptr);
if (is_golem(ptr)) {
mon->mhpmax = mon->mhp = golemhp(mndx);
} else if (is_rider(ptr)) {
/* we want low HP, but a high mlevel so they can attack well */
mon->mhpmax = mon->mhp = d(10,8);
} else if (ptr->mlevel > 49) {
/* "special" fixed hp monster
* the hit points are encoded in the mlevel in a somewhat strange
* way to fit in the 50..127 positive range of a signed character
* above the 1..49 that indicate "normal" monster levels */
mon->mhpmax = mon->mhp = 2 * (ptr->mlevel - 6);
mon->m_lev = mon->mhp / 4; /* approximation */
} else if (ptr->mlet == S_DRAGON && mndx >= PM_GRAY_DRAGON) {
/* adult dragons */
mon->mhpmax = mon->mhp = (int) (In_endgame(&u.uz) ?
(8 * mon->m_lev) : (4 * mon->m_lev + d((int)mon->m_lev, 4)));
} else if (!mon->m_lev) {
mon->mhpmax = mon->mhp = rnd(4);
} else {
mon->mhpmax = mon->mhp = d((int)mon->m_lev, 8);
if (is_home_elemental(ptr))
mon->mhpmax = (mon->mhp *= 3);
}
}
/*
* called with [x,y] = coordinates;
* [0,0] means anyplace
@@ -904,30 +939,8 @@ register int mmflags;
mtmp->mxlth = xlth;
mtmp->mnum = mndx;
mtmp->m_lev = adj_lev(ptr);
if (is_golem(ptr)) {
mtmp->mhpmax = mtmp->mhp = golemhp(mndx);
} else if (is_rider(ptr)) {
/* We want low HP, but a high mlevel so they can attack well */
mtmp->mhpmax = mtmp->mhp = d(10,8);
} else if (ptr->mlevel > 49) {
/* "special" fixed hp monster
* the hit points are encoded in the mlevel in a somewhat strange
* way to fit in the 50..127 positive range of a signed character
* above the 1..49 that indicate "normal" monster levels */
mtmp->mhpmax = mtmp->mhp = 2*(ptr->mlevel - 6);
mtmp->m_lev = mtmp->mhp / 4; /* approximation */
} else if (ptr->mlet == S_DRAGON && mndx >= PM_GRAY_DRAGON) {
/* adult dragons */
mtmp->mhpmax = mtmp->mhp = (int) (In_endgame(&u.uz) ?
(8 * mtmp->m_lev) : (4 * mtmp->m_lev + d((int)mtmp->m_lev, 4)));
} else if (!mtmp->m_lev) {
mtmp->mhpmax = mtmp->mhp = rnd(4);
} else {
mtmp->mhpmax = mtmp->mhp = d((int)mtmp->m_lev, 8);
if (is_home_elemental(ptr))
mtmp->mhpmax = (mtmp->mhp *= 3);
}
/* set up level and hit points */
newmonhp(mtmp, mndx);
if (is_female(ptr)) mtmp->female = TRUE;
else if (is_male(ptr)) mtmp->female = FALSE;

View File

@@ -1,4 +1,4 @@
/* SCCS Id: @(#)mon.c 3.4 2003/12/04 */
/* SCCS Id: @(#)mon.c 3.4 2004/05/21 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -2372,7 +2372,7 @@ struct permonst *mdat;
boolean polyspot; /* change is the result of wand or spell of polymorph */
boolean msg; /* "The oldmon turns into a newmon!" */
{
int mhp, hpn, hpd;
int hpn, hpd;
int mndx, tryct;
struct permonst *olddata = mtmp->data;
char oldname[BUFSZ], newname[BUFSZ];
@@ -2432,32 +2432,24 @@ boolean msg; /* "The oldmon turns into a newmon!" */
place_monster(mtmp, mtmp->mx, mtmp->my);
}
/* (this code used to try to adjust the monster's health based on
a normal one of its type but there are too many special cases
which need to handled in order to do that correctly, so just
give the new form the same proportion of HP as its old one had) */
hpn = mtmp->mhp;
hpd = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel;
if(!hpd) hpd = 4;
mtmp->m_lev = adj_lev(mdat); /* new monster level */
mhp = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel;
if(!mhp) mhp = 4;
hpd = mtmp->mhpmax;
/* set level and hit points */
newmonhp(mtmp, monsndx(mdat));
/* new hp: same fraction of max as before */
#ifndef LINT
mtmp->mhp = (int)(((long)hpn*(long)mhp)/(long)hpd);
mtmp->mhp = (int)(((long)hpn * (long)mtmp->mhp) / (long)hpd);
#endif
if(mtmp->mhp < 0) mtmp->mhp = hpn; /* overflow */
/* Unlikely but not impossible; a 1HD creature with 1HP that changes into a
0HD creature will require this statement */
/* sanity check (potentional overflow) */
if (mtmp->mhp < 0 || mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
/* unlikely but not impossible; a 1HD creature with 1HP that changes
into a 0HD creature will require this statement */
if (!mtmp->mhp) mtmp->mhp = 1;
/* and the same for maximum hit points */
hpn = mtmp->mhpmax;
#ifndef LINT
mtmp->mhpmax = (int)(((long)hpn*(long)mhp)/(long)hpd);
#endif
if(mtmp->mhpmax < 0) mtmp->mhpmax = hpn; /* overflow */
if (!mtmp->mhpmax) mtmp->mhpmax = 1;
/* take on the new form... */
set_mon_data(mtmp, mdat, 0);