status hilites: Hp and Pw percentages

The hitpoints and power/energy status values (and corresponding
maxima) shown on the screen are capped at 9999 to control status line
width.  The actual values can be bigger than that.  Highlights based
on percentages were doing their calculations on the potentially
truncated values rather than on the actual ones.

Add another field to the blstat[] structure, populate it for BL_HP,
BL_HPMAX, BL_ENE, and BL_EXEMAX and switch to it for their percentage
calculations.

Doesn't seem to break highlighting of 'normal' range values but hasn't
been tested for extreme ones.
This commit is contained in:
PatR
2023-09-16 12:42:26 -07:00
parent 1958daef4c
commit 2a5f03a3b4
2 changed files with 52 additions and 32 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 botl.h $NHDT-Date: 1596498528 2020/08/03 23:48:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.34 $ */ /* NetHack 3.7 botl.h $NHDT-Date: 1694893330 2023/09/16 19:42:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.37 $ */
/* Copyright (c) Michael Allison, 2003 */ /* Copyright (c) Michael Allison, 2003 */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -255,7 +255,7 @@ struct istat_s {
boolean percent_matters; boolean percent_matters;
short percent_value; short percent_value;
unsigned anytype; unsigned anytype;
anything a; anything a, rawval;
char *val; char *val;
int valwidth; int valwidth;
enum statusfields idxmax; enum statusfields idxmax;

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 botl.c $NHDT-Date: 1685863332 2023/06/04 07:22:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.233 $ */ /* NetHack 3.7 botl.c $NHDT-Date: 1694893342 2023/09/16 19:42:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.239 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2006. */ /*-Copyright (c) Michael Allison, 2006. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -529,12 +529,12 @@ static void status_hilites_viewall(void);
#define INIT_BLSTAT(name, fmtstr, anytyp, wid, fld) \ #define INIT_BLSTAT(name, fmtstr, anytyp, wid, fld) \
{ name, fmtstr, 0L, FALSE, FALSE, 0, anytyp, \ { name, fmtstr, 0L, FALSE, FALSE, 0, anytyp, \
{ (genericptr_t) 0 }, (char *) 0, \ { (genericptr_t) 0 }, { (genericptr_t) 0 }, (char *) 0, \
wid, -1, fld INIT_THRESH } wid, -1, fld INIT_THRESH }
#define INIT_BLSTATP(name, fmtstr, anytyp, wid, maxfld, fld) \ #define INIT_BLSTATP(name, fmtstr, anytyp, wid, maxfld, fld) \
{ name, fmtstr, 0L, FALSE, TRUE, 0, anytyp, \ { name, fmtstr, 0L, FALSE, TRUE, 0, anytyp, \
{ (genericptr_t) 0 }, (char *) 0, \ { (genericptr_t) 0 }, { (genericptr_t) 0 }, (char *) 0, \
wid, maxfld, fld INIT_THRESH } wid, maxfld, fld INIT_THRESH }
/* If entries are added to this, botl.h will require updating too. /* If entries are added to this, botl.h will require updating too.
'max' value of BL_EXP gets special handling since the percentage 'max' value of BL_EXP gets special handling since the percentage
@@ -795,10 +795,12 @@ bot_via_windowport(void)
/* Hit points */ /* Hit points */
i = Upolyd ? u.mh : u.uhp; i = Upolyd ? u.mh : u.uhp;
if (i < 0) if (i < 0) /* gameover sets u.uhp to -1 */
i = 0; i = 0;
gb.blstats[idx][BL_HP].rawval.a_int = i;
gb.blstats[idx][BL_HP].a.a_int = min(i, 9999); gb.blstats[idx][BL_HP].a.a_int = min(i, 9999);
i = Upolyd ? u.mhmax : u.uhpmax; i = Upolyd ? u.mhmax : u.uhpmax;
gb.blstats[idx][BL_HPMAX].rawval.a_int = i;
gb.blstats[idx][BL_HPMAX].a.a_int = min(i, 9999); gb.blstats[idx][BL_HPMAX].a.a_int = min(i, 9999);
/* Dungeon level. */ /* Dungeon level. */
@@ -831,7 +833,9 @@ bot_via_windowport(void)
gv.valset[BL_GOLD] = TRUE; /* indicate val already set */ gv.valset[BL_GOLD] = TRUE; /* indicate val already set */
/* Power (magical energy) */ /* Power (magical energy) */
gb.blstats[idx][BL_ENE].rawval.a_int = u.uen;
gb.blstats[idx][BL_ENE].a.a_int = min(u.uen, 9999); gb.blstats[idx][BL_ENE].a.a_int = min(u.uen, 9999);
gb.blstats[idx][BL_ENEMAX].rawval.a_int = u.uenmax;
gb.blstats[idx][BL_ENEMAX].a.a_int = min(u.uenmax, 9999); gb.blstats[idx][BL_ENEMAX].a.a_int = min(u.uenmax, 9999);
/* Armor class */ /* Armor class */
@@ -1241,9 +1245,9 @@ eval_notify_windowport_field(
|| (fld == BL_HP && iflags.wc2_hitpointbar)) { || (fld == BL_HP && iflags.wc2_hitpointbar)) {
fldmax = curr->idxmax; fldmax = curr->idxmax;
pc = (fldmax == BL_EXP) ? exp_percentage() pc = (fldmax == BL_EXP) ? exp_percentage()
: (fldmax >= 0 && fldmax < MAXBLSTATS) : (fldmax >= 0 && fldmax < MAXBLSTATS)
? percentage(curr, &gb.blstats[idx][fldmax]) ? percentage(curr, &gb.blstats[idx][fldmax])
: 0; /* bullet proofing; can't get here */ : 0; /* bullet proofing; can't get here */
if (pc != prev->percent_value) if (pc != prev->percent_value)
chg = (pc < prev->percent_value) ? -1 : 1; chg = (pc < prev->percent_value) ? -1 : 1;
curr->percent_value = pc; curr->percent_value = pc;
@@ -1504,7 +1508,9 @@ init_blstats(void)
static int static int
compare_blstats(struct istat_s *bl1, struct istat_s *bl2) compare_blstats(struct istat_s *bl1, struct istat_s *bl2)
{ {
int anytype, result = 0; anything *a1, *a2;
boolean use_rawval;
int anytype, fld, result = 0;
if (!bl1 || !bl2) { if (!bl1 || !bl2) {
panic("compare_blstat: bad istat pointer %s, %s", panic("compare_blstat: bad istat pointer %s, %s",
@@ -1520,44 +1526,50 @@ compare_blstats(struct istat_s *bl1, struct istat_s *bl2)
fmt_ptr((genericptr_t) bl2->a.a_void)); fmt_ptr((genericptr_t) bl2->a.a_void));
} }
fld = bl1->fld;
use_rawval = (fld == BL_HP || fld == BL_HPMAX
|| fld == BL_ENE || fld == BL_ENEMAX);
a1 = use_rawval ? &bl1->rawval : &bl1->a;
a2 = use_rawval ? &bl2->rawval : &bl2->a;
switch (anytype) { switch (anytype) {
case ANY_INT: case ANY_INT:
result = (bl1->a.a_int < bl2->a.a_int) ? 1 result = (a1->a_int < a2->a_int) ? 1
: (bl1->a.a_int > bl2->a.a_int) ? -1 : 0; : (a1->a_int > a2->a_int) ? -1 : 0;
break; break;
case ANY_IPTR: case ANY_IPTR:
result = (*bl1->a.a_iptr < *bl2->a.a_iptr) ? 1 result = (*a1->a_iptr < *a2->a_iptr) ? 1
: (*bl1->a.a_iptr > *bl2->a.a_iptr) ? -1 : 0; : (*a1->a_iptr > *a2->a_iptr) ? -1 : 0;
break; break;
case ANY_LONG: case ANY_LONG:
result = (bl1->a.a_long < bl2->a.a_long) ? 1 result = (a1->a_long < a2->a_long) ? 1
: (bl1->a.a_long > bl2->a.a_long) ? -1 : 0; : (a1->a_long > a2->a_long) ? -1 : 0;
break; break;
case ANY_LPTR: case ANY_LPTR:
result = (*bl1->a.a_lptr < *bl2->a.a_lptr) ? 1 result = (*a1->a_lptr < *a2->a_lptr) ? 1
: (*bl1->a.a_lptr > *bl2->a.a_lptr) ? -1 : 0; : (*a1->a_lptr > *a2->a_lptr) ? -1 : 0;
break; break;
case ANY_UINT: case ANY_UINT:
result = (bl1->a.a_uint < bl2->a.a_uint) ? 1 result = (a1->a_uint < a2->a_uint) ? 1
: (bl1->a.a_uint > bl2->a.a_uint) ? -1 : 0; : (a1->a_uint > a2->a_uint) ? -1 : 0;
break; break;
case ANY_UPTR: case ANY_UPTR:
result = (*bl1->a.a_uptr < *bl2->a.a_uptr) ? 1 result = (*a1->a_uptr < *a2->a_uptr) ? 1
: (*bl1->a.a_uptr > *bl2->a.a_uptr) ? -1 : 0; : (*a1->a_uptr > *a2->a_uptr) ? -1 : 0;
break; break;
case ANY_ULONG: case ANY_ULONG:
result = (bl1->a.a_ulong < bl2->a.a_ulong) ? 1 result = (a1->a_ulong < a2->a_ulong) ? 1
: (bl1->a.a_ulong > bl2->a.a_ulong) ? -1 : 0; : (a1->a_ulong > a2->a_ulong) ? -1 : 0;
break; break;
case ANY_ULPTR: case ANY_ULPTR:
result = (*bl1->a.a_ulptr < *bl2->a.a_ulptr) ? 1 result = (*a1->a_ulptr < *a2->a_ulptr) ? 1
: (*bl1->a.a_ulptr > *bl2->a.a_ulptr) ? -1 : 0; : (*a1->a_ulptr > *a2->a_ulptr) ? -1 : 0;
break; break;
case ANY_STR: case ANY_STR:
result = sgn(strcmp(bl1->val, bl2->val)); result = sgn(strcmp(bl1->val, bl2->val));
break; break;
case ANY_MASK32: case ANY_MASK32:
result = (bl1->a.a_ulong != bl2->a.a_ulong); result = (a1->a_ulong != a2->a_ulong);
break; break;
default: default:
result = 1; result = 1;
@@ -1655,15 +1667,18 @@ s_to_anything(anything *a, char *buf, int anytype)
} }
#endif /* STATUS_HILITES */ #endif /* STATUS_HILITES */
/* integer percentage is 100 * bl->a / maxbl->a */
static int static int
percentage(struct istat_s *bl, struct istat_s *maxbl) percentage(struct istat_s *bl, struct istat_s *maxbl)
{ {
int result = 0; int result = 0;
int anytype; int anytype;
int ival; int ival, mval;
long lval; long lval;
unsigned uval; unsigned uval;
unsigned long ulval; unsigned long ulval;
int fld = bl->fld;
boolean use_rawval = (fld == BL_HP || fld == BL_ENE);
if (!bl || !maxbl) { if (!bl || !maxbl) {
impossible("percentage: bad istat pointer %s, %s", impossible("percentage: bad istat pointer %s, %s",
@@ -1676,8 +1691,12 @@ percentage(struct istat_s *bl, struct istat_s *maxbl)
if (maxbl->a.a_void) { if (maxbl->a.a_void) {
switch (anytype) { switch (anytype) {
case ANY_INT: case ANY_INT:
ival = bl->a.a_int; /* HP and energy are int so this is the only case that cares
result = ((100 * ival) / maxbl->a.a_int); about 'rawval'; for them, we use that rather than their
potentially truncated (to 9999) display value */
ival = use_rawval ? bl->rawval.a_int : bl->a.a_int;
mval = use_rawval ? maxbl->rawval.a_int : maxbl->a.a_int;
result = ((100 * ival) / mval);
break; break;
case ANY_LONG: case ANY_LONG:
lval = bl->a.a_long; lval = bl->a.a_long;
@@ -1749,6 +1768,7 @@ exp_percentage(void)
curval.a = maxval.a = cg.zeroany; curval.a = maxval.a = cg.zeroany;
curval.a.a_long = exp_val; curval.a.a_long = exp_val;
maxval.a.a_long = nxt_exp_val; maxval.a.a_long = nxt_exp_val;
curval.fld = maxval.fld = BL_EXP; /* (neither BL_HP nor BL_ENE) */
/* maximum delta between levels is 10000000; calculation of /* maximum delta between levels is 10000000; calculation of
100 * (10000000 - N) / 10000000 fits within 32-bit long */ 100 * (10000000 - N) / 10000000 fits within 32-bit long */
res = percentage(&curval, &maxval); res = percentage(&curval, &maxval);