no artifacts have been discovered yet, same as `<any-object-class>;
likewise for `u to ask to see unique items
reduce eucalyptus leaf nutrition to 1
+life-saving might increase max HP; if level drain triggers that, don't let max
+ HP go up because it confuses healing for monster wielding Stormbringer
+HP recovery and/or max HP boost from eating royal jelly didn't perform a
+ status update to show the change
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
extern void redist_attr(void);
extern void adjabil(int, int);
extern int newhp(void);
+extern int minuhpmax(int);
+extern void setuhpmax(int);
extern schar acurr(int);
extern schar acurrstr(void);
extern boolean extremeattr(int);
/* adjust an attribute; return TRUE if change is made, FALSE otherwise */
boolean
-adjattrib(int ndx, int incr, int msgflg) /* positive => no message, zero => message, and */
-{ /* negative => conditional (msg if change made) */
+adjattrib(
+ int ndx, /* which characteristic */
+ int incr, /* amount of change */
+ int msgflg) /* positive => no message, zero => message, and */
+{ /* negative => conditional (msg if change made) */
int old_acurr, old_abase, old_amax, decr;
boolean abonflg;
const char *attrstr;
return FALSE;
}
+ g.context.botl = TRUE;
if (msgflg <= 0)
You_feel("%s%s!", (incr > 1 || incr < -1) ? "very " : "", attrstr);
- g.context.botl = TRUE;
if (g.program_state.in_moveloop && (ndx == A_STR || ndx == A_CON))
(void) encumber_msg();
return TRUE;
void
losestr(int num)
{
+ int uhpmin = minuhpmax(1), olduhpmax = u.uhpmax;
int ustr = ABASE(A_STR) - num;
while (ustr < 3) {
u.mhmax -= 6;
} else {
u.uhp -= 6;
- u.uhpmax -= 6;
+ setuhpmax(u.uhpmax - 6);
}
+ g.context.botl = TRUE;
+ }
+ if (u.uhpmax < uhpmin) {
+ setuhpmax(min(olduhpmax, uhpmin));
+ if (!Drain_resistance)
+ losexp(NULL); /* won't be fatal when no 'drainer' is supplied */
}
(void) adjattrib(A_STR, -num, 1);
}
return hp;
}
+/* minimum value for uhpmax is ulevel but for life-saving it is always at
+ least 10 if ulevel is less than that */
+int
+minuhpmax(int altmin)
+{
+ if (altmin < 1)
+ altmin = 1;
+ return max(u.ulevel, altmin);
+}
+
+/* update u.uhpmax and values of other things that depend upon it */
+void
+setuhpmax(int newmax)
+{
+ if (newmax != u.uhpmax) {
+ u.uhpmax = newmax;
+ if (u.uhpmax > u.uhppeak)
+ u.uhppeak = u.uhpmax;
+ g.context.botl = TRUE;
+ }
+ if (u.uhp > u.uhpmax)
+ u.uhp = u.uhpmax, g.context.botl = TRUE;
+}
+
schar
acurr(int x)
{
/* This stuff seems to be VERY healthy! */
gainstr(otmp, 1, TRUE);
if (Upolyd) {
- u.mh += otmp->cursed ? -rnd(20) : rnd(20);
+ u.mh += otmp->cursed ? -rnd(20) : rnd(20), g.context.botl = TRUE;
if (u.mh > u.mhmax) {
if (!rn2(17))
u.mhmax++;
rehumanize();
}
} else {
- u.uhp += otmp->cursed ? -rnd(20) : rnd(20);
+ u.uhp += otmp->cursed ? -rnd(20) : rnd(20), g.context.botl = TRUE;
if (u.uhp > u.uhpmax) {
- if (!rn2(17)) {
- u.uhpmax++;
- if (u.uhpmax > u.uhppeak)
- u.uhppeak = u.uhpmax;
- }
+ if (!rn2(17))
+ setuhpmax(u.uhpmax + 1);
u.uhp = u.uhpmax;
} else if (u.uhp <= 0) {
g.killer.format = KILLED_BY_AN;
reducing ulevel below 1, but include this for bulletproofing */
if (u.ulevel < 1)
u.ulevel = 1;
- uhpmin = max(2 * u.ulevel, 10);
+ uhpmin = minuhpmax(10);
if (u.uhpmax < uhpmin)
- u.uhpmax = uhpmin;
+ setuhpmax(uhpmin);
u.uhp = u.uhpmax;
if (Upolyd) /* Unchanging, or death which bypasses losing hit points */
u.mh = u.mhmax;
if (u.uhunger < 500 || how == CHOKING) {
init_uhunger();
}
- /* cure impending doom of sickness hero won't have time to fix */
+ /* cure impending doom of sickness hero won't have time to fix
+ [shouldn't this also be applied to other fatal timeouts?] */
if ((Sick & TIMEOUT) == 1L) {
make_sick(0L, (char *) 0, FALSE, SICK_ALL);
}
g.multi = -1;
if (u.utrap && u.utraptype == TT_LAVA)
reset_utrap(FALSE);
- g.context.botl = 1;
+ g.context.botl = TRUE;
u.ugrave_arise = NON_PM;
HUnchanging = 0L;
curs_on_u();
/* e.g., hit by drain life attack */
void
-losexp(const char *drainer) /* cause of death, if drain should be fatal */
+losexp(
+ const char *drainer) /* cause of death, if drain should be fatal */
{
- register int num;
+ int num, uhpmin, olduhpmax;
/* override life-drain resistance when handling an explicit
wizard mode request to reduce level; never fatal though */
u.uexp = 0;
livelog_printf(LL_MINORAC, "lost all experience");
}
+
+ olduhpmax = u.uhpmax;
+ uhpmin = minuhpmax(10); /* same minimum as is used by life-saving */
num = (int) u.uhpinc[u.ulevel];
u.uhpmax -= num;
- if (u.uhpmax < 1)
- u.uhpmax = 1;
+ if (u.uhpmax < uhpmin)
+ setuhpmax(uhpmin);
+ /* uhpmax might try to go up if it has previously been reduced by
+ strength loss or by a fire trap or by an attack by Death which
+ all use a different minimum than life-saving or experience loss;
+ we don't allow it to go up because that contradicts assumptions
+ elsewhere (such as healing wielder who drains with Strombringer) */
+ if (u.uhpmax > olduhpmax)
+ setuhpmax(olduhpmax);
+
u.uhp -= num;
if (u.uhp < 1)
u.uhp = 1;
u.mh += hpinc;
}
hpinc = newhp();
- u.uhpmax += hpinc;
- if (u.uhpmax > u.uhppeak)
- u.uhppeak = u.uhpmax;
+ setuhpmax(u.uhpmax + hpinc);
u.uhp += hpinc;
/* increase spell power/energy points */
lowerlimit = min((int) g.youmonst.data->mlevel, u.ulevel);
} else {
hpmax_p = &u.uhpmax;
- lowerlimit = u.ulevel;
+ lowerlimit = minuhpmax(1);
}
if (*hpmax_p - mhm.permdmg > lowerlimit)
*hpmax_p -= mhm.permdmg;
if (alt > num)
num = alt;
if (u.mhmax > mons[u.umonnum].mlevel)
- u.mhmax -= rn2(min(u.mhmax, num + 1)), g.context.botl = 1;
+ u.mhmax -= rn2(min(u.mhmax, num + 1)), g.context.botl = TRUE;
+ if (u.mh > u.mhmax)
+ u.mh = u.mhmax, g.context.botl = TRUE;
} else {
+ int uhpmin = minuhpmax(1), olduhpmax = u.uhpmax;
+
num = d(2, 4);
- if (u.uhpmax > u.ulevel)
- u.uhpmax -= rn2(min(u.uhpmax, num + 1)), g.context.botl = 1;
+ if (u.uhpmax > uhpmin) {
+ u.uhpmax -= rn2(min(u.uhpmax, num + 1)), g.context.botl = TRUE;
+ } /* note: no 'else' here */
+ if (u.uhpmax < uhpmin) {
+ setuhpmax(min(olduhpmax, uhpmin)); /* sets g.context.botl */
+ if (!Drain_resistance)
+ losexp(NULL); /* never fatal when 'drainer' is Null */
+ }
+ if (u.uhp > u.uhpmax)
+ u.uhp = u.uhpmax, g.context.botl = TRUE;
}
if (!num)
You("are uninjured.");