new 'showvers' option
Add options 'showvers' (boolean) and 'versinfo' (numeric mask) to show nethack's version on the status lines during play. It won't be particularly interesting to ordinary players but should be useful when making screenshots or video to be streamed, or for someone who switches between git branches or between nethack and variants. I worked on this several months back but it was combined with unfinished changes to 'hitpointbar'. I've separated it out so that it can be put into use. When enabled, one or more components of "<name> <branch> <version>" will be shown right justified after status conditions. At present the default is "<branch>" if that is available and overall status isn't 'released', or "<version>" if 'released' or if branch isn't available. That might need some refinement. It works as intended for tty and curses, although some abbreviation mechanism would be useful if/when the program resorts to abbreviating status conditions to make things narrow enough to fit. For X11, it works ok for fancy_status:True (the default, controlled via NetHack.ad settings) but is messed up for tty-style status. The text is positioned correctly but there are gaps in it, making it appear garbled, similar to what I saw when I tried and failed to implement statuslines:3 for X11. [It might be due to having empty condition widgets be 1 pixel wide instead of being totally removed but I don't think the situation is that simple.] For Qt, if the text needs to be truncated in order to fit, the center portion of the string will be shown, discarding parts from the left and right. That ought to discard from left and retain rightmost portion instead. For win32|mswin|Win GUI, no attempt to support it has been included. Things should be ok when 'showvers' is left as False (the default) but I don't know what will happen if that gets toggled to True. At a minimum, the version info won't be right justified. The information, or at least some of it, is displayed in the game window's title bar so there isn't any pressing need to add it to status, but toggling the option will need to behave sensibly if it doesn't already.
This commit is contained in:
76
src/botl.c
76
src/botl.c
@@ -106,9 +106,10 @@ do_statusline2(void)
|
||||
/* dungeon location (and gold), hero health (HP, PW, AC),
|
||||
experience (HD if poly'd, else Exp level and maybe Exp points),
|
||||
time (in moves), varying number of status conditions */
|
||||
dloc[QBUFSZ], hlth[QBUFSZ], expr[QBUFSZ], tmmv[QBUFSZ], cond[QBUFSZ];
|
||||
dloc[QBUFSZ], hlth[QBUFSZ], expr[QBUFSZ],
|
||||
tmmv[QBUFSZ], cond[QBUFSZ], vers[QBUFSZ];
|
||||
char *nb;
|
||||
size_t dln, dx, hln, xln, tln, cln;
|
||||
size_t dln, dx, hln, xln, tln, cln, vrn;
|
||||
int hp, hpmax, cap;
|
||||
long money;
|
||||
|
||||
@@ -206,6 +207,13 @@ do_statusline2(void)
|
||||
Strcpy(nb = eos(nb), " Ride");
|
||||
cln = strlen(cond);
|
||||
|
||||
/* version on status line, with leading space */
|
||||
if (flags.showvers)
|
||||
(void) status_version(vers, sizeof vers, TRUE);
|
||||
else
|
||||
vers[0] = '\0';
|
||||
vrn = strlen(vers);
|
||||
|
||||
/*
|
||||
* Put the pieces together. If they all fit, keep the traditional
|
||||
* sequence. Otherwise, move least important parts to the end in
|
||||
@@ -218,23 +226,24 @@ do_statusline2(void)
|
||||
* wider displays can still show wider status than the map if the
|
||||
* interface supports that.
|
||||
*/
|
||||
if ((dln - dx) + 1 + hln + 1 + xln + 1 + tln + 1 + cln <= COLNO) {
|
||||
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s", dloc, hlth, expr,
|
||||
tmmv, cond);
|
||||
if ((dln - dx) + 1 + hln + 1 + xln + 1 + tln + 1 + cln + vrn <= COLNO) {
|
||||
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s%s", dloc, hlth,
|
||||
expr, tmmv, cond, vers);
|
||||
} else {
|
||||
if (dln + 1 + hln + 1 + xln + 1 + tln + 1 + cln + 1 > MAXCO) {
|
||||
if (dln + 1 + hln + 1 + xln + 1 + tln + 1 + cln + vrn > MAXCO) {
|
||||
panic("bot2: second status line exceeds MAXCO (%u > %d)",
|
||||
(unsigned)(dln + 1 + hln + 1 + xln + 1 + tln + 1 + cln + 1),
|
||||
(unsigned) (dln + 1 + hln + 1 + xln + 1 + tln + 1 + cln
|
||||
+ vrn),
|
||||
MAXCO);
|
||||
} else if ((dln - dx) + 1 + hln + 1 + xln + 1 + cln <= COLNO) {
|
||||
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s", dloc, hlth,
|
||||
expr, cond, tmmv);
|
||||
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s%s", dloc, hlth,
|
||||
expr, cond, tmmv, vers);
|
||||
} else if ((dln - dx) + 1 + hln + 1 + cln <= COLNO) {
|
||||
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s", dloc, hlth,
|
||||
cond, expr, tmmv);
|
||||
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s%s", dloc, hlth,
|
||||
cond, expr, tmmv, vers);
|
||||
} else {
|
||||
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s", hlth, cond,
|
||||
dloc, expr, tmmv);
|
||||
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s%s", hlth, cond,
|
||||
dloc, expr, tmmv, vers);
|
||||
}
|
||||
/* only two or three consecutive spaces available to squeeze out */
|
||||
mungspaces(newbot2);
|
||||
@@ -567,7 +576,12 @@ static struct istat_s initblstats[MAXBLSTATS] = {
|
||||
INIT_BLSTAT("hitpoints-max", "(%s)", ANY_INT, 10, BL_HPMAX),
|
||||
INIT_BLSTAT("dungeon-level", "%s", ANY_STR, MAXVALWIDTH, BL_LEVELDESC),
|
||||
INIT_BLSTATP("experience", "/%s", ANY_LONG, 20, BL_EXP, BL_EXP),
|
||||
INIT_BLSTAT("condition", "%s", ANY_MASK32, 0, BL_CONDITION)
|
||||
INIT_BLSTAT("condition", "%s", ANY_MASK32, 0, BL_CONDITION),
|
||||
/* optional; once set it doesn't change unless 'showvers' option is
|
||||
toggled or player modifies the 'versinfo' option;
|
||||
available mostly for screenshots or someone looking over shoulder;
|
||||
blstat[][BL_VERS] is actually an int copy of flags.versinfo (0...7) */
|
||||
INIT_BLSTAT("version", " %s", ANY_STR, MAXVALWIDTH, BL_VERS),
|
||||
};
|
||||
|
||||
#undef INIT_BLSTATP
|
||||
@@ -873,6 +887,18 @@ bot_via_windowport(void)
|
||||
(cap > UNENCUMBERED) ? enc_stat[cap] : "");
|
||||
gv.valset[BL_CAP] = TRUE;
|
||||
|
||||
/* Version; unchanging unless player toggles 'showvers' option or
|
||||
modifies 'versinfo' option; toggling showvers off will clear it */
|
||||
if (gb.blstats[idx][BL_VERS].a.a_int != (int) flags.versinfo) {
|
||||
gb.blstats[idx][BL_VERS].a.a_int = (int) flags.versinfo;
|
||||
gv.valset[BL_VERS] = FALSE;
|
||||
}
|
||||
if (!gv.valset[BL_VERS]) {
|
||||
(void) status_version(gb.blstats[idx][BL_VERS].val,
|
||||
gb.blstats[idx][BL_VERS].valwidth, FALSE);
|
||||
gv.valset[BL_VERS] = TRUE;
|
||||
}
|
||||
|
||||
/* Conditions */
|
||||
|
||||
gb.blstats[idx][BL_CONDITION].a.a_ulong = 0L;
|
||||
@@ -1342,21 +1368,24 @@ evaluate_and_notify_windowport(
|
||||
boolean *valsetlist,
|
||||
int idx)
|
||||
{
|
||||
int i, updated = 0, notpresent UNUSED = 0;
|
||||
int i, fld, updated = 0, notpresent UNUSED = 0;
|
||||
|
||||
/*
|
||||
* Now pass the changed values to window port.
|
||||
*/
|
||||
for (i = 0; i < MAXBLSTATS; i++) {
|
||||
if (((i == BL_SCORE) && !flags.showscore)
|
||||
|| ((i == BL_EXP) && !flags.showexp)
|
||||
|| ((i == BL_TIME) && !flags.time)
|
||||
|| ((i == BL_HD) && !Upolyd)
|
||||
|| ((i == BL_XP || i == BL_EXP) && Upolyd)) {
|
||||
fld = initblstats[i].fld;
|
||||
if (((fld == BL_SCORE) && !flags.showscore)
|
||||
|| ((fld == BL_EXP) && !flags.showexp)
|
||||
|| ((fld == BL_TIME) && !flags.time)
|
||||
|| ((fld == BL_HD) && !Upolyd)
|
||||
|| ((fld == BL_XP || i == BL_EXP) && Upolyd)
|
||||
|| ((fld == BL_VERS) && !flags.showvers)
|
||||
) {
|
||||
notpresent++;
|
||||
continue;
|
||||
}
|
||||
if (eval_notify_windowport_field(i, valsetlist, idx))
|
||||
if (eval_notify_windowport_field(fld, valsetlist, idx))
|
||||
updated++;
|
||||
}
|
||||
/*
|
||||
@@ -1419,7 +1448,8 @@ status_initialize(
|
||||
: (fld == BL_EXP) ? (boolean) (flags.showexp && !Upolyd)
|
||||
: (fld == BL_XP) ? (boolean) !Upolyd
|
||||
: (fld == BL_HD) ? (boolean) Upolyd
|
||||
: TRUE;
|
||||
: (fld == BL_VERS) ? flags.showvers
|
||||
: TRUE;
|
||||
|
||||
fieldname = initblstats[i].fldname;
|
||||
fieldfmt = (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30.30s"
|
||||
@@ -3433,7 +3463,7 @@ status_hilite_menu_choose_behavior(int fld)
|
||||
nopts++;
|
||||
}
|
||||
|
||||
if (fld != BL_CONDITION) {
|
||||
if (fld != BL_CONDITION && fld != BL_VERS) {
|
||||
any = cg.zeroany;
|
||||
any.a_int = onlybeh = BL_TH_UPDOWN;
|
||||
Sprintf(buf, "%s value changes", initblstats[fld].fldname);
|
||||
|
||||
116
src/options.c
116
src/options.c
@@ -379,6 +379,7 @@ static int handler_runmode(void);
|
||||
static int handler_petattr(void);
|
||||
static int handler_sortloot(void);
|
||||
static int handler_symset(int);
|
||||
static int handler_versinfo(void);
|
||||
static int handler_whatis_coord(void);
|
||||
static int handler_whatis_filter(void);
|
||||
/* next few are not allopt[] entries, so will only be called
|
||||
@@ -4324,6 +4325,71 @@ optfn_vary_msgcount(
|
||||
return optn_ok;
|
||||
}
|
||||
|
||||
static int
|
||||
optfn_versinfo(
|
||||
int optidx, int req, boolean negated,
|
||||
char *opts, char *op)
|
||||
{
|
||||
const char *optname = allopt[optidx].name;
|
||||
unsigned vi = flags.versinfo;
|
||||
|
||||
if (req == do_init) {
|
||||
return optn_ok;
|
||||
}
|
||||
if (req == do_set) {
|
||||
/* versinfo: what to include when 'showvers' displays version
|
||||
on status lines; bitmask with up to three bits:
|
||||
(1) x.y.z number, (2) program name, (4) git branch if available.
|
||||
If branch is requested but unavailable, status_version will
|
||||
treat 4 as 1.
|
||||
*/
|
||||
boolean have_branch = (nomakedefs.git_branch
|
||||
&& *nomakedefs.git_branch);
|
||||
int val, dflt = have_branch ? VI_BRANCH : VI_NUMBER;
|
||||
|
||||
if (negated) {
|
||||
bad_negation(allopt[optidx].name, TRUE);
|
||||
return optn_silenterr;
|
||||
}
|
||||
op = string_for_opt(opts, FALSE);
|
||||
if (op == empty_optstr) {
|
||||
config_error_add("'%s' requires a value; defaulting to %d",
|
||||
optname, dflt);
|
||||
return optn_silenterr;
|
||||
}
|
||||
val = atoi(op);
|
||||
if (!val || (val & ~7) != 0) {
|
||||
config_error_add("'%s' must be one of 1, 2, 4, or"
|
||||
" the sum of two or all three of those",
|
||||
optname);
|
||||
return optn_silenterr;
|
||||
}
|
||||
flags.versinfo = (unsigned) val;
|
||||
} else if (req == do_handler) {
|
||||
/* return handler_versinfo(); */
|
||||
(void) handler_versinfo();
|
||||
pline("'%s' %s %u.", optname,
|
||||
(flags.versinfo == vi) ? "not changed, still" : "changed to",
|
||||
flags.versinfo);
|
||||
} else if (req == get_val) {
|
||||
char vbuf[QBUFSZ];
|
||||
boolean g = (vi & VI_NAME) != 0,
|
||||
b = (vi & VI_BRANCH) != 0,
|
||||
n = (vi & VI_NUMBER) != 0;
|
||||
|
||||
Sprintf(opts, "%u: %s%s%s%s%s (%.99s)", flags.versinfo,
|
||||
g ? "name" : "", (b && g) ? "+" : "", b ? "branch" : "",
|
||||
(n && (b || g)) ? "+" : "", n ? "number" : "",
|
||||
status_version(vbuf, sizeof vbuf, FALSE));
|
||||
} else if (req == get_cnf_val) {
|
||||
Sprintf(opts, "%u", flags.versinfo);
|
||||
}
|
||||
if (flags.versinfo != vi && !go.opt_initial)
|
||||
go.opt_need_redraw = TRUE; /* context.botlx = TRUE ought to suffice
|
||||
* but doesn't for X11 fancy status */
|
||||
return optn_ok;
|
||||
}
|
||||
|
||||
#ifdef VIDEOSHADES
|
||||
static int
|
||||
optfn_videocolors(int optidx, int req, boolean negated UNUSED,
|
||||
@@ -5085,6 +5151,7 @@ optfn_boolean(
|
||||
#ifdef SCORE_ON_BOTL
|
||||
case opt_showscore:
|
||||
#endif
|
||||
case opt_showvers:
|
||||
case opt_showexp:
|
||||
if (VIA_WINDOWPORT())
|
||||
status_initialize(REASSESS_ONLY);
|
||||
@@ -6244,6 +6311,53 @@ handler_msgtype(void)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
handler_versinfo(void)
|
||||
{
|
||||
winid tmpwin;
|
||||
anything any;
|
||||
menu_item *vi_pick = (menu_item *) 0;
|
||||
boolean have_branch = (nomakedefs.git_branch && *nomakedefs.git_branch);
|
||||
int n, vi = (int) flags.versinfo;
|
||||
|
||||
tmpwin = create_nhwindow(NHW_MENU);
|
||||
start_menu(tmpwin, MENU_BEHAVE_STANDARD);
|
||||
any = cg.zeroany;
|
||||
|
||||
any.a_int = n = VI_NUMBER; /* 1 */
|
||||
add_menu(tmpwin, &nul_glyphinfo, &any, 'n', n + '0', ATR_NONE, NO_COLOR,
|
||||
"version number",
|
||||
(vi & n) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
|
||||
any.a_int = n = VI_NAME; /* 2 */
|
||||
add_menu(tmpwin, &nul_glyphinfo, &any, 'g', n + '0', ATR_NONE, NO_COLOR,
|
||||
"game name",
|
||||
(vi & n) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
|
||||
any.a_int = n = VI_BRANCH; /* 4 */
|
||||
add_menu(tmpwin, &nul_glyphinfo, &any, 'b', n + '0', ATR_NONE, NO_COLOR,
|
||||
(have_branch ? "development branch"
|
||||
#if (NH_DEVEL_STATUS == NH_STATUS_RELEASED)
|
||||
: "(not applicable)"
|
||||
#else
|
||||
: "(not available)"
|
||||
#endif
|
||||
), (vi & n) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
|
||||
|
||||
end_menu(tmpwin, "Select version information flags:");
|
||||
n = select_menu(tmpwin, PICK_ANY, &vi_pick);
|
||||
if (n > 0) {
|
||||
int i, newval = 0;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
newval |= vi_pick[i].item.a_int;
|
||||
newval &= 7;
|
||||
if (newval)
|
||||
flags.versinfo = (unsigned) newval;
|
||||
free((genericptr_t) vi_pick);
|
||||
}
|
||||
destroy_nhwindow(tmpwin);
|
||||
return optn_ok;
|
||||
}
|
||||
|
||||
static int
|
||||
handler_windowborders(void)
|
||||
{
|
||||
@@ -6759,6 +6873,7 @@ initoptions_init(void)
|
||||
char *opts;
|
||||
#endif
|
||||
int i;
|
||||
boolean have_branch = (nomakedefs.git_branch && *nomakedefs.git_branch);
|
||||
|
||||
go.opt_phase = builtin_opt; // Did I need to move this here?
|
||||
memcpy(allopt, allopt_init, sizeof(allopt));
|
||||
@@ -6809,6 +6924,7 @@ initoptions_init(void)
|
||||
flags.end_top = 3;
|
||||
flags.end_around = 2;
|
||||
flags.paranoia_bits = PARANOID_PRAY | PARANOID_SWIM;
|
||||
flags.versinfo = have_branch ? 4 : 1;
|
||||
flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */
|
||||
flags.runmode = RUN_LEAP;
|
||||
iflags.msg_history = 20;
|
||||
|
||||
@@ -70,6 +70,79 @@ getversionstring(char *buf, size_t bufsz)
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* version info that could be displayed on status lines;
|
||||
"<game name> <git branch name> <x.y.z version number>";
|
||||
if game name is a prefix of--or same as--branch name, it is omitted
|
||||
"<git branch name> <x.y.z version number>";
|
||||
after release--or if branch info is unavailable--it will be
|
||||
"<game name> <x.y.z version number>";
|
||||
game name or branch name or both can be requested via flags */
|
||||
char *
|
||||
status_version(char *buf, size_t bufsz, boolean indent)
|
||||
{
|
||||
const char *name = NULL, *altname = NULL, *indentation;
|
||||
unsigned vflags = flags.versinfo;
|
||||
boolean shownum = ((vflags & VI_NUMBER) != 0),
|
||||
showname = ((vflags & VI_NAME) != 0),
|
||||
showbranch = ((vflags & VI_BRANCH) != 0);
|
||||
|
||||
/* game's name {variants should use own name, not "NetHack"} */
|
||||
if (showname) {
|
||||
#ifdef VERS_GAME_NAME /* can be set to override default (base of filename) */
|
||||
name = VERS_GAME_NAME;
|
||||
#else
|
||||
name = nh_basename(gh.hname, FALSE); /* hname is from xxxmain.c */
|
||||
#endif
|
||||
if (!name || !*name) /* shouldn't happen */
|
||||
showname = FALSE;
|
||||
}
|
||||
/* git branch name, if available */
|
||||
if (showbranch) {
|
||||
#if 1 /*#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)*/
|
||||
altname = nomakedefs.git_branch;
|
||||
#endif
|
||||
if (!altname || !*altname)
|
||||
showbranch = FALSE;
|
||||
}
|
||||
if (showname && showbranch) {
|
||||
if (!strncmpi(name, altname, strlen(name)))
|
||||
showname = FALSE;
|
||||
#if 0
|
||||
/* note: it's possible for branch name to be a prefix of game name
|
||||
but that's unlikely enough that we won't bother with it; having
|
||||
branch "nethack-3.7" be a superset of game "nethack" seems like
|
||||
including both is redundant, but having branch "net" be a subset
|
||||
of game "nethack" doesn't feel that way; optimizing "net" out
|
||||
seems like it would be a mistake */
|
||||
else if (!strncmpi(altname, name, strlen(altname)))
|
||||
showbranch = FALSE;
|
||||
#endif
|
||||
} else if (!showname && !showbranch) {
|
||||
/* flags.versinfo could be set to only 'branch' but it might not
|
||||
be available */
|
||||
shownum = TRUE;
|
||||
}
|
||||
|
||||
*buf = '\0';
|
||||
indentation = indent ? " " : "";
|
||||
if (showname) {
|
||||
Snprintf(eos(buf), bufsz - strlen(buf), "%s%s", indentation, name);
|
||||
indentation = " "; /* forced separator rather than optional indent */
|
||||
}
|
||||
if (showbranch) {
|
||||
Snprintf(eos(buf), bufsz - strlen(buf), "%s%s", indentation, altname);
|
||||
indentation = " ";
|
||||
}
|
||||
if (shownum) {
|
||||
/* x.y.z version number */
|
||||
Snprintf(eos(buf), bufsz - strlen(buf), "%s%s", indentation,
|
||||
(nomakedefs.version_string && nomakedefs.version_string[0])
|
||||
? nomakedefs.version_string
|
||||
: mdlib_version_string(buf, "."));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* the #versionshort command */
|
||||
int
|
||||
doversion(void)
|
||||
|
||||
Reference in New Issue
Block a user