diff --git a/doc/fixes36.2 b/doc/fixes36.2 index f22af782e..3ea0db50f 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -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 diff --git a/include/botl.h b/include/botl.h index ce2a94496..4d9347088 100644 --- a/include/botl.h +++ b/include/botl.h @@ -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) diff --git a/src/botl.c b/src/botl.c index daa1dd468..c219d3db3 100644 --- a/src/botl.c +++ b/src/botl.c @@ -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)