hilite_status support for <=, >=, explicit =

Add threshold relationships <= and >= so that the change to make <
and > perform their expected comparison can be resolved.  "Point
release shouldn't force players to update their config files" does
not carry sufficient weight given that they already had to do that
to turn on status highlighting when going from 3.6.0 to 3.6.1.  The
3.6.2 release notes can warn them about the need to update their
status highlight options if they're currently using '<' and/or '>'.

Entering new hilite rules via the 'O' command accepted '=' prefix
for numbers, but rules from config files did not.  Now they do.
The '=' prefix is optional in both situations.

With 'O', percent rules and absolute rules had separate menu entries
so picking one was already choosing the rule type, but entering a
numeric value without percent sign (for percent) or with one (for
absolute) would change the type on the fly.  If someone has already
picked percentage they shouldn't be required to append '%' to the
digits, so that is now optional.  If explicitly included with the
number after having picked absolute, the value is rejected.  It is
trivial to back up in those menus and choose the alternate type if
someone changes his/her mind part way through.

If a status field has both persistent (percent, absolute, always)
and temporary highlights (up, down, changed), give the temporary one
precedence when the value has changed.  To do that with 3.6.1, the
rules for temporary had to follow the ones for persistent highlights
since whichever matched last was the one used.  Now their order
relative to each other doesn't matter.  If a value increases and
there is both an 'up' rule and a 'changed' rule, the more specific
'up' takes precedence, regardless of their relative order; likewise
for decreases and 'down' vs 'changed'.

There were a couple more tweaks needed to support negative values;
I overlooked the 'O' menu handling before.  >-1% and <101% now work
for both the config file and interactive adding via 'O' methods of
defining highlight rules, although new >=0% and <=100% will be
clearer to anyone examining a rule set.

'enum relationship' was forcing LT_VALUE to be -1 but that fact was
never utilized anywhere, and the code was using magic number -2 to
mean "no relationship yet".  This adds NO_LTEQGT to replace the
latter and gives it value -1.  EQ_VALUE is still 0 so effectively
the default if a highlight hasn't been fully set up yet.  LT_VALUE
is now just another positive value along with GT_VALUE, LE_VALUE, &c.

The Guidebook hasn't caught up with the code yet.

The rule choosing code used when deciding how to highlight something
only supports 'int' fields and relies on 'long' having the same bits.
It needs to be extended to support 'long' properly.  Fixing should
be straightforward (except maybe for the initialization of min/max
best fit handling) but this doesn't address that.  Also, data type
for encumbrance/carrying-capacity should be changed from unsigned to
plain int so that no extra handling for just one field will be needed.
This commit is contained in:
PatR
2018-05-21 05:58:01 -07:00
parent b142456787
commit dc00df935b
3 changed files with 258 additions and 147 deletions

View File

