From: nethack.rankin Date: Sat, 22 May 2004 03:24:23 +0000 (+0000) Subject: shapechanger hit points (trunk only) X-Git-Tag: MOVE2GIT~1469 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9620eefd50e877f6633062fd3ebf07d354e2ff97;p=nethack 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). --- 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);