]> granicus.if.org Git - nethack/commitdiff
HP and Pw multiplication (trunk only)
authornethack.rankin <nethack.rankin>
Wed, 21 Sep 2005 05:31:42 +0000 (05:31 +0000)
committernethack.rankin <nethack.rankin>
Wed, 21 Sep 2005 05:31:42 +0000 (05:31 +0000)
     Fix the problem pointed out by <email deleted>
where polymorphing into a new man at level 1 could be used to approximately
double or triple your hit points and spell power.  With means to drain
level back down to 1 and with amulets of life saving to survive those times
you lose levels instead of gain, you could do this repeatedly and end up
with HP and Pw values in the millions.

     This uses the earlier patch that records the HP and Pw increments from
level gains.  Now when polymorphing into a new man, level based HP and Pw
are removed from the current values, remainder get multiplied by 80%, 90%,
100%, or 110% (average 95%, so tend to drop slightly), then a brand new set
of level gain increments (reflecting new man's Con and Wis) are added in.

     Code for calculating spell energy is moved from pluslvl() and u_init()
into new routine newpw().  It and newhp() take over responsibility for
remembering the level based increments from pluslvl() which didn't deal
with the initial amount (stored in slot [0]; earlier patch didn't need it).

doc/fixes35.0
include/extern.h
src/attrib.c
src/exper.c
src/polyself.c
src/u_init.c

index 7441ef10e69dd989b2940ab01f3d165d293406aa..dcc66ec72f342d893ca8d603450525735680d65f 100644 (file)
@@ -85,6 +85,7 @@ various actions--such as enchanting--performed on an unpaid shop object
        increase the current bill (when its value is raised)
 adjust health threshold where wounded hero will be healed by successful prayer
 prevent lose-level+regain-level cycle from arbritrarily boosting HP and Pw
+prevent polymorphing into "new man" at low level from magnifying HP and Pw
 
 
 Platform- and/or Interface-Specific Fixes
index 6623fdf608131b6b8f965dc5bd8fa7109aaedc5e..1584fea30fe8393ef7d202c10a453350b56cfbe4 100644 (file)
@@ -620,6 +620,7 @@ E void FDECL(make_grave, (int,int,const char *));
 
 /* ### exper.c ### */
 
+E int NDECL(newpw);
 E int FDECL(experience, (struct monst *,int));
 E void FDECL(more_experienced, (int,int));
 E void FDECL(losexp, (const char *));
index 539511ea063e21d7242a9b34d28f1a189308929a..283c08315de9d638edb4dd72a011409778f51149 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)attrib.c   3.5     2003/11/26      */
+/*     SCCS Id: @(#)attrib.c   3.5     2005/09/19      */
 /*     Copyright 1988, 1989, 1990, 1992, M. Stephenson           */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -789,40 +789,39 @@ newhp()
 {
        int     hp, conplus;
 
-
        if (u.ulevel == 0) {
            /* Initialize hit points */
            hp = urole.hpadv.infix + urace.hpadv.infix;
            if (urole.hpadv.inrnd > 0) hp += rnd(urole.hpadv.inrnd);
            if (urace.hpadv.inrnd > 0) hp += rnd(urace.hpadv.inrnd);
-
-           /* Initialize alignment stuff */
-           u.ualign.type = aligns[flags.initalign].value;
-           u.ualign.record = urole.initrecord;
-
-               return hp;
+           if (moves <= 1L) { /* initial hero; skip for polyself to new man */
+               /* Initialize alignment stuff */
+               u.ualign.type = aligns[flags.initalign].value;
+               u.ualign.record = urole.initrecord;
+           }
+           /* no Con adjustment for initial hit points */
        } else {
            if (u.ulevel < urole.xlev) {
-               hp = urole.hpadv.lofix + urace.hpadv.lofix;
-               if (urole.hpadv.lornd > 0) hp += rnd(urole.hpadv.lornd);
-               if (urace.hpadv.lornd > 0) hp += rnd(urace.hpadv.lornd);
+               hp = urole.hpadv.lofix + urace.hpadv.lofix;
+               if (urole.hpadv.lornd > 0) hp += rnd(urole.hpadv.lornd);
+               if (urace.hpadv.lornd > 0) hp += rnd(urace.hpadv.lornd);
            } else {
-               hp = urole.hpadv.hifix + urace.hpadv.hifix;
-               if (urole.hpadv.hirnd > 0) hp += rnd(urole.hpadv.hirnd);
-               if (urace.hpadv.hirnd > 0) hp += rnd(urace.hpadv.hirnd);
+               hp = urole.hpadv.hifix + urace.hpadv.hifix;
+               if (urole.hpadv.hirnd > 0) hp += rnd(urole.hpadv.hirnd);
+               if (urace.hpadv.hirnd > 0) hp += rnd(urace.hpadv.hirnd);
            }
+           if (ACURR(A_CON) <= 3) conplus = -2;
+           else if (ACURR(A_CON) <= 6) conplus = -1;
+           else if (ACURR(A_CON) <= 14) conplus = 0;
+           else if (ACURR(A_CON) <= 16) conplus = 1;
+           else if (ACURR(A_CON) == 17) conplus = 2;
+           else if (ACURR(A_CON) == 18) conplus = 3;
+           else conplus = 4;
+           hp += conplus;
        }
-
-       if (ACURR(A_CON) <= 3) conplus = -2;
-       else if (ACURR(A_CON) <= 6) conplus = -1;
-       else if (ACURR(A_CON) <= 14) conplus = 0;
-       else if (ACURR(A_CON) <= 16) conplus = 1;
-       else if (ACURR(A_CON) == 17) conplus = 2;
-       else if (ACURR(A_CON) == 18) conplus = 3;
-       else conplus = 4;
-       
-       hp += conplus;
-       return((hp <= 0) ? 1 : hp);
+       if (hp <= 0) hp = 1;
+       if (u.ulevel < MAXULEV) u.uhpinc[u.ulevel] = (xchar)hp;
+       return hp;
 }
 
 schar
index 9c5de9b57de720b5ddd0591a9563557568115212..ec276c4da35baeb7cf9a8d2a7428ec747baeffd1 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)exper.c    3.5     2005/09/12      */
+/*     SCCS Id: @(#)exper.c    3.5     2005/09/19      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -36,6 +36,32 @@ int en;
        }
 }
 
+/* calculate spell power/energy points for new level */
+int
+newpw()
+{
+    int en = 0, enrnd, enfix;
+
+    if (u.ulevel == 0) {
+       en = urole.enadv.infix + urace.enadv.infix;
+       if (urole.enadv.inrnd > 0) en += rnd(urole.enadv.inrnd);
+       if (urace.enadv.inrnd > 0) en += rnd(urace.enadv.inrnd);
+    } else {
+       enrnd = (int)ACURR(A_WIS) / 2;
+       if (u.ulevel < urole.xlev) {
+           enrnd += urole.enadv.lornd + urace.enadv.lornd;
+           enfix = urole.enadv.lofix + urace.enadv.lofix;
+       } else {
+           enrnd += urole.enadv.hirnd + urace.enadv.hirnd;
+           enfix = urole.enadv.hifix + urace.enadv.hifix;
+       }
+       en = enermod(rn1(enrnd, enfix));
+    }
+    if (en <= 0) en = 1;
+    if (u.ulevel < MAXULEV) u.ueninc[u.ulevel] = (xchar)en;
+    return en;
+}
+
 int
 experience(mtmp, nk)   /* return # of exp points for mtmp after nk killed */
        register struct monst *mtmp;