@@ -56,6 +56,10 @@ unix: Makefile.src and Makefile.utl inadvertently relied on a 'gnu make'
General New Features
--------------------
integrate aklys feature introduced in 3.6.1 into display
status_hilite options which use comparisons may now use <= and >= in
addition to previous < and >; in 3.6.1 the latter operated as if
they were <= and >= but now behave as conventional less than and
greater than; old highlight rules using them should be updated
Code Cleanup and Reorganization

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 botl.h $NHDT-Date: 1452660165 2016/01/13 04:42:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ */
/* NetHack 3.6 botl.h $NHDT-Date: 1526907469 2018/05/21 12:57:49 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.19 $ */
/* Copyright (c) Michael Allison, 2003 */
/* NetHack may be freely redistributed. See license for details. */
@@ -32,11 +32,13 @@ enum statusfields {
BL_FLUSH = -1, BL_TITLE = 0,
BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, /* 1..6 */
BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, /* 7..12 */
BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, /* 13..20 */
BL_EXP, BL_CONDITION
BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, /* 13..18 */
BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION /* 19..22 */
};
enum relationships { LT_VALUE = -1, EQ_VALUE, GT_VALUE, TXT_VALUE };
enum relationships { NO_LTEQGT = -1,
EQ_VALUE, LT_VALUE, LE_VALUE,
GE_VALUE, GT_VALUE, TXT_VALUE };
#define MAXBLSTATS (BL_CONDITION + 1)

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 botl.c $NHDT-Date: 1526804444 2018/05/20 08:20:44 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.95 $ */
/* NetHack 3.6 botl.c $NHDT-Date: 1526907473 2018/05/21 12:57:53 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.96 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2006. */
/* NetHack may be freely redistributed. See license for details. */
@@ -455,12 +455,15 @@ STATIC_DCL void FDECL(split_clridx, (int, int *, int *));
STATIC_DCL char *FDECL(hlattr2attrname, (int, char *, int));
STATIC_DCL void FDECL(status_hilite_linestr_add, (int, struct hilite_s *,
unsigned long, const char *));
STATIC_DCL void NDECL(status_hilite_linestr_done);
STATIC_DCL int FDECL(status_hilite_linestr_countfield, (int));
STATIC_DCL void NDECL(status_hilite_linestr_gather_conditions);
STATIC_DCL void NDECL(status_hilite_linestr_gather);
STATIC_DCL char *FDECL(status_hilite2str, (struct hilite_s *));
STATIC_DCL int NDECL(status_hilite_menu_choose_field);
STATIC_DCL int FDECL(status_hilite_menu_choose_behavior, (int));
STATIC_DCL int FDECL(status_hilite_menu_choose_updownboth, (int,
const char *));
STATIC_DCL boolean FDECL(status_hilite_menu_add, (int));
#define has_hilite(i) (blstats[0][(i)].thresholds)
#endif
@@ -1357,14 +1360,18 @@ int *colorptr;
if (blstats[idx][fldidx].thresholds) {
/* there are hilites set here */
int max_pc = 0, min_pc = 100;
int max_pc = -1, min_pc = 101;
int max_val = -LARGEST_INT, min_val = LARGEST_INT;
boolean exactmatch = FALSE;
hl = blstats[idx][fldidx].thresholds;
boolean exactmatch = FALSE, updown = FALSE, changed = FALSE;
/* min_/max_ are used to track best fit */
while (hl) {
for (hl = blstats[idx][fldidx].thresholds; hl; hl = hl->next) {
/* if we've already matched a temporary highlight, it takes
precedence over all persistent ones; we still process
updown rules to get the last one which qualifies */
if ((updown || changed) && hl->behavior != BL_TH_UPDOWN)
continue;
switch (hl->behavior) {
case BL_TH_VAL_PERCENTAGE:
if (hl->rel == EQ_VALUE && pc == hl->value.a_int) {
@@ -1376,24 +1383,43 @@ int *colorptr;
&& (hl->value.a_int <= min_pc)) {
merge_bestcolor(&bestcolor, hl->coloridx);
min_pc = hl->value.a_int;
} else if (hl->rel == LE_VALUE && !exactmatch
&& (pc <= hl->value.a_int)
&& (hl->value.a_int <= min_pc)) {
merge_bestcolor(&bestcolor, hl->coloridx);
min_pc = hl->value.a_int;
} else if (hl->rel == GT_VALUE && !exactmatch
&& (pc > hl->value.a_int)
&& (hl->value.a_int >= max_pc)) {
merge_bestcolor(&bestcolor, hl->coloridx);
max_pc = hl->value.a_int;
} else if (hl->rel == GE_VALUE && !exactmatch
&& (pc >= hl->value.a_int)
&& (hl->value.a_int >= max_pc)) {
merge_bestcolor(&bestcolor, hl->coloridx);
max_pc = hl->value.a_int;
}
break;
case BL_TH_UPDOWN:
/* specific 'up' or 'down' takes precedence over general
'changed' regardless of their order in the rule set */
if (chg < 0 && hl->rel == LT_VALUE) {
merge_bestcolor(&bestcolor, hl->coloridx);
updown = TRUE;
} else if (chg > 0 && hl->rel == GT_VALUE) {
merge_bestcolor(&bestcolor, hl->coloridx);
} else if (hl->rel == EQ_VALUE && chg) {
updown = TRUE;
} else if (chg != 0 && hl->rel == EQ_VALUE && !updown) {
merge_bestcolor(&bestcolor, hl->coloridx);
min_val = max_val = hl->value.a_int;
changed = TRUE;
}
break;
case BL_TH_VAL_ABSOLUTE:
/*
* TODO:
* This covers data type ANY_INT. We need to handle ANY_LONG
* separately using a_long and new min_lval, max_lval.
*/
if (hl->rel == EQ_VALUE && hl->value.a_int == value->a_int) {
merge_bestcolor(&bestcolor, hl->coloridx);
min_val = max_val = hl->value.a_int;
@@ -1403,18 +1429,29 @@ int *colorptr;
&& (hl->value.a_int <= min_val)) {
merge_bestcolor(&bestcolor, hl->coloridx);
min_val = hl->value.a_int;
} else if (hl->rel == LE_VALUE && !exactmatch
&& (value->a_int <= hl->value.a_int)
&& (hl->value.a_int <= min_val)) {
merge_bestcolor(&bestcolor, hl->coloridx);
min_val = hl->value.a_int;
} else if (hl->rel == GT_VALUE && !exactmatch
&& (value->a_int > hl->value.a_int)
&& (hl->value.a_int >= max_val)) {
merge_bestcolor(&bestcolor, hl->coloridx);
max_val = hl->value.a_int;
} else if (hl->rel == GE_VALUE && !exactmatch
&& (value->a_int >= hl->value.a_int)
&& (hl->value.a_int >= max_val)) {
merge_bestcolor(&bestcolor, hl->coloridx);
max_val = hl->value.a_int;
}
break;
case BL_TH_TEXTMATCH:
txtstr = dupstr(blstats[idx][fldidx].val);
cmpstr = txtstr;
if (fldidx == BL_TITLE) {
int len = (strlen(plname) + sizeof(" the"));
int len = (int) (strlen(plname) + sizeof (" the"));
cmpstr += len;
}
(void) trimspaces(cmpstr);
@@ -1432,7 +1469,6 @@ int *colorptr;
default:
break;
}
hl = hl->next;
}
}
*colorptr = bestcolor;
@@ -1444,9 +1480,9 @@ split_clridx(idx, coloridx, attrib)
int idx;
int *coloridx, *attrib;
{
if (idx && coloridx && attrib) {
*coloridx = idx & 0x00FF;
*attrib = (idx & 0xFF00) >> 8;
if (coloridx && attrib) {
*coloridx = idx & 0x00FF;
*attrib = (idx >> 8) & 0x00FF;
}
}
@@ -1516,7 +1552,7 @@ boolean from_configfile;
return TRUE;
}
/* is str in the format of "[<>]?[-+]?[0-9]+%?" regex */
/* is str in the format of "[<>]?=?[-+]?[0-9]+%?" regex */
STATIC_OVL boolean
is_ltgt_percentnumber(str)
const char *str;
@@ -1525,6 +1561,8 @@ const char *str;
if (*s == '<' || *s == '>')
s++;
if (*s == '=')
s++;
if (*s == '-' || *s == '+')
s++;
if (!digit(*s))
@@ -1536,7 +1574,7 @@ const char *str;
return (*s == '\0');
}
/* does str only contain "<>-+0-9%" chars */
/* does str only contain "<>=-+0-9%" chars */
STATIC_OVL boolean
has_ltgt_percentnumber(str)
const char *str;
@@ -1544,7 +1582,7 @@ const char *str;
const char *s = str;
while (*s) {
if (!index("<>-+0123456789%", *s))
if (!index("<>=-+0123456789%", *s))
return FALSE;
s++;
}
@@ -1661,22 +1699,15 @@ struct hilite_s *hilite;
return;
/* alloc and initialize a new hilite_s struct */
new_hilite = (struct hilite_s *) alloc(sizeof(struct hilite_s));
new_hilite = (struct hilite_s *) alloc(sizeof (struct hilite_s));
*new_hilite = *hilite; /* copy struct */
new_hilite->set = TRUE;
new_hilite->fld = fld;
new_hilite->next = (struct hilite_s *)0;
new_hilite->next = blstats[0][fld].thresholds;
blstats[0][fld].thresholds = new_hilite;
/* sort_hilites(fld) */
/* Does that status field currently have any hilite thresholds? */
if (!blstats[0][fld].thresholds) {
blstats[0][fld].thresholds = new_hilite;
} else {
struct hilite_s *temp_hilite = blstats[0][fld].thresholds;
new_hilite->next = temp_hilite;
blstats[0][fld].thresholds = new_hilite;
/* sort_hilites(fld) */
}
/* current and prev must both point at the same hilites */
blstats[1][fld].thresholds = blstats[0][fld].thresholds;
}
@@ -1691,11 +1722,8 @@ boolean from_configfile;
int sidx = 0, i = -1, dt = -1;
int coloridx = -1, successes = 0;
int disp_attrib = 0;
boolean percent = FALSE, changed = FALSE, numeric = FALSE;
boolean down= FALSE, up = FALSE;
boolean gt = FALSE, lt = FALSE, eq = FALSE, neq = FALSE;
boolean txtval = FALSE;
boolean always = FALSE;
boolean percent, changed, numeric, down, up,
gt, lt, ge, le, eq, txtval, always;
const char *txt;
enum statusfields fld = BL_FLUSH;
struct hilite_s hilite;
@@ -1744,10 +1772,9 @@ boolean from_configfile;
int kidx;
txt = (const char *)0;
percent = changed = numeric = FALSE;
down = up = FALSE;
gt = eq = lt = neq = txtval = FALSE;
always = FALSE;
percent = numeric = always = FALSE;
down = up = changed = FALSE;
gt = ge = eq = le = lt = txtval = FALSE;
/* threshold value */
if (!s[sidx][0])
@@ -1786,29 +1813,38 @@ boolean from_configfile;
} else if (!strcmpi(s[sidx], "changed")) {
changed = TRUE;
} else if (is_ltgt_percentnumber(s[sidx])) {
tmp = s[sidx]; /* is_ltgt_() guarantees [<>]?[-+]?[0-9]+%? */
tmp = s[sidx]; /* is_ltgt_() guarantees [<>]?=?[-+]?[0-9]+%? */
if (strchr(tmp, '%'))
percent = TRUE;
if (*tmp == '<')
lt = TRUE;
else if (*tmp == '>')
gt = TRUE;
/* '%', '<', '>' have served their purpose, unary '+' is
if (*tmp == '<') {
if (tmp[1] == '=')
le = TRUE;
else
lt = TRUE;
} else if (*tmp == '>') {
if (tmp[1] == '=')
ge = TRUE;
else
gt = TRUE;
}
/* '%', '<', '>' have served their purpose, '=' is either
part of '<' or '>' or optional for '=N', unary '+' is
just decorative, so get rid of them, leaving -?[0-9]+ */
tmp = stripchars(tmpbuf, "%<>+", tmp);
tmp = stripchars(tmpbuf, "%<>=+", tmp);
numeric = TRUE;
dt = percent ? ANY_INT : initblstats[fld].anytype;
(void) s_to_anything(&hilite.value, tmp, dt);
if (dt == ANY_INT
/* AC is the only field where negative values make sense but
accept >-1 for other fields since we don't support >=0
which someone might want to use in a catch-all rule */
accept >-1 for other fields */
&& (hilite.value.a_int < (fld == BL_AC ? -128 : gt ? -1 : 0)
/* percentages have another more comprehensive check below */
|| hilite.value.a_int > (percent ? 100 : LARGEST_INT))) {
|| hilite.value.a_int > (percent ? (lt ? 101 : 100)
: LARGEST_INT))) {
config_error_add(
"hilite_status threshold '%s%d%s' is out of range",
gt ? ">" : lt ? "<" : "",
gt ? ">" : ge ? ">="
: lt ? "<" : le ? "<=" : "=",
hilite.value.a_int,
percent ? "%" : "");
return FALSE;
@@ -1836,22 +1872,16 @@ boolean from_configfile;
return FALSE;
}
/* relationships { LT_VALUE, GT_VALUE, EQ_VALUE} */
if (gt)
/* relationships {LT_VALUE, LE_VALUE, EQ_VALUE, GE_VALUE, GT_VALUE} */
if (gt || up)
hilite.rel = GT_VALUE;
else if (eq)
hilite.rel = EQ_VALUE;
else if (lt)
else if (lt || down)
hilite.rel = LT_VALUE;
else if (percent)
hilite.rel = EQ_VALUE;
else if (numeric)
hilite.rel = EQ_VALUE;
else if (down)
hilite.rel = LT_VALUE;
else if (up)
hilite.rel = GT_VALUE;
else if (changed)
else if (ge)
hilite.rel = GE_VALUE;
else if (le)
hilite.rel = LE_VALUE;
else if (eq || percent || numeric || changed)
hilite.rel = EQ_VALUE;
else if (txtval)
hilite.rel = TXT_VALUE;
@@ -1869,13 +1899,24 @@ boolean from_configfile;
config_error_add("Cannot use percent with '%s'",
initblstats[fld].fldname);
return FALSE;
} else if ((hilite.value.a_int < 0)
} else if ((hilite.value.a_int < -1)
|| (hilite.value.a_int == -1
&& hilite.value.a_int != GT_VALUE)
|| (hilite.value.a_int == 0
&& hilite.rel == LT_VALUE)
|| (hilite.value.a_int > 100)
|| (hilite.value.a_int == 100
&& hilite.rel == GT_VALUE)) {
config_error_add("Illegal percentage value");
&& hilite.rel == GT_VALUE)
|| (hilite.value.a_int == 101
&& hilite.value.a_int != LT_VALUE)
|| (hilite.value.a_int > 101)) {
config_error_add(
"hilite_status: invalid percentage value '%s%d%%'",
(hilite.rel == LT_VALUE) ? "<"
: (hilite.rel == LE_VALUE) ? "<="
: (hilite.rel == GT_VALUE) ? ">"
: (hilite.rel == GE_VALUE) ? ">="
: "=",
hilite.value.a_int);
return FALSE;
}
}
@@ -1898,6 +1939,7 @@ boolean from_configfile;
for (i = 0; i < sf; ++i) {
int a = match_str2attr(subfields[i], FALSE);
if (a == ATR_DIM)
disp_attrib |= HL_DIM;
else if (a == ATR_BLINK)
@@ -1942,7 +1984,7 @@ boolean from_configfile;
hilite.anytype = dt;
if (hilite.behavior == BL_TH_TEXTMATCH && txt
&& strlen(txt) < QBUFSZ-1) {
&& strlen(txt) < QBUFSZ - 1) {
Strcpy(hilite.textmatch, txt);
(void) trimspaces(hilite.textmatch);
}
@@ -2466,21 +2508,24 @@ struct hilite_s *hl;
char clrbuf[BUFSZ];
char attrbuf[BUFSZ];
char *tmpattr;
const char *op;
if (!hl)
return (char *) 0;
behavebuf[0] = '\0';
clrbuf[0] = '\0';
op = (hl->rel == LT_VALUE) ? "<"
: (hl->rel == LE_VALUE) ? "<="
: (hl->rel == GT_VALUE) ? ">"
: (hl->rel == GE_VALUE) ? ">="
: (hl->rel == EQ_VALUE) ? "="
: 0;
switch (hl->behavior) {
case BL_TH_VAL_PERCENTAGE:
if (hl->rel == LT_VALUE)
Sprintf(behavebuf, "<%i%%", hl->value.a_int);
else if (hl->rel == GT_VALUE)
Sprintf(behavebuf, ">%i%%", hl->value.a_int);
else if (hl->rel == EQ_VALUE)
Sprintf(behavebuf, "%i%%", hl->value.a_int);
if (op)
Sprintf(behavebuf, "%s%d%%", op, hl->value.a_int);
else
impossible("hl->behavior=percentage, rel error");
break;
@@ -2495,12 +2540,8 @@ struct hilite_s *hl;
impossible("hl->behavior=updown, rel error");
break;
case BL_TH_VAL_ABSOLUTE:
if (hl->rel == LT_VALUE)
Sprintf(behavebuf, "<%i", hl->value.a_int);
else if (hl->rel == GT_VALUE)
Sprintf(behavebuf, ">%i", hl->value.a_int);
else if (hl->rel == EQ_VALUE)
Sprintf(behavebuf, "%i", hl->value.a_int);
if (op)
Sprintf(behavebuf, "%s%d", op, hl->value.a_int);
else
impossible("hl->behavior=absolute, rel error");
break;
@@ -2540,7 +2581,7 @@ struct hilite_s *hl;
return buf;
}
int
STATIC_OVL int
status_hilite_menu_choose_field()
{
winid tmpwin;
@@ -2569,7 +2610,7 @@ status_hilite_menu_choose_field()
return fld;
}
int
STATIC_OVL int
status_hilite_menu_choose_behavior(fld)
int fld;
{
@@ -2615,7 +2656,8 @@ int fld;
nopts++;
}
if (fld != BL_CAP && fld != BL_HUNGER && (at == ANY_INT || at == ANY_LONG || at == ANY_UINT)) {
if (fld != BL_CAP && fld != BL_HUNGER
&& (at == ANY_INT || at == ANY_LONG || at == ANY_UINT)) {
any = zeroany;
any.a_int = onlybeh = BL_TH_VAL_ABSOLUTE;
add_menu(tmpwin, NO_GLYPH, &any, 'n', 0, ATR_NONE,
@@ -2631,7 +2673,8 @@ int fld;
nopts++;
}
if (initblstats[fld].anytype == ANY_STR || fld == BL_CAP || fld == BL_HUNGER) {
if (initblstats[fld].anytype == ANY_STR
|| fld == BL_CAP || fld == BL_HUNGER) {
any = zeroany;
any.a_int = onlybeh = BL_TH_TEXTMATCH;
Sprintf(buf, "%s text match", initblstats[fld].fldname);
@@ -2659,12 +2702,12 @@ int fld;
return beh;
}
int
STATIC_OVL int
status_hilite_menu_choose_updownboth(fld, str)
int fld;
const char *str;
{
int res, ret = -2;
int res, ret = NO_LTEQGT;
winid tmpwin;
char buf[BUFSZ];
anything any;
@@ -2674,7 +2717,8 @@ const char *str;
start_menu(tmpwin);
if (str)
Sprintf(buf, "%s than %s", (fld == BL_AC) ? "Better" : "Less", str);
Sprintf(buf, "%s than %s",
(fld == BL_AC) ? "Better (lower)" : "Less", str);
else
Sprintf(buf, "Value goes down");
any = zeroany;
@@ -2682,6 +2726,15 @@ const char *str;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
buf, MENU_UNSELECTED);
if (str) {
Sprintf(buf, "%s or %s",
str, (fld == BL_AC) ? "better (lower)" : "less");
any = zeroany;
any.a_int = 10 + LE_VALUE;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
buf, MENU_UNSELECTED);
}
if (str)
Sprintf(buf, "Exactly %s", str);
else
@@ -2691,8 +2744,18 @@ const char *str;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
buf, MENU_UNSELECTED);
if (str) {
Sprintf(buf, "%s or %s",
str, (fld == BL_AC) ? "worse (higher)" : "more");
any = zeroany;
any.a_int = 10 + GE_VALUE;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
buf, MENU_UNSELECTED);
}
if (str)
Sprintf(buf, "%s than %s", (fld == BL_AC) ? "Worse" : "More", str);
Sprintf(buf, "%s than %s",
(fld == BL_AC) ? "Worse (higher)" : "More", str);
else
Sprintf(buf, "Value goes up");
any = zeroany;
@@ -2719,7 +2782,7 @@ int origfld;
{
int fld;
int behavior;
int lt_gt_eq = 0;
int lt_gt_eq = NO_LTEQGT; /* not set up yet */
int clr = NO_COLOR, atr = HL_UNDEF;
struct hilite_s hilite;
unsigned long cond = 0UL;
@@ -2740,55 +2803,63 @@ choose_field:
colorqry[0] = '\0';
attrqry[0] = '\0';
memset((genericptr_t) &hilite, 0, sizeof(struct hilite_s));
memset((genericptr_t) &hilite, 0, sizeof (struct hilite_s));
hilite.set = FALSE; /* mark it "unset" */
hilite.fld = fld;
choose_behavior:
behavior = status_hilite_menu_choose_behavior(fld);
if (behavior == (BL_TH_NONE-1)) {
if (behavior == (BL_TH_NONE - 1)) {
return FALSE;
} else if (behavior == BL_TH_NONE) {
if (origfld == BL_FLUSH)
goto choose_field;
else
return FALSE;
return FALSE;
}
hilite.behavior = behavior;
choose_value:
if (behavior == BL_TH_VAL_PERCENTAGE
|| behavior == BL_TH_VAL_ABSOLUTE) {
char inbuf[BUFSZ] = DUMMY, buf[BUFSZ];
int val;
boolean skipltgt = FALSE;
boolean gotnum = FALSE;
char *inp = inbuf;
char *numstart = inbuf;
char inbuf[BUFSZ], buf[BUFSZ];
anything aval;
int val, dt;
boolean skipltgt = FALSE, gotnum = FALSE,
percent = (behavior == BL_TH_VAL_PERCENTAGE);
char *inp, *numstart;
inbuf[0] = '\0';
Sprintf(buf, "Enter %svalue for %s threshold:",
(behavior == BL_TH_VAL_PERCENTAGE) ? "percentage " : "",
percent ? "percentage " : "",
initblstats[fld].fldname);
getlin(buf, inbuf);
if (inbuf[0] == '\0' || inbuf[0] == '\033')
goto choose_behavior;
inp = trimspaces(inbuf);
inp = numstart = trimspaces(inbuf);
if (!*inp)
goto choose_behavior;
/* allow user to enter "<50%" or ">50" or just "50" */
/* allow user to enter "<50%" or ">50" or just "50"
or <=50% or >=50 or =50 */
if (*inp == '>' || *inp == '<' || *inp == '=') {
lt_gt_eq = (*inp == '>') ? GT_VALUE
: (*inp == '<') ? LT_VALUE : EQ_VALUE;
lt_gt_eq = (*inp == '>') ? ((inp[1] == '=') ? GE_VALUE : GT_VALUE)
: (*inp == '<') ? ((inp[1] == '=') ? LE_VALUE : LT_VALUE)
: EQ_VALUE;
skipltgt = TRUE;
*inp = ' ';
*inp++ = ' ';
numstart++;
if (lt_gt_eq == GE_VALUE || lt_gt_eq == LE_VALUE) {
*inp++ = ' ';
numstart++;
}
}
if (*inp == '-') {
inp++;
} else if (*inp == '+') {
*inp++ = ' ';
numstart++;
}
while (digit(*inp)) {
@@ -2796,11 +2867,12 @@ choose_value:
gotnum = TRUE;
}
if (*inp == '%') {
behavior = BL_TH_VAL_PERCENTAGE;
*inp = '\0';
} else if (!*inp) {
behavior = BL_TH_VAL_ABSOLUTE;
} else {
if (!percent) {
pline("Not expecting a percentage.");
goto choose_behavior;
}
*inp = '\0'; /* strip '%' [this accepts trailing junk!] */
} else if (*inp) {
/* some random characters */
pline("\"%s\" is not a recognized number.", inp);
goto choose_value;
@@ -2810,64 +2882,92 @@ choose_value:
goto choose_value;
}
val = atoi(numstart);
if (behavior == BL_TH_VAL_PERCENTAGE) {
aval = zeroany;
dt = percent ? ANY_INT : initblstats[fld].anytype;
(void) s_to_anything(&aval, numstart, dt);
if (percent) {
val = aval.a_int;
if (initblstats[fld].idxmax == -1) {
pline("Field '%s' does not support percentage values.",
initblstats[fld].fldname);
behavior = BL_TH_VAL_ABSOLUTE;
goto choose_value;
}
if (val < 0 || val > 100) {
pline("Not a valid percent value.");
/* if player only specified a number then lt_gt_eq isn't set
up yet and the >-1 and <101 exceptions can't be honored;
deliberate use of those should be uncommon enough for
that to be palatable; unfortunately, it also lets 0 with
later < and 100 with later > through too but those won't
break anything, just end up as no-ops */
if ((val < 0 && (val != -1 || lt_gt_eq != GT_VALUE))
|| (val == 0 && lt_gt_eq == LT_VALUE)
|| (val == 100 && lt_gt_eq == GT_VALUE)
|| (val > 100 && (val != 101 || lt_gt_eq != LT_VALUE))) {
pline("'%s%d%%' is not a valid percent value.",
(lt_gt_eq == LT_VALUE) ? "<"
: (lt_gt_eq == LE_VALUE) ? "<="
: (lt_gt_eq == GT_VALUE) ? ">"
: (lt_gt_eq == GE_VALUE) ? ">="
: (lt_gt_eq == EQ_VALUE) ? "="
/* didn't specify lt_gt_eq with number */
: "",
val);
goto choose_value;
}
/* restore suffix for use in color and attribute prompts */
if (!index(numstart, '%'))
Strcat(numstart, "%");
}
if (!skipltgt) {
lt_gt_eq = status_hilite_menu_choose_updownboth(fld, inbuf);
if (lt_gt_eq == -2)
if (lt_gt_eq == NO_LTEQGT)
goto choose_value;
}
Sprintf(colorqry, "Choose a color for when %s is %s%s:",
Sprintf(colorqry, "Choose a color for when %s is %s%s%s:",
initblstats[fld].fldname,
(lt_gt_eq == LT_VALUE) ? "less than "
: (lt_gt_eq == GT_VALUE) ? "more than "
: "",
numstart,
(lt_gt_eq == EQ_VALUE) ? ""
: (lt_gt_eq == LT_VALUE) ? " or less"
: " or more");
Sprintf(attrqry, "Choose attribute for when %s is %s%s:",
(lt_gt_eq == LE_VALUE) ? " or less"
: (lt_gt_eq == GE_VALUE) ? " or more"
: "");
Sprintf(attrqry, "Choose attribute for when %s is %s%s%s:",
initblstats[fld].fldname,
inbuf,
(lt_gt_eq == EQ_VALUE) ? ""
: (lt_gt_eq == LT_VALUE) ? " or less"
: " or more");
(lt_gt_eq == LT_VALUE) ? "less than "
: (lt_gt_eq == GT_VALUE) ? "more than "
: "",
numstart,
(lt_gt_eq == LE_VALUE) ? " or less"
: (lt_gt_eq == GE_VALUE) ? " or more"
: "");
hilite.rel = lt_gt_eq;
hilite.value.a_int = val;
hilite.value = aval;
} else if (behavior == BL_TH_UPDOWN) {
lt_gt_eq = status_hilite_menu_choose_updownboth(fld, (char *)0);
if (lt_gt_eq == -2)
if (lt_gt_eq == NO_LTEQGT)
goto choose_behavior;
Sprintf(colorqry, "Choose a color for when %s %s:",
initblstats[fld].fldname,
(lt_gt_eq == EQ_VALUE) ? "changes"
: (lt_gt_eq == LT_VALUE) ? "decreases"
: "increases");
: (lt_gt_eq == LT_VALUE) ? "decreases"
: "increases");
Sprintf(attrqry, "Choose attribute for when %s %s:",
initblstats[fld].fldname,
(lt_gt_eq == EQ_VALUE) ? "changes"
: (lt_gt_eq == LT_VALUE) ? "decreases"
: "increases");
: (lt_gt_eq == LT_VALUE) ? "decreases"
: "increases");
hilite.rel = lt_gt_eq;
} else if (behavior == BL_TH_CONDITION) {
cond = query_conditions();
if (!cond) {
if (origfld == BL_FLUSH)
goto choose_field;
else
return FALSE;
return FALSE;
}
Sprintf(colorqry, "Choose a color for conditions %s:",
conditionbitmask2str(cond));
@@ -2875,6 +2975,7 @@ choose_value:
conditionbitmask2str(cond));
} else if (behavior == BL_TH_TEXTMATCH) {
char qry_buf[BUFSZ];
Sprintf(qry_buf, "%s %s text value to match:",
(fld == BL_CAP
|| fld == BL_ALIGN
@@ -2884,27 +2985,31 @@ choose_value:
if (fld == BL_CAP) {
int rv = query_arrayvalue(qry_buf,
enc_stat,
SLT_ENCUMBER, OVERLOADED+1);
SLT_ENCUMBER, OVERLOADED + 1);
if (rv < SLT_ENCUMBER)
goto choose_behavior;
hilite.rel = TXT_VALUE;
Strcpy(hilite.textmatch, enc_stat[rv]);
} else if (fld == BL_ALIGN) {
const char *aligntxt[] = {"chaotic", "neutral", "lawful"};
static const char *aligntxt[] = { "chaotic", "neutral", "lawful" };
int rv = query_arrayvalue(qry_buf,
aligntxt, 0, 3);
aligntxt, 0, 2 + 1);
if (rv < 0)
goto choose_behavior;
hilite.rel = TXT_VALUE;
Strcpy(hilite.textmatch, aligntxt[rv]);
} else if (fld == BL_HUNGER) {
const char *hutxt[] = {"Satiated", (char *)0, "Hungry", "Weak",
"Fainting", "Fainted", "Starved"};
static const char *hutxt[] = { "Satiated", (char *) 0, "Hungry",
"Weak", "Fainting", "Fainted",
"Starved" };
int rv = query_arrayvalue(qry_buf,
hutxt,
SATIATED, STARVED+1);
SATIATED, STARVED + 1);
if (rv < SATIATED)
goto choose_behavior;
@@ -2925,7 +3030,7 @@ choose_value:
hilite.rel = TXT_VALUE;
Strcpy(hilite.textmatch, rolelist[rv]);
} else {
char inbuf[BUFSZ] = DUMMY;
char inbuf[BUFSZ];
inbuf[0] = '\0';
getlin(qry_buf, inbuf);
@@ -2933,7 +3038,7 @@ choose_value:
goto choose_behavior;
hilite.rel = TXT_VALUE;
if (strlen(inbuf) < QBUFSZ-1)
if (strlen(inbuf) < QBUFSZ - 1)
Strcpy(hilite.textmatch, inbuf);
else
return FALSE;
@@ -2950,7 +3055,6 @@ choose_value:
}
choose_color:
clr = query_color(colorqry);
if (clr == -1) {
if (behavior != BL_TH_ALWAYS_HILITE)
@@ -2984,6 +3088,7 @@ choose_color:
char clrbuf[BUFSZ];
char attrbuf[BUFSZ];
char *tmpattr;
if (atr == HL_DIM)
cond_hilites[HL_ATTCLR_DIM] |= cond;
else if (atr == HL_BLINK)