From 5bc6f1444ea32f17d5ef74aff89307b4cc6e2ea9 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Wed, 21 Sep 2005 05:31:42 +0000 Subject: [PATCH] HP and Pw multiplication (trunk only) Fix the problem pointed out by 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 | 1 + include/extern.h | 1 + src/attrib.c | 49 ++++++++++++++-------------- src/exper.c | 43 +++++++++++++++++-------- src/polyself.c | 83 ++++++++++++++++++++++++++---------------------- src/u_init.c | 9 ++---- 6 files changed, 102 insertions(+), 84 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 7441ef10e..dcc66ec72 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/include/extern.h b/include/extern.h index 6623fdf60..1584fea30 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 *)); diff --git a/src/attrib.c b/src/attrib.c index 539511ea0..283c08315 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -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 diff --git a/src/exper.c b/src/exper.c index 9c5de9b57..ec276c4da 100644 --- a/src/exper.c +++ b/src/exper.c @@ -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); diff --git a/src/polyself.c b/src/polyself.c index 6787f43d8..3dada624e 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -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."); diff --git a/src/u_init.c b/src/u_init.c index f1ee4b2d4..0c5ea57aa 100644 --- a/src/u_init.c +++ b/src/u_init.c @@ -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; -- 2.50.1