@@ -184,7 +210,7 @@ void
 pluslvl(incr)
 boolean incr;  /* true iff via incremental experience growth */
 {              /*      (false for potion of gain level)      */
-       int hpinc, eninc, enrnd, enfix;
+       int hpinc, eninc;
 
        if (!incr) You_feel("more experienced.");
 
@@ -200,23 +226,12 @@ boolean incr;     /* true iff via incremental experience growth */
        u.uhp += hpinc;
 
        /* increase spell power/energy points */
-       enrnd = (int)ACURR(A_WIS) / 2;
-       if (u.ulevel < urole.xlev) {
-           enrnd += urole.enadv.lornd + urace.enadv.lornd;
-           enfix = urole.enadv.lofix + urace.enadv.lofix;
-       } else {
-           enrnd += urole.enadv.hirnd + urace.enadv.hirnd;
-           enfix = urole.enadv.hifix + urace.enadv.hifix;
-       }
-       eninc = enermod(rn1(enrnd, enfix));     /* M. Stephenson */
+       eninc = newpw();
        u.uenmax += eninc;
        u.uen += eninc;
 
        /* increase level (unless already maxxed) */
        if (u.ulevel < MAXULEV) {
-           /* remember hp and pw/en gains in case this level is later lost */
-           u.uhpinc[u.ulevel] = (xchar) hpinc;
-           u.ueninc[u.ulevel] = (xchar) eninc;
            /* increase experience points to reflect new level */
            if (incr) {
                long tmp = newuexp(u.ulevel + 1);
index 6787f43d86c2cec49b2cd85fbf1b74711c31919c..3dada624e49dd5a613a9edbb7f35770ee41090b2 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)polyself.c 3.5     2005/06/21      */
+/*     SCCS Id: @(#)polyself.c 3.5     2005/09/19      */
 /*     Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -136,24 +136,23 @@ change_sex()
 STATIC_OVL void
 newman()
 {
-       int tmp, oldlvl;
+       int i, oldlvl, newlvl, hpmax, enmax;
 
-       tmp = u.uhpmax;
        oldlvl = u.ulevel;
-       u.ulevel = u.ulevel + rn1(5, -2);
-       if (u.ulevel > 127 || u.ulevel < 1) { /* level went below 0? */
-           u.ulevel = oldlvl; /* restore old level in case they lifesave */
-           goto dead;
+       newlvl = oldlvl + rn1(5, -2);   /* new = old + {-2,-1,0,+1,+2} */
+       if (newlvl > 127 || newlvl < 1) { /* level went below 0? */
+           goto dead;  /* old level is still intact (in case of lifesaving) */
        }
-       if (u.ulevel > MAXULEV) u.ulevel = MAXULEV;
+       if (newlvl > MAXULEV) newlvl = MAXULEV;
        /* If your level goes down, your peak level goes down by
           the same amount so that you can't simply use blessed
           full healing to undo the decrease.  But if your level
           goes up, your peak level does *not* undergo the same
           adjustment; you might end up losing out on the chance
           to regain some levels previously lost to other causes. */
-       if (u.ulevel < oldlvl) u.ulevelmax -= (oldlvl - u.ulevel);
-       if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
+       if (newlvl < oldlvl) u.ulevelmax -= (oldlvl - newlvl);
+       if (u.ulevelmax < newlvl) u.ulevelmax = newlvl;
+       u.ulevel = newlvl;
 
        if (!rn2(10)) change_sex();
 
@@ -163,41 +162,49 @@ newman()
        /* random experience points for the new experience level */
        u.uexp = rndexp(FALSE);
 
-       /* u.uhpmax * u.ulevel / oldlvl: proportionate hit points to new level
-        * -10 and +10: don't apply proportionate HP to 10 of a starting
-        *   character's hit points (since a starting character's hit points
-        *   are not on the same scale with hit points obtained through level
-        *   gain)
-        * 9 - rn2(19): random change of -9 to +9 hit points
-        */
-#ifndef LINT
-       u.uhpmax = ((u.uhpmax - 10) * (long)u.ulevel / oldlvl + 10) +
-               (9 - rn2(19));
-#endif
-
-#ifdef LINT
-       u.uhp = u.uhp + tmp;
-#else
-       u.uhp = u.uhp * (long)u.uhpmax/tmp;
-#endif
+       /* set up new attribute points (particularly Con) */
+       redist_attr();
 
-       tmp = u.uenmax;
-#ifndef LINT
-       u.uenmax = u.uenmax * (long)u.ulevel / oldlvl + 9 - rn2(19);
-#endif
-       if (u.uenmax < 0) u.uenmax = 0;
-#ifndef LINT
-       u.uen = (tmp ? u.uen * (long)u.uenmax / tmp : u.uenmax);
-#endif
+       /*
+        * New hit points:
+        *      remove level-gain based HP from any extra HP accumulated
+        *      (the "extra" might actually be negative);
+        *      modify the extra, retaining {80%, 90%, 100%, or 110%};
+        *      add in newly generated set of level-gain HP.
+        * (This used to calculate new HP in direct proportion to old HP,
+        * but that was subject to abuse:  accumulate a large amount of
+        * extra HP, drain level down to 1, then polyself to level 2 or 3
+        * [lifesaving capability needed to handle level 0 and -1 cases]
+        * and the extra got multiplied by 2 or 3.  Repeat the level
+        * drain and polyself steps until out of lifesaving capability.)
+        */
+       hpmax = u.uhpmax;
+       for (i = 0; i < oldlvl; i++) hpmax -= (int)u.uhpinc[i];
+       /* hpmax * rn1(4,8) / 10; 0.95*hpmax on average */
+       hpmax = rounddiv((long)hpmax * (long)rn1(4, 8), 10);
+       for (i = 0; (u.ulevel = i) < newlvl; i++) hpmax += newhp();
+       if (hpmax < u.ulevel) hpmax = u.ulevel; /* min of 1 HP per level */
+       /* retain same proportion for current HP; u.uhp * hpmax / u.uhpmax */
+       u.uhp = rounddiv((long)u.uhp * (long)hpmax, u.uhpmax);
+       u.uhpmax = hpmax;
+       /*
+        * Do the same for spell power.
+        */
+       enmax = u.uenmax;
+       for (i = 0; i < oldlvl; i++) enmax -= (int)u.ueninc[i];
+       enmax = rounddiv((long)enmax * (long)rn1(4, 8), 10);
+       for (i = 0; (u.ulevel = i) < newlvl; i++) enmax += newpw();
+       if (enmax < u.ulevel) enmax = u.ulevel;
+       u.uen = rounddiv((long)u.uen * (long)enmax, u.uenmax);
+       u.uenmax = enmax;
+       /* [should alignment record be tweaked too?] */
 
-       redist_attr();
        u.uhunger = rn1(500,500);
        if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL);
        if (Stoned) make_stoned(0L, (char *)0, 0, (char *)0);
-       if (u.uhp <= 0 || u.uhpmax <= 0) {
+       if (u.uhp <= 0) {
                if (Polymorph_control) {
                    if (u.uhp <= 0) u.uhp = 1;
-                   if (u.uhpmax <= 0) u.uhpmax = 1;
                } else {
 dead: /* we come directly here if their experience level went to 0 or less */
                    Your("new form doesn't seem healthy enough to survive.");
index f1ee4b2d4871b36b918a191b404b35ecb1c2d87a..0c5ea57aa6ead5abeea3567d328f5349e9567c9a 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)u_init.c   3.5     2002/10/22      */
+/*     SCCS Id: @(#)u_init.c   3.5     2005/09/19      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -566,12 +566,7 @@ u_init()
 
        u.ulevel = 0;   /* set up some of the initial attributes */
        u.uhp = u.uhpmax = newhp();
-       u.uenmax = urole.enadv.infix + urace.enadv.infix;
-       if (urole.enadv.inrnd > 0)
-           u.uenmax += rnd(urole.enadv.inrnd);
-       if (urace.enadv.inrnd > 0)
-           u.uenmax += rnd(urace.enadv.inrnd);
-       u.uen = u.uenmax;
+       u.uen = u.uenmax = newpw();
        u.uspellprot = 0;
        adjabil(0,1);
        u.ulevel = u.ulevelmax = 1;