]> granicus.if.org Git - nethack/commitdiff
shapechanger hit points (trunk only)
authornethack.rankin <nethack.rankin>
Sat, 22 May 2004 03:24:23 +0000 (03:24 +0000)
committernethack.rankin <nethack.rankin>
Sat, 22 May 2004 03:24:23 +0000 (03:24 +0000)
     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).

doc/fixes35.0
include/extern.h
src/makemon.c
src/mon.c

index 6b6667cdd5fbee6532a1524953205deeb7a2ecba..3ee77e4a0568d45d348ae2280f70dd7011d2056a 100644 (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
index 0f4746482d53aaa678c7eb2f82008f8e8720fbbd..2639e73a360f9a9e1087efc08d24068ee99b3b43 100644 (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);
index 6a94826e8eced9d2784ad8c91497f0abe66231df..2a7de4253e25b04ecc2f3d68048f7f8828366679 100644 (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;
index 6312e612268a6268e722fc7682d00c0ddd1f060e..cf958b598188c641d61720fe94b6a67508952eb2 100644 (file)
--- 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);