From 5a44a34420bf730ac76f8e6dc4973523c38b8c9b Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 1 Sep 2018 10:43:26 -0400 Subject: [PATCH 01/15] wizidentify suppress unnecessary prompt; allow individual items for perm ID Don't display the selection to identify all items if there are none. Complete an item marked ToDo in cmd.c: allow selection of one or more particular items to permanently identify rather than just all or nothing. --- doc/fixes36.2 | 3 ++ include/extern.h | 3 +- src/cmd.c | 1 - src/invent.c | 114 ++++++++++++++++++++++++++++++++--------------- 4 files changed, 82 insertions(+), 39 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 576701c53..803c0abd9 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -154,6 +154,9 @@ sortloot option has been enhanced to improve object ordering; primarily, within each class or sub-class of objects YAFM when stumbling on an undetected monster while hallucinating Make it clear when a leprechaun dodges your attack +wizard mode #wizidentify can now select individual items for permanent + identification and don't display the selection to permanently + identify everything if everything is already fully identified Code Cleanup and Reorganization diff --git a/include/extern.h b/include/extern.h index bd1924a6b..abd4be118 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1525012590 2018/04/29 14:36:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.629 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1535812936 2018/09/01 14:42:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.636 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -973,6 +973,7 @@ E int FDECL(askchain, (struct obj **, const char *, int, int (*)(OBJ_P), int (*)(OBJ_P), int, const char *)); E void FDECL(fully_identify_obj, (struct obj *)); E int FDECL(identify, (struct obj *)); +E int FDECL(count_unidentified, (struct obj *)); E void FDECL(identify_pack, (int, BOOLEAN_P)); E void NDECL(learn_unseen_invent); E void FDECL(prinv, (const char *, struct obj *, long)); diff --git a/src/cmd.c b/src/cmd.c index 3afa198b0..d73d0e60e 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -652,7 +652,6 @@ wiz_identify(VOID_ARGS) it doesn't matter whether the command has been remapped */ if (display_inventory((char *) 0, TRUE) == C('I')) identify_pack(0, FALSE); - /* [TODO? if player picks a specific inventory item, ID it] */ iflags.override_ID = 0; } else pline("Unavailable command '%s'.", diff --git a/src/invent.c b/src/invent.c index 6355a255a..ea7868e1d 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2279,6 +2279,19 @@ int id_limit; } } } +/* count the unidentified items */ +int +count_unidentified(objchn) +struct obj *objchn; +{ + int unid_cnt = 0; + struct obj *obj; + + for (obj = objchn; obj; obj = obj->nobj) + if (not_fully_identified(obj)) + ++unid_cnt; + return unid_cnt; +} /* dialog with user to identify a given number of items; 0 means all */ void @@ -2286,28 +2299,21 @@ identify_pack(id_limit, learning_id) int id_limit; boolean learning_id; /* true if we just read unknown identify scroll */ { - struct obj *obj, *the_obj; - int n, unid_cnt; - - unid_cnt = 0; - the_obj = 0; /* if unid_cnt ends up 1, this will be it */ - for (obj = invent; obj; obj = obj->nobj) - if (not_fully_identified(obj)) - ++unid_cnt, the_obj = obj; + struct obj *obj; + int n, unid_cnt = count_unidentified(invent); if (!unid_cnt) { You("have already identified all %sof your possessions.", learning_id ? "the rest " : ""); } else if (!id_limit || id_limit >= unid_cnt) { /* identify everything */ - if (unid_cnt == 1) { - (void) identify(the_obj); - } else { - /* TODO: use fully_identify_obj and cornline/menu/whatever here - */ - for (obj = invent; obj; obj = obj->nobj) - if (not_fully_identified(obj)) - (void) identify(obj); + /* TODO: use fully_identify_obj and cornline/menu/whatever here */ + for (obj = invent; obj; obj = obj->nobj) { + if (not_fully_identified(obj)) { + (void) identify(obj); + if (unid_cnt == 1) + break; + } } } else { /* identify up to `id_limit' items */ @@ -2491,7 +2497,7 @@ boolean want_reply; long *out_cnt; { static const char not_carrying_anything[] = "Not carrying anything"; - struct obj *otmp; + struct obj *otmp, wizid_fakeobj; char ilet, ret; char *invlet = flags.inv_order; int n, classcount; @@ -2500,6 +2506,7 @@ long *out_cnt; menu_item *selected; unsigned sortflags; Loot *sortedinvent, *srtinv; + boolean wizid = FALSE; if (lets && !*lets) lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */ @@ -2582,22 +2589,30 @@ long *out_cnt; start_menu(win); any = zeroany; if (wizard && iflags.override_ID) { + int unid_cnt; char prompt[QBUFSZ]; - /* C('I') == ^I == default keystroke for wiz_identify; - it is guaranteed not to be in use as an inventory letter - (wiz_identify might be remapped to an ordinary letter, - making iflags.override_ID ambiguous as a return value) */ - any.a_char = C('I'); - /* wiz_identify stuffed the wiz_identify command character (^I) - into iflags.override_ID for our use as an accelerator; - it could be ambiguous as a selector but the only time it - is wanted is in case where no item is being selected */ - Sprintf(prompt, "Debug Identify (%s to permanently identify)", - visctrl(iflags.override_ID)); - add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE, - prompt, MENU_UNSELECTED); - } else if (xtra_choice) { + unid_cnt = count_unidentified(invent); + if (!unid_cnt) { + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, + "(all items are permanently identified already)", + MENU_UNSELECTED); + } else { + any.a_obj = &wizid_fakeobj; + /* wiz_identify stuffed the wiz_identify command character (^I) + into iflags.override_ID for our use as an accelerator; + it could be ambiguous as a selector but the only time it + is wanted is in case where no item is being selected */ + Sprintf(prompt, + "Select any to identify permanently (%s for %s %d bolded item%s)", + visctrl(iflags.override_ID), + (unid_cnt == 1) ? "the" : "all", unid_cnt, + (unid_cnt > 1) ? "s" : ""); + add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE, + prompt, MENU_UNSELECTED); + wizid = TRUE; + } + } else if (xtra_choice) { /* wizard override ID and xtra_choice are mutually exclusive */ if (flags.sortpack) add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, @@ -2621,8 +2636,13 @@ nextclass: MENU_UNSELECTED); classcount++; } - any.a_char = ilet; - add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE, + if (wizid) + any.a_obj = otmp; + else + any.a_char = ilet; + add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, + (wizid && not_fully_identified(otmp)) ? + ATR_BOLD : ATR_NONE, doname(otmp), MENU_UNSELECTED); } } @@ -2655,11 +2675,31 @@ nextclass: } end_menu(win, query && *query ? query : (char *) 0); - n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); + n = select_menu(win, wizid ? PICK_ANY : + want_reply ? PICK_ONE : PICK_NONE, &selected); if (n > 0) { - ret = selected[0].item.a_char; - if (out_cnt) - *out_cnt = selected[0].count; + if (wizid) { + int i = n; + + ret = '\0'; + while (--i >= 0) { + otmp = selected[i].item.a_obj; + if (otmp == &wizid_fakeobj) { + /* C('I') == ^I == default keystroke for wiz_identify; + it is guaranteed not to be in use as an inventory letter + (wiz_identify might be remapped to an ordinary letter, + making iflags.override_ID ambiguous as a return value) */ + ret = C('I'); + } else { + if (not_fully_identified(otmp)) + (void) identify(otmp); + } + } + } else { + ret = selected[0].item.a_char; + if (out_cnt) + *out_cnt = selected[0].count; + } free((genericptr_t) selected); } else ret = !n ? '\0' : '\033'; /* cancelled */ From cd9c0e880a6f7df77b6314b0ee1197e4c42a9796 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 1 Sep 2018 11:16:08 -0400 Subject: [PATCH 02/15] adjust wizidentify title and prompt --- src/invent.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/invent.c b/src/invent.c index ea7868e1d..25280839b 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2593,6 +2593,9 @@ long *out_cnt; char prompt[QBUFSZ]; unid_cnt = count_unidentified(invent); + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, + "Debug Identify", + MENU_UNSELECTED); if (!unid_cnt) { add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "(all items are permanently identified already)", @@ -2604,10 +2607,10 @@ long *out_cnt; it could be ambiguous as a selector but the only time it is wanted is in case where no item is being selected */ Sprintf(prompt, - "Select any to identify permanently (%s for %s %d bolded item%s)", - visctrl(iflags.override_ID), - (unid_cnt == 1) ? "the" : "all", unid_cnt, - (unid_cnt > 1) ? "s" : ""); + "Select %sthe %d bolded item%s to permanently identify (%s for all)", + (unid_cnt == 1) ? "": "any of ", unid_cnt, + (unid_cnt > 1) ? "s" : "", + visctrl(iflags.override_ID)); add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE, prompt, MENU_UNSELECTED); wizid = TRUE; From 9e35a9409704f0d583b7522fa774aef879c68ab0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 1 Sep 2018 19:42:23 +0300 Subject: [PATCH 03/15] Fix pickup awful hack If pickup has been bound to some other key than ',', the awful hack did not work correctly. Testing, I couldn't notice the difference, but probably just not doing the right thing... --- src/hack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hack.c b/src/hack.c index 0687c0ef6..3246bb6af 100644 --- a/src/hack.c +++ b/src/hack.c @@ -2476,7 +2476,7 @@ dopickup() struct trap *traphere = t_at(u.ux, u.uy); /* awful kludge to work around parse()'s pre-decrement */ - count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0; + count = (multi || (save_cm && *save_cm == cmd_from_func(dopickup))) ? multi + 1 : 0; multi = 0; /* always reset */ /* uswallow case added by GAN 01/29/87 */ if (u.uswallow) { From 27d7f216c7e380118244340d776d19f78bf9633a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 1 Sep 2018 20:45:51 +0300 Subject: [PATCH 04/15] Split pickup checks out of dopickup --- src/hack.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/hack.c b/src/hack.c index 3246bb6af..2eb45803b 100644 --- a/src/hack.c +++ b/src/hack.c @@ -2468,16 +2468,14 @@ register boolean newlev; return; } -/* the ',' command */ +/* returns + 1 = cannot pickup, time taken + 0 = cannot pickup, no time taken + -1 = do normal pickup + -2 = loot the monster */ int -dopickup() +pickup_checks() { - int count, tmpcount; - struct trap *traphere = t_at(u.ux, u.uy); - - /* awful kludge to work around parse()'s pre-decrement */ - count = (multi || (save_cm && *save_cm == cmd_from_func(dopickup))) ? multi + 1 : 0; - multi = 0; /* always reset */ /* uswallow case added by GAN 01/29/87 */ if (u.uswallow) { if (!u.ustuck->minvent) { @@ -2489,8 +2487,7 @@ dopickup() Blind ? "feel" : "see"); return 1; } else { - tmpcount = -count; - return loot_mon(u.ustuck, &tmpcount, (boolean *) 0); + return -2; /* loot the monster inventory */ } } if (is_pool(u.ux, u.uy)) { @@ -2532,6 +2529,7 @@ dopickup() return 0; } if (!can_reach_floor(TRUE)) { + struct trap *traphere = t_at(u.ux, u.uy); if (traphere && uteetering_at_seen_pit(traphere)) You("cannot reach the bottom of the pit."); else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) @@ -2542,6 +2540,25 @@ dopickup() You("cannot reach the %s.", surface(u.ux, u.uy)); return 0; } + return -1; /* can do normal pickup */ +} + +/* the ',' command */ +int +dopickup() +{ + int count, tmpcount, ret; + + /* awful kludge to work around parse()'s pre-decrement */ + count = (multi || (save_cm && *save_cm == cmd_from_func(dopickup))) ? multi + 1 : 0; + multi = 0; /* always reset */ + + if ((ret = pickup_checks() >= 0)) + return ret; + else if (ret == -2) { + tmpcount = -count; + return loot_mon(u.ustuck, &tmpcount, (boolean *) 0); + } /* else ret == -1 */ return pickup(-count); } From 1462f69f54eb2c43f884ffd5002d7c596c79f373 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 1 Sep 2018 14:52:47 -0400 Subject: [PATCH 05/15] reports on windows of partial status lines after level change tty: turn off an optimization that is the suspected cause of Windows reported partial status lines following level changes. It was turned on for non-unix platforms only --- doc/fixes36.2 | 2 ++ win/tty/wintty.c | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 803c0abd9..fbf1544ba 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -112,6 +112,8 @@ fix access violation when --debug:xxxx has no other args after it setting the inverse attribute for gold had the space before "$:" getting highlighted along with the gold field sortloot segfaulted when filtering a subset of items (seen with 'A' command) +tty: turn off an optimization that is the suspected cause of Windows reported + partial status lines following level changes Platform- and/or Interface-Specific Fixes diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 42dad00c2..a0e2f66ed 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3552,11 +3552,13 @@ static boolean truncation_expected = FALSE; * for all platforms eventually and the conditional * setting below can be removed. */ -#if defined(UNIX) -static int do_field_opt = 0; +static int do_field_opt = +#if defined(ENABLE_TTY_FIELD_OPT) + 1; #else -static int do_field_opt = 1; + 0; #endif + #endif /* STATUS_HILITES */ /* @@ -3691,7 +3693,8 @@ unsigned long *colormasks; /* The core botl engine sends a single blank to the window port for carrying-capacity when its unused. Let's suppress that */ - if (tty_status[NOW][fldidx].lth == 1 && status_vals[fldidx][0] == ' ') { + if (fldidx != BL_FLUSH && + tty_status[NOW][fldidx].lth == 1 && status_vals[fldidx][0] == ' ') { status_vals[fldidx][0] = '\0'; tty_status[NOW][fldidx].lth = 0; } From b77f559d58a43ab9c0a1a743ca0ea9ca58005964 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 1 Sep 2018 15:07:19 -0400 Subject: [PATCH 06/15] quiet a new visual studio compiler complaint from recent code change ..\src\hack.c(2553): warning C4113: 'int (__cdecl *)()' differs in parameter lists from 'int (__cdecl *)(void)' --- src/hack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hack.c b/src/hack.c index 2eb45803b..cb92b93ad 100644 --- a/src/hack.c +++ b/src/hack.c @@ -2545,7 +2545,7 @@ pickup_checks() /* the ',' command */ int -dopickup() +dopickup(VOID_ARGS) { int count, tmpcount, ret; From e2b187f2f1e38987ece327f43ae6500ce5cd5567 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Sep 2018 17:54:00 -0400 Subject: [PATCH 07/15] transformation message when you apply a figurine make transformation message of a deliberate apply of a figurine seem a bit less definite when blind. Put 'I' unseen monster marker at the spot you expect it to be. --- doc/fixes36.2 | 3 +++ src/apply.c | 56 +++++++++++++++++---------------------------------- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index fbf1544ba..66171870b 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -104,6 +104,9 @@ wizard mode ^I^I didn't make temporary identifications become persistent if the build configuration makes plain 'char' unsigned wizard mode #wizidentify didn't disclose extra information for unID'd items if key bindings took away ^I and didn't bind #wizidentify to another key +make transformation message of a deliberate apply of a figurine seem a bit + less definite when blind and place unseen monster marker at the spot + you think it should be Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/apply.c b/src/apply.c index d7b770f4d..c40d1ac62 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 apply.c $NHDT-Date: 1526769961 2018/05/19 22:46:01 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.246 $ */ +/* NetHack 3.6 apply.c $NHDT-Date: 1519598527 2018/02/25 22:42:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.243 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -767,7 +767,7 @@ register xchar x, y; corpse less likely to remain tame after revival */ xkilled(mtmp, XKILL_NOMSG); /* life-saving doesn't ordinarily reset this */ - if (!DEADMONSTER(mtmp)) + if (mtmp->mhp > 0) u.uconduct.killer = save_pacifism; } else { pline("%s is choked by the leash!", Monnam(mtmp)); @@ -2865,41 +2865,21 @@ coord *pos; int min_range, max_range; { struct monst *mtmp; - coord mpos; - boolean impaired; - int x, y, lo_x, hi_x, lo_y, hi_y, rt, glyph; + struct monst *selmon = (struct monst *) 0; - if (Blind) - return FALSE; /* must be able to see target location */ - impaired = (Confusion || Stunned || Hallucination); - mpos.x = mpos.y = 0; /* no candidate location yet */ - rt = isqrt(max_range); - lo_x = max(u.ux - rt, 1), hi_x = min(u.ux + rt, COLNO - 1); - lo_y = max(u.uy - rt, 0), hi_y = min(u.uy + rt, ROWNO - 1); - for (x = lo_x; x <= hi_x; ++x) { - for (y = lo_y; y <= hi_y; ++y) { - if (distu(x, y) < min_range || distu(x, y) > max_range - || !isok(x, y) || !cansee(x, y)) - continue; - glyph = glyph_at(x, y); - if (!impaired - && glyph_is_monster(glyph) - && (mtmp = m_at(x, y)) != 0 - && (mtmp->mtame || (mtmp->mpeaceful && flags.confirm))) - continue; - if (glyph_is_monster(glyph) - || glyph_is_warning(glyph) - || glyph_is_invisible(glyph) - || (glyph_is_statue(glyph) && impaired)) { - if (mpos.x) - return FALSE; /* more than one candidate location */ - mpos.x = x, mpos.y = y; - } + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) + if (mtmp && !DEADMONSTER(mtmp) && !mtmp->mtame + && cansee(mtmp->mx, mtmp->my) + && distu(mtmp->mx, mtmp->my) <= max_range + && distu(mtmp->mx, mtmp->my) >= min_range) { + if (selmon) + return FALSE; + selmon = mtmp; } - } - if (!mpos.x) - return FALSE; /* no candidate location */ - *pos = mpos; + if (!selmon) + return FALSE; + pos->x = selmon->mx; + pos->y = selmon->my; return TRUE; } @@ -2907,8 +2887,8 @@ static int polearm_range_min = -1; static int polearm_range_max = -1; STATIC_OVL boolean -get_valid_polearm_position(x, y) -int x, y; +get_valid_polearm_position(x,y) +int x,y; { return (isok(x, y) && ACCESSIBLE(levl[x][y].typ) && distu(x, y) >= polearm_range_min @@ -3018,7 +2998,7 @@ struct obj *obj; return res; } - context.polearm.hitmon = (struct monst *) 0; + context.polearm.hitmon = NULL; /* Attack the monster there */ bhitpos = cc; if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != (struct monst *) 0) { From ee4c12b2388981926577d8095c314ab3490aff93 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Sep 2018 18:05:16 -0400 Subject: [PATCH 08/15] ensure BL_FLUSH always gets sent down to the window port whenever bot() is called with context.botlx set so that status updates work as expected after full screen clear after a level change Fixes #107 --- doc/fixes36.2 | 3 + src/botl.c | 974 +++++++++++++++++++------------------------------- 2 files changed, 362 insertions(+), 615 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 66171870b..bcd2e1670 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -107,6 +107,9 @@ wizard mode #wizidentify didn't disclose extra information for unID'd items if make transformation message of a deliberate apply of a figurine seem a bit less definite when blind and place unseen monster marker at the spot you think it should be +ensure BL_FLUSH always gets sent down to the window port whenever bot() is + called with context.botlx set so that status updates work as + expected after full screen clear after a level change Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/botl.c b/src/botl.c index a1ea62483..f58c45947 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1527042178 2018/05/23 02:22:58 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.101 $ */ +/* NetHack 3.6 botl.c $NHDT-Date: 1506903619 2017/10/02 00:20:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -446,25 +446,21 @@ STATIC_DCL boolean FDECL(is_ltgt_percentnumber, (const char *)); STATIC_DCL boolean FDECL(has_ltgt_percentnumber, (const char *)); STATIC_DCL boolean FDECL(parse_status_hl2, (char (*)[QBUFSZ],BOOLEAN_P)); STATIC_DCL boolean FDECL(parse_condition, (char (*)[QBUFSZ], int)); -STATIC_DCL boolean FDECL(noneoftheabove, (const char *)); STATIC_DCL void FDECL(merge_bestcolor, (int *, int)); STATIC_DCL void FDECL(get_hilite_color, (int, int, genericptr_t, int, - int, int *)); + int, int *)); STATIC_DCL unsigned long FDECL(match_str2conditionbitmask, (const char *)); STATIC_DCL unsigned long FDECL(str2conditionbitmask, (char *)); 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 *)); + 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 *, - BOOLEAN_P, BOOLEAN_P)); STATIC_DCL boolean FDECL(status_hilite_menu_add, (int)); #define has_hilite(i) (blstats[0][(i)].thresholds) #endif @@ -487,16 +483,15 @@ STATIC_DCL struct istat_s initblstats[MAXBLSTATS] = { INIT_BLSTAT("charisma", " Ch:%s", ANY_INT, 10, BL_CH), INIT_BLSTAT("alignment", " %s", ANY_STR, 40, BL_ALIGN), INIT_BLSTAT("score", " S:%s", ANY_LONG, 20, BL_SCORE), - INIT_BLSTAT("carrying-capacity", " %s", ANY_INT, 20, BL_CAP), + INIT_BLSTAT("carrying-capacity", " %s", ANY_LONG, 20, BL_CAP), INIT_BLSTAT("gold", " %s", ANY_LONG, 30, BL_GOLD), INIT_BLSTATP("power", " Pw:%s", ANY_INT, 10, BL_ENEMAX, BL_ENE), INIT_BLSTAT("power-max", "(%s)", ANY_INT, 10, BL_ENEMAX), - INIT_BLSTAT("experience-level", " Xp:%s", ANY_INT, 10, BL_XP), + INIT_BLSTAT("experience-level", " Xp:%s", ANY_LONG, 10, BL_XP), INIT_BLSTAT("armor-class", " AC:%s", ANY_INT, 10, BL_AC), INIT_BLSTAT("HD", " HD:%s", ANY_INT, 10, BL_HD), - INIT_BLSTAT("time", " T:%s", ANY_LONG, 20, BL_TIME), - /* hunger used to be 'ANY_UINT'; see note below in bot_via_windowport() */ - INIT_BLSTAT("hunger", " %s", ANY_INT, 40, BL_HUNGER), + INIT_BLSTAT("time", " T:%s", ANY_INT, 20, BL_TIME), + INIT_BLSTAT("hunger", " %s", ANY_UINT, 40, BL_HUNGER), INIT_BLSTATP("hitpoints", " HP:%s", ANY_INT, 10, BL_HPMAX, BL_HP), INIT_BLSTAT("hitpoints-max", "(%s)", ANY_INT, 10, BL_HPMAX), INIT_BLSTAT("dungeon-level", "%s", ANY_STR, 80, BL_LEVELDESC), @@ -635,17 +630,13 @@ bot_via_windowport() /* Experience */ blstats[idx][BL_XP].a.a_int = u.ulevel; - blstats[idx][BL_EXP].a.a_long = u.uexp; + blstats[idx][BL_EXP].a.a_int = u.uexp; /* Time (moves) */ blstats[idx][BL_TIME].a.a_long = moves; /* Hunger */ - /* note: u.uhs is unsigned, and 3.6.1's STATUS_HILITE defined - BL_HUNGER to be ANY_UINT, but that was the only non-int/non-long - numeric field so it's far simpler to treat it as plain int and - not need ANY_UINT handling at all */ - blstats[idx][BL_HUNGER].a.a_int = (int) u.uhs; + blstats[idx][BL_HUNGER].a.a_uint = u.uhs; Strcpy(blstats[idx][BL_HUNGER].val, (u.uhs != NOT_HUNGRY) ? hu_stat[u.uhs] : ""); valset[BL_HUNGER] = TRUE; @@ -867,10 +858,7 @@ boolean : TRUE; fieldname = initblstats[i].fldname; - if (fld == BL_TITLE && iflags.wc2_hitpointbar) - fieldfmt = "%-30s"; - else - fieldfmt = initblstats[i].fldfmt; + fieldfmt = initblstats[i].fldfmt; status_enablefield(fld, fieldname, fieldfmt, fldenabled); } update_all = TRUE; @@ -882,8 +870,7 @@ status_finish() int i; /* call the window port cleanup routine first */ - if (windowprocs.win_status_finish) - (*windowprocs.win_status_finish)(); + (*windowprocs.win_status_finish)(); /* free memory that we alloc'd now */ for (i = 0; i < MAXBLSTATS; ++i) { @@ -902,7 +889,7 @@ status_finish() blstats[1][i].thresholds = blstats[0][i].thresholds; temp = next; } - } + } #endif /* STATUS_HILITES */ } } @@ -924,7 +911,6 @@ init_blstats() #ifdef STATUS_HILITES struct hilite_s *keep_hilite_chain = blstats[i][j].thresholds; #endif - blstats[i][j] = initblstats[j]; blstats[i][j].a = zeroany; if (blstats[i][j].valwidth) { @@ -933,7 +919,8 @@ init_blstats() } else blstats[i][j].val = (char *) 0; #ifdef STATUS_HILITES - blstats[i][j].thresholds = keep_hilite_chain; + if (keep_hilite_chain) + blstats[i][j].thresholds = keep_hilite_chain; #endif } } @@ -1204,34 +1191,28 @@ static struct fieldid_t { const char *fieldname; enum statusfields fldid; } fieldids_alias[] = { - { "characteristics", BL_CHARACTERISTICS }, - { "encumbrance", BL_CAP }, - { "experience-points", BL_EXP }, - { "dx", BL_DX }, - { "co", BL_CO }, - { "con", BL_CO }, - { "points", BL_SCORE }, - { "cap", BL_CAP }, - { "pw", BL_ENE }, - { "pw-max", BL_ENEMAX }, - { "xl", BL_XP }, - { "xplvl", BL_XP }, - { "ac", BL_AC }, - { "hit-dice", BL_HD }, - { "turns", BL_TIME }, - { "hp", BL_HP }, - { "hp-max", BL_HPMAX }, - { "dgn", BL_LEVELDESC }, - { "xp", BL_EXP }, - { "exp", BL_EXP }, - { "flags", BL_CONDITION }, - {0, BL_FLUSH } + {"characteristics", BL_CHARACTERISTICS}, + {"dx", BL_DX}, + {"co", BL_CO}, + {"con", BL_CO}, + {"points", BL_SCORE}, + {"cap", BL_CAP}, + {"pw", BL_ENE}, + {"pw-max", BL_ENEMAX}, + {"xl", BL_XP}, + {"xplvl", BL_XP}, + {"ac", BL_AC}, + {"hit-dice", BL_HD}, + {"turns", BL_TIME}, + {"hp", BL_HP}, + {"hp-max", BL_HPMAX}, + {"dgn", BL_LEVELDESC}, + {"xp", BL_EXP}, + {"exp", BL_EXP}, + {"flags", BL_CONDITION}, + {0, BL_FLUSH} }; -/* format arguments */ -static const char threshold_value[] = "hilite_status threshold ", - is_out_of_range[] = " is out of range"; - /* field name to bottom line index */ STATIC_OVL enum statusfields fldname_to_bl_indx(name) @@ -1260,7 +1241,6 @@ const char *name; if (!nmatches) { /* check partial matches to canonical names */ int len = (int) strlen(name); - for (i = 0; i < SIZE(initblstats); i++) if (!strncmpi(name, initblstats[i].fldname, len)) { fld = initblstats[i].fld; @@ -1289,8 +1269,7 @@ long augmented_time; return FALSE; while (tl) { - /* only this style times out (includes general 'changed' - as well as specific 'up' and 'down') */ + /* only this style times out */ if (tl->behavior == BL_TH_UPDOWN) return TRUE; tl = tl->next; @@ -1313,20 +1292,6 @@ reset_status_hilites() context.botlx = TRUE; } -/* test whether the text from a title rule matches the string for - title-while-polymorphed in the 'textmatch' menu */ -STATIC_OVL boolean -noneoftheabove(hl_text) -const char *hl_text; -{ - if (fuzzymatch(hl_text, "none of the above", "\" -_", TRUE) - || fuzzymatch(hl_text, "(polymorphed)", "\"()", TRUE) - || fuzzymatch(hl_text, "none of the above (polymorphed)", - "\" -_()", TRUE)) - return TRUE; - return FALSE; -} - STATIC_OVL void merge_bestcolor(bestcolor, newcolor) int *bestcolor; @@ -1349,7 +1314,7 @@ int newcolor; /* * get_hilite_color - * + * * Figures out, based on the value and the * direction it is moving, the color that the field * should be displayed in. @@ -1381,133 +1346,79 @@ int *colorptr; { int bestcolor = NO_COLOR; struct hilite_s *hl; - anything *value = (anything *) vp; - char *txtstr; + anything *value = (anything *)vp; + char *txtstr, *cmpstr; if (!colorptr || fldidx < 0 || fldidx >= MAXBLSTATS) return; if (blstats[idx][fldidx].thresholds) { /* there are hilites set here */ - int max_pc = -1, min_pc = 101; - int max_val = -LARGEST_INT, min_val = LARGEST_INT; - boolean exactmatch = FALSE, updown = FALSE, changed = FALSE, - perc_or_abs = FALSE; + int max_pc = 0, min_pc = 100; + int max_val = 0, min_val = LARGEST_INT; + boolean exactmatch = FALSE; - /* min_/max_ are used to track best fit */ - 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; - /* among persistent highlights, if a 'percentage' or 'absolute' - rule has been matched, it takes precedence over 'always' */ - if (perc_or_abs && hl->behavior == BL_TH_ALWAYS_HILITE) - continue; + hl = blstats[idx][fldidx].thresholds; + while (hl) { switch (hl->behavior) { case BL_TH_VAL_PERCENTAGE: if (hl->rel == EQ_VALUE && pc == hl->value.a_int) { merge_bestcolor(&bestcolor, hl->coloridx); min_pc = max_pc = hl->value.a_int; - exactmatch = perc_or_abs = TRUE; - } else if (exactmatch) { - ; /* already found best fit, skip lt,ge,&c */ - } else if (hl->rel == LT_VALUE - && (pc < hl->value.a_int) + exactmatch = TRUE; + } else if (hl->rel == LT_VALUE && !exactmatch + && (hl->value.a_int >= pc) && (hl->value.a_int <= min_pc)) { merge_bestcolor(&bestcolor, hl->coloridx); min_pc = hl->value.a_int; - perc_or_abs = TRUE; - } else if (hl->rel == LE_VALUE - && (pc <= hl->value.a_int) - && (hl->value.a_int <= min_pc)) { - merge_bestcolor(&bestcolor, hl->coloridx); - min_pc = hl->value.a_int; - perc_or_abs = TRUE; - } else if (hl->rel == GT_VALUE - && (pc > hl->value.a_int) + } else if (hl->rel == GT_VALUE && !exactmatch + && (hl->value.a_int <= pc) && (hl->value.a_int >= max_pc)) { merge_bestcolor(&bestcolor, hl->coloridx); max_pc = hl->value.a_int; - perc_or_abs = TRUE; - } else if (hl->rel == GE_VALUE - && (pc >= hl->value.a_int) - && (hl->value.a_int >= max_pc)) { - merge_bestcolor(&bestcolor, hl->coloridx); - max_pc = hl->value.a_int; - perc_or_abs = TRUE; } 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); - updown = TRUE; - } else if (chg != 0 && hl->rel == EQ_VALUE && !updown) { + } else if (hl->rel == EQ_VALUE && chg) { merge_bestcolor(&bestcolor, hl->coloridx); - changed = TRUE; + min_val = max_val = hl->value.a_int; } 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; - exactmatch = perc_or_abs = TRUE; - } else if (exactmatch) { - ; /* already found best fit, skip lt,ge,&c */ - } else if (hl->rel == LT_VALUE - && (value->a_int < hl->value.a_int) - && (hl->value.a_int <= min_val)) { + exactmatch = TRUE; + } else if (hl->rel == LT_VALUE && !exactmatch + && (hl->value.a_int >= value->a_int) + && (hl->value.a_int < min_val)) { merge_bestcolor(&bestcolor, hl->coloridx); min_val = hl->value.a_int; - perc_or_abs = TRUE; - } else if (hl->rel == LE_VALUE - && (value->a_int <= hl->value.a_int) - && (hl->value.a_int <= min_val)) { - merge_bestcolor(&bestcolor, hl->coloridx); - min_val = hl->value.a_int; - perc_or_abs = TRUE; - } else if (hl->rel == GT_VALUE - && (value->a_int > hl->value.a_int) - && (hl->value.a_int >= max_val)) { + } else if (hl->rel == GT_VALUE && !exactmatch + && (hl->value.a_int <= value->a_int) + && (hl->value.a_int > max_val)) { merge_bestcolor(&bestcolor, hl->coloridx); max_val = hl->value.a_int; - perc_or_abs = TRUE; - } else if (hl->rel == GE_VALUE - && (value->a_int >= hl->value.a_int) - && (hl->value.a_int >= max_val)) { - merge_bestcolor(&bestcolor, hl->coloridx); - max_val = hl->value.a_int; - perc_or_abs = TRUE; } break; case BL_TH_TEXTMATCH: - txtstr = blstats[idx][fldidx].val; - if (fldidx == BL_TITLE) - /* " the ", skip past " the " */ - txtstr += (strlen(plname) + sizeof " the " - sizeof ""); - if (hl->rel == TXT_VALUE && hl->textmatch[0]) { - if (fuzzymatch(hl->textmatch, txtstr, "\" -_", TRUE)) { - merge_bestcolor(&bestcolor, hl->coloridx); - exactmatch = TRUE; - } else if (exactmatch) { - ; /* already found best fit, skip "noneoftheabove" */ - } else if (fldidx == BL_TITLE - && Upolyd && noneoftheabove(hl->textmatch)) { - merge_bestcolor(&bestcolor, hl->coloridx); - } + txtstr = dupstr(blstats[idx][fldidx].val); + cmpstr = txtstr; + if (fldidx == BL_TITLE) { + int len = (strlen(plname) + sizeof(" the")); + cmpstr += len; } + (void) trimspaces(cmpstr); + if (hl->rel == TXT_VALUE && hl->textmatch[0] && + !strcmpi(hl->textmatch, cmpstr)) { + merge_bestcolor(&bestcolor, hl->coloridx); + } + free(txtstr); break; case BL_TH_ALWAYS_HILITE: merge_bestcolor(&bestcolor, hl->coloridx); @@ -1517,7 +1428,8 @@ int *colorptr; default: break; } - } + hl = hl->next; + } } *colorptr = bestcolor; return; @@ -1528,14 +1440,15 @@ split_clridx(idx, coloridx, attrib) int idx; int *coloridx, *attrib; { - if (coloridx) - *coloridx = idx & 0x00FF; - if (attrib) - *attrib = (idx >> 8) & 0x00FF; + if (idx && coloridx && attrib) { + *coloridx = idx & 0x00FF; + *attrib = (idx & 0xFF00) >> 8; + } } + /* - * This is the parser for the hilite options. + * This is the parser for the hilite options * * parse_status_hl1() separates each hilite entry into * a set of field threshold/action component strings, @@ -1561,13 +1474,6 @@ boolean from_configfile; c = lowc(*op); if (c == ' ') { if (fldnum >= 1) { - if (fldnum == 1 && strcmpi(hsbuf[0], "title") == 0) { - /* spaces are allowed in title */ - hsbuf[fldnum][ccount++] = c; - hsbuf[fldnum][ccount] = '\0'; - op++; - continue; - } rslt = parse_status_hl2(hsbuf, from_configfile); if (!rslt) { badopt = TRUE; @@ -1598,29 +1504,21 @@ 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; { const char *s = str; - if (*s == '<' || *s == '>') - s++; - if (*s == '=') - s++; - if (*s == '-' || *s == '+') - s++; - if (!digit(*s)) - return FALSE; - while (digit(*s)) - s++; - if (*s == '%') - s++; + if (*s == '<' || *s == '>') s++; + while (digit(*s)) s++; + if (*s == '%') s++; + 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; @@ -1628,7 +1526,7 @@ const char *str; const char *s = str; while (*s) { - if (!index("<>=-+0123456789%", *s)) + if (!index("<>0123456789%", *s)) return FALSE; s++; } @@ -1745,15 +1643,22 @@ 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 = blstats[0][fld].thresholds; - blstats[0][fld].thresholds = new_hilite; - /* sort_hilites(fld) */ + new_hilite->next = (struct hilite_s *)0; + /* 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; } @@ -1768,16 +1673,19 @@ boolean from_configfile; int sidx = 0, i = -1, dt = -1; int coloridx = -1, successes = 0; int disp_attrib = 0; - boolean percent, changed, numeric, down, up, - gt, lt, ge, le, eq, txtval, always; + 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; const char *txt; enum statusfields fld = BL_FLUSH; struct hilite_s hilite; char tmpbuf[BUFSZ]; - static const char *aligntxt[] = { "chaotic", "neutral", "lawful" }; + const char *aligntxt[] = {"chaotic", "neutral", "lawful"}; /* hu_stat[] from eat.c has trailing spaces which foul up comparisons */ - static const char *hutxt[] = { "Satiated", "", "Hungry", "Weak", - "Fainting", "Fainted", "Starved" }; + const char *hutxt[] = {"Satiated", "", "Hungry", "Weak", + "Fainting", "Fainted", "Starved"}; /* Examples: 3.6.1: @@ -1812,124 +1720,119 @@ boolean from_configfile; return parse_condition(s, sidx); ++sidx; - while (s[sidx]) { + while(s[sidx]) { char buf[BUFSZ], **subfields; int sf = 0; /* subfield count */ int kidx; txt = (const char *)0; - percent = numeric = always = FALSE; - down = up = changed = FALSE; - gt = ge = eq = le = lt = txtval = FALSE; + percent = changed = numeric = FALSE; + down = up = FALSE; + gt = eq = lt = neq = txtval = FALSE; + always = FALSE; /* threshold value */ if (!s[sidx][0]) return TRUE; - 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; - if (*s[sidx + 1] == '\0' || !strcmpi(s[sidx], "always")) { + if (*s[sidx+1] == '\0' || !strcmpi(s[sidx], "always")) { /* "field/always/color" OR "field/color" */ always = TRUE; - if (*s[sidx + 1] == '\0') + if (*s[sidx+1] == '\0') sidx--; + goto do_rel; } else if (!strcmpi(s[sidx], "up") || !strcmpi(s[sidx], "down")) { if (!strcmpi(s[sidx], "down")) down = TRUE; else up = TRUE; changed = TRUE; - } else if (fld == BL_CAP + goto do_rel; + } else if (fld == BL_CAP && is_fld_arrayvalues(s[sidx], enc_stat, - SLT_ENCUMBER, OVERLOADED + 1, - &kidx)) { + SLT_ENCUMBER, OVERLOADED+1, &kidx)) { txt = enc_stat[kidx]; txtval = TRUE; + goto do_rel; } else if (fld == BL_ALIGN && is_fld_arrayvalues(s[sidx], aligntxt, 0, 3, &kidx)) { txt = aligntxt[kidx]; txtval = TRUE; + goto do_rel; } else if (fld == BL_HUNGER && is_fld_arrayvalues(s[sidx], hutxt, - SATIATED, STARVED + 1, &kidx)) { + SATIATED, STARVED+1, &kidx)) { txt = hu_stat[kidx]; /* store hu_stat[] val, not hutxt[] */ txtval = TRUE; + goto do_rel; } else if (!strcmpi(s[sidx], "changed")) { changed = TRUE; + goto do_rel; } else if (is_ltgt_percentnumber(s[sidx])) { - const char *op; - - tmp = s[sidx]; /* is_ltgt_() guarantees [<>]?=?[-+]?[0-9]+%? */ + tmp = s[sidx]; if (strchr(tmp, '%')) percent = TRUE; - if (*tmp == '<') { - if (tmp[1] == '=') - le = TRUE; - else - lt = TRUE; - } else if (*tmp == '>') { - if (tmp[1] == '=') - ge = TRUE; - else - gt = TRUE; + if (strchr(tmp, '<')) + lt = TRUE; + if (strchr(tmp, '>')) + gt = TRUE; + (void) stripchars(tmpbuf, "%<>", tmp); + tmp = tmpbuf; + while (*tmp) { + if (!index("0123456789", *tmp)) + return FALSE; + tmp++; } - /* '%', '<', '>' 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); numeric = TRUE; - dt = percent ? ANY_INT : initblstats[fld].anytype; - (void) s_to_anything(&hilite.value, tmp, dt); - - op = gt ? ">" : ge ? ">=" : lt ? "<" : le ? "<=" : "="; - if (dt == ANY_INT - /* AC is the only field where negative values make sense but - accept >-1 for other fields; reject <0 for non-AC */ - && (hilite.value.a_int - < ((fld == BL_AC) ? -128 : gt ? -1 : lt ? 1 : 0) - /* percentages have another more comprehensive check below */ - || hilite.value.a_int > (percent ? (lt ? 101 : 100) - : LARGEST_INT))) { - config_error_add("%s'%s%d%s'%s", threshold_value, - op, hilite.value.a_int, percent ? "%" : "", - is_out_of_range); + tmp = tmpbuf; + if (strlen(tmp) > 0) { + dt = initblstats[fld].anytype; + if (percent) + dt = ANY_INT; + (void) s_to_anything(&hilite.value, tmp, dt); + } else return FALSE; - } else if (dt == ANY_LONG - && (hilite.value.a_long < (gt ? -1L : lt ? 1L : 0L))) { - config_error_add("%s'%s%ld'%s", threshold_value, - op, hilite.value.a_long, is_out_of_range); - return FALSE; - } + if (!hilite.value.a_void && (strcmp(tmp, "0") != 0)) + return FALSE; } else if (initblstats[fld].anytype == ANY_STR) { txt = s[sidx]; txtval = TRUE; + goto do_rel; } else { config_error_add(has_ltgt_percentnumber(s[sidx]) ? "Wrong format '%s', expected a threshold number or percent" - : "Unknown behavior '%s'", - s[sidx]); + : "Unknown behavior '%s'", s[sidx]); return FALSE; } - - /* relationships {LT_VALUE, LE_VALUE, EQ_VALUE, GE_VALUE, GT_VALUE} */ - if (gt || up) +do_rel: + /* relationships { LT_VALUE, GT_VALUE, EQ_VALUE} */ + if (gt) hilite.rel = GT_VALUE; - else if (lt || down) + else if (eq) + hilite.rel = EQ_VALUE; + else if (lt) hilite.rel = LT_VALUE; - else if (ge) - hilite.rel = GE_VALUE; - else if (le) - hilite.rel = LE_VALUE; - else if (eq || percent || numeric || changed) + 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) hilite.rel = EQ_VALUE; else if (txtval) hilite.rel = TXT_VALUE; else hilite.rel = LT_VALUE; - if (initblstats[fld].anytype == ANY_STR && (percent || numeric)) { + if (initblstats[fld].anytype == ANY_STR + && (percent || numeric)) { config_error_add("Field '%s' does not support numeric values", initblstats[fld].fldname); return FALSE; @@ -1940,24 +1843,13 @@ boolean from_configfile; config_error_add("Cannot use percent with '%s'", initblstats[fld].fldname); return FALSE; - } else if ((hilite.value.a_int < -1) - || (hilite.value.a_int == -1 - && hilite.value.a_int != GT_VALUE) + } else if ((hilite.value.a_int < 0) || (hilite.value.a_int == 0 && hilite.rel == LT_VALUE) + || (hilite.value.a_int > 100) || (hilite.value.a_int == 100 - && 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); + && hilite.rel == GT_VALUE)) { + config_error_add("Illegal percentage value"); return FALSE; } } @@ -1980,7 +1872,6 @@ 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) @@ -1999,7 +1890,7 @@ boolean from_configfile; if (c >= CLR_MAX || coloridx != -1) return FALSE; coloridx = c; - } + } } if (coloridx == -1) coloridx = NO_COLOR; @@ -2025,7 +1916,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); } @@ -2160,7 +2051,6 @@ const char *str; if (!nmatches) { /* check partial matches to aliases */ int len = (int) strlen(str); - for (i = 0; i < SIZE(condition_aliases); i++) if (!strncmpi(str, condition_aliases[i].id, len)) { mask |= condition_aliases[i].bitmask; @@ -2224,7 +2114,7 @@ int sidx; if (!success) config_error_add("Missing condition(s)"); return success; - } + } Strcpy(buf, tmp); conditions_bitmask = str2conditionbitmask(buf); @@ -2287,18 +2177,18 @@ int sidx; else if (a == ATR_BOLD) cond_hilites[HL_ATTCLR_BOLD] |= conditions_bitmask; else if (a == ATR_NONE) { - cond_hilites[HL_ATTCLR_DIM] &= ~conditions_bitmask; - cond_hilites[HL_ATTCLR_BLINK] &= ~conditions_bitmask; - cond_hilites[HL_ATTCLR_ULINE] &= ~conditions_bitmask; - cond_hilites[HL_ATTCLR_INVERSE] &= ~conditions_bitmask; - cond_hilites[HL_ATTCLR_BOLD] &= ~conditions_bitmask; + cond_hilites[HL_ATTCLR_DIM] = 0UL; + cond_hilites[HL_ATTCLR_BLINK] = 0UL; + cond_hilites[HL_ATTCLR_ULINE] = 0UL; + cond_hilites[HL_ATTCLR_INVERSE] = 0UL; + cond_hilites[HL_ATTCLR_BOLD] = 0UL; } else { int k = match_str2clr(subfields[i]); if (k >= CLR_MAX) return FALSE; coloridx = k; - } + } } /* set the bits in the appropriate member of the condition array according to color chosen as index */ @@ -2326,7 +2216,7 @@ clear_status_hilites() blstats[1][i].thresholds = blstats[0][i].thresholds; temp = next; } - } + } } } @@ -2340,7 +2230,7 @@ char *buf; int k, first = 0; attbuf[0] = '\0'; - if (attrib == HL_NONE) { + if (attrib & HL_NONE) { Strcpy(buf, "normal"); return buf; } @@ -2374,7 +2264,8 @@ struct _status_hilite_line_str { struct _status_hilite_line_str *next; }; -static struct _status_hilite_line_str *status_hilite_str = 0; +struct _status_hilite_line_str *status_hilite_str = + (struct _status_hilite_line_str *) 0; static int status_hilite_str_id = 0; STATIC_OVL void @@ -2384,26 +2275,26 @@ struct hilite_s *hl; unsigned long mask; const char *str; { - struct _status_hilite_line_str *tmp, *nxt; + struct _status_hilite_line_str *tmp = (struct _status_hilite_line_str *) + alloc(sizeof(struct _status_hilite_line_str)); + struct _status_hilite_line_str *nxt = status_hilite_str; - tmp = (struct _status_hilite_line_str *) alloc(sizeof *tmp); - (void) memset(tmp, 0, sizeof *tmp); - tmp->next = (struct _status_hilite_line_str *) 0; + (void) memset(tmp, 0, sizeof(struct _status_hilite_line_str)); - tmp->id = ++status_hilite_str_id; + ++status_hilite_str_id; tmp->fld = fld; tmp->hl = hl; tmp->mask = mask; - if (fld == BL_TITLE) - Strcpy(tmp->str, str); - else - (void) stripchars(tmp->str, " ", str); + (void) stripchars(tmp->str, " ", str); - if ((nxt = status_hilite_str) != 0) { - while (nxt->next) + tmp->id = status_hilite_str_id; + + if (nxt) { + while (nxt && nxt->next) nxt = nxt->next; nxt->next = tmp; } else { + tmp->next = (struct _status_hilite_line_str *) 0; status_hilite_str = tmp; } } @@ -2411,7 +2302,8 @@ const char *str; STATIC_OVL void status_hilite_linestr_done() { - struct _status_hilite_line_str *nxt, *tmp = status_hilite_str; + struct _status_hilite_line_str *tmp = status_hilite_str; + struct _status_hilite_line_str *nxt; while (tmp) { nxt = tmp->next; @@ -2426,23 +2318,21 @@ STATIC_OVL int status_hilite_linestr_countfield(fld) int fld; { - struct _status_hilite_line_str *tmp; - boolean countall = (fld == BL_FLUSH); + struct _status_hilite_line_str *tmp = status_hilite_str; int count = 0; - for (tmp = status_hilite_str; tmp; tmp = tmp->next) { - if (countall || tmp->fld == fld) + while (tmp) { + if (tmp->fld == fld || fld == BL_FLUSH) count++; + tmp = tmp->next; } return count; } -/* used by options handling, doset(options.c) */ int count_status_hilites(VOID_ARGS) { int count; - status_hilite_linestr_gather(); count = status_hilite_linestr_countfield(BL_FLUSH); status_hilite_linestr_done(); @@ -2458,19 +2348,16 @@ status_hilite_linestr_gather_conditions() unsigned long clratr; } cond_maps[SIZE(valid_conditions)]; - (void) memset(cond_maps, 0, - SIZE(valid_conditions) * sizeof (struct _cond_map)); + (void)memset(cond_maps, 0, + sizeof(struct _cond_map) * SIZE(valid_conditions)); for (i = 0; i < SIZE(valid_conditions); i++) { int clr = NO_COLOR; int atr = HL_NONE; int j; - for (j = 0; j < CLR_MAX; j++) - if (cond_hilites[j] & valid_conditions[i].bitmask) { + if (cond_hilites[j] & valid_conditions[i].bitmask) clr = j; - break; - } if (cond_hilites[HL_ATTCLR_DIM] & valid_conditions[i].bitmask) atr |= HL_DIM; if (cond_hilites[HL_ATTCLR_BOLD] & valid_conditions[i].bitmask) @@ -2481,13 +2368,10 @@ status_hilite_linestr_gather_conditions() atr |= HL_ULINE; if (cond_hilites[HL_ATTCLR_INVERSE] & valid_conditions[i].bitmask) atr |= HL_INVERSE; - if (atr != HL_NONE) - atr &= ~HL_NONE; if (clr != NO_COLOR || atr != HL_NONE) { unsigned long ca = clr | (atr << 8); boolean added_condmap = FALSE; - for (j = 0; j < SIZE(valid_conditions); j++) if (cond_maps[j].clratr == ca) { cond_maps[j].bm |= valid_conditions[i].bitmask; @@ -2508,16 +2392,13 @@ status_hilite_linestr_gather_conditions() for (i = 0; i < SIZE(valid_conditions); i++) if (cond_maps[i].bm) { int clr = NO_COLOR, atr = HL_NONE; - split_clridx(cond_maps[i].clratr, &clr, &atr); if (clr != NO_COLOR || atr != HL_NONE) { char clrbuf[BUFSZ]; char attrbuf[BUFSZ]; char condbuf[BUFSZ]; char *tmpattr; - - (void) strNsubst(strcpy(clrbuf, clr2colorname(clr)), - " ", "-", 0); + (void) stripchars(clrbuf, " ", clr2colorname(clr)); tmpattr = hlattr2attrname(atr, attrbuf, BUFSZ); if (tmpattr) Sprintf(eos(clrbuf), "&%s", tmpattr); @@ -2559,24 +2440,21 @@ 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 (op) - Sprintf(behavebuf, "%s%d%%", op, hl->value.a_int); + 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); else impossible("hl->behavior=percentage, rel error"); break; @@ -2591,8 +2469,12 @@ struct hilite_s *hl; impossible("hl->behavior=updown, rel error"); break; case BL_TH_VAL_ABSOLUTE: - if (op) - Sprintf(behavebuf, "%s%d", op, hl->value.a_int); + 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); else impossible("hl->behavior=absolute, rel error"); break; @@ -2618,17 +2500,21 @@ struct hilite_s *hl; } split_clridx(hl->coloridx, &clr, &attr); - (void) strNsubst(strcpy(clrbuf, clr2colorname(clr)), " ", "-", 0); + if (clr != NO_COLOR) + (void) stripchars(clrbuf, " ", clr2colorname(clr)); if (attr != HL_UNDEF) { - if ((tmpattr = hlattr2attrname(attr, attrbuf, BUFSZ)) != 0) - Sprintf(eos(clrbuf), "&%s", tmpattr); + tmpattr = hlattr2attrname(attr, attrbuf, BUFSZ); + if (tmpattr) + Sprintf(eos(clrbuf), "%s%s", + (clr != NO_COLOR) ? "&" : "", + tmpattr); } Sprintf(buf, "%s/%s/%s", initblstats[hl->fld].fldname, behavebuf, clrbuf); return buf; } -STATIC_OVL int +int status_hilite_menu_choose_field() { winid tmpwin; @@ -2640,13 +2526,8 @@ status_hilite_menu_choose_field() start_menu(tmpwin); for (i = 0; i < MAXBLSTATS; i++) { -#ifndef SCORE_ON_BOTL - if (initblstats[i].fld == BL_SCORE - && !blstats[0][BL_SCORE].thresholds) - continue; -#endif any = zeroany; - any.a_int = (i + 1); + any.a_int = (i+1); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, initblstats[i].fldname, MENU_UNSELECTED); } @@ -2662,7 +2543,7 @@ status_hilite_menu_choose_field() return fld; } -STATIC_OVL int +int status_hilite_menu_choose_behavior(fld) int fld; { @@ -2708,8 +2589,7 @@ int fld; nopts++; } - if (fld != BL_CAP && fld != BL_HUNGER - && (at == ANY_INT || at == ANY_LONG)) { + 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, @@ -2725,8 +2605,7 @@ 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); @@ -2754,13 +2633,12 @@ int fld; return beh; } -STATIC_OVL int -status_hilite_menu_choose_updownboth(fld, str, ltok, gtok) +int +status_hilite_menu_choose_updownboth(fld, str) int fld; const char *str; -boolean ltok, gtok; { - int res, ret = NO_LTEQGT; + int res, ret = -2; winid tmpwin; char buf[BUFSZ]; anything any; @@ -2769,26 +2647,14 @@ boolean ltok, gtok; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); - if (ltok) { - if (str) - Sprintf(buf, "%s than %s", - (fld == BL_AC) ? "Better (lower)" : "Less", str); - else - Sprintf(buf, "Value goes down"); - any = zeroany; - any.a_int = 10 + LT_VALUE; - 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, "%s or less", str); + else + Sprintf(buf, "Value goes down"); + any = zeroany; + any.a_int = 10 + LT_VALUE; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + buf, MENU_UNSELECTED); if (str) Sprintf(buf, "Exactly %s", str); @@ -2799,26 +2665,15 @@ boolean ltok, gtok; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); - if (gtok) { - 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 (higher)" : "More", str); - else - Sprintf(buf, "Value goes up"); - any = zeroany; - any.a_int = 10 + GT_VALUE; - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + if (str) + Sprintf(buf, "%s or more", str); + else + Sprintf(buf, "Value goes up"); + any = zeroany; + any.a_int = 10 + GT_VALUE; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); - } + Sprintf(buf, "Select field %s value:", initblstats[fld].fldname); end_menu(tmpwin, buf); @@ -2838,7 +2693,7 @@ int origfld; { int fld; int behavior; - int lt_gt_eq; + int lt_gt_eq = 0; int clr = NO_COLOR, atr = HL_UNDEF; struct hilite_s hilite; unsigned long cond = 0UL; @@ -2859,64 +2714,55 @@ choose_field: colorqry[0] = '\0'; attrqry[0] = '\0'; - memset((genericptr_t) &hilite, 0, sizeof (struct hilite_s)); - hilite.next = (struct hilite_s *) 0; + 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; - return FALSE; + else + return FALSE; } hilite.behavior = behavior; choose_value: + if (behavior == BL_TH_VAL_PERCENTAGE || behavior == BL_TH_VAL_ABSOLUTE) { - char inbuf[BUFSZ], buf[BUFSZ]; - anything aval; - int val, dt; - boolean gotnum = FALSE, percent = (behavior == BL_TH_VAL_PERCENTAGE); - char *inp, *numstart; - const char *op; + char inbuf[BUFSZ] = DUMMY, buf[BUFSZ]; + int val; + boolean skipltgt = FALSE; + boolean gotnum = FALSE; + char *inp = inbuf; + char *numstart = inbuf; - lt_gt_eq = NO_LTEQGT; /* not set up yet */ inbuf[0] = '\0'; Sprintf(buf, "Enter %svalue for %s threshold:", - percent ? "percentage " : "", + (behavior == BL_TH_VAL_PERCENTAGE) ? "percentage " : "", initblstats[fld].fldname); getlin(buf, inbuf); if (inbuf[0] == '\0' || inbuf[0] == '\033') goto choose_behavior; - inp = numstart = trimspaces(inbuf); + inp = trimspaces(inbuf); if (!*inp) goto choose_behavior; - /* allow user to enter "<50%" or ">50" or just "50" - or <=50% or >=50 or =50 */ + /* allow user to enter "<50%" or ">50" or just "50" */ if (*inp == '>' || *inp == '<' || *inp == '=') { - lt_gt_eq = (*inp == '>') ? ((inp[1] == '=') ? GE_VALUE : GT_VALUE) - : (*inp == '<') ? ((inp[1] == '=') ? LE_VALUE : LT_VALUE) - : EQ_VALUE; - *inp++ = ' '; - numstart++; - if (lt_gt_eq == GE_VALUE || lt_gt_eq == LE_VALUE) { - *inp++ = ' '; - numstart++; - } - } - if (*inp == '-') { + lt_gt_eq = (*inp == '>') ? GT_VALUE + : (*inp == '<') ? LT_VALUE : EQ_VALUE; + skipltgt = TRUE; + *inp = ' '; inp++; - } else if (*inp == '+') { - *inp++ = ' '; numstart++; } while (digit(*inp)) { @@ -2924,12 +2770,11 @@ choose_value: gotnum = TRUE; } if (*inp == '%') { - if (!percent) { - pline("Not expecting a percentage."); - goto choose_behavior; - } - *inp = '\0'; /* strip '%' [this accepts trailing junk!] */ - } else if (*inp) { + behavior = BL_TH_VAL_PERCENTAGE; + *inp = '\0'; + } else if (!*inp) { + behavior = BL_TH_VAL_ABSOLUTE; + } else { /* some random characters */ pline("\"%s\" is not a recognized number.", inp); goto choose_value; @@ -2938,114 +2783,65 @@ choose_value: pline("Is that an invisible number?"); goto choose_value; } - op = (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 */ - aval = zeroany; - dt = percent ? ANY_INT : initblstats[fld].anytype; - (void) s_to_anything(&aval, numstart, dt); - - if (percent) { - val = aval.a_int; + val = atoi(numstart); + if (behavior == BL_TH_VAL_PERCENTAGE) { 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 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; for 0 and 100, choose_updown_both() - will prevent useless operations */ - 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.", op, val); + if (val < 0 || val > 100) { + pline("Not a valid percent value."); goto choose_value; } - /* restore suffix for use in color and attribute prompts */ - if (!index(numstart, '%')) - Strcat(numstart, "%"); - - /* reject negative values except for AC and >-1; reject 0 for < */ - } else if (dt == ANY_INT - && (aval.a_int < ((fld == BL_AC) ? -128 - : (lt_gt_eq == GT_VALUE) ? -1 - : (lt_gt_eq == LT_VALUE) ? 1 : 0))) { - pline("%s'%s%d'%s", threshold_value, - op, aval.a_int, is_out_of_range); - goto choose_value; - } else if (dt == ANY_LONG - && (aval.a_long < (lt_gt_eq == GT_VALUE) ? -1L - : (lt_gt_eq == LT_VALUE) ? 1L : 0L)) { - pline("%s'%s%ld'%s", threshold_value, - op, aval.a_long, is_out_of_range); - goto choose_value; } - if (lt_gt_eq == NO_LTEQGT) { - boolean ltok = ((dt == ANY_INT) - ? (aval.a_int > 0 || fld == BL_AC) - : (aval.a_long > 0L)), - gtok = (!percent || aval.a_long < 100); - - lt_gt_eq = status_hilite_menu_choose_updownboth(fld, inbuf, - ltok, gtok); - if (lt_gt_eq == NO_LTEQGT) + if (!skipltgt) { + lt_gt_eq = status_hilite_menu_choose_updownboth(fld, inbuf); + if (lt_gt_eq == -2) goto choose_value; } - Sprintf(colorqry, "Choose a color for when %s is %s%s%s:", + Sprintf(colorqry, "Choose a color for when %s is %s%s:", initblstats[fld].fldname, - (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" - : ""); - Sprintf(attrqry, "Choose attribute for when %s is %s%s%s:", + (lt_gt_eq == EQ_VALUE) ? "" + : (lt_gt_eq == LT_VALUE) ? " or less" + : " or more"); + + Sprintf(attrqry, "Choose attribute for when %s is %s%s:", initblstats[fld].fldname, - (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" - : ""); + inbuf, + (lt_gt_eq == EQ_VALUE) ? "" + : (lt_gt_eq == LT_VALUE) ? " or less" + : " or more"); hilite.rel = lt_gt_eq; - hilite.value = aval; + hilite.value.a_int = val; } else if (behavior == BL_TH_UPDOWN) { - boolean ltok = (fld != BL_TIME), gtok = TRUE; - - lt_gt_eq = status_hilite_menu_choose_updownboth(fld, (char *)0, - ltok, gtok); - if (lt_gt_eq == NO_LTEQGT) + lt_gt_eq = status_hilite_menu_choose_updownboth(fld, (char *)0); + if (lt_gt_eq == -2) 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; - return FALSE; + else + return FALSE; } Sprintf(colorqry, "Choose a color for conditions %s:", conditionbitmask2str(cond)); @@ -3053,7 +2849,6 @@ 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 @@ -3063,78 +2858,48 @@ 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) { - static const char *aligntxt[] = { "chaotic", "neutral", "lawful" }; + const char *aligntxt[] = {"chaotic", "neutral", "lawful"}; int rv = query_arrayvalue(qry_buf, - aligntxt, 0, 2 + 1); - + aligntxt, 0, 3); if (rv < 0) goto choose_behavior; hilite.rel = TXT_VALUE; Strcpy(hilite.textmatch, aligntxt[rv]); } else if (fld == BL_HUNGER) { - static const char *hutxt[] = { "Satiated", (char *) 0, "Hungry", - "Weak", "Fainting", "Fainted", - "Starved" }; + 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; hilite.rel = TXT_VALUE; Strcpy(hilite.textmatch, hutxt[rv]); } else if (fld == BL_TITLE) { - const char *rolelist[3 * 9 + 1]; - char mbuf[QBUFSZ], fbuf[QBUFSZ], obuf[QBUFSZ]; - int i, j, rv; + const char *rolelist[9]; + int i, rv; - for (i = j = 0; i < 9; i++) { - Sprintf(mbuf, "\"%s\"", urole.rank[i].m); - if (urole.rank[i].f) { - Sprintf(fbuf, "\"%s\"", urole.rank[i].f); - Sprintf(obuf, "%s or %s", - flags.female ? fbuf : mbuf, - flags.female ? mbuf : fbuf); - } else { - fbuf[0] = obuf[0] = '\0'; - } - if (flags.female) { - if (*fbuf) - rolelist[j++] = dupstr(fbuf); - rolelist[j++] = dupstr(mbuf); - if (*obuf) - rolelist[j++] = dupstr(obuf); - } else { - rolelist[j++] = dupstr(mbuf); - if (*fbuf) - rolelist[j++] = dupstr(fbuf); - if (*obuf) - rolelist[j++] = dupstr(obuf); - } - } - rolelist[j++] = dupstr("\"none of the above (polymorphed)\""); + for (i = 0; i < 9; i++) + rolelist[i] = (flags.female && urole.rank[i].f) + ? urole.rank[i].f : urole.rank[i].m; - rv = query_arrayvalue(qry_buf, rolelist, 0, j); - if (rv >= 0) { - hilite.rel = TXT_VALUE; - Strcpy(hilite.textmatch, rolelist[rv]); - } - for (i = 0; i < j; i++) - free((genericptr_t) rolelist[i]), rolelist[i] = 0; + rv = query_arrayvalue(qry_buf, rolelist, 0, 9); if (rv < 0) goto choose_behavior; + + hilite.rel = TXT_VALUE; + Strcpy(hilite.textmatch, rolelist[rv]); } else { - char inbuf[BUFSZ]; + char inbuf[BUFSZ] = DUMMY; inbuf[0] = '\0'; getlin(qry_buf, inbuf); @@ -3142,14 +2907,14 @@ 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; } Sprintf(colorqry, "Choose a color for when %s is '%s':", initblstats[fld].fldname, hilite.textmatch); - Sprintf(attrqry, "Choose attribute for when %s is '%s':", + Sprintf(colorqry, "Choose attribute for when %s is '%s':", initblstats[fld].fldname, hilite.textmatch); } else if (behavior == BL_TH_ALWAYS_HILITE) { Sprintf(colorqry, "Choose a color to always hilite %s:", @@ -3159,6 +2924,7 @@ choose_value: } choose_color: + clr = query_color(colorqry); if (clr == -1) { if (behavior != BL_TH_ALWAYS_HILITE) @@ -3166,59 +2932,60 @@ choose_color: else goto choose_behavior; } - atr = query_attr(attrqry); + + atr = query_attr(attrqry); /* FIXME: pick multiple attrs */ if (atr == -1) goto choose_color; + if (atr == ATR_DIM) + atr = HL_DIM; + else if (atr == ATR_BLINK) + atr = HL_BLINK; + else if (atr == ATR_ULINE) + atr = HL_ULINE; + else if (atr == ATR_INVERSE) + atr = HL_INVERSE; + else if (atr == ATR_BOLD) + atr = HL_BOLD; + else if (atr == ATR_NONE) + atr = HL_NONE; + else + atr = HL_UNDEF; + + if (clr == -1) + clr = NO_COLOR; if (behavior == BL_TH_CONDITION) { char clrbuf[BUFSZ]; char attrbuf[BUFSZ]; char *tmpattr; - - if (atr & HL_DIM) + if (atr == HL_DIM) cond_hilites[HL_ATTCLR_DIM] |= cond; - else if (atr & HL_BLINK) + else if (atr == HL_BLINK) cond_hilites[HL_ATTCLR_BLINK] |= cond; - else if (atr & HL_ULINE) + else if (atr == HL_ULINE) cond_hilites[HL_ATTCLR_ULINE] |= cond; - else if (atr & HL_INVERSE) + else if (atr == HL_INVERSE) cond_hilites[HL_ATTCLR_INVERSE] |= cond; - else if (atr & HL_BOLD) + else if (atr == HL_BOLD) cond_hilites[HL_ATTCLR_BOLD] |= cond; else if (atr == HL_NONE) { - cond_hilites[HL_ATTCLR_DIM] &= ~cond; - cond_hilites[HL_ATTCLR_BLINK] &= ~cond; - cond_hilites[HL_ATTCLR_ULINE] &= ~cond; - cond_hilites[HL_ATTCLR_INVERSE] &= ~cond; - cond_hilites[HL_ATTCLR_BOLD] &= ~cond; + cond_hilites[HL_ATTCLR_DIM] = 0UL; + cond_hilites[HL_ATTCLR_BLINK] = 0UL; + cond_hilites[HL_ATTCLR_ULINE] = 0UL; + cond_hilites[HL_ATTCLR_INVERSE] = 0UL; + cond_hilites[HL_ATTCLR_BOLD] = 0UL; } cond_hilites[clr] |= cond; - (void) strNsubst(strcpy(clrbuf, clr2colorname(clr)), " ", "-", 0); + (void) stripchars(clrbuf, " ", clr2colorname(clr)); tmpattr = hlattr2attrname(atr, attrbuf, BUFSZ); if (tmpattr) Sprintf(eos(clrbuf), "&%s", tmpattr); pline("Added hilite condition/%s/%s", conditionbitmask2str(cond), clrbuf); } else { - char *p, *q; - hilite.coloridx = clr | (atr << 8); hilite.anytype = initblstats[fld].anytype; - if (fld == BL_TITLE && (p = strstri(hilite.textmatch, " or ")) != 0) { - /* split menu choice "male-rank or female-rank" into two distinct - but otherwise identical rules, "male-rank" and "female-rank" */ - *p = '\0'; /* chop off " or female-rank" */ - /* new rule for male-rank */ - status_hilite_add_threshold(fld, &hilite); - pline("Added hilite %s", status_hilite2str(&hilite)); - /* transfer female-rank to start of hilite.textmatch buffer */ - p += sizeof " or " - sizeof ""; - q = hilite.textmatch; - while ((*q++ = *p++) != '\0') - continue; - /* proceed with normal addition of new rule */ - } status_hilite_add_threshold(fld, &hilite); pline("Added hilite %s", status_hilite2str(&hilite)); } @@ -3258,14 +3025,14 @@ int id; if (hl) { while (hl) { if (hlstr->hl == hl) { - if (hlprev) { + if (hlprev) hlprev->next = hl->next; - } else { + else { blstats[0][fld].thresholds = hl->next; blstats[1][fld].thresholds = blstats[0][fld].thresholds; } - free((genericptr_t) hl); + free(hl); return TRUE; } hlprev = hl; @@ -3329,31 +3096,19 @@ int fld; "Remove selected hilites", MENU_UNSELECTED); } -#ifndef SCORE_ON_BOTL - if (fld == BL_SCORE) { - /* suppress 'Z - Add a new hilite' for 'score' when SCORE_ON_BOTL - is disabled; we wouldn't be called for 'score' unless it has - hilite rules from the config file, so count must be positive - (hence there's no risk that we're putting up an empty menu) */ - ; - } else -#endif - { - any = zeroany; - any.a_int = -2; - add_menu(tmpwin, NO_GLYPH, &any, 'Z', 0, ATR_NONE, - "Add a new hilite", MENU_UNSELECTED); - } + any = zeroany; + any.a_int = -2; + add_menu(tmpwin, NO_GLYPH, &any, 'Z', 0, ATR_NONE, + "Add a new hilite", MENU_UNSELECTED); + Sprintf(buf, "Current %s hilites:", initblstats[fld].fldname); end_menu(tmpwin, buf); if ((res = select_menu(tmpwin, PICK_ANY, &picks)) > 0) { int mode = 0; - for (i = 0; i < res; i++) { int idx = picks[i].item.a_int; - if (idx == -1) { /* delete selected hilites */ if (mode) @@ -3373,7 +3128,6 @@ int fld; /* delete selected hilites */ for (i = 0; i < res; i++) { int idx = picks[i].item.a_int; - if (idx > 0) (void) status_hilite_remove(idx); } @@ -3406,7 +3160,7 @@ status_hilites_viewall() while (hlstr) { Sprintf(buf, "OPTIONS=hilite_status: %.*s", - (int) (BUFSZ - sizeof "OPTIONS=hilite_status: " - 1), + (int)(BUFSZ - sizeof "OPTIONS=hilite_status: " - 1), hlstr->str); putstr(datawin, 0, buf); hlstr = hlstr->next; @@ -3433,7 +3187,9 @@ shlmenu_redo: start_menu(tmpwin); status_hilite_linestr_gather(); + countall = status_hilite_linestr_countfield(BL_FLUSH); + if (countall) { any = zeroany; any.a_int = -1; @@ -3448,23 +3204,18 @@ shlmenu_redo: int count = status_hilite_linestr_countfield(i); char buf[BUFSZ]; -#ifndef SCORE_ON_BOTL - /* config file might contain rules for highlighting 'score' - even when SCORE_ON_BOTL is disabled; if so, 'O' command - menus will show them and allow deletions but not additions, - otherwise, it won't show 'score' at all */ - if (initblstats[i].fld == BL_SCORE && !count) - continue; -#endif any = zeroany; - any.a_int = i + 1; - Sprintf(buf, "%-18s", initblstats[i].fldname); + any.a_int = (i+1); if (count) - Sprintf(eos(buf), " (%d defined)", count); + Sprintf(buf, "%-18s (%i defined)", + initblstats[i].fldname, count); + else + Sprintf(buf, "%-18s", initblstats[i].fldname); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } + end_menu(tmpwin, "Status hilites:"); if ((res = select_menu(tmpwin, PICK_ONE, &picks)) > 0) { i = picks->item.a_int - 1; @@ -3472,24 +3223,17 @@ shlmenu_redo: status_hilites_viewall(); else (void) status_hilite_menu_fld(i); - free((genericptr_t) picks), picks = (menu_item *) 0; + free((genericptr_t) picks); redo = TRUE; } + picks = (menu_item *) 0; destroy_nhwindow(tmpwin); - countall = status_hilite_linestr_countfield(BL_FLUSH); status_hilite_linestr_done(); if (redo) goto shlmenu_redo; - /* hilite_delta=='statushilites' does double duty: it is the - number of turns for temporary highlights to remain visible - and also when non-zero it is the flag to enable highlighting */ - if (countall > 0 && !iflags.hilite_delta) - pline( - "To have highlights become active, set 'statushilites' option to non-zero."); - return TRUE; } From 9323f074f7269acbc601ea5b9d25df12b6f13a51 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Sep 2018 18:10:40 -0400 Subject: [PATCH 09/15] Revert "ensure BL_FLUSH always gets sent down to the window port whenever bot() is" This reverts commit ee4c12b2388981926577d8095c314ab3490aff93. --- doc/fixes36.2 | 3 - src/botl.c | 974 +++++++++++++++++++++++++++++++------------------- 2 files changed, 615 insertions(+), 362 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index bcd2e1670..66171870b 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -107,9 +107,6 @@ wizard mode #wizidentify didn't disclose extra information for unID'd items if make transformation message of a deliberate apply of a figurine seem a bit less definite when blind and place unseen monster marker at the spot you think it should be -ensure BL_FLUSH always gets sent down to the window port whenever bot() is - called with context.botlx set so that status updates work as - expected after full screen clear after a level change Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/botl.c b/src/botl.c index f58c45947..a1ea62483 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1506903619 2017/10/02 00:20:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */ +/* NetHack 3.6 botl.c $NHDT-Date: 1527042178 2018/05/23 02:22:58 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.101 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -446,21 +446,25 @@ STATIC_DCL boolean FDECL(is_ltgt_percentnumber, (const char *)); STATIC_DCL boolean FDECL(has_ltgt_percentnumber, (const char *)); STATIC_DCL boolean FDECL(parse_status_hl2, (char (*)[QBUFSZ],BOOLEAN_P)); STATIC_DCL boolean FDECL(parse_condition, (char (*)[QBUFSZ], int)); +STATIC_DCL boolean FDECL(noneoftheabove, (const char *)); STATIC_DCL void FDECL(merge_bestcolor, (int *, int)); STATIC_DCL void FDECL(get_hilite_color, (int, int, genericptr_t, int, - int, int *)); + int, int *)); STATIC_DCL unsigned long FDECL(match_str2conditionbitmask, (const char *)); STATIC_DCL unsigned long FDECL(str2conditionbitmask, (char *)); 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 *)); - + 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 *, + BOOLEAN_P, BOOLEAN_P)); STATIC_DCL boolean FDECL(status_hilite_menu_add, (int)); #define has_hilite(i) (blstats[0][(i)].thresholds) #endif @@ -483,15 +487,16 @@ STATIC_DCL struct istat_s initblstats[MAXBLSTATS] = { INIT_BLSTAT("charisma", " Ch:%s", ANY_INT, 10, BL_CH), INIT_BLSTAT("alignment", " %s", ANY_STR, 40, BL_ALIGN), INIT_BLSTAT("score", " S:%s", ANY_LONG, 20, BL_SCORE), - INIT_BLSTAT("carrying-capacity", " %s", ANY_LONG, 20, BL_CAP), + INIT_BLSTAT("carrying-capacity", " %s", ANY_INT, 20, BL_CAP), INIT_BLSTAT("gold", " %s", ANY_LONG, 30, BL_GOLD), INIT_BLSTATP("power", " Pw:%s", ANY_INT, 10, BL_ENEMAX, BL_ENE), INIT_BLSTAT("power-max", "(%s)", ANY_INT, 10, BL_ENEMAX), - INIT_BLSTAT("experience-level", " Xp:%s", ANY_LONG, 10, BL_XP), + INIT_BLSTAT("experience-level", " Xp:%s", ANY_INT, 10, BL_XP), INIT_BLSTAT("armor-class", " AC:%s", ANY_INT, 10, BL_AC), INIT_BLSTAT("HD", " HD:%s", ANY_INT, 10, BL_HD), - INIT_BLSTAT("time", " T:%s", ANY_INT, 20, BL_TIME), - INIT_BLSTAT("hunger", " %s", ANY_UINT, 40, BL_HUNGER), + INIT_BLSTAT("time", " T:%s", ANY_LONG, 20, BL_TIME), + /* hunger used to be 'ANY_UINT'; see note below in bot_via_windowport() */ + INIT_BLSTAT("hunger", " %s", ANY_INT, 40, BL_HUNGER), INIT_BLSTATP("hitpoints", " HP:%s", ANY_INT, 10, BL_HPMAX, BL_HP), INIT_BLSTAT("hitpoints-max", "(%s)", ANY_INT, 10, BL_HPMAX), INIT_BLSTAT("dungeon-level", "%s", ANY_STR, 80, BL_LEVELDESC), @@ -630,13 +635,17 @@ bot_via_windowport() /* Experience */ blstats[idx][BL_XP].a.a_int = u.ulevel; - blstats[idx][BL_EXP].a.a_int = u.uexp; + blstats[idx][BL_EXP].a.a_long = u.uexp; /* Time (moves) */ blstats[idx][BL_TIME].a.a_long = moves; /* Hunger */ - blstats[idx][BL_HUNGER].a.a_uint = u.uhs; + /* note: u.uhs is unsigned, and 3.6.1's STATUS_HILITE defined + BL_HUNGER to be ANY_UINT, but that was the only non-int/non-long + numeric field so it's far simpler to treat it as plain int and + not need ANY_UINT handling at all */ + blstats[idx][BL_HUNGER].a.a_int = (int) u.uhs; Strcpy(blstats[idx][BL_HUNGER].val, (u.uhs != NOT_HUNGRY) ? hu_stat[u.uhs] : ""); valset[BL_HUNGER] = TRUE; @@ -858,7 +867,10 @@ boolean : TRUE; fieldname = initblstats[i].fldname; - fieldfmt = initblstats[i].fldfmt; + if (fld == BL_TITLE && iflags.wc2_hitpointbar) + fieldfmt = "%-30s"; + else + fieldfmt = initblstats[i].fldfmt; status_enablefield(fld, fieldname, fieldfmt, fldenabled); } update_all = TRUE; @@ -870,7 +882,8 @@ status_finish() int i; /* call the window port cleanup routine first */ - (*windowprocs.win_status_finish)(); + if (windowprocs.win_status_finish) + (*windowprocs.win_status_finish)(); /* free memory that we alloc'd now */ for (i = 0; i < MAXBLSTATS; ++i) { @@ -889,7 +902,7 @@ status_finish() blstats[1][i].thresholds = blstats[0][i].thresholds; temp = next; } - } + } #endif /* STATUS_HILITES */ } } @@ -911,6 +924,7 @@ init_blstats() #ifdef STATUS_HILITES struct hilite_s *keep_hilite_chain = blstats[i][j].thresholds; #endif + blstats[i][j] = initblstats[j]; blstats[i][j].a = zeroany; if (blstats[i][j].valwidth) { @@ -919,8 +933,7 @@ init_blstats() } else blstats[i][j].val = (char *) 0; #ifdef STATUS_HILITES - if (keep_hilite_chain) - blstats[i][j].thresholds = keep_hilite_chain; + blstats[i][j].thresholds = keep_hilite_chain; #endif } } @@ -1191,28 +1204,34 @@ static struct fieldid_t { const char *fieldname; enum statusfields fldid; } fieldids_alias[] = { - {"characteristics", BL_CHARACTERISTICS}, - {"dx", BL_DX}, - {"co", BL_CO}, - {"con", BL_CO}, - {"points", BL_SCORE}, - {"cap", BL_CAP}, - {"pw", BL_ENE}, - {"pw-max", BL_ENEMAX}, - {"xl", BL_XP}, - {"xplvl", BL_XP}, - {"ac", BL_AC}, - {"hit-dice", BL_HD}, - {"turns", BL_TIME}, - {"hp", BL_HP}, - {"hp-max", BL_HPMAX}, - {"dgn", BL_LEVELDESC}, - {"xp", BL_EXP}, - {"exp", BL_EXP}, - {"flags", BL_CONDITION}, - {0, BL_FLUSH} + { "characteristics", BL_CHARACTERISTICS }, + { "encumbrance", BL_CAP }, + { "experience-points", BL_EXP }, + { "dx", BL_DX }, + { "co", BL_CO }, + { "con", BL_CO }, + { "points", BL_SCORE }, + { "cap", BL_CAP }, + { "pw", BL_ENE }, + { "pw-max", BL_ENEMAX }, + { "xl", BL_XP }, + { "xplvl", BL_XP }, + { "ac", BL_AC }, + { "hit-dice", BL_HD }, + { "turns", BL_TIME }, + { "hp", BL_HP }, + { "hp-max", BL_HPMAX }, + { "dgn", BL_LEVELDESC }, + { "xp", BL_EXP }, + { "exp", BL_EXP }, + { "flags", BL_CONDITION }, + {0, BL_FLUSH } }; +/* format arguments */ +static const char threshold_value[] = "hilite_status threshold ", + is_out_of_range[] = " is out of range"; + /* field name to bottom line index */ STATIC_OVL enum statusfields fldname_to_bl_indx(name) @@ -1241,6 +1260,7 @@ const char *name; if (!nmatches) { /* check partial matches to canonical names */ int len = (int) strlen(name); + for (i = 0; i < SIZE(initblstats); i++) if (!strncmpi(name, initblstats[i].fldname, len)) { fld = initblstats[i].fld; @@ -1269,7 +1289,8 @@ long augmented_time; return FALSE; while (tl) { - /* only this style times out */ + /* only this style times out (includes general 'changed' + as well as specific 'up' and 'down') */ if (tl->behavior == BL_TH_UPDOWN) return TRUE; tl = tl->next; @@ -1292,6 +1313,20 @@ reset_status_hilites() context.botlx = TRUE; } +/* test whether the text from a title rule matches the string for + title-while-polymorphed in the 'textmatch' menu */ +STATIC_OVL boolean +noneoftheabove(hl_text) +const char *hl_text; +{ + if (fuzzymatch(hl_text, "none of the above", "\" -_", TRUE) + || fuzzymatch(hl_text, "(polymorphed)", "\"()", TRUE) + || fuzzymatch(hl_text, "none of the above (polymorphed)", + "\" -_()", TRUE)) + return TRUE; + return FALSE; +} + STATIC_OVL void merge_bestcolor(bestcolor, newcolor) int *bestcolor; @@ -1314,7 +1349,7 @@ int newcolor; /* * get_hilite_color - * + * * Figures out, based on the value and the * direction it is moving, the color that the field * should be displayed in. @@ -1346,79 +1381,133 @@ int *colorptr; { int bestcolor = NO_COLOR; struct hilite_s *hl; - anything *value = (anything *)vp; - char *txtstr, *cmpstr; + anything *value = (anything *) vp; + char *txtstr; if (!colorptr || fldidx < 0 || fldidx >= MAXBLSTATS) return; if (blstats[idx][fldidx].thresholds) { /* there are hilites set here */ - int max_pc = 0, min_pc = 100; - int max_val = 0, min_val = LARGEST_INT; - boolean exactmatch = FALSE; + int max_pc = -1, min_pc = 101; + int max_val = -LARGEST_INT, min_val = LARGEST_INT; + boolean exactmatch = FALSE, updown = FALSE, changed = FALSE, + perc_or_abs = FALSE; - hl = blstats[idx][fldidx].thresholds; + /* min_/max_ are used to track best fit */ + 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; + /* among persistent highlights, if a 'percentage' or 'absolute' + rule has been matched, it takes precedence over 'always' */ + if (perc_or_abs && hl->behavior == BL_TH_ALWAYS_HILITE) + continue; - while (hl) { switch (hl->behavior) { case BL_TH_VAL_PERCENTAGE: if (hl->rel == EQ_VALUE && pc == hl->value.a_int) { merge_bestcolor(&bestcolor, hl->coloridx); min_pc = max_pc = hl->value.a_int; - exactmatch = TRUE; - } else if (hl->rel == LT_VALUE && !exactmatch - && (hl->value.a_int >= pc) + exactmatch = perc_or_abs = TRUE; + } else if (exactmatch) { + ; /* already found best fit, skip lt,ge,&c */ + } else if (hl->rel == LT_VALUE + && (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 - && (hl->value.a_int <= pc) + perc_or_abs = TRUE; + } else if (hl->rel == LE_VALUE + && (pc <= hl->value.a_int) + && (hl->value.a_int <= min_pc)) { + merge_bestcolor(&bestcolor, hl->coloridx); + min_pc = hl->value.a_int; + perc_or_abs = TRUE; + } else if (hl->rel == GT_VALUE + && (pc > hl->value.a_int) && (hl->value.a_int >= max_pc)) { merge_bestcolor(&bestcolor, hl->coloridx); max_pc = hl->value.a_int; + perc_or_abs = TRUE; + } else if (hl->rel == GE_VALUE + && (pc >= hl->value.a_int) + && (hl->value.a_int >= max_pc)) { + merge_bestcolor(&bestcolor, hl->coloridx); + max_pc = hl->value.a_int; + perc_or_abs = TRUE; } 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; - exactmatch = TRUE; - } else if (hl->rel == LT_VALUE && !exactmatch - && (hl->value.a_int >= value->a_int) - && (hl->value.a_int < min_val)) { + exactmatch = perc_or_abs = TRUE; + } else if (exactmatch) { + ; /* already found best fit, skip lt,ge,&c */ + } else if (hl->rel == LT_VALUE + && (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 - && (hl->value.a_int <= value->a_int) - && (hl->value.a_int > max_val)) { + perc_or_abs = TRUE; + } else if (hl->rel == LE_VALUE + && (value->a_int <= hl->value.a_int) + && (hl->value.a_int <= min_val)) { + merge_bestcolor(&bestcolor, hl->coloridx); + min_val = hl->value.a_int; + perc_or_abs = TRUE; + } else if (hl->rel == GT_VALUE + && (value->a_int > hl->value.a_int) + && (hl->value.a_int >= max_val)) { merge_bestcolor(&bestcolor, hl->coloridx); max_val = hl->value.a_int; + perc_or_abs = TRUE; + } else if (hl->rel == GE_VALUE + && (value->a_int >= hl->value.a_int) + && (hl->value.a_int >= max_val)) { + merge_bestcolor(&bestcolor, hl->coloridx); + max_val = hl->value.a_int; + perc_or_abs = TRUE; } break; case BL_TH_TEXTMATCH: - txtstr = dupstr(blstats[idx][fldidx].val); - cmpstr = txtstr; - if (fldidx == BL_TITLE) { - int len = (strlen(plname) + sizeof(" the")); - cmpstr += len; + txtstr = blstats[idx][fldidx].val; + if (fldidx == BL_TITLE) + /* " the ", skip past " the " */ + txtstr += (strlen(plname) + sizeof " the " - sizeof ""); + if (hl->rel == TXT_VALUE && hl->textmatch[0]) { + if (fuzzymatch(hl->textmatch, txtstr, "\" -_", TRUE)) { + merge_bestcolor(&bestcolor, hl->coloridx); + exactmatch = TRUE; + } else if (exactmatch) { + ; /* already found best fit, skip "noneoftheabove" */ + } else if (fldidx == BL_TITLE + && Upolyd && noneoftheabove(hl->textmatch)) { + merge_bestcolor(&bestcolor, hl->coloridx); + } } - (void) trimspaces(cmpstr); - if (hl->rel == TXT_VALUE && hl->textmatch[0] && - !strcmpi(hl->textmatch, cmpstr)) { - merge_bestcolor(&bestcolor, hl->coloridx); - } - free(txtstr); break; case BL_TH_ALWAYS_HILITE: merge_bestcolor(&bestcolor, hl->coloridx); @@ -1428,8 +1517,7 @@ int *colorptr; default: break; } - hl = hl->next; - } + } } *colorptr = bestcolor; return; @@ -1440,15 +1528,14 @@ split_clridx(idx, coloridx, attrib) int idx; int *coloridx, *attrib; { - if (idx && coloridx && attrib) { - *coloridx = idx & 0x00FF; - *attrib = (idx & 0xFF00) >> 8; - } + if (coloridx) + *coloridx = idx & 0x00FF; + if (attrib) + *attrib = (idx >> 8) & 0x00FF; } - /* - * This is the parser for the hilite options + * This is the parser for the hilite options. * * parse_status_hl1() separates each hilite entry into * a set of field threshold/action component strings, @@ -1474,6 +1561,13 @@ boolean from_configfile; c = lowc(*op); if (c == ' ') { if (fldnum >= 1) { + if (fldnum == 1 && strcmpi(hsbuf[0], "title") == 0) { + /* spaces are allowed in title */ + hsbuf[fldnum][ccount++] = c; + hsbuf[fldnum][ccount] = '\0'; + op++; + continue; + } rslt = parse_status_hl2(hsbuf, from_configfile); if (!rslt) { badopt = TRUE; @@ -1504,21 +1598,29 @@ 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; { const char *s = str; - if (*s == '<' || *s == '>') s++; - while (digit(*s)) s++; - if (*s == '%') s++; - + if (*s == '<' || *s == '>') + s++; + if (*s == '=') + s++; + if (*s == '-' || *s == '+') + s++; + if (!digit(*s)) + return FALSE; + while (digit(*s)) + s++; + if (*s == '%') + s++; 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; @@ -1526,7 +1628,7 @@ const char *str; const char *s = str; while (*s) { - if (!index("<>0123456789%", *s)) + if (!index("<>=-+0123456789%", *s)) return FALSE; s++; } @@ -1643,22 +1745,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; } @@ -1673,19 +1768,16 @@ 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; char tmpbuf[BUFSZ]; - const char *aligntxt[] = {"chaotic", "neutral", "lawful"}; + static const char *aligntxt[] = { "chaotic", "neutral", "lawful" }; /* hu_stat[] from eat.c has trailing spaces which foul up comparisons */ - const char *hutxt[] = {"Satiated", "", "Hungry", "Weak", - "Fainting", "Fainted", "Starved"}; + static const char *hutxt[] = { "Satiated", "", "Hungry", "Weak", + "Fainting", "Fainted", "Starved" }; /* Examples: 3.6.1: @@ -1720,119 +1812,124 @@ boolean from_configfile; return parse_condition(s, sidx); ++sidx; - while(s[sidx]) { + while (s[sidx]) { char buf[BUFSZ], **subfields; int sf = 0; /* subfield count */ 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]) return TRUE; - 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; - if (*s[sidx+1] == '\0' || !strcmpi(s[sidx], "always")) { + if (*s[sidx + 1] == '\0' || !strcmpi(s[sidx], "always")) { /* "field/always/color" OR "field/color" */ always = TRUE; - if (*s[sidx+1] == '\0') + if (*s[sidx + 1] == '\0') sidx--; - goto do_rel; } else if (!strcmpi(s[sidx], "up") || !strcmpi(s[sidx], "down")) { if (!strcmpi(s[sidx], "down")) down = TRUE; else up = TRUE; changed = TRUE; - goto do_rel; - } else if (fld == BL_CAP + } else if (fld == BL_CAP && is_fld_arrayvalues(s[sidx], enc_stat, - SLT_ENCUMBER, OVERLOADED+1, &kidx)) { + SLT_ENCUMBER, OVERLOADED + 1, + &kidx)) { txt = enc_stat[kidx]; txtval = TRUE; - goto do_rel; } else if (fld == BL_ALIGN && is_fld_arrayvalues(s[sidx], aligntxt, 0, 3, &kidx)) { txt = aligntxt[kidx]; txtval = TRUE; - goto do_rel; } else if (fld == BL_HUNGER && is_fld_arrayvalues(s[sidx], hutxt, - SATIATED, STARVED+1, &kidx)) { + SATIATED, STARVED + 1, &kidx)) { txt = hu_stat[kidx]; /* store hu_stat[] val, not hutxt[] */ txtval = TRUE; - goto do_rel; } else if (!strcmpi(s[sidx], "changed")) { changed = TRUE; - goto do_rel; } else if (is_ltgt_percentnumber(s[sidx])) { - tmp = s[sidx]; + const char *op; + + tmp = s[sidx]; /* is_ltgt_() guarantees [<>]?=?[-+]?[0-9]+%? */ if (strchr(tmp, '%')) percent = TRUE; - if (strchr(tmp, '<')) - lt = TRUE; - if (strchr(tmp, '>')) - gt = TRUE; - (void) stripchars(tmpbuf, "%<>", tmp); - tmp = tmpbuf; - while (*tmp) { - if (!index("0123456789", *tmp)) - return FALSE; - tmp++; + 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); numeric = TRUE; - tmp = tmpbuf; - if (strlen(tmp) > 0) { - dt = initblstats[fld].anytype; - if (percent) - dt = ANY_INT; - (void) s_to_anything(&hilite.value, tmp, dt); - } else + dt = percent ? ANY_INT : initblstats[fld].anytype; + (void) s_to_anything(&hilite.value, tmp, dt); + + op = gt ? ">" : ge ? ">=" : lt ? "<" : le ? "<=" : "="; + if (dt == ANY_INT + /* AC is the only field where negative values make sense but + accept >-1 for other fields; reject <0 for non-AC */ + && (hilite.value.a_int + < ((fld == BL_AC) ? -128 : gt ? -1 : lt ? 1 : 0) + /* percentages have another more comprehensive check below */ + || hilite.value.a_int > (percent ? (lt ? 101 : 100) + : LARGEST_INT))) { + config_error_add("%s'%s%d%s'%s", threshold_value, + op, hilite.value.a_int, percent ? "%" : "", + is_out_of_range); return FALSE; - if (!hilite.value.a_void && (strcmp(tmp, "0") != 0)) - return FALSE; + } else if (dt == ANY_LONG + && (hilite.value.a_long < (gt ? -1L : lt ? 1L : 0L))) { + config_error_add("%s'%s%ld'%s", threshold_value, + op, hilite.value.a_long, is_out_of_range); + return FALSE; + } } else if (initblstats[fld].anytype == ANY_STR) { txt = s[sidx]; txtval = TRUE; - goto do_rel; } else { config_error_add(has_ltgt_percentnumber(s[sidx]) ? "Wrong format '%s', expected a threshold number or percent" - : "Unknown behavior '%s'", s[sidx]); + : "Unknown behavior '%s'", + s[sidx]); return FALSE; } -do_rel: - /* 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; else hilite.rel = LT_VALUE; - if (initblstats[fld].anytype == ANY_STR - && (percent || numeric)) { + if (initblstats[fld].anytype == ANY_STR && (percent || numeric)) { config_error_add("Field '%s' does not support numeric values", initblstats[fld].fldname); return FALSE; @@ -1843,13 +1940,24 @@ do_rel: 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; } } @@ -1872,6 +1980,7 @@ do_rel: 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) @@ -1890,7 +1999,7 @@ do_rel: if (c >= CLR_MAX || coloridx != -1) return FALSE; coloridx = c; - } + } } if (coloridx == -1) coloridx = NO_COLOR; @@ -1916,7 +2025,7 @@ do_rel: 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); } @@ -2051,6 +2160,7 @@ const char *str; if (!nmatches) { /* check partial matches to aliases */ int len = (int) strlen(str); + for (i = 0; i < SIZE(condition_aliases); i++) if (!strncmpi(str, condition_aliases[i].id, len)) { mask |= condition_aliases[i].bitmask; @@ -2114,7 +2224,7 @@ int sidx; if (!success) config_error_add("Missing condition(s)"); return success; - } + } Strcpy(buf, tmp); conditions_bitmask = str2conditionbitmask(buf); @@ -2177,18 +2287,18 @@ int sidx; else if (a == ATR_BOLD) cond_hilites[HL_ATTCLR_BOLD] |= conditions_bitmask; else if (a == ATR_NONE) { - cond_hilites[HL_ATTCLR_DIM] = 0UL; - cond_hilites[HL_ATTCLR_BLINK] = 0UL; - cond_hilites[HL_ATTCLR_ULINE] = 0UL; - cond_hilites[HL_ATTCLR_INVERSE] = 0UL; - cond_hilites[HL_ATTCLR_BOLD] = 0UL; + cond_hilites[HL_ATTCLR_DIM] &= ~conditions_bitmask; + cond_hilites[HL_ATTCLR_BLINK] &= ~conditions_bitmask; + cond_hilites[HL_ATTCLR_ULINE] &= ~conditions_bitmask; + cond_hilites[HL_ATTCLR_INVERSE] &= ~conditions_bitmask; + cond_hilites[HL_ATTCLR_BOLD] &= ~conditions_bitmask; } else { int k = match_str2clr(subfields[i]); if (k >= CLR_MAX) return FALSE; coloridx = k; - } + } } /* set the bits in the appropriate member of the condition array according to color chosen as index */ @@ -2216,7 +2326,7 @@ clear_status_hilites() blstats[1][i].thresholds = blstats[0][i].thresholds; temp = next; } - } + } } } @@ -2230,7 +2340,7 @@ char *buf; int k, first = 0; attbuf[0] = '\0'; - if (attrib & HL_NONE) { + if (attrib == HL_NONE) { Strcpy(buf, "normal"); return buf; } @@ -2264,8 +2374,7 @@ struct _status_hilite_line_str { struct _status_hilite_line_str *next; }; -struct _status_hilite_line_str *status_hilite_str = - (struct _status_hilite_line_str *) 0; +static struct _status_hilite_line_str *status_hilite_str = 0; static int status_hilite_str_id = 0; STATIC_OVL void @@ -2275,26 +2384,26 @@ struct hilite_s *hl; unsigned long mask; const char *str; { - struct _status_hilite_line_str *tmp = (struct _status_hilite_line_str *) - alloc(sizeof(struct _status_hilite_line_str)); - struct _status_hilite_line_str *nxt = status_hilite_str; + struct _status_hilite_line_str *tmp, *nxt; - (void) memset(tmp, 0, sizeof(struct _status_hilite_line_str)); + tmp = (struct _status_hilite_line_str *) alloc(sizeof *tmp); + (void) memset(tmp, 0, sizeof *tmp); + tmp->next = (struct _status_hilite_line_str *) 0; - ++status_hilite_str_id; + tmp->id = ++status_hilite_str_id; tmp->fld = fld; tmp->hl = hl; tmp->mask = mask; - (void) stripchars(tmp->str, " ", str); + if (fld == BL_TITLE) + Strcpy(tmp->str, str); + else + (void) stripchars(tmp->str, " ", str); - tmp->id = status_hilite_str_id; - - if (nxt) { - while (nxt && nxt->next) + if ((nxt = status_hilite_str) != 0) { + while (nxt->next) nxt = nxt->next; nxt->next = tmp; } else { - tmp->next = (struct _status_hilite_line_str *) 0; status_hilite_str = tmp; } } @@ -2302,8 +2411,7 @@ const char *str; STATIC_OVL void status_hilite_linestr_done() { - struct _status_hilite_line_str *tmp = status_hilite_str; - struct _status_hilite_line_str *nxt; + struct _status_hilite_line_str *nxt, *tmp = status_hilite_str; while (tmp) { nxt = tmp->next; @@ -2318,21 +2426,23 @@ STATIC_OVL int status_hilite_linestr_countfield(fld) int fld; { - struct _status_hilite_line_str *tmp = status_hilite_str; + struct _status_hilite_line_str *tmp; + boolean countall = (fld == BL_FLUSH); int count = 0; - while (tmp) { - if (tmp->fld == fld || fld == BL_FLUSH) + for (tmp = status_hilite_str; tmp; tmp = tmp->next) { + if (countall || tmp->fld == fld) count++; - tmp = tmp->next; } return count; } +/* used by options handling, doset(options.c) */ int count_status_hilites(VOID_ARGS) { int count; + status_hilite_linestr_gather(); count = status_hilite_linestr_countfield(BL_FLUSH); status_hilite_linestr_done(); @@ -2348,16 +2458,19 @@ status_hilite_linestr_gather_conditions() unsigned long clratr; } cond_maps[SIZE(valid_conditions)]; - (void)memset(cond_maps, 0, - sizeof(struct _cond_map) * SIZE(valid_conditions)); + (void) memset(cond_maps, 0, + SIZE(valid_conditions) * sizeof (struct _cond_map)); for (i = 0; i < SIZE(valid_conditions); i++) { int clr = NO_COLOR; int atr = HL_NONE; int j; + for (j = 0; j < CLR_MAX; j++) - if (cond_hilites[j] & valid_conditions[i].bitmask) + if (cond_hilites[j] & valid_conditions[i].bitmask) { clr = j; + break; + } if (cond_hilites[HL_ATTCLR_DIM] & valid_conditions[i].bitmask) atr |= HL_DIM; if (cond_hilites[HL_ATTCLR_BOLD] & valid_conditions[i].bitmask) @@ -2368,10 +2481,13 @@ status_hilite_linestr_gather_conditions() atr |= HL_ULINE; if (cond_hilites[HL_ATTCLR_INVERSE] & valid_conditions[i].bitmask) atr |= HL_INVERSE; + if (atr != HL_NONE) + atr &= ~HL_NONE; if (clr != NO_COLOR || atr != HL_NONE) { unsigned long ca = clr | (atr << 8); boolean added_condmap = FALSE; + for (j = 0; j < SIZE(valid_conditions); j++) if (cond_maps[j].clratr == ca) { cond_maps[j].bm |= valid_conditions[i].bitmask; @@ -2392,13 +2508,16 @@ status_hilite_linestr_gather_conditions() for (i = 0; i < SIZE(valid_conditions); i++) if (cond_maps[i].bm) { int clr = NO_COLOR, atr = HL_NONE; + split_clridx(cond_maps[i].clratr, &clr, &atr); if (clr != NO_COLOR || atr != HL_NONE) { char clrbuf[BUFSZ]; char attrbuf[BUFSZ]; char condbuf[BUFSZ]; char *tmpattr; - (void) stripchars(clrbuf, " ", clr2colorname(clr)); + + (void) strNsubst(strcpy(clrbuf, clr2colorname(clr)), + " ", "-", 0); tmpattr = hlattr2attrname(atr, attrbuf, BUFSZ); if (tmpattr) Sprintf(eos(clrbuf), "&%s", tmpattr); @@ -2440,21 +2559,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; @@ -2469,12 +2591,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; @@ -2500,21 +2618,17 @@ struct hilite_s *hl; } split_clridx(hl->coloridx, &clr, &attr); - if (clr != NO_COLOR) - (void) stripchars(clrbuf, " ", clr2colorname(clr)); + (void) strNsubst(strcpy(clrbuf, clr2colorname(clr)), " ", "-", 0); if (attr != HL_UNDEF) { - tmpattr = hlattr2attrname(attr, attrbuf, BUFSZ); - if (tmpattr) - Sprintf(eos(clrbuf), "%s%s", - (clr != NO_COLOR) ? "&" : "", - tmpattr); + if ((tmpattr = hlattr2attrname(attr, attrbuf, BUFSZ)) != 0) + Sprintf(eos(clrbuf), "&%s", tmpattr); } Sprintf(buf, "%s/%s/%s", initblstats[hl->fld].fldname, behavebuf, clrbuf); return buf; } -int +STATIC_OVL int status_hilite_menu_choose_field() { winid tmpwin; @@ -2526,8 +2640,13 @@ status_hilite_menu_choose_field() start_menu(tmpwin); for (i = 0; i < MAXBLSTATS; i++) { +#ifndef SCORE_ON_BOTL + if (initblstats[i].fld == BL_SCORE + && !blstats[0][BL_SCORE].thresholds) + continue; +#endif any = zeroany; - any.a_int = (i+1); + any.a_int = (i + 1); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, initblstats[i].fldname, MENU_UNSELECTED); } @@ -2543,7 +2662,7 @@ status_hilite_menu_choose_field() return fld; } -int +STATIC_OVL int status_hilite_menu_choose_behavior(fld) int fld; { @@ -2589,7 +2708,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)) { any = zeroany; any.a_int = onlybeh = BL_TH_VAL_ABSOLUTE; add_menu(tmpwin, NO_GLYPH, &any, 'n', 0, ATR_NONE, @@ -2605,7 +2725,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); @@ -2633,12 +2754,13 @@ int fld; return beh; } -int -status_hilite_menu_choose_updownboth(fld, str) +STATIC_OVL int +status_hilite_menu_choose_updownboth(fld, str, ltok, gtok) int fld; const char *str; +boolean ltok, gtok; { - int res, ret = -2; + int res, ret = NO_LTEQGT; winid tmpwin; char buf[BUFSZ]; anything any; @@ -2647,14 +2769,26 @@ const char *str; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); - if (str) - Sprintf(buf, "%s or less", str); - else - Sprintf(buf, "Value goes down"); - any = zeroany; - any.a_int = 10 + LT_VALUE; - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, - buf, MENU_UNSELECTED); + if (ltok) { + if (str) + Sprintf(buf, "%s than %s", + (fld == BL_AC) ? "Better (lower)" : "Less", str); + else + Sprintf(buf, "Value goes down"); + any = zeroany; + any.a_int = 10 + LT_VALUE; + 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); @@ -2665,15 +2799,26 @@ const char *str; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); - if (str) - Sprintf(buf, "%s or more", str); - else - Sprintf(buf, "Value goes up"); - any = zeroany; - any.a_int = 10 + GT_VALUE; - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, - buf, MENU_UNSELECTED); + if (gtok) { + 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 (higher)" : "More", str); + else + Sprintf(buf, "Value goes up"); + any = zeroany; + any.a_int = 10 + GT_VALUE; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + buf, MENU_UNSELECTED); + } Sprintf(buf, "Select field %s value:", initblstats[fld].fldname); end_menu(tmpwin, buf); @@ -2693,7 +2838,7 @@ int origfld; { int fld; int behavior; - int lt_gt_eq = 0; + int lt_gt_eq; int clr = NO_COLOR, atr = HL_UNDEF; struct hilite_s hilite; unsigned long cond = 0UL; @@ -2714,55 +2859,64 @@ 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.next = (struct hilite_s *) 0; 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 gotnum = FALSE, percent = (behavior == BL_TH_VAL_PERCENTAGE); + char *inp, *numstart; + const char *op; + lt_gt_eq = NO_LTEQGT; /* not set up yet */ 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; - skipltgt = TRUE; - *inp = ' '; + lt_gt_eq = (*inp == '>') ? ((inp[1] == '=') ? GE_VALUE : GT_VALUE) + : (*inp == '<') ? ((inp[1] == '=') ? LE_VALUE : LT_VALUE) + : EQ_VALUE; + *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)) { @@ -2770,11 +2924,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; @@ -2783,65 +2938,114 @@ choose_value: pline("Is that an invisible number?"); goto choose_value; } + op = (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 = 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; for 0 and 100, choose_updown_both() + will prevent useless operations */ + 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.", op, val); goto choose_value; } + /* restore suffix for use in color and attribute prompts */ + if (!index(numstart, '%')) + Strcat(numstart, "%"); + + /* reject negative values except for AC and >-1; reject 0 for < */ + } else if (dt == ANY_INT + && (aval.a_int < ((fld == BL_AC) ? -128 + : (lt_gt_eq == GT_VALUE) ? -1 + : (lt_gt_eq == LT_VALUE) ? 1 : 0))) { + pline("%s'%s%d'%s", threshold_value, + op, aval.a_int, is_out_of_range); + goto choose_value; + } else if (dt == ANY_LONG + && (aval.a_long < (lt_gt_eq == GT_VALUE) ? -1L + : (lt_gt_eq == LT_VALUE) ? 1L : 0L)) { + pline("%s'%s%ld'%s", threshold_value, + op, aval.a_long, is_out_of_range); + goto choose_value; } - if (!skipltgt) { - lt_gt_eq = status_hilite_menu_choose_updownboth(fld, inbuf); - if (lt_gt_eq == -2) + if (lt_gt_eq == NO_LTEQGT) { + boolean ltok = ((dt == ANY_INT) + ? (aval.a_int > 0 || fld == BL_AC) + : (aval.a_long > 0L)), + gtok = (!percent || aval.a_long < 100); + + lt_gt_eq = status_hilite_menu_choose_updownboth(fld, inbuf, + ltok, gtok); + 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) + boolean ltok = (fld != BL_TIME), gtok = TRUE; + + lt_gt_eq = status_hilite_menu_choose_updownboth(fld, (char *)0, + ltok, gtok); + 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)); @@ -2849,6 +3053,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 @@ -2858,48 +3063,78 @@ 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; hilite.rel = TXT_VALUE; Strcpy(hilite.textmatch, hutxt[rv]); } else if (fld == BL_TITLE) { - const char *rolelist[9]; - int i, rv; + const char *rolelist[3 * 9 + 1]; + char mbuf[QBUFSZ], fbuf[QBUFSZ], obuf[QBUFSZ]; + int i, j, rv; - for (i = 0; i < 9; i++) - rolelist[i] = (flags.female && urole.rank[i].f) - ? urole.rank[i].f : urole.rank[i].m; + for (i = j = 0; i < 9; i++) { + Sprintf(mbuf, "\"%s\"", urole.rank[i].m); + if (urole.rank[i].f) { + Sprintf(fbuf, "\"%s\"", urole.rank[i].f); + Sprintf(obuf, "%s or %s", + flags.female ? fbuf : mbuf, + flags.female ? mbuf : fbuf); + } else { + fbuf[0] = obuf[0] = '\0'; + } + if (flags.female) { + if (*fbuf) + rolelist[j++] = dupstr(fbuf); + rolelist[j++] = dupstr(mbuf); + if (*obuf) + rolelist[j++] = dupstr(obuf); + } else { + rolelist[j++] = dupstr(mbuf); + if (*fbuf) + rolelist[j++] = dupstr(fbuf); + if (*obuf) + rolelist[j++] = dupstr(obuf); + } + } + rolelist[j++] = dupstr("\"none of the above (polymorphed)\""); - rv = query_arrayvalue(qry_buf, rolelist, 0, 9); + rv = query_arrayvalue(qry_buf, rolelist, 0, j); + if (rv >= 0) { + hilite.rel = TXT_VALUE; + Strcpy(hilite.textmatch, rolelist[rv]); + } + for (i = 0; i < j; i++) + free((genericptr_t) rolelist[i]), rolelist[i] = 0; if (rv < 0) goto choose_behavior; - - hilite.rel = TXT_VALUE; - Strcpy(hilite.textmatch, rolelist[rv]); } else { - char inbuf[BUFSZ] = DUMMY; + char inbuf[BUFSZ]; inbuf[0] = '\0'; getlin(qry_buf, inbuf); @@ -2907,14 +3142,14 @@ 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; } Sprintf(colorqry, "Choose a color for when %s is '%s':", initblstats[fld].fldname, hilite.textmatch); - Sprintf(colorqry, "Choose attribute for when %s is '%s':", + Sprintf(attrqry, "Choose attribute for when %s is '%s':", initblstats[fld].fldname, hilite.textmatch); } else if (behavior == BL_TH_ALWAYS_HILITE) { Sprintf(colorqry, "Choose a color to always hilite %s:", @@ -2924,7 +3159,6 @@ choose_value: } choose_color: - clr = query_color(colorqry); if (clr == -1) { if (behavior != BL_TH_ALWAYS_HILITE) @@ -2932,60 +3166,59 @@ choose_color: else goto choose_behavior; } - - atr = query_attr(attrqry); /* FIXME: pick multiple attrs */ + atr = query_attr(attrqry); if (atr == -1) goto choose_color; - if (atr == ATR_DIM) - atr = HL_DIM; - else if (atr == ATR_BLINK) - atr = HL_BLINK; - else if (atr == ATR_ULINE) - atr = HL_ULINE; - else if (atr == ATR_INVERSE) - atr = HL_INVERSE; - else if (atr == ATR_BOLD) - atr = HL_BOLD; - else if (atr == ATR_NONE) - atr = HL_NONE; - else - atr = HL_UNDEF; - - if (clr == -1) - clr = NO_COLOR; if (behavior == BL_TH_CONDITION) { char clrbuf[BUFSZ]; char attrbuf[BUFSZ]; char *tmpattr; - if (atr == HL_DIM) + + if (atr & HL_DIM) cond_hilites[HL_ATTCLR_DIM] |= cond; - else if (atr == HL_BLINK) + else if (atr & HL_BLINK) cond_hilites[HL_ATTCLR_BLINK] |= cond; - else if (atr == HL_ULINE) + else if (atr & HL_ULINE) cond_hilites[HL_ATTCLR_ULINE] |= cond; - else if (atr == HL_INVERSE) + else if (atr & HL_INVERSE) cond_hilites[HL_ATTCLR_INVERSE] |= cond; - else if (atr == HL_BOLD) + else if (atr & HL_BOLD) cond_hilites[HL_ATTCLR_BOLD] |= cond; else if (atr == HL_NONE) { - cond_hilites[HL_ATTCLR_DIM] = 0UL; - cond_hilites[HL_ATTCLR_BLINK] = 0UL; - cond_hilites[HL_ATTCLR_ULINE] = 0UL; - cond_hilites[HL_ATTCLR_INVERSE] = 0UL; - cond_hilites[HL_ATTCLR_BOLD] = 0UL; + cond_hilites[HL_ATTCLR_DIM] &= ~cond; + cond_hilites[HL_ATTCLR_BLINK] &= ~cond; + cond_hilites[HL_ATTCLR_ULINE] &= ~cond; + cond_hilites[HL_ATTCLR_INVERSE] &= ~cond; + cond_hilites[HL_ATTCLR_BOLD] &= ~cond; } cond_hilites[clr] |= cond; - (void) stripchars(clrbuf, " ", clr2colorname(clr)); + (void) strNsubst(strcpy(clrbuf, clr2colorname(clr)), " ", "-", 0); tmpattr = hlattr2attrname(atr, attrbuf, BUFSZ); if (tmpattr) Sprintf(eos(clrbuf), "&%s", tmpattr); pline("Added hilite condition/%s/%s", conditionbitmask2str(cond), clrbuf); } else { + char *p, *q; + hilite.coloridx = clr | (atr << 8); hilite.anytype = initblstats[fld].anytype; + if (fld == BL_TITLE && (p = strstri(hilite.textmatch, " or ")) != 0) { + /* split menu choice "male-rank or female-rank" into two distinct + but otherwise identical rules, "male-rank" and "female-rank" */ + *p = '\0'; /* chop off " or female-rank" */ + /* new rule for male-rank */ + status_hilite_add_threshold(fld, &hilite); + pline("Added hilite %s", status_hilite2str(&hilite)); + /* transfer female-rank to start of hilite.textmatch buffer */ + p += sizeof " or " - sizeof ""; + q = hilite.textmatch; + while ((*q++ = *p++) != '\0') + continue; + /* proceed with normal addition of new rule */ + } status_hilite_add_threshold(fld, &hilite); pline("Added hilite %s", status_hilite2str(&hilite)); } @@ -3025,14 +3258,14 @@ int id; if (hl) { while (hl) { if (hlstr->hl == hl) { - if (hlprev) + if (hlprev) { hlprev->next = hl->next; - else { + } else { blstats[0][fld].thresholds = hl->next; blstats[1][fld].thresholds = blstats[0][fld].thresholds; } - free(hl); + free((genericptr_t) hl); return TRUE; } hlprev = hl; @@ -3096,19 +3329,31 @@ int fld; "Remove selected hilites", MENU_UNSELECTED); } - any = zeroany; - any.a_int = -2; - add_menu(tmpwin, NO_GLYPH, &any, 'Z', 0, ATR_NONE, - "Add a new hilite", MENU_UNSELECTED); - +#ifndef SCORE_ON_BOTL + if (fld == BL_SCORE) { + /* suppress 'Z - Add a new hilite' for 'score' when SCORE_ON_BOTL + is disabled; we wouldn't be called for 'score' unless it has + hilite rules from the config file, so count must be positive + (hence there's no risk that we're putting up an empty menu) */ + ; + } else +#endif + { + any = zeroany; + any.a_int = -2; + add_menu(tmpwin, NO_GLYPH, &any, 'Z', 0, ATR_NONE, + "Add a new hilite", MENU_UNSELECTED); + } Sprintf(buf, "Current %s hilites:", initblstats[fld].fldname); end_menu(tmpwin, buf); if ((res = select_menu(tmpwin, PICK_ANY, &picks)) > 0) { int mode = 0; + for (i = 0; i < res; i++) { int idx = picks[i].item.a_int; + if (idx == -1) { /* delete selected hilites */ if (mode) @@ -3128,6 +3373,7 @@ int fld; /* delete selected hilites */ for (i = 0; i < res; i++) { int idx = picks[i].item.a_int; + if (idx > 0) (void) status_hilite_remove(idx); } @@ -3160,7 +3406,7 @@ status_hilites_viewall() while (hlstr) { Sprintf(buf, "OPTIONS=hilite_status: %.*s", - (int)(BUFSZ - sizeof "OPTIONS=hilite_status: " - 1), + (int) (BUFSZ - sizeof "OPTIONS=hilite_status: " - 1), hlstr->str); putstr(datawin, 0, buf); hlstr = hlstr->next; @@ -3187,9 +3433,7 @@ shlmenu_redo: start_menu(tmpwin); status_hilite_linestr_gather(); - countall = status_hilite_linestr_countfield(BL_FLUSH); - if (countall) { any = zeroany; any.a_int = -1; @@ -3204,18 +3448,23 @@ shlmenu_redo: int count = status_hilite_linestr_countfield(i); char buf[BUFSZ]; +#ifndef SCORE_ON_BOTL + /* config file might contain rules for highlighting 'score' + even when SCORE_ON_BOTL is disabled; if so, 'O' command + menus will show them and allow deletions but not additions, + otherwise, it won't show 'score' at all */ + if (initblstats[i].fld == BL_SCORE && !count) + continue; +#endif any = zeroany; - any.a_int = (i+1); + any.a_int = i + 1; + Sprintf(buf, "%-18s", initblstats[i].fldname); if (count) - Sprintf(buf, "%-18s (%i defined)", - initblstats[i].fldname, count); - else - Sprintf(buf, "%-18s", initblstats[i].fldname); + Sprintf(eos(buf), " (%d defined)", count); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } - end_menu(tmpwin, "Status hilites:"); if ((res = select_menu(tmpwin, PICK_ONE, &picks)) > 0) { i = picks->item.a_int - 1; @@ -3223,17 +3472,24 @@ shlmenu_redo: status_hilites_viewall(); else (void) status_hilite_menu_fld(i); - free((genericptr_t) picks); + free((genericptr_t) picks), picks = (menu_item *) 0; redo = TRUE; } - picks = (menu_item *) 0; destroy_nhwindow(tmpwin); + countall = status_hilite_linestr_countfield(BL_FLUSH); status_hilite_linestr_done(); if (redo) goto shlmenu_redo; + /* hilite_delta=='statushilites' does double duty: it is the + number of turns for temporary highlights to remain visible + and also when non-zero it is the flag to enable highlighting */ + if (countall > 0 && !iflags.hilite_delta) + pline( + "To have highlights become active, set 'statushilites' option to non-zero."); + return TRUE; } From 7bc0ce66e68f4e6f39e39a7422a29d95222f38ad Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Sep 2018 18:11:03 -0400 Subject: [PATCH 10/15] Revert "transformation message when you apply a figurine" This reverts commit e2b187f2f1e38987ece327f43ae6500ce5cd5567. --- doc/fixes36.2 | 3 --- src/apply.c | 56 ++++++++++++++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 66171870b..fbf1544ba 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -104,9 +104,6 @@ wizard mode ^I^I didn't make temporary identifications become persistent if the build configuration makes plain 'char' unsigned wizard mode #wizidentify didn't disclose extra information for unID'd items if key bindings took away ^I and didn't bind #wizidentify to another key -make transformation message of a deliberate apply of a figurine seem a bit - less definite when blind and place unseen monster marker at the spot - you think it should be Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/apply.c b/src/apply.c index c40d1ac62..d7b770f4d 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 apply.c $NHDT-Date: 1519598527 2018/02/25 22:42:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.243 $ */ +/* NetHack 3.6 apply.c $NHDT-Date: 1526769961 2018/05/19 22:46:01 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.246 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -767,7 +767,7 @@ register xchar x, y; corpse less likely to remain tame after revival */ xkilled(mtmp, XKILL_NOMSG); /* life-saving doesn't ordinarily reset this */ - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) u.uconduct.killer = save_pacifism; } else { pline("%s is choked by the leash!", Monnam(mtmp)); @@ -2865,21 +2865,41 @@ coord *pos; int min_range, max_range; { struct monst *mtmp; - struct monst *selmon = (struct monst *) 0; + coord mpos; + boolean impaired; + int x, y, lo_x, hi_x, lo_y, hi_y, rt, glyph; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) - if (mtmp && !DEADMONSTER(mtmp) && !mtmp->mtame - && cansee(mtmp->mx, mtmp->my) - && distu(mtmp->mx, mtmp->my) <= max_range - && distu(mtmp->mx, mtmp->my) >= min_range) { - if (selmon) - return FALSE; - selmon = mtmp; + if (Blind) + return FALSE; /* must be able to see target location */ + impaired = (Confusion || Stunned || Hallucination); + mpos.x = mpos.y = 0; /* no candidate location yet */ + rt = isqrt(max_range); + lo_x = max(u.ux - rt, 1), hi_x = min(u.ux + rt, COLNO - 1); + lo_y = max(u.uy - rt, 0), hi_y = min(u.uy + rt, ROWNO - 1); + for (x = lo_x; x <= hi_x; ++x) { + for (y = lo_y; y <= hi_y; ++y) { + if (distu(x, y) < min_range || distu(x, y) > max_range + || !isok(x, y) || !cansee(x, y)) + continue; + glyph = glyph_at(x, y); + if (!impaired + && glyph_is_monster(glyph) + && (mtmp = m_at(x, y)) != 0 + && (mtmp->mtame || (mtmp->mpeaceful && flags.confirm))) + continue; + if (glyph_is_monster(glyph) + || glyph_is_warning(glyph) + || glyph_is_invisible(glyph) + || (glyph_is_statue(glyph) && impaired)) { + if (mpos.x) + return FALSE; /* more than one candidate location */ + mpos.x = x, mpos.y = y; + } } - if (!selmon) - return FALSE; - pos->x = selmon->mx; - pos->y = selmon->my; + } + if (!mpos.x) + return FALSE; /* no candidate location */ + *pos = mpos; return TRUE; } @@ -2887,8 +2907,8 @@ static int polearm_range_min = -1; static int polearm_range_max = -1; STATIC_OVL boolean -get_valid_polearm_position(x,y) -int x,y; +get_valid_polearm_position(x, y) +int x, y; { return (isok(x, y) && ACCESSIBLE(levl[x][y].typ) && distu(x, y) >= polearm_range_min @@ -2998,7 +3018,7 @@ struct obj *obj; return res; } - context.polearm.hitmon = NULL; + context.polearm.hitmon = (struct monst *) 0; /* Attack the monster there */ bhitpos = cc; if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != (struct monst *) 0) { From 65948058112409634f2f6dc98a718ff0833139b5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Sep 2018 18:20:40 -0400 Subject: [PATCH 11/15] transformation message when you apply a figurine make the transformation message of a deliberate apply of a figurine seem a bit less definite when blind. Put 'I' unseen monster marker at the spot you expect it to be. --- doc/fixes36.2 | 3 +++ src/apply.c | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index fbf1544ba..66171870b 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -104,6 +104,9 @@ wizard mode ^I^I didn't make temporary identifications become persistent if the build configuration makes plain 'char' unsigned wizard mode #wizidentify didn't disclose extra information for unID'd items if key bindings took away ^I and didn't bind #wizidentify to another key +make transformation message of a deliberate apply of a figurine seem a bit + less definite when blind and place unseen monster marker at the spot + you think it should be Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/apply.c b/src/apply.c index d7b770f4d..07269a358 100644 --- a/src/apply.c +++ b/src/apply.c @@ -2236,16 +2236,19 @@ struct obj **optr; /* Passing FALSE arg here will result in messages displayed */ if (!figurine_location_checks(obj, &cc, FALSE)) return; - You("%s and it transforms.", + You("%s and it %stransforms.", (u.dx || u.dy) ? "set the figurine beside you" : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || is_pool(cc.x, cc.y)) ? "release the figurine" : (u.dz < 0 ? "toss the figurine into the air" - : "set the figurine on the ground")); + : "set the figurine on the ground"), + Blind ? "supposedly " : ""); (void) make_familiar(obj, cc.x, cc.y, FALSE); (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj)); useup(obj); + if (Blind) + map_invisible(cc.x, cc.y); *optr = 0; } From 0b32735ff85a5d1d166b9635e563db62fe459509 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Sep 2018 18:26:42 -0400 Subject: [PATCH 12/15] ensure BL_FLUSH always sent when context.botlx is set ensure BL_FLUSH always gets sent down to the window port whenever bot() is called with context.botlx set so that status updates work as expected after full screen clear after a level change Fixes #107 --- doc/fixes36.2 | 3 +++ src/botl.c | 33 ++++++++++++++++++++------------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 66171870b..89c6129ac 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -107,6 +107,9 @@ wizard mode #wizidentify didn't disclose extra information for unID'd items if make transformation message of a deliberate apply of a figurine seem a bit less definite when blind and place unseen monster marker at the spot you think it should be +ensure BL_FLUSH always gets sent down to the window port whenever bot() is + called with context.botlx set so that status updates work as + expected after full screen clear after a level change Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/botl.c b/src/botl.c index a1ea62483..dc862ab0e 100644 --- a/src/botl.c +++ b/src/botl.c @@ -770,8 +770,7 @@ evaluate_and_notify_windowport(valsetlist, idx, idx_p) int idx, idx_p; boolean *valsetlist; { - int i; - boolean updated = FALSE; + int i, updated = 0, notpresent = 0; /* * Now pass the changed values to window port. @@ -781,24 +780,32 @@ boolean *valsetlist; || ((i == BL_EXP) && !flags.showexp) || ((i == BL_TIME) && !flags.time) || ((i == BL_HD) && !Upolyd) - || ((i == BL_XP || i == BL_EXP) && Upolyd)) + || ((i == BL_XP || i == BL_EXP) && Upolyd)) { + notpresent++; continue; + } if (evaluate_and_notify_windowport_field(i, valsetlist, idx, idx_p)) - updated = TRUE; + updated++; } /* - * It is possible to get here, with nothing having been pushed - * to the window port, when none of the info has changed. In that - * case, we need to force a call to status_update() when - * context.botlx is set. The tty port in particular has a problem - * if that isn't done, since it sets context.botlx when a menu or - * text display obliterates the status line. + * Notes: + * 1. It is possible to get here, with nothing having been pushed + * to the window port, when none of the info has changed. * - * To work around it, we call status_update() with fictitious + * 2. Some window ports are also known to optimize by only drawing + * fields that have changed since the previous update. + * + * In both of those situations, we need to force updates to + * all of the fields when context.botlx is set. + * + * The tty port in particular has a problem + * if that isn't done, since it sets context.botlx when a menu or + * text display obliterates the status line. + * + * To trigger the full update we call status_update() with fictitious * index of BL_FLUSH (-1). */ - if ((context.botlx && !updated) - || (windowprocs.wincap2 & WC2_FLUSH_STATUS) != 0L) + if (context.botlx || (windowprocs.wincap2 & WC2_FLUSH_STATUS) != 0L) status_update(BL_FLUSH, (genericptr_t) 0, 0, 0, NO_COLOR, &cond_hilites[0]); From a417d67572cc08bcf81cdc55690fd9b6e5574bb5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 3 Sep 2018 08:18:18 -0400 Subject: [PATCH 13/15] status_update distinguish new BL_RESET from BL_FLUSH This adds BL_RESET to status_update to send a flag to a window port that every field should be updated because something has happened in the core to make current values shown to be untrustworthy or potentially obliterated. That is now distinguished from BL_FLUSH, which now has no bearing on whether every field needs to be redone, and instead can be used by a window port indicator that it is time to render any buffered status field changes to the display. tty port now sets WC2_FLUSH_STATUS indicator for BL_FLUSH support and now does one rendering per bot() call, instead of up to 22. Side note: The tty hitpoint bar code was relying on the old behavior of redrawing everything upon BL_FLUSH apparently, so it initially had some color change lag issues, corrected by marking BL_STATUS as dirty (in need of updating) in tty_status_update() whenever BL_HP was marked as dirty. --- doc/fixes36.2 | 12 ++++--- doc/window.doc | 4 +++ include/botl.h | 6 ++-- src/botl.c | 33 +++++++++++------- win/tty/wintty.c | 81 ++++++++++++++++++++++++++++----------------- win/win32/mswproc.c | 14 +++++--- 6 files changed, 97 insertions(+), 53 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 89c6129ac..c200e88f3 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -107,9 +107,10 @@ wizard mode #wizidentify didn't disclose extra information for unID'd items if make transformation message of a deliberate apply of a figurine seem a bit less definite when blind and place unseen monster marker at the spot you think it should be -ensure BL_FLUSH always gets sent down to the window port whenever bot() is - called with context.botlx set so that status updates work as - expected after full screen clear after a level change +add window port status_update() value BL_RESET to use as a flag to + redraw all status fields, distinguished from BL_FLUSH which now only + specifies that the bot() call has completed so any buffered changes + should now be rendered Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -125,7 +126,8 @@ tty: turn off an optimization that is the suspected cause of Windows reported Platform- and/or Interface-Specific Fixes ----------------------------------------- windows-gui: In nethackw, there could be conflicts between menu accelerators - and an extra choice accelerator to fix H7132. + and an extra choice accelerator to fix H7132. +windows-gui: recognize new BL_RESET in status_update; behavior currently the same windows-tty: Specify both width and height when creating font for width testing windows-tty: To counter lag problems that were occuring with the Win32 console port, implement a console back buffer to reduce the number of calls @@ -142,6 +144,8 @@ windows-tty: Use nhraykey by default if the players keyboard layout is windows-tty: We now support changing altkeyhandler in game windows: Added ntassert() mechanism for Windows based port use tty: significant optimizations for performance and per field rendering +tty: use WC2_FLUSH_STATUS to buffer changes until BL_FLUSH is received +tty: support BL_RESET in status_update to force an update to all status fields unix: Makefile.src and Makefile.utl inadvertently relied on a 'gnu make' extension when using $(VERBOSEMAKE) to reduce build-time feedback; replace with $(QUIETCC) which operates the same but defaults to diff --git a/doc/window.doc b/doc/window.doc index e648b23a4..59b90255d 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -412,6 +412,10 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percentage, int color BL_LEVELDESC, BL_EXP, BL_CONDITION -- fldindex could also be BL_FLUSH (-1), which is not really a field index, but is a special trigger to tell the + windowport that it should output all changes received + to this point. It marks the end of a bot() cycle. + -- fldindex could also be BL_RESET (-2), which is not really + a field index, but is a special advisory to to tell the windowport that it should redisplay all its status fields, even if no changes have been presented to it. -- ptr is usually a "char *", unless fldindex is BL_CONDITION. diff --git a/include/botl.h b/include/botl.h index 4d9347088..9e4e36595 100644 --- a/include/botl.h +++ b/include/botl.h @@ -28,8 +28,10 @@ Astral Plane \GXXXXNNNN:123456 HP:1234(1234) Pw:1234(1234) AC:-127 #endif enum statusfields { - BL_CHARACTERISTICS = -2, /* alias for BL_STR..BL_CH */ - BL_FLUSH = -1, BL_TITLE = 0, + BL_CHARACTERISTICS = -3, /* alias for BL_STR..BL_CH */ + BL_RESET = -2, /* Force everything to redisplay */ + BL_FLUSH = -1, /* Finished cycling through bot fields */ + 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, /* 13..18 */ diff --git a/src/botl.c b/src/botl.c index dc862ab0e..784438a14 100644 --- a/src/botl.c +++ b/src/botl.c @@ -736,7 +736,7 @@ boolean *valsetlist; if (update_all || chg || reset) { idxmax = curr->idxmax; - pc = (idxmax > BL_FLUSH) ? percentage(curr, &blstats[idx][idxmax]) : 0; + pc = (idxmax >= 0) ? percentage(curr, &blstats[idx][idxmax]) : 0; if (!valsetlist[fld]) (void) anything_to_s(curr->val, &curr->a, anytype); @@ -796,19 +796,27 @@ boolean *valsetlist; * fields that have changed since the previous update. * * In both of those situations, we need to force updates to - * all of the fields when context.botlx is set. + * all of the fields when context.botlx is set. The tty port in + * particular has a problem if that isn't done, since the core sets + * context.botlx when a menu or text display obliterates the status + * line. * - * The tty port in particular has a problem - * if that isn't done, since it sets context.botlx when a menu or - * text display obliterates the status line. + * For those situations, to trigger the full update of every field + * whether changed or not, call status_update() with BL_RESET. + * + * For regular processing and to notify the window port that a + * bot() round has finished and it's time to trigger a flush of + * all buffered changes received thus far but not reflected in + * the display, call status_update() with BL_FLUSH. * - * To trigger the full update we call status_update() with fictitious - * index of BL_FLUSH (-1). */ - if (context.botlx || (windowprocs.wincap2 & WC2_FLUSH_STATUS) != 0L) + if (context.botlx) + status_update(BL_RESET, (genericptr_t) 0, 0, 0, + NO_COLOR, &cond_hilites[0]); + else if ((windowprocs.wincap2 & WC2_FLUSH_STATUS) != 0L) status_update(BL_FLUSH, (genericptr_t) 0, 0, 0, NO_COLOR, &cond_hilites[0]); - + context.botl = context.botlx = 0; update_all = FALSE; } @@ -1943,7 +1951,7 @@ boolean from_configfile; } if (percent) { - if (initblstats[fld].idxmax <= BL_FLUSH) { + if (initblstats[fld].idxmax < 0) { config_error_add("Cannot use percent with '%s'", initblstats[fld].fldname); return FALSE; @@ -2681,7 +2689,7 @@ int fld; int at; int onlybeh = BL_TH_NONE, nopts = 0; - if (fld <= BL_FLUSH || fld >= MAXBLSTATS) + if (fld < 0 || fld >= MAXBLSTATS) return BL_TH_NONE; at = initblstats[fld].anytype; @@ -2724,7 +2732,7 @@ int fld; nopts++; } - if (initblstats[fld].idxmax > BL_FLUSH) { + if (initblstats[fld].idxmax >= 0) { any = zeroany; any.a_int = onlybeh = BL_TH_VAL_PERCENTAGE; add_menu(tmpwin, NO_GLYPH, &any, 'p', 0, ATR_NONE, @@ -2856,6 +2864,7 @@ choose_field: fld = origfld; if (fld == BL_FLUSH) { fld = status_hilite_menu_choose_field(); + /* isn't this redundant given what follows? */ if (fld == BL_FLUSH) return FALSE; } diff --git a/win/tty/wintty.c b/win/tty/wintty.c index a0e2f66ed..5ad7a3dcc 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -66,7 +66,7 @@ struct window_procs tty_procs = { | WC2_SELECTSAVED #endif #if defined(STATUS_HILITES) - | WC2_HILITE_STATUS | WC2_HITPOINTBAR + | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS #endif | WC2_DARKGRAY), tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event, @@ -3543,6 +3543,8 @@ static int cond_shrinklvl = 0, cond_width_at_shrink = 0; static int enclev = 0, enc_shrinklvl = 0; /* static int dl_shrinklvl = 0; */ static boolean truncation_expected = FALSE; +#define FORCE_RESET TRUE +#define NO_RESET FALSE /* This controls whether to skip fields that aren't * flagged as requiring updating during the current @@ -3553,10 +3555,10 @@ static boolean truncation_expected = FALSE; * setting below can be removed. */ static int do_field_opt = -#if defined(ENABLE_TTY_FIELD_OPT) - 1; -#else +#if defined(DISABLE_TTY_FIELD_OPT) 0; +#else + 1; #endif #endif /* STATUS_HILITES */ @@ -3573,7 +3575,7 @@ tty_status_init() int i; for (i = 0; i < MAXBLSTATS; ++i) { - tty_status[NOW][i].idx = -1; + tty_status[NOW][i].idx = BL_FLUSH; tty_status[NOW][i].color = NO_COLOR; /* no color */ tty_status[NOW][i].attr = ATR_NONE; tty_status[NOW][i].x = 0; @@ -3604,7 +3606,11 @@ tty_status_init() * BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, * BL_LEVELDESC, BL_EXP, BL_CONDITION * -- fldindex could also be BL_FLUSH (-1), which is not really - * a field index, but is a special trigger to tell the + * a field index, but is a special trigger to tell the + * windowport that it should output all changes received + * to this point. It marks the end of a bot() cycle. + * -- fldindex could also be BL_RESET (-3), which is not really + * a field index, but is a special advisory to to tell the * windowport that it should redisplay all its status fields, * even if no changes have been presented to it. * -- ptr is usually a "char *", unless fldindex is BL_CONDITION. @@ -3657,9 +3663,9 @@ unsigned long *colormasks; char *text = (char *) ptr; char *lastchar = (char *) 0; char *fval = (char *) 0; - boolean force_update = FALSE; + boolean reset_state = NO_RESET; - if (fldidx != BL_FLUSH && !status_activefields[fldidx]) + if ((fldidx >= 0 && fldidx < MAXBLSTATS) && !status_activefields[fldidx]) return; #ifndef TEXTCOLOR @@ -3667,9 +3673,13 @@ unsigned long *colormasks; #endif switch (fldidx) { + case BL_RESET: + reset_state = FORCE_RESET; + /* FALLTHRU */ case BL_FLUSH: - force_update = TRUE; - break; + if (make_things_fit(reset_state) || truncation_expected) + render_status(); + return; case BL_CONDITION: tty_status[NOW][fldidx].idx = fldidx; tty_condition_bits = *condptr; @@ -3693,7 +3703,7 @@ unsigned long *colormasks; /* The core botl engine sends a single blank to the window port for carrying-capacity when its unused. Let's suppress that */ - if (fldidx != BL_FLUSH && + if (fldidx >= 0 && fldidx < MAXBLSTATS && tty_status[NOW][fldidx].lth == 1 && status_vals[fldidx][0] == ' ') { status_vals[fldidx][0] = '\0'; tty_status[NOW][fldidx].lth = 0; @@ -3707,6 +3717,10 @@ unsigned long *colormasks; hpbar_percent = percent; hpbar_color = (color & 0x00FF); } + if (iflags.wc2_hitpointbar && (tty_procs.wincap2 & WC2_FLUSH_STATUS) != 0L) { + tty_status[NOW][BL_TITLE].color = hpbar_color; + tty_status[NOW][BL_TITLE].dirty = TRUE; + } break; case BL_LEVELDESC: case BL_HUNGER: @@ -3740,8 +3754,7 @@ unsigned long *colormasks; } break; } - if (make_things_fit(force_update) || truncation_expected) - render_status(); + /* 3.6.2 we only render on BL_FLUSH (or BL_RESET) */ return; } @@ -3805,7 +3818,7 @@ boolean forcefields; int *topsz, *bottomsz; { int c, i, row, col, trackx, idx; - boolean valid = TRUE, matchprev = FALSE, update_right; + boolean valid = TRUE, matchprev = FALSE, update_right, disregard; if (!windowdata_init && !check_windowdata()) return FALSE; @@ -3833,25 +3846,32 @@ int *topsz, *bottomsz; * Check values against those already on the dislay. * - Is the additional processing time for this worth it? */ - matchprev = FALSE; - if (do_field_opt && tty_status[NOW][idx].dirty) { - /* compare values */ - const char *ob, *nb; /* old byte, new byte */ + if (do_field_opt) { + matchprev = FALSE; + disregard = (tty_status[NOW][idx].lth == 0); + if (do_field_opt && !disregard + && tty_status[NOW][idx].dirty) { + /* compare values */ + const char *ob, *nb; /* old byte, new byte */ - c = col - 1; - ob = &wins[WIN_STATUS]->data[row][c]; - nb = status_vals[idx]; - while (*nb && c < wins[WIN_STATUS]->cols) { - if (*nb != *ob) - break; - nb++; - ob++; - c++; + c = col - 1; + ob = &wins[WIN_STATUS]->data[row][c]; + nb = status_vals[idx]; + while (*nb && c < wins[WIN_STATUS]->cols) { + if (*nb != *ob) + break; + nb++; + ob++; + c++; + } + if (!*nb && c > col - 1) + matchprev = TRUE; } - if (!*nb && c > col - 1) - matchprev = TRUE; + } else { + matchprev = FALSE; } } + /* * With STATUS_HILITES, it is possible that the color * needs to change even if the text is the same, so @@ -3861,7 +3881,8 @@ int *topsz, *bottomsz; * After the field has been updated, render_status() * will also clear .redraw and .dirty. */ - if (forcefields || update_right || !matchprev + if (forcefields || update_right + || (!matchprev && tty_status[NOW][idx].dirty && !disregard) || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) tty_status[NOW][idx].redraw = TRUE; diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 8f3e1ae1f..165efd34a 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -2857,10 +2857,14 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percent, int color, u BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION - -- fldindex could also be BL_FLUSH (-1), which is not really - a field index, but is a special trigger to tell the - windowport that it should redisplay all its status fields, - even if no changes have been presented to it. + -- fldindex could also be BL_FLUSH (-1), which is not really + a field index, but is a special trigger to tell the + windowport that it should output all changes received + to this point. It marks the end of a bot() cycle. + -- fldindex could also be BL_RESET (-3), which is not really + a field index, but is a special advisory to to tell the + windowport that it should redisplay all its status fields, + even if no changes have been presented to it. -- ptr is usually a "char *", unless fldindex is BL_CONDITION. If fldindex is BL_CONDITION, then ptr is a long value with any or none of the following bits set (from botl.h): @@ -2898,7 +2902,7 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", idx, ptr, chg, percent, color, colormasks); - if (idx != BL_FLUSH) { + if (idx != BL_FLUSH || idx == BL_RESET) { if (!_status_activefields[idx]) return; _status_percents[idx] = percent; From ec2258ae70f31637914de8056f6ee07519ad4ad4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 3 Sep 2018 08:49:47 -0400 Subject: [PATCH 14/15] mswproc.c bit --- win/win32/mswproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 165efd34a..63f7972d0 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -2902,7 +2902,7 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", idx, ptr, chg, percent, color, colormasks); - if (idx != BL_FLUSH || idx == BL_RESET) { + if (idx != BL_FLUSH && idx != BL_RESET) { if (!_status_activefields[idx]) return; _status_percents[idx] = percent; From 878823ad8aa7b76e8ec8052378b2856e41cad68c Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 3 Sep 2018 08:52:16 -0400 Subject: [PATCH 15/15] another mswproc bit - remove enum values from comments --- win/win32/mswproc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 63f7972d0..fb9ad0a94 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -2857,11 +2857,11 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percent, int color, u BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION - -- fldindex could also be BL_FLUSH (-1), which is not really + -- fldindex could also be BL_FLUSH, which is not really a field index, but is a special trigger to tell the windowport that it should output all changes received to this point. It marks the end of a bot() cycle. - -- fldindex could also be BL_RESET (-3), which is not really + -- fldindex could also be BL_RESET, which is not really a field index, but is a special advisory to to tell the windowport that it should redisplay all its status fields, even if no changes have been presented to it.