diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 6b6667cdd..3ee77e4a0 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/include/extern.h b/include/extern.h index 0f4746482..2639e73a3 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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); diff --git a/src/makemon.c b/src/makemon.c index 6a94826e8..2a7de4253 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -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; diff --git a/src/mon.c b/src/mon.c index 6312e6122..cf958b598 100644 --- a/src/mon.c +++ b/src/mon.c @@ -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);