Skip to content

Commit

Permalink
HP and Pw multiplication (trunk only)
Browse files Browse the repository at this point in the history
     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).
  • Loading branch information
nethack.rankin committed Sep 21, 2005
1 parent 25a9c0c commit 5bc6f14
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 84 deletions.
1 change: 1 addition & 0 deletions doc/fixes35.0
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/extern.h
Expand Up @@ -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 *));
Expand Down
49 changes: 24 additions & 25 deletions 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. */

Expand Down Expand Up @@ -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
Expand Down
43 changes: 29 additions & 14 deletions 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. */

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.");

Expand All @@ -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);
Expand Down
83 changes: 45 additions & 38 deletions 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. */

Expand Down Expand Up @@ -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();

Expand All @@ -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.");
Expand Down
9 changes: 2 additions & 7 deletions 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. */

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 5bc6f14

Please sign in to comment.