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:
PatR
2024-02-28 11:47:16 -08:00
parent 5c3fd7b485
commit 41a5565403
20 changed files with 713 additions and 178 deletions

View File

@@ -64,6 +64,7 @@ safe_wait require use of 'm' prefix before '.' or 's' to [True]
sanity_check perform data sanity checks [False] sanity_check perform data sanity checks [False]
showexp display your accumulated experience points [False] showexp display your accumulated experience points [False]
showrace show yourself by your race rather than by role [False] showrace show yourself by your race rather than by role [False]
showvers show version number on status lines [False]
silent don't use your terminal's bell sound [True] silent don't use your terminal's bell sound [True]
sortpack group similar kinds of objects in inventory [True] sortpack group similar kinds of objects in inventory [True]
sparkle display sparkly effect for resisted magical [True] sparkle display sparkly effect for resisted magical [True]
@@ -289,6 +290,8 @@ suppress_alert disable various version-specific warnings about changes []
for the 'Q' command that quitting is now done via #quit for the 'Q' command that quitting is now done via #quit
(e.g., use suppress_alert:3.3.1 to stop that and any other (e.g., use suppress_alert:3.3.1 to stop that and any other
notifications added in that version or earlier) notifications added in that version or earlier)
versinfo selects what information is displayed when showvers [1 or 4]
is true (default depends on program development status)
whatis_coord controls whether to include map coordinates when [n] whatis_coord controls whether to include map coordinates when [n]
autodescribe is active for the '/' and ';' commands. autodescribe is active for the '/' and ';' commands.
Value is the first letter of one of Value is the first letter of one of

View File

@@ -4580,11 +4580,23 @@ Show your accumulated experience points on bottom line (default off).
Persistent. Persistent.
.lp showrace .lp showrace
Display yourself as the glyph for your race, rather than the glyph Display yourself as the glyph for your race, rather than the glyph
for your role (default off). Note that this setting affects only for your role (default off).
Note that this setting affects only
the appearance of the display, not the way the game treats you. the appearance of the display, not the way the game treats you.
Persistent. Persistent.
.lp showscore .lp showscore
Show your approximate accumulated score on bottom line (default off). Show your approximate accumulated score on bottom line (default off).
By default, this feature is suppressed when building the program.
Persistent.
.lp showvers
Include the game's version number on the status lines (default off).
Potentially useful if you switch between different versions or variants,
or you are making screenshots or streaming video.
Using the
.op statuslines:3
option is recommended so that there will be more room available for
status information, unless you're using nethack's \fIQt\fP interface
or your terminal emulator window displays fewer than 25 lines.
Persistent. Persistent.
.lp "silent " .lp "silent "
Suppress terminal beeps (default on). Suppress terminal beeps (default on).

View File

@@ -5021,6 +5021,18 @@ Persistent.
%.lp %.lp
\item[\ib{showscore}] \item[\ib{showscore}]
Show your approximate accumulated score on bottom line (default off). Show your approximate accumulated score on bottom line (default off).
By default, this feature is suppressed when building the program.
Persistent.
%.lp
\item[\ib{showvers}]
Include the game's version number on the status lines (default off).
Potentially useful if you switch between different versions or variants,
or you are making screenshots or streaming video.
Using the
{\it statuslines:3\/}
option is recommended so that there will be more room available for
status information, unless you're using nethack's {\it Qt\/} interface
or your terminal emulator window displays fewer than 25 lines.
Persistent. Persistent.
%.lp %.lp
\item[\ib{silent}] \item[\ib{silent}]

View File

@@ -2504,6 +2504,9 @@ accessibility command #lookaround which will describe what hero can see
if hero is punished or tethered to a buried iron ball and has no inventory (or if hero is punished or tethered to a buried iron ball and has no inventory (or
only carries gold or embedded dragon scales or both), a nymph might only carries gold or embedded dragon scales or both), a nymph might
remove the chain when finding nothing else to steal remove the chain when finding nothing else to steal
'showvers' option (and companion 'versinfo' option) to include program version
in the status display so that it will be visible for screenshots or
during streaming video
Platform- and/or Interface-Specific New Features Platform- and/or Interface-Specific New Features

View File

@@ -453,7 +453,7 @@ status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable)
BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, 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_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
BL_LEVELDESC, BL_EXP, BL_CONDITION BL_LEVELDESC, BL_EXP, BL_CONDITION, BL_VERS
-- There are MAXBLSTATS status fields (from botl.h) -- There are MAXBLSTATS status fields (from botl.h)
status_update(int fldindex, genericptr_t ptr, int chg, int percentage, \ status_update(int fldindex, genericptr_t ptr, int chg, int percentage, \
int color, long *colormasks) int color, long *colormasks)
@@ -464,7 +464,7 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percentage, \
BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, 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_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
BL_LEVELDESC, BL_EXP, BL_CONDITION BL_LEVELDESC, BL_EXP, BL_CONDITION, BL_VERS
-- fldindex could also be BL_FLUSH (-1), which is not really -- 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 windowport that it should output all changes received

View File

@@ -41,7 +41,8 @@ enum statusfields {
BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, /* 7..12 */ 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 */ BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, /* 13..18 */
BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION, /* 19..22 */ BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION, /* 19..22 */
MAXBLSTATS /* [23] */ BL_VERS, /* 23 */
MAXBLSTATS, /* [24] */
}; };
enum relationships { enum relationships {

View File

@@ -3390,6 +3390,7 @@ extern void vault_gd_watching(unsigned int);
extern char *version_string(char *, size_t bufsz) NONNULL NONNULLARG1; extern char *version_string(char *, size_t bufsz) NONNULL NONNULLARG1;
extern char *getversionstring(char *, size_t bufsz) NONNULL NONNULLARG1; extern char *getversionstring(char *, size_t bufsz) NONNULL NONNULLARG1;
extern char *status_version(char *, size_t, boolean) NONNULL NONNULLARG1;
extern int doversion(void); extern int doversion(void);
extern int doextversion(void); extern int doextversion(void);
#ifdef MICRO #ifdef MICRO

View File

@@ -58,6 +58,7 @@ struct flag {
boolean safe_wait; /* prevent wait or search next to hostile */ boolean safe_wait; /* prevent wait or search next to hostile */
boolean showexp; /* show experience points */ boolean showexp; /* show experience points */
boolean showscore; /* show score */ boolean showscore; /* show score */
boolean showvers; /* show version on status lines */
boolean silent; /* whether the bell rings or not */ boolean silent; /* whether the bell rings or not */
boolean sortpack; /* sorted inventory */ boolean sortpack; /* sorted inventory */
boolean sparkle; /* show "resisting" special FX (Scott Bigham) */ boolean sparkle; /* show "resisting" special FX (Scott Bigham) */
@@ -89,6 +90,12 @@ struct flag {
#define PARANOID_SWIM 0x0400 #define PARANOID_SWIM 0x0400
#define PARANOID_TRAP 0x0800 #define PARANOID_TRAP 0x0800
#define PARANOID_AUTOALL 0x1000 #define PARANOID_AUTOALL 0x1000
unsigned versinfo; /* flag mask for 'showvers' option */
/* mask bits for 'versinfo'; numeric order does not match display order
which is "name branch number" */
#define VI_NUMBER 1 /* x.y.z */
#define VI_NAME 2 /* game's name (ie, "nethack") */
#define VI_BRANCH 4 /* development branch (from git, via Makefile -CFLAGS) */
int pickup_burden; /* maximum burden before prompt */ int pickup_burden; /* maximum burden before prompt */
int pile_limit; /* controls feedback when walking over objects */ int pile_limit; /* controls feedback when walking over objects */
char discosort; /* order of dodiscovery/doclassdisco output: o,s,c,a */ char discosort; /* order of dodiscovery/doclassdisco output: o,s,c,a */

View File

@@ -641,6 +641,9 @@ static int optfn_##a(int, int, boolean, char *, char *);
Off, Yes, No, No, NoAlias, (boolean *) 0, Term_False, Off, Yes, No, No, NoAlias, (boolean *) 0, Term_False,
(char *)0) (char *)0)
#endif #endif
NHOPTB(showvers, Status, 0, opt_in, set_in_game,
Off, Yes, No, No, NoAlias, &flags.showvers, Term_False,
"show version info on status line")
NHOPTB(silent, Advanced, 0, opt_out, set_in_game, NHOPTB(silent, Advanced, 0, opt_out, set_in_game,
On, Yes, No, No, NoAlias, &flags.silent, Term_False, On, Yes, No, No, NoAlias, &flags.silent, Term_False,
"don't use terminal bell") "don't use terminal bell")
@@ -779,6 +782,8 @@ static int optfn_##a(int, int, boolean, char *, char *);
NHOPTB(verbose, Advanced, 0, opt_out, set_in_game, NHOPTB(verbose, Advanced, 0, opt_out, set_in_game,
On, Yes, No, No, NoAlias, &flags.verbose, Term_False, On, Yes, No, No, NoAlias, &flags.verbose, Term_False,
(char *)0) (char *)0)
NHOPTC(versinfo, Advanced, 80, opt_out, set_in_game,
No, Yes, No, Yes, NoAlias, "extra information for 'showvers'")
#ifdef MSDOS #ifdef MSDOS
NHOPTC(video, Advanced, 20, opt_in, set_in_config, NHOPTC(video, Advanced, 20, opt_in, set_in_config,
No, Yes, No, No, NoAlias, "method of video updating") No, Yes, No, No, NoAlias, "method of video updating")

View File

@@ -17,7 +17,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones * Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files. * and save files.
*/ */
#define EDITLEVEL 97 #define EDITLEVEL 98
/* /*
* Development status possibilities. * Development status possibilities.

View File

@@ -106,9 +106,10 @@ do_statusline2(void)
/* dungeon location (and gold), hero health (HP, PW, AC), /* dungeon location (and gold), hero health (HP, PW, AC),
experience (HD if poly'd, else Exp level and maybe Exp points), experience (HD if poly'd, else Exp level and maybe Exp points),
time (in moves), varying number of status conditions */ 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; char *nb;
size_t dln, dx, hln, xln, tln, cln; size_t dln, dx, hln, xln, tln, cln, vrn;
int hp, hpmax, cap; int hp, hpmax, cap;
long money; long money;
@@ -206,6 +207,13 @@ do_statusline2(void)
Strcpy(nb = eos(nb), " Ride"); Strcpy(nb = eos(nb), " Ride");
cln = strlen(cond); 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 * Put the pieces together. If they all fit, keep the traditional
* sequence. Otherwise, move least important parts to the end in * 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 * wider displays can still show wider status than the map if the
* interface supports that. * interface supports that.
*/ */
if ((dln - dx) + 1 + hln + 1 + xln + 1 + tln + 1 + cln <= COLNO) { if ((dln - dx) + 1 + hln + 1 + xln + 1 + tln + 1 + cln + vrn <= COLNO) {
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s", dloc, hlth, expr, Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s%s", dloc, hlth,
tmmv, cond); expr, tmmv, cond, vers);
} else { } 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)", 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); MAXCO);
} else if ((dln - dx) + 1 + hln + 1 + xln + 1 + cln <= COLNO) { } else if ((dln - dx) + 1 + hln + 1 + xln + 1 + cln <= COLNO) {
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s", dloc, hlth, Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s%s", dloc, hlth,
expr, cond, tmmv); expr, cond, tmmv, vers);
} else if ((dln - dx) + 1 + hln + 1 + cln <= COLNO) { } else if ((dln - dx) + 1 + hln + 1 + cln <= COLNO) {
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s", dloc, hlth, Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s%s", dloc, hlth,
cond, expr, tmmv); cond, expr, tmmv, vers);
} else { } else {
Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s", hlth, cond, Snprintf(newbot2, sizeof newbot2, "%s %s %s %s %s%s", hlth, cond,
dloc, expr, tmmv); dloc, expr, tmmv, vers);
} }
/* only two or three consecutive spaces available to squeeze out */ /* only two or three consecutive spaces available to squeeze out */
mungspaces(newbot2); mungspaces(newbot2);
@@ -567,7 +576,12 @@ static struct istat_s initblstats[MAXBLSTATS] = {
INIT_BLSTAT("hitpoints-max", "(%s)", ANY_INT, 10, BL_HPMAX), INIT_BLSTAT("hitpoints-max", "(%s)", ANY_INT, 10, BL_HPMAX),
INIT_BLSTAT("dungeon-level", "%s", ANY_STR, MAXVALWIDTH, BL_LEVELDESC), INIT_BLSTAT("dungeon-level", "%s", ANY_STR, MAXVALWIDTH, BL_LEVELDESC),
INIT_BLSTATP("experience", "/%s", ANY_LONG, 20, BL_EXP, BL_EXP), 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 #undef INIT_BLSTATP
@@ -873,6 +887,18 @@ bot_via_windowport(void)
(cap > UNENCUMBERED) ? enc_stat[cap] : ""); (cap > UNENCUMBERED) ? enc_stat[cap] : "");
gv.valset[BL_CAP] = TRUE; 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 */ /* Conditions */
gb.blstats[idx][BL_CONDITION].a.a_ulong = 0L; gb.blstats[idx][BL_CONDITION].a.a_ulong = 0L;
@@ -1342,21 +1368,24 @@ evaluate_and_notify_windowport(
boolean *valsetlist, boolean *valsetlist,
int idx) 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. * Now pass the changed values to window port.
*/ */
for (i = 0; i < MAXBLSTATS; i++) { for (i = 0; i < MAXBLSTATS; i++) {
if (((i == BL_SCORE) && !flags.showscore) fld = initblstats[i].fld;
|| ((i == BL_EXP) && !flags.showexp) if (((fld == BL_SCORE) && !flags.showscore)
|| ((i == BL_TIME) && !flags.time) || ((fld == BL_EXP) && !flags.showexp)
|| ((i == BL_HD) && !Upolyd) || ((fld == BL_TIME) && !flags.time)
|| ((i == BL_XP || i == BL_EXP) && Upolyd)) { || ((fld == BL_HD) && !Upolyd)
|| ((fld == BL_XP || i == BL_EXP) && Upolyd)
|| ((fld == BL_VERS) && !flags.showvers)
) {
notpresent++; notpresent++;
continue; continue;
} }
if (eval_notify_windowport_field(i, valsetlist, idx)) if (eval_notify_windowport_field(fld, valsetlist, idx))
updated++; updated++;
} }
/* /*
@@ -1419,7 +1448,8 @@ status_initialize(
: (fld == BL_EXP) ? (boolean) (flags.showexp && !Upolyd) : (fld == BL_EXP) ? (boolean) (flags.showexp && !Upolyd)
: (fld == BL_XP) ? (boolean) !Upolyd : (fld == BL_XP) ? (boolean) !Upolyd
: (fld == BL_HD) ? (boolean) Upolyd : (fld == BL_HD) ? (boolean) Upolyd
: TRUE; : (fld == BL_VERS) ? flags.showvers
: TRUE;
fieldname = initblstats[i].fldname; fieldname = initblstats[i].fldname;
fieldfmt = (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30.30s" fieldfmt = (fld == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30.30s"
@@ -3433,7 +3463,7 @@ status_hilite_menu_choose_behavior(int fld)
nopts++; nopts++;
} }
if (fld != BL_CONDITION) { if (fld != BL_CONDITION && fld != BL_VERS) {
any = cg.zeroany; any = cg.zeroany;
any.a_int = onlybeh = BL_TH_UPDOWN; any.a_int = onlybeh = BL_TH_UPDOWN;
Sprintf(buf, "%s value changes", initblstats[fld].fldname); Sprintf(buf, "%s value changes", initblstats[fld].fldname);

View File

@@ -379,6 +379,7 @@ static int handler_runmode(void);
static int handler_petattr(void); static int handler_petattr(void);
static int handler_sortloot(void); static int handler_sortloot(void);
static int handler_symset(int); static int handler_symset(int);
static int handler_versinfo(void);
static int handler_whatis_coord(void); static int handler_whatis_coord(void);
static int handler_whatis_filter(void); static int handler_whatis_filter(void);
/* next few are not allopt[] entries, so will only be called /* next few are not allopt[] entries, so will only be called
@@ -4324,6 +4325,71 @@ optfn_vary_msgcount(
return optn_ok; 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 #ifdef VIDEOSHADES
static int static int
optfn_videocolors(int optidx, int req, boolean negated UNUSED, optfn_videocolors(int optidx, int req, boolean negated UNUSED,
@@ -5085,6 +5151,7 @@ optfn_boolean(
#ifdef SCORE_ON_BOTL #ifdef SCORE_ON_BOTL
case opt_showscore: case opt_showscore:
#endif #endif
case opt_showvers:
case opt_showexp: case opt_showexp:
if (VIA_WINDOWPORT()) if (VIA_WINDOWPORT())
status_initialize(REASSESS_ONLY); 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 static int
handler_windowborders(void) handler_windowborders(void)
{ {
@@ -6759,6 +6873,7 @@ initoptions_init(void)
char *opts; char *opts;
#endif #endif
int i; int i;
boolean have_branch = (nomakedefs.git_branch && *nomakedefs.git_branch);
go.opt_phase = builtin_opt; // Did I need to move this here? go.opt_phase = builtin_opt; // Did I need to move this here?
memcpy(allopt, allopt_init, sizeof(allopt)); memcpy(allopt, allopt_init, sizeof(allopt));
@@ -6809,6 +6924,7 @@ initoptions_init(void)
flags.end_top = 3; flags.end_top = 3;
flags.end_around = 2; flags.end_around = 2;
flags.paranoia_bits = PARANOID_PRAY | PARANOID_SWIM; flags.paranoia_bits = PARANOID_PRAY | PARANOID_SWIM;
flags.versinfo = have_branch ? 4 : 1;
flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */ flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */
flags.runmode = RUN_LEAP; flags.runmode = RUN_LEAP;
iflags.msg_history = 20; iflags.msg_history = 20;

View File

@@ -70,6 +70,79 @@ getversionstring(char *buf, size_t bufsz)
return buf; 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 */ /* the #versionshort command */
int int
doversion(void) doversion(void)

View File

@@ -86,6 +86,7 @@ NetHackQtSettings::NetHackQtSettings() :
normalfixed("courier"), normalfixed("courier"),
#endif #endif
large("times"), large("times"),
small("times"),
theglyphs(0) theglyphs(0)
{ {
int default_fontsize; int default_fontsize;
@@ -326,6 +327,13 @@ const QFont& NetHackQtSettings::largeFont()
return large; return large;
} }
const QFont& NetHackQtSettings::smallFont()
{
static int size[]={ 14, 12, 10, 8, 8 };
small.setPointSize(size[fontsize.currentIndex()]);
return small;
}
bool NetHackQtSettings::ynInMessages() bool NetHackQtSettings::ynInMessages()
{ {
return !qt_compact_mode && !iflags.wc_popup_dialog; return !qt_compact_mode && !iflags.wc_popup_dialog;

View File

@@ -36,6 +36,7 @@ public:
const QFont& normalFont(); const QFont& normalFont();
const QFont& normalFixedFont(); const QFont& normalFixedFont();
const QFont& largeFont(); const QFont& largeFont();
const QFont& smallFont();
bool ynInMessages(); bool ynInMessages();
@@ -71,7 +72,7 @@ private:
QComboBox fontsize; QComboBox fontsize;
QFont normal, normalfixed, large; QFont normal, normalfixed, large, small;
NetHackQtGlyphs* theglyphs; NetHackQtGlyphs* theglyphs;
#if 0 #if 0

View File

@@ -20,6 +20,7 @@
// varying number of icons (one or more, each paired with...) // varying number of icons (one or more, each paired with...)
// corresponding text (Alignment plus zero or more status conditions // corresponding text (Alignment plus zero or more status conditions
// including Hunger if not "normal" and encumbrance if not "normal") // including Hunger if not "normal" and encumbrance if not "normal")
// and version description (text only) right justified (when enabled)
// //
// The hitpoint bar spans the width of the status window when enabled. // The hitpoint bar spans the width of the status window when enabled.
// Title and location are centered. // Title and location are centered.
@@ -64,6 +65,10 @@
// Hungry similar but with a slightly concave belly, Weak either a // Hungry similar but with a slightly concave belly, Weak either a
// collapsing figure or a much larger concavity or both, Fainting/ // collapsing figure or a much larger concavity or both, Fainting/
// Fainted a fully collapsed figure. // Fainted a fully collapsed figure.
// If 'version' is being shown but gets squeezed by the cumulative width
// of conditions, the default clipping shows the center portion of the
// text string with beginning and end omitted. We want to force the
// end of the string to be shown with only the beginning omitted.
// //
// TODO: // TODO:
// If/when status conditions become too wide for the status window, scale // If/when status conditions become too wide for the status window, scale
@@ -138,6 +143,7 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() :
lev(this,"Lev"), // 'other' conditions lev(this,"Lev"), // 'other' conditions
fly(this,"Fly"), fly(this,"Fly"),
ride(this,"Ride"), ride(this,"Ride"),
vers(this,""), // optional, right justified after 'conditions'
hline1(this), // separators hline1(this), // separators
hline2(this), hline2(this),
hline3(this), hline3(this),
@@ -149,7 +155,8 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() :
alreadyfullhp(false), alreadyfullhp(false),
was_polyd(false), was_polyd(false),
had_exp(false), had_exp(false),
had_score(false) had_score(false),
prev_versinfo(0U)
{ {
if (!qt_compact_mode) { if (!qt_compact_mode) {
int w = NetHackQtBind::mainWidget()->width(); int w = NetHackQtBind::mainWidget()->width();
@@ -195,6 +202,8 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() :
p_fly = QPixmap(fly_xpm); p_fly = QPixmap(fly_xpm);
p_ride = QPixmap(ride_xpm); p_ride = QPixmap(ride_xpm);
p_vers = QPixmap(blank_xpm); // same all-background pixmap as blank2
str.setIcon(p_str, "strength"); str.setIcon(p_str, "strength");
dex.setIcon(p_dex, "dexterity"); dex.setIcon(p_dex, "dexterity");
con.setIcon(p_con, "constitution"); con.setIcon(p_con, "constitution");
@@ -221,6 +230,8 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() :
fly.setIcon(p_fly, "flying"); fly.setIcon(p_fly, "flying");
ride.setIcon(p_ride, "riding"); ride.setIcon(p_ride, "riding");
vers.setIcon(p_vers); // used to align text-only version with conditions
// separator lines // separator lines
#if __cplusplus >= 202002L #if __cplusplus >= 202002L
hline1.setFrameStyle(static_cast<int>(QFrame::HLine) hline1.setFrameStyle(static_cast<int>(QFrame::HLine)
@@ -251,7 +262,7 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() :
vline2.setLineWidth(1); vline2.setLineWidth(1);
vline2.hide(); // padding to keep row 2 aligned with row 1, never shown vline2.hide(); // padding to keep row 2 aligned with row 1, never shown
// set up last but shown first (above name) via layout below */ // when 'hitpointbar' is On, the bar gets drawn above name/title
QHBoxLayout *hpbar = InitHitpointBar(); QHBoxLayout *hpbar = InitHitpointBar();
// 'statuslines' takes a value of 2 or 3; we use 3 as a request to put // 'statuslines' takes a value of 2 or 3; we use 3 as a request to put
@@ -342,7 +353,15 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() :
condbox->addWidget(&lev); condbox->addWidget(&lev);
condbox->addWidget(&fly); condbox->addWidget(&fly);
condbox->addWidget(&ride); condbox->addWidget(&ride);
condbox->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); condbox->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
// left justify conditions, whether 'vers' is present or absent
int stretch = 0;
condbox->addStretch(++stretch); // stretch==1
// to right justify 'vers', use bigger stretch than condbox separator
condbox->addWidget(&vers, ++stretch, // stretch==2
// text is below a blank icon, so bottom-aligned with the rest
// of the line with its text centered within that bottom area
Qt::AlignRight | Qt::AlignVCenter);
vbox->addLayout(condbox); vbox->addLayout(condbox);
setLayout(vbox); setLayout(vbox);
#endif #endif
@@ -396,6 +415,7 @@ void NetHackQtStatusWindow::doUpdate()
lev.setFont(normal); lev.setFont(normal);
fly.setFont(normal); fly.setFont(normal);
ride.setFont(normal); ride.setFont(normal);
vers.setFont(normal); // shouldn't need small font
updateStats(); updateStats();
} }
@@ -496,6 +516,11 @@ void NetHackQtStatusWindow::resizeEvent(QResizeEvent*)
lev.setGeometry(x,y,iw,lh); x+=iw; lev.setGeometry(x,y,iw,lh); x+=iw;
fly.setGeometry(x,y,iw,lh); x+=iw; fly.setGeometry(x,y,iw,lh); x+=iw;
ride.setGeometry(x,y,iw,lh); x+=iw; ride.setGeometry(x,y,iw,lh); x+=iw;
#if 0
// [not fully implemented; this big chunk of code is no longer used]
//X = [get version, set font, measure width of version string]
vers.setGeometry(width() - X, y, width(), lh); x=width();
#endif
x=0; y+=lh; x=0; y+=lh;
#else #else
// This is clumsy. But QLayout objects are proving balky. // This is clumsy. But QLayout objects are proving balky.
@@ -540,6 +565,7 @@ void NetHackQtStatusWindow::fadeHighlighting()
//time.dissipateHighlight(); //time.dissipateHighlight();
score.dissipateHighlight(); score.dissipateHighlight();
//vers.dissipateHighlight(); // never gets highlighted
hunger.dissipateHighlight(); hunger.dissipateHighlight();
encumber.dissipateHighlight(); encumber.dissipateHighlight();
@@ -813,6 +839,21 @@ void NetHackQtStatusWindow::updateStats()
if (Flying) ++k, fly.show(); else fly.hide(); if (Flying) ++k, fly.show(); else fly.hide();
if (u.usteed) ++k, ride.show(); else ride.hide(); if (u.usteed) ++k, ride.show(); else ride.hide();
// version is optional; displayed to the right of conditions when present
if (::flags.showvers) {
// the value only changes if user modifies the 'versinfo' option
if (::flags.versinfo != prev_versinfo) {
char vbuf[80], *cvers = status_version(vbuf, sizeof vbuf, FALSE);
vers.setLabel(QString(cvers));
// FIXME: this shouldn't be necessary but without hide() before
// forthcoming show(), the new value isn't appearing
if (!vers.isHidden()) vers.hide();
prev_versinfo = ::flags.versinfo;
}
++k, vers.show();
} else
vers.hide();
if (Upolyd) { if (Upolyd) {
buf = nh_capitalize_words(pmname(&mons[u.umonnum], buf = nh_capitalize_words(pmname(&mons[u.umonnum],
::flags.female ? FEMALE : MALE)); ::flags.female ? FEMALE : MALE));
@@ -929,6 +970,7 @@ void NetHackQtStatusWindow::updateStats()
} else { } else {
time.setLabel(""); time.setLabel("");
} }
#ifdef SCORE_ON_BOTL #ifdef SCORE_ON_BOTL
int score_toggled = !had_score ^ !::flags.showscore; int score_toggled = !had_score ^ !::flags.showscore;
if (::flags.showscore) { if (::flags.showscore) {
@@ -1023,6 +1065,9 @@ void NetHackQtStatusWindow::updateStats()
fly.setCompareMode(NeitherIsBetter); fly.setCompareMode(NeitherIsBetter);
ride.highlightWhenChanging(); ride.highlightWhenChanging();
ride.setCompareMode(NeitherIsBetter); ride.setCompareMode(NeitherIsBetter);
// not a true status condition; doesn't change (unless 'showvers'
// gets toggled or 'versinfo' is modified) so doesn't get highlighted
vers.setCompareMode(NoCompare);
} }
} }

View File

@@ -65,6 +65,7 @@ private:
QPixmap p_lev; QPixmap p_lev;
QPixmap p_fly; QPixmap p_fly;
QPixmap p_ride; QPixmap p_ride;
QPixmap p_vers; // version, when shown, is like a pseudo-condition
/* /*
* Status fields, in display order (the three separator lines * Status fields, in display order (the three separator lines
@@ -127,6 +128,8 @@ private:
NetHackQtLabelledIcon lev; NetHackQtLabelledIcon lev;
NetHackQtLabelledIcon fly; NetHackQtLabelledIcon fly;
NetHackQtLabelledIcon ride; NetHackQtLabelledIcon ride;
/* to right of conditions, right justified */
NetHackQtLabelledIcon vers; // version
QFrame hline1; // between dlevel and characteristics QFrame hline1; // between dlevel and characteristics
QFrame hline2; // between characteristics and regular status fields QFrame hline2; // between characteristics and regular status fields
@@ -143,6 +146,7 @@ private:
bool was_polyd; bool was_polyd;
bool had_exp; bool had_exp;
bool had_score; bool had_score;
unsigned prev_versinfo;
QHBoxLayout *InitHitpointBar(); QHBoxLayout *InitHitpointBar();
void HitpointBar(); void HitpointBar();

View File

@@ -93,7 +93,8 @@
#define F_CONF 39 #define F_CONF 39
#define F_HALLU 40 #define F_HALLU 40
#define NUM_STATS 41 #define F_VERS 41 /* version info */
#define NUM_STATS 42
static int condcolor(long, unsigned long *); static int condcolor(long, unsigned long *);
static int condattr(long, unsigned long *); static int condattr(long, unsigned long *);
@@ -107,6 +108,7 @@ static void tt_reset_color(int, int, unsigned long *);
static void tt_status_fixup(void); static void tt_status_fixup(void);
static Widget create_tty_status_field(int, int, Widget, Widget); static Widget create_tty_status_field(int, int, Widget, Widget);
static Widget create_tty_status(Widget, Widget); static Widget create_tty_status(Widget, Widget);
static void stat_resized(Widget, XtPointer, XtPointer);
static void update_fancy_status_field(int, int, int); static void update_fancy_status_field(int, int, int);
static void update_fancy_status(boolean); static void update_fancy_status(boolean);
static Widget create_fancy_status(Widget, Widget); static Widget create_fancy_status(Widget, Widget);
@@ -133,15 +135,15 @@ static int next_cond_indx = 0, prev_cond_indx = 0;
/* TODO: support statuslines:3 in addition to 2 for the tty-style status */ /* TODO: support statuslines:3 in addition to 2 for the tty-style status */
#define X11_NUM_STATUS_LINES 2 #define X11_NUM_STATUS_LINES 2
#define X11_NUM_STATUS_FIELD 15 #define X11_NUM_STATUS_FIELD 16
static enum statusfields X11_fieldorder[][X11_NUM_STATUS_FIELD] = { static enum statusfields X11_fieldorder[][X11_NUM_STATUS_FIELD] = {
{ BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH,
BL_FLUSH }, BL_FLUSH, BL_FLUSH },
{ BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
BL_CAP, BL_CONDITION, BL_FLUSH } BL_CAP, BL_CONDITION, BL_VERS, BL_FLUSH }
}; };
/* condition list for tty-style display, roughly in order of importance */ /* condition list for tty-style display, roughly in order of importance */
@@ -157,7 +159,7 @@ static struct tt_condinfo {
{ BL_MASK_TERMILL, "TermIll" }, { BL_MASK_TERMILL, "TermIll" },
{ BL_MASK_INLAVA, "InLava" }, { BL_MASK_INLAVA, "InLava" },
{ BL_MASK_HELD, "Held" }, { BL_MASK_HELD, "Held" },
{ BL_MASK_HELD, "Holding" }, { BL_MASK_HOLDING, "Holding" },
{ BL_MASK_BLIND, "Blind" }, { BL_MASK_BLIND, "Blind" },
{ BL_MASK_DEAF, "Deaf" }, { BL_MASK_DEAF, "Deaf" },
{ BL_MASK_STUN, "Stun" }, { BL_MASK_STUN, "Stun" },
@@ -170,7 +172,7 @@ static struct tt_condinfo {
{ BL_MASK_RIDE, "Ride" }, { BL_MASK_RIDE, "Ride" },
}; };
static const char *fancy_status_hilite_colors[] = { static const char *const fancy_status_hilite_colors[] = {
"grey15", "grey15",
"red3", "red3",
"dark green", "dark green",
@@ -396,8 +398,9 @@ PrepStatusField(int fld, Widget label, const char *text)
/* set up one status condition for tty-style status display */ /* set up one status condition for tty-style status display */
static void static void
DisplayCond(int c_idx, /* index into tt_condorder[] */ DisplayCond(
unsigned long *colormasks) int c_idx, /* index into tt_condorder[] */
unsigned long *colormasks)
{ {
Widget label; Widget label;
Arg args[6]; Arg args[6];
@@ -507,7 +510,10 @@ render_conditions(int row, int dx)
/* reset status_hilite for BL_RESET; if highlighting has been disabled or /* reset status_hilite for BL_RESET; if highlighting has been disabled or
this field is disabled, clear highlighting for this field or condition */ this field is disabled, clear highlighting for this field or condition */
static void static void
tt_reset_color(int fld, int cond, unsigned long *colormasks) tt_reset_color(
int fld,
int cond,
unsigned long *colormasks)
{ {
Widget label; Widget label;
int colrattr = NO_COLOR; int colrattr = NO_COLOR;
@@ -637,6 +643,12 @@ tt_status_fixup(void)
XtSetArg(args[num_args], nhStr(XtNborderWidth), &si->brd); num_args++; XtSetArg(args[num_args], nhStr(XtNborderWidth), &si->brd); num_args++;
XtSetArg(args[num_args], nhStr(XtNinternalWidth), &si->in_wd); num_args++; XtSetArg(args[num_args], nhStr(XtNinternalWidth), &si->in_wd); num_args++;
XtGetValues(X11_status_labels[0], args, num_args); XtGetValues(X11_status_labels[0], args, num_args);
/* X11_status_update_tty() wants this in order to right justify 'vers' */
if (!xw_status_win->pixel_width) {
XtSetArg(args[0], nhStr(XtNwidth), &xw_status_win->pixel_width);
XtGetValues(xw_status_win->w, args, ONE);
}
} }
DISABLE_WARNING_FORMAT_NONLITERAL DISABLE_WARNING_FORMAT_NONLITERAL
@@ -644,10 +656,13 @@ DISABLE_WARNING_FORMAT_NONLITERAL
/* core requests updating one status field (or is indicating that it's time /* core requests updating one status field (or is indicating that it's time
to flush all updated fields); tty-style handling */ to flush all updated fields); tty-style handling */
static void static void
X11_status_update_tty(int fld, genericptr_t ptr, int chg UNUSED, int percent, X11_status_update_tty(
int color, int fld,
unsigned long *colormasks) /* bitmask of highlights genericptr_t ptr,
for conditions */ int chg UNUSED,
int percent,
int color,
unsigned long *colormasks) /* bitmask of highlights for conditions */
{ {
static int xtra_space[MAXBLSTATS]; static int xtra_space[MAXBLSTATS];
static unsigned long *cond_colormasks = (unsigned long *) 0; static unsigned long *cond_colormasks = (unsigned long *) 0;
@@ -785,6 +800,20 @@ X11_status_update_tty(int fld, genericptr_t ptr, int chg UNUSED, int percent,
/* where to display the current widget */ /* where to display the current widget */
lbl_x = (Position) (dx + 1); lbl_x = (Position) (dx + 1);
if (f == BL_VERS) {
Dimension win_wid = xw_status_win->pixel_width,
fld_wid = lbl_wid + 2 * brd_wid;
/* in case the doodad for resizing the window via click and
drag is in the lower right corner; justifying all the way
to the edge results in the last character being obscured;
avoid that by treating the 'vers' widget as one char
bigger than it actually is (an implicit trailing space) */
fld_wid += si->spacew;
/* right justify if there's room */
if (dx < win_wid - fld_wid)
lbl_x = win_wid - fld_wid;
}
(void) memset((genericptr_t) args, 0, sizeof args); (void) memset((genericptr_t) args, 0, sizeof args);
num_args = 0; num_args = 0;
@@ -809,9 +838,12 @@ RESTORE_WARNING_FORMAT_NONLITERAL
/*ARGSUSED*/ /*ARGSUSED*/
static void static void
X11_status_update_fancy(int fld, genericptr_t ptr, int chg UNUSED, X11_status_update_fancy(
int percent UNUSED, int colrattr, int fld,
unsigned long *colormasks UNUSED) genericptr_t ptr,
int chg UNUSED, int percent UNUSED,
int colrattr,
unsigned long *colormasks UNUSED)
{ {
static const struct bl_to_ff { static const struct bl_to_ff {
int bl, ff; int bl, ff;
@@ -836,6 +868,7 @@ X11_status_update_fancy(int fld, genericptr_t ptr, int chg UNUSED,
{ BL_HP, F_HP }, { BL_HP, F_HP },
{ BL_HPMAX, F_MAXHP }, { BL_HPMAX, F_MAXHP },
{ BL_LEVELDESC, F_DLEVEL }, { BL_LEVELDESC, F_DLEVEL },
{ BL_VERS, F_VERS },
{ BL_EXP, F_EXP_PTS } { BL_EXP, F_EXP_PTS }
}; };
static const struct mask_to_ff { static const struct mask_to_ff {
@@ -902,9 +935,12 @@ X11_status_update_fancy(int fld, genericptr_t ptr, int chg UNUSED,
} }
void void
X11_status_update(int fld, genericptr_t ptr, int chg, X11_status_update(
int percent, int color, int fld,
unsigned long *colormasks) genericptr_t ptr,
int chg, int percent,
int color,
unsigned long *colormasks)
{ {
if (fld < BL_RESET || fld >= MAXBLSTATS) if (fld < BL_RESET || fld >= MAXBLSTATS)
panic("X11_status_update(%d) -- invalid field", fld); panic("X11_status_update(%d) -- invalid field", fld);
@@ -1024,7 +1060,7 @@ create_status_window_tty(struct xwindow *wp, /* window pointer */
void void
destroy_status_window_tty(struct xwindow *wp) destroy_status_window_tty(struct xwindow *wp)
{ {
/* If status_information is defined, then it a "text" status window. */ /* if status_information is defined, then it is a "text" status window */
if (wp->status_information) { if (wp->status_information) {
if (wp->popup) { if (wp->popup) {
nh_XtPopdown(wp->popup); nh_XtPopdown(wp->popup);
@@ -1049,8 +1085,10 @@ adjust_status_tty(struct xwindow *wp UNUSED, const char *str UNUSED)
} }
void void
create_status_window(struct xwindow *wp, /* window pointer */ create_status_window(
boolean create_popup, Widget parent) struct xwindow *wp, /* window pointer */
boolean create_popup,
Widget parent)
{ {
struct status_info_t *si = (struct status_info_t *) alloc(sizeof *si); struct status_info_t *si = (struct status_info_t *) alloc(sizeof *si);
@@ -1064,6 +1102,39 @@ create_status_window(struct xwindow *wp, /* window pointer */
create_status_window_tty(wp, create_popup, parent); create_status_window_tty(wp, create_popup, parent);
else else
create_status_window_fancy(wp, create_popup, parent); create_status_window_fancy(wp, create_popup, parent);
#if 0 /*
* this does not work as intended; it triggers
* "Warning: Cannot find callback list in XtAddCallback"
*/
XtAddCallback(wp->w, XtNresizeCallback, stat_resized, (XtPointer) 0);
#else
nhUse(stat_resized);
#endif
}
/* callback to deal with the game window being resized */
static void
stat_resized(Widget w, XtPointer call_data, XtPointer client_data)
{
Arg args[4];
Cardinal num_args;
struct xwindow *wp = xw_status_win;
nhUse(call_data);
nhUse(client_data);
if (w == wp->w) {
num_args = 0;
XtSetArg(args[num_args], XtNwidth, &wp->pixel_width); num_args++;
XtSetArg(args[num_args], XtNwidth, &wp->pixel_height); num_args++;
XtGetValues(w, args, num_args);
} else {
impossible("Status Window resized, but of what widget?");
}
/* tell core to call us back for a full status update */
disp.botlx = TRUE;
} }
void void
@@ -1264,6 +1335,9 @@ static Widget init_column(const char *, Widget, Widget, Widget, int *, int);
static void fixup_cond_widths(void); static void fixup_cond_widths(void);
static Widget init_info_form(Widget, Widget, Widget); static Widget init_info_form(Widget, Widget, Widget);
/* narrower values for the array initializer */
#define W0 (Widget) 0
#define P0 (Pixel) 0
/* /*
* Notes: * Notes:
* + Alignment needs a different init value, because -1 is an alignment. * + Alignment needs a different init value, because -1 is an alignment.
@@ -1274,67 +1348,71 @@ static Widget init_info_form(Widget, Widget, Widget);
*/ */
static struct X_status_value shown_stats[NUM_STATS] = { static struct X_status_value shown_stats[NUM_STATS] = {
/* 0 */ /* 0 */
{ "", SV_NAME, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "", SV_NAME, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* 1 */ /* 1 */
{ "Strength", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Strength", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Dexterity", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Dexterity", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Constitution", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Constitution", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Intelligence", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Intelligence", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* 5 */ /* 5 */
{ "Wisdom", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Wisdom", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Charisma", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Charisma", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* F_NAME: 7 */ /* F_NAME: 7 */
{ "", SV_LABEL, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "", SV_LABEL, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* F_DLEVEL: 8 */ /* F_DLEVEL: 8 */
{ "", SV_LABEL, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "", SV_LABEL, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Gold", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Gold", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* F_HP: 10 */ /* F_HP: 10 */
{ "Hit Points", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Hit Points", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Max HP", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Max HP", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Power", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Power", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Max Power", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Max Power", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Armor Class", SV_VALUE, (Widget) 0, 256L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Armor Class", SV_VALUE, W0, 256L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* F_XP_LEVL: 15 */ /* F_XP_LEVL: 15 */
{ "Xp Level", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Xp Level", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* also 15 (overloaded field) */ /* also 15 (overloaded field) */
/*{ "Hit Dice", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 },*/ /*{ "Hit Dice", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },*/
/* F_EXP_PTS: 16 (optionally displayed) */ /* F_EXP_PTS: 16 (optionally displayed) */
{ "Exp Points", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Exp Points", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
{ "Alignment", SV_VALUE, (Widget) 0, -2L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Alignment", SV_VALUE, W0, -2L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* 18, optionally displayed */ /* 18, optionally displayed */
{ "Time", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Time", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* 19, condtionally present, optionally displayed when present */ /* 19, condtionally present, optionally displayed when present */
{ "Score", SV_VALUE, (Widget) 0, -1L, 0, FALSE, FALSE, FALSE, 0, 0, 0 }, { "Score", SV_VALUE, W0, -1L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
/* F_HUNGER: 20 (blank if 'normal') */ /* F_HUNGER: 20 (blank if 'normal') */
{ "", SV_NAME, (Widget) 0, -1L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "", SV_NAME, W0, -1L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
/* F_ENCUMBER: 21 (blank if unencumbered) */ /* F_ENCUMBER: 21 (blank if unencumbered) */
{ "", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Trapped", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Trapped", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Tethered", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Tethered", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Levitating", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Levitating", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
/* 25 */ /* 25 */
{ "Flying", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Flying", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Riding", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Riding", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Grabbed!", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Grabbed!", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
/* F_STONE: 28 */ /* F_STONE: 28 */
{ "Petrifying", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Petrifying", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Slimed", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Slimed", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
/* 30 */ /* 30 */
{ "Strangled", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Strangled", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Food Pois", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Food Pois", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Term Ill", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Term Ill", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
/* F_IN_LAVA: 33 */ /* F_IN_LAVA: 33 */
{ "Sinking", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Sinking", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Held", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Held", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
/* 35 */ /* 35 */
{ "Holding", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Holding", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Blind", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Blind", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Deaf", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Deaf", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Stunned", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Stunned", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
{ "Confused", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Confused", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
/* F_HALLU: 40 (full spelling truncated due to space limitations) */ /* F_HALLU: 40 (full spelling truncated due to space limitations) */
{ "Hallucinat", SV_NAME, (Widget) 0, 0L, 0, FALSE, TRUE, FALSE, 0, 0, 0 }, { "Hallucinat", SV_NAME, W0, 0L, 0, FALSE, TRUE, FALSE, P0, 0, 0 },
/* F_VERS; optionally shown, generally treated as a pseudo-condition */
{ "Version 1.2.3", SV_LABEL, W0, 0L, 0, FALSE, FALSE, FALSE, P0, 0, 0 },
}; };
#undef W0
#undef P0
/* /*
* The following are supported by the core but not yet handled here: * The following are supported by the core but not yet handled here:
* bareh 'bare handed' (no weapon and no gloves) * bareh 'bare handed' (no weapon and no gloves)
@@ -1350,13 +1428,17 @@ static struct X_status_value shown_stats[NUM_STATS] = {
* woundedl 'wounded legs' (can't kick; temporary dex loss) * woundedl 'wounded legs' (can't kick; temporary dex loss)
*/ */
/* overloaded condition fields */ /* some conditions are mutually exclusive so we overload their fields in
order to share same display slot */
static const struct f_overload cond_ovl[] = { static const struct f_overload cond_ovl[] = {
{ (BL_MASK_TRAPPED | BL_MASK_TETHERED), { (BL_MASK_TRAPPED | BL_MASK_TETHERED),
{ { BL_MASK_TRAPPED, F_TRAPPED }, { { BL_MASK_TRAPPED, F_TRAPPED },
{ BL_MASK_TETHERED, F_TETHERED } }, { BL_MASK_TETHERED, F_TETHERED } },
}, },
{ (BL_MASK_HELD | BL_MASK_HOLDING), {
/* BL_GRABBED is mutually exclusive with these but is more severe so
is shown separately rather than being overloaded with them */
(BL_MASK_HELD | BL_MASK_HOLDING),
{ { BL_MASK_HELD, F_HELD }, { { BL_MASK_HELD, F_HELD },
{ BL_MASK_HOLDING, F_HOLDING } }, { BL_MASK_HOLDING, F_HOLDING } },
}, },
@@ -1466,22 +1548,28 @@ update_val(struct X_status_value *attr_rec, long new_value)
mnam[k] = highc(mnam[k]); mnam[k] = highc(mnam[k]);
} }
Strcat(buf, mnam); Strcat(buf, mnam);
} else } else {
Strcat(buf, Strcat(buf,
rank_of(u.ulevel, gp.pl_character[0], flags.female)); rank_of(u.ulevel, gp.pl_character[0], flags.female));
}
} else if (attr_rec == &shown_stats[F_DLEVEL]) { } else if (attr_rec == &shown_stats[F_DLEVEL]) {
if (!describe_level(buf, 0)) { if (!describe_level(buf, 0)) {
Strcpy(buf, gd.dungeons[u.uz.dnum].dname); Strcpy(buf, gd.dungeons[u.uz.dnum].dname);
Sprintf(eos(buf), ", level %d", depth(&u.uz)); Sprintf(eos(buf), ", level %d", depth(&u.uz));
} }
} else if (attr_rec == &shown_stats[F_VERS]) {
if (flags.showvers)
(void) status_version(buf, sizeof buf, FALSE);
else
buf[0] = '\0';
} else { } else {
impossible("update_val: unknown label type \"%s\"", impossible("update_val: unknown label type \"%s\"",
attr_rec->name); attr_rec->name);
return; return;
} }
if (strcmp(buf, attr_rec->name) == 0) if (!strcmp(buf, attr_rec->name))
return; /* same */ return; /* same */
/* Set the label. 'name' field is const for most entries; /* Set the label. 'name' field is const for most entries;
@@ -1619,8 +1707,10 @@ update_val(struct X_status_value *attr_rec, long new_value)
/* /*
* Now highlight the changed information. Don't highlight Time because * Now highlight the changed information. Don't highlight Time because
* it's continually changing. For others, don't highlight if this is * it's continually changing. Don't highlight version because once set
* the first update. If already highlighted, don't change it unless * it only changes if player modifies 'versinfo' option. For others,
* don't highlight if this is the first update.
* If already highlighted, don't change it unless
* it's being set to blank (where that item should be reset now instead * it's being set to blank (where that item should be reset now instead
* of showing highlighted blank until the next expiration check). * of showing highlighted blank until the next expiration check).
* *
@@ -1630,9 +1720,11 @@ update_val(struct X_status_value *attr_rec, long new_value)
* highlight because the field becomes blank. * highlight because the field becomes blank.
*/ */
if (attr_rec->after_init) { if (attr_rec->after_init) {
/* toggle if not highlighted and just set to nonblank or if /* toggle if not highlighted and being set to nonblank or if
already highlighted and just set to blank */ already highlighted and being set to blank */
if (attr_rec != &shown_stats[F_TIME] && !attr_rec->set ^ !*buf) { if (attr_rec != &shown_stats[F_TIME]
&& attr_rec != &shown_stats[F_VERS]
&& !attr_rec->set ^ !*buf) {
/* But don't hilite if inverted from status_hilite since /* But don't hilite if inverted from status_hilite since
it will already be hilited by apply_hilite_attributes(). */ it will already be hilited by apply_hilite_attributes(). */
if (!attr_rec->inverted_hilite) { if (!attr_rec->inverted_hilite) {
@@ -1708,7 +1800,7 @@ name_widget_has_label(struct X_status_value *sv)
XtSetArg(args[0], XtNlabel, &label); XtSetArg(args[0], XtNlabel, &label);
XtGetValues(sv->w, args, ONE); XtGetValues(sv->w, args, ONE);
return strlen(label) > 0; return (*label != '\0');
} }
static void static void
@@ -1746,10 +1838,11 @@ apply_hilite_attributes(struct X_status_value *sv, int attributes)
* dlvl, gold, hp, power, ac, {level & exp or HD **}, time, * dlvl, gold, hp, power, ac, {level & exp or HD **}, time,
* status * (stone, slime, strngl, foodpois, termill, * status * (stone, slime, strngl, foodpois, termill,
* hunger, encumbrance, lev, fly, ride, * hunger, encumbrance, lev, fly, ride,
* blind, deaf, stun, conf, hallu) * blind, deaf, stun, conf, hallu, version ***)
* *
* [*] order of status fields is different on tty. * [*] order of status fields is different on tty.
* [**] HD is shown instead of level and exp if Upolyd. * [**] HD is shown instead of level and exp if Upolyd.
* [***] version is optional, right-justified after conditions
*/ */
static void static void
update_fancy_status_field(int i, int color, int attributes) update_fancy_status_field(int i, int color, int attributes)
@@ -1853,6 +1946,11 @@ update_fancy_status_field(int i, int color, int attributes)
condmask = BL_MASK_HALLU; condmask = BL_MASK_HALLU;
break; break;
/* pseudo-condition */
case F_VERS:
val = (long) flags.versinfo; /* 1..7 */
break;
case F_NAME: case F_NAME:
case F_DLEVEL: case F_DLEVEL:
val = (long) 0L; val = (long) 0L;
@@ -1942,7 +2040,7 @@ update_fancy_status_field(int i, int color, int attributes)
static void static void
update_fancy_status(boolean force_update) update_fancy_status(boolean force_update)
{ {
static boolean old_showtime, old_showexp, old_showscore; static boolean old_showtime, old_showexp, old_showscore, old_showvers;
static int old_upolyd = -1; /* -1: force first time update */ static int old_upolyd = -1; /* -1: force first time update */
int i; int i;
@@ -1950,7 +2048,8 @@ update_fancy_status(boolean force_update)
|| Upolyd != old_upolyd /* Xp vs HD */ || Upolyd != old_upolyd /* Xp vs HD */
|| flags.time != old_showtime || flags.time != old_showtime
|| flags.showexp != old_showexp || flags.showexp != old_showexp
|| flags.showscore != old_showscore) { || flags.showscore != old_showscore
|| flags.showvers != old_showvers) {
/* update everything; usually only need this on the very first /* update everything; usually only need this on the very first
time, then later if the window gets resized or if poly/unpoly time, then later if the window gets resized or if poly/unpoly
triggers Xp <-> HD switch or if an optional field gets triggers Xp <-> HD switch or if an optional field gets
@@ -1965,6 +2064,7 @@ update_fancy_status(boolean force_update)
old_showtime = flags.time; old_showtime = flags.time;
old_showexp = flags.showexp; old_showexp = flags.showexp;
old_showscore = flags.showscore; old_showscore = flags.showscore;
old_showvers = flags.showvers;
} }
} }
@@ -2188,8 +2288,10 @@ set_widths(struct X_status_value *sv, int width1, int width2)
} }
static Widget static Widget
init_column(const char *name, Widget parent, Widget top, Widget left, init_column(
int *col_indices, int xtrawidth) const char *name,
Widget parent, Widget top, Widget left,
int *col_indices, int xtrawidth)
{ {
Widget form; Widget form;
Arg args[4]; Arg args[4];
@@ -2251,6 +2353,7 @@ init_column(const char *name, Widget parent, Widget top, Widget left,
* on run-time settings; Xp-level is replaced by Hit-Dice (and Exp-points * on run-time settings; Xp-level is replaced by Hit-Dice (and Exp-points
* suppressed) when the hero is polymorphed. Title and Dungeon-Level span * suppressed) when the hero is polymorphed. Title and Dungeon-Level span
* two columns and might expand to more if 'hitpointbar' is implemented. * two columns and might expand to more if 'hitpointbar' is implemented.
* Version is optional, right justified, and much wider than the others.
* *
Title ("Plname the Rank") <> <> <> <> Title ("Plname the Rank") <> <> <> <>
Dungeon-Branch-and-Level <> Hunger Grabbed Held Dungeon-Branch-and-Level <> Hunger Grabbed Held
@@ -2258,13 +2361,10 @@ init_column(const char *name, Widget parent, Widget top, Widget left,
Power-points Max-Power Dexterity Trapped Slimed Deaf Power-points Max-Power Dexterity Trapped Slimed Deaf
Armor-class Alignment Constitution Levitation Strangled Stunned Armor-class Alignment Constitution Levitation Strangled Stunned
Xp-level [Exp-points] Intelligence Flying Food-Pois Confused Xp-level [Exp-points] Intelligence Flying Food-Pois Confused
Gold [Score] Wisdom Riding Term-Ill Hallucinatg Gold [Score] Wisdom Riding Term-Ill Hallucinat
<> [Time] Charisma <> Sinking <> <> [Time] Charisma <> Sinking Version
* *
* A seventh column is going to be needed to fit in more conditions. * A seventh column is going to be needed to fit in more conditions.
*
* Possible enhancement: if Exp-points and Score are both disabled, move
* Gold to the Exp-points slot.
*/ */
/* including F_DUMMY makes the three status condition columns evenly /* including F_DUMMY makes the three status condition columns evenly
@@ -2278,7 +2378,7 @@ static int status_indices[3][11] = {
{ F_DUMMY, F_GRABBED, F_STONE, F_SLIME, F_STRNGL, { F_DUMMY, F_GRABBED, F_STONE, F_SLIME, F_STRNGL,
F_FOODPOIS, F_TERMILL, F_IN_LAVA, -1, 0, 0 }, F_FOODPOIS, F_TERMILL, F_IN_LAVA, -1, 0, 0 },
{ F_DUMMY, F_HELD, F_BLIND, F_DEAF, F_STUN, { F_DUMMY, F_HELD, F_BLIND, F_DEAF, F_STUN,
F_CONF, F_HALLU, F_DUMMY, -1, 0, 0 }, F_CONF, F_HALLU, F_VERS, -1, 0, 0 },
}; };
/* used to fill up the empty space to right of 3rd status condition column */ /* used to fill up the empty space to right of 3rd status condition column */
static int leftover_indices[] = { F_DUMMY, -1, 0, 0 }; static int leftover_indices[] = { F_DUMMY, -1, 0, 0 };
@@ -2398,6 +2498,23 @@ fixup_cond_widths(void)
w2 += 15; w2 += 15;
} }
} }
{
Arg args[3];
Dimension vers_width = 0;
struct X_status_value *sv = &shown_stats[F_VERS];
if (sv) {
XtSetArg(args[0], XtNwidth, &vers_width);
XtGetValues(sv->w, args, ONE);
if (vers_width) {
vers_width *= 3;
XtSetArg(args[0], XtNwidth, vers_width);
XtSetArg(args[1], nhStr(XtNjustify), XtJustifyRight);
XtSetValues(sv->w, args, TWO);
}
}
}
} }
/* /*
@@ -2434,7 +2551,14 @@ create_fancy_status(Widget parent, Widget top)
Sprintf(buf, "status_condition%d", i + 1); Sprintf(buf, "status_condition%d", i + 1);
w = init_column(buf, form, (Widget) 0, w, status_indices[i], 0); w = init_column(buf, form, (Widget) 0, w, status_indices[i], 0);
} }
fixup_cond_widths(); /* make all 3 status_conditionN columns same width */ fixup_cond_widths(); /* make all 3 status_conditionN columns same width
* (actually, the slot for F_VERS is much wider) */
/* TODO:
* Calculate and set the width of the F_VERS widjet to be from the
* start of the third condition column through the right edge and
* get rid of the dummy column.
*/
/* extra dummy 'column' to allocate any remaining space below the map */ /* extra dummy 'column' to allocate any remaining space below the map */
(void) init_column("status_leftover", form, (Widget) 0, w, (void) init_column("status_leftover", form, (Widget) 0, w,
leftover_indices, 0); leftover_indices, 0);

View File

@@ -251,12 +251,12 @@ draw_horizontal(boolean border)
/* almost all fields already come with a leading space; /* almost all fields already come with a leading space;
"xspace" indicates places where we'll generate an extra one */ "xspace" indicates places where we'll generate an extra one */
static const enum statusfields static const enum statusfields
twolineorder[3][15] = { twolineorder[3][16] = {
{ BL_TITLE, { BL_TITLE,
/*xspace*/ BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, /*xspace*/ BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
/*xspace*/ BL_ALIGN, /*xspace*/ BL_ALIGN,
/*xspace*/ BL_SCORE, /*xspace*/ BL_SCORE,
BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD }, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD },
{ BL_LEVELDESC, { BL_LEVELDESC,
/*xspace*/ BL_GOLD, /*xspace*/ BL_GOLD,
/*xspace*/ BL_HP, BL_HPMAX, /*xspace*/ BL_HP, BL_HPMAX,
@@ -264,16 +264,16 @@ draw_horizontal(boolean border)
/*xspace*/ BL_AC, /*xspace*/ BL_AC,
/*xspace*/ BL_XP, BL_EXP, BL_HD, /*xspace*/ BL_XP, BL_EXP, BL_HD,
/*xspace*/ BL_TIME, /*xspace*/ BL_TIME,
/*xspace*/ BL_HUNGER, BL_CAP, BL_CONDITION, /*xspace*/ BL_HUNGER, BL_CAP, BL_CONDITION, BL_VERS,
BL_FLUSH }, BL_FLUSH },
{ BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, { BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD,
blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }
}, },
threelineorder[3][15] = { /* moves align to line 2, leveldesc+ to 3 */ threelineorder[3][16] = { /* moves align to line 2, leveldesc+ to 3 */
{ BL_TITLE, { BL_TITLE,
/*xspace*/ BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, /*xspace*/ BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
/*xspace*/ BL_SCORE, /*xspace*/ BL_SCORE,
BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD },
{ BL_ALIGN, { BL_ALIGN,
/*xspace*/ BL_GOLD, /*xspace*/ BL_GOLD,
/*xspace*/ BL_HP, BL_HPMAX, /*xspace*/ BL_HP, BL_HPMAX,
@@ -281,14 +281,15 @@ draw_horizontal(boolean border)
/*xspace*/ BL_AC, /*xspace*/ BL_AC,
/*xspace*/ BL_XP, BL_EXP, BL_HD, /*xspace*/ BL_XP, BL_EXP, BL_HD,
/*xspace*/ BL_HUNGER, BL_CAP, /*xspace*/ BL_HUNGER, BL_CAP,
BL_FLUSH, blPAD, blPAD }, BL_FLUSH, blPAD, blPAD, blPAD },
{ BL_LEVELDESC, { BL_LEVELDESC,
/*xspace*/ BL_TIME, /*xspace*/ BL_TIME,
/*xspecial*/ BL_CONDITION, /*xspecial*/ BL_CONDITION,
/*xspecial*/ BL_VERS,
BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD,
blPAD, blPAD, blPAD, blPAD } blPAD, blPAD, blPAD, blPAD }
}; };
const enum statusfields (*fieldorder)[15]; const enum statusfields (*fieldorder)[16];
coordxy spacing[MAXBLSTATS], valline[MAXBLSTATS]; coordxy spacing[MAXBLSTATS], valline[MAXBLSTATS];
enum statusfields fld, prev_fld; enum statusfields fld, prev_fld;
char *text, *p, cbuf[BUFSZ], ebuf[STATVAL_WIDTH]; char *text, *p, cbuf[BUFSZ], ebuf[STATVAL_WIDTH];
@@ -297,11 +298,11 @@ draw_horizontal(boolean border)
char sbuf[STATVAL_WIDTH]; char sbuf[STATVAL_WIDTH];
#endif #endif
int i, j, number_of_lines, int i, j, number_of_lines,
cap_and_hunger, exp_points, sho_score, cap_and_hunger, exp_points, sho_score, sho_vers,
/* both height and width get their values set, /* both height and width get their values set,
* but only width gets used in this function */ * but only width gets used in this function */
height UNUSED, width, w, xtra, clen, x, y, t, ex, ey, height UNUSED, width, w, xtra, clen, x, y, t, ex, ey,
condstart = 0, conddummy = 0; condstart = 0, conddummy = 0, versstart = 0;
#ifdef STATUS_HILITES #ifdef STATUS_HILITES
int coloridx = NO_COLOR, attrmask = 0; int coloridx = NO_COLOR, attrmask = 0;
#endif /* STATUS_HILITES */ #endif /* STATUS_HILITES */
@@ -357,6 +358,10 @@ draw_horizontal(boolean border)
exp_points = (flags.showexp ? 1 : 0); exp_points = (flags.showexp ? 1 : 0);
/* don't bother conditionalizing this; always 0 for !SCORE_ON_BOTL */ /* don't bother conditionalizing this; always 0 for !SCORE_ON_BOTL */
sho_score = (status_activefields[BL_SCORE] != 0); sho_score = (status_activefields[BL_SCORE] != 0);
sho_vers = (status_activefields[BL_VERS] != 0);
versstart = sho_vers ? (width - (int) strlen(status_vals[BL_VERS])
+ (border ? 1 : 0))
: 0;
/* simplify testing which fields reside on which lines; assume line #0 */ /* simplify testing which fields reside on which lines; assume line #0 */
(void) memset((genericptr_t) valline, 0, sizeof valline); (void) memset((genericptr_t) valline, 0, sizeof valline);
@@ -423,6 +428,8 @@ draw_horizontal(boolean border)
text = cbuf; /* for 'w += strlen(text)' below */ text = cbuf; /* for 'w += strlen(text)' below */
spacing[fld] = (cap_and_hunger == 0); spacing[fld] = (cap_and_hunger == 0);
break; break;
case BL_VERS:
spacing[fld] = 1;
case BL_STR: case BL_STR:
case BL_HP: case BL_HP:
case BL_ENE: case BL_ENE:
@@ -573,6 +580,11 @@ draw_horizontal(boolean border)
} else if (fld != BL_CONDITION) { } else if (fld != BL_CONDITION) {
/* regular field, including title if no hitpointbar */ /* regular field, including title if no hitpointbar */
if (fld == BL_VERS) {
getyx(win, y, x);
if (x < versstart)
wmove(win, y, versstart); /* right justify */
}
#ifdef STATUS_HILITES #ifdef STATUS_HILITES
coloridx = curses_status_colors[fld]; /* includes attribute */ coloridx = curses_status_colors[fld]; /* includes attribute */
if (iflags.hilite_delta && coloridx != NO_COLOR) { if (iflags.hilite_delta && coloridx != NO_COLOR) {
@@ -615,6 +627,14 @@ draw_horizontal(boolean border)
y = j + (border ? 1 : 0); y = j + (border ? 1 : 0);
/* cbuf[] was populated above; clen is its length */ /* cbuf[] was populated above; clen is its length */
if (number_of_lines == 3) { if (number_of_lines == 3) {
int vlen = (sho_vers
&& fieldorder[j][i + 1] == BL_VERS)
? ((int) strlen(status_vals[BL_VERS])
+ spacing[BL_VERS])
: 0;
clen += vlen; /* when aligning conditions, treat
* version as if an added condition */
/* /*
* For 3-line status, align conditions with hunger * For 3-line status, align conditions with hunger
* (or where it would have been, when not shown), * (or where it would have been, when not shown),
@@ -632,6 +652,7 @@ draw_horizontal(boolean border)
else else
wmove(win, y, width + (border ? 1 : 0) - clen); wmove(win, y, width + (border ? 1 : 0) - clen);
} }
clen -= vlen;
} }
/* 'asis' was set up by first curs_stat_conds() call /* 'asis' was set up by first curs_stat_conds() call
above; True means that none of the conditions above; True means that none of the conditions
@@ -663,31 +684,34 @@ draw_vertical(boolean border)
removed if we need to shrink to fit within height limit (very rare) */ removed if we need to shrink to fit within height limit (very rare) */
static const enum statusfields fieldorder[] = { static const enum statusfields fieldorder[] = {
BL_TITLE, /* might be overlaid by hitpoint bar */ BL_TITLE, /* might be overlaid by hitpoint bar */
/* 4:blank */ /* 5:blank */
BL_HP, BL_HPMAX, BL_HP, BL_HPMAX,
BL_ENE, BL_ENEMAX, BL_ENE, BL_ENEMAX,
BL_AC, BL_AC,
/* 3:blank */ /* 4:blank */
BL_LEVELDESC, BL_LEVELDESC,
BL_ALIGN, BL_ALIGN,
BL_XP, BL_EXP, BL_HD, BL_XP, BL_EXP, BL_HD,
BL_GOLD, BL_GOLD,
/* 2:blank (but only if time or score or both enabled) */ /* 3:blank (but only if time or score or both enabled) */
BL_TIME, BL_TIME,
BL_SCORE, BL_SCORE,
/* 1:blank */ /* 2:blank */
BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
/* 5:blank (if any of hunger, encumbrance, or conditions appear) */ /* 6:blank (if any of hunger, encumbrance, or conditions appear) */
BL_HUNGER, BL_CAP, /* these two are shown on same line */ BL_HUNGER, BL_CAP, /* these two are shown on same line */
BL_CONDITION, /* shown three per line so may take up to four lines */ BL_CONDITION, /* shown three per line so may take up to four lines */
/* 1:blank (bottom justified) */
BL_VERS,
BL_FLUSH BL_FLUSH
}; };
static const enum statusfields shrinkorder[] = { static const enum statusfields shrinkorder[] = {
BL_STR, BL_SCORE, BL_TIME, BL_LEVELDESC, BL_HP, BL_VERS, BL_STR, BL_SCORE, BL_TIME, BL_LEVELDESC, BL_HP,
BL_CONDITION, BL_CAP, BL_HUNGER BL_CONDITION, BL_CAP, BL_HUNGER
}; };
coordxy spacing[MAXBLSTATS]; coordxy spacing[MAXBLSTATS];
int i, fld, cap_and_hunger, time_and_score, cond_count, per_line; int i, fld, cap_and_hunger, time_and_score, cond_count,
sho_vers, per_line;
char *text; char *text;
#ifdef STATUS_HILITES #ifdef STATUS_HILITES
char *p = 0, savedch = '\0'; char *p = 0, savedch = '\0';
@@ -729,6 +753,7 @@ draw_vertical(boolean border)
++cond_count; ++cond_count;
} }
per_line = 2; /* will be changed to 3 if status becomes too tall */ per_line = 2; /* will be changed to 3 if status becomes too tall */
sho_vers = (status_activefields[BL_VERS] ? 1 : 0);
/* count how many lines we'll need; we normally space several groups of /* count how many lines we'll need; we normally space several groups of
fields with blank lines but might need to compress some of those out */ fields with blank lines but might need to compress some of those out */
@@ -753,7 +778,7 @@ draw_vertical(boolean border)
/* unlike hunger+cap, score is shown on separate line from time; /* unlike hunger+cap, score is shown on separate line from time;
needs time+score separator if time is inactive */ needs time+score separator if time is inactive */
spacing[fld] = (time_and_score == 2) ? 2 spacing[fld] = (time_and_score == 2) ? 2
: (time_and_score & 1) ? 1 : 0; : (time_and_score == 3) ? 1 : 0;
break; break;
case BL_HUNGER: case BL_HUNGER:
/* separated from characteristics unless blank */ /* separated from characteristics unless blank */
@@ -773,6 +798,9 @@ draw_vertical(boolean border)
if (cond_count > per_line) if (cond_count > per_line)
height_needed += (cond_count - 1) / per_line; height_needed += (cond_count - 1) / per_line;
break; break;
case BL_VERS:
spacing[fld] = sho_vers ? 2 : 0;
break;
case BL_XP: case BL_XP:
case BL_HD: case BL_HD:
default: default:
@@ -785,9 +813,9 @@ draw_vertical(boolean border)
if (height_needed > height) { if (height_needed > height) {
/* if there are a lot of status conditions, compress them first */ /* if there are a lot of status conditions, compress them first */
if (per_line == 2 && cond_count > per_line) { if (per_line == 2 && cond_count > per_line) {
height_needed -= (cond_count - 1) / per_line; height_needed -= (cond_count - 1) / per_line;
per_line = 3; per_line = 3;
height_needed += (cond_count - 1) / per_line; height_needed += (cond_count - 1) / per_line;
} }
if (height_needed > height) { if (height_needed > height) {
for (i = 0; i < SIZE(shrinkorder); ++i) { for (i = 0; i < SIZE(shrinkorder); ++i) {
@@ -802,7 +830,7 @@ draw_vertical(boolean border)
#ifdef SCORE_ON_BOTL #ifdef SCORE_ON_BOTL
/* with all optional fields and every status condition (12 out /* with all optional fields and every status condition (12 out
of the 13 since two are mutually exclusive) active, we need of the 13 since two are mutually exclusive) active, we need
21 non-blank lines; curses_create_main_windows() used to 22 non-blank lines; curses_create_main_windows() used to
require 24 lines or more in order to enable vertical status, require 24 lines or more in order to enable vertical status,
but that has been relaxed to 20 so height_needed might still but that has been relaxed to 20 so height_needed might still
be too high after suppressing all the blank lines */ be too high after suppressing all the blank lines */
@@ -810,11 +838,18 @@ draw_vertical(boolean border)
height_needed -= spacing[BL_SCORE]; height_needed -= spacing[BL_SCORE];
spacing[BL_SCORE] = 0; spacing[BL_SCORE] = 0;
time_and_score &= ~2; time_and_score &= ~2;
/* height_needed isn't used beyond here but we keep it accurate */
nhUse(height_needed);
} }
#endif #endif
} else if (height_needed < height) {
if (sho_vers) {
/* bottom justify 'version' */
spacing[BL_VERS] += height - height_needed; /* 2 + (h - h') */
height_needed = height;
}
} }
/* height_needed isn't used beyond here but was updated (for BL_SCORE
or BL_VERS) to keep it accurate in case that changes someday */
nhUse(height_needed);
if (border) if (border)
x++, y++; x++, y++;
@@ -828,9 +863,8 @@ draw_vertical(boolean border)
continue; continue;
if (spacing[fld]) { if (spacing[fld]) {
wmove(win, y++, x); /* move to next line */ y += spacing[fld];
if (spacing[fld] == 2) wmove(win, y - 1, x); /* move to next (or further) line */
wmove(win, y++, x); /* skip a line */
} }
if (fld == BL_TITLE && iflags.wc2_hitpointbar) { if (fld == BL_TITLE && iflags.wc2_hitpointbar) {
@@ -903,7 +937,7 @@ draw_vertical(boolean border)
} else { } else {
/* status conditions */ /* status conditions */
if (cond_count) { if (cond_count) {
/* output active conditions; usually two per line, but /* output active conditions; usually two per line, but if
window isn't tall enough, it's increased to three per line; window isn't tall enough, it's increased to three per line;
cursor is already positioned where they should start */ cursor is already positioned where they should start */
curs_stat_conds(1, per_line, &x, &y, curs_stat_conds(1, per_line, &x, &y,
@@ -987,7 +1021,7 @@ DISABLE_WARNING_FORMAT_NONLITERAL
static void static void
curs_stat_conds( curs_stat_conds(
int vert_cond, /* 0 => horizontal, 1 => vertical */ int vert_cond, /* 0 => horizontal, 1 => vertical */
int per_line, /* for vertical number of conditions per line */ int per_line, /* for vertical, number of conditions per line */
int *x, int *y, /* real for vertical, ignored otherwise */ int *x, int *y, /* real for vertical, ignored otherwise */
char *condbuf, /* optional output; collect string of conds */ char *condbuf, /* optional output; collect string of conds */
boolean *nohilite) /* optional output; indicates whether -*/ boolean *nohilite) /* optional output; indicates whether -*/
@@ -1087,7 +1121,7 @@ curs_stat_conds(
} }
#endif /* STATUS_HILITES */ #endif /* STATUS_HILITES */
/* if that was #3 of 3 advance to next line */ /* if that was #3 of 3 advance to next line */
if (do_vert && (++vert_cond % per_line) == 1) if (do_vert && cond_bits && (++vert_cond % per_line) == 1)
wmove(win, (*y)++, *x); wmove(win, (*y)++, *x);
} /* if cond_bits & bitmask */ } /* if cond_bits & bitmask */
} /* for i */ } /* for i */
@@ -1189,6 +1223,7 @@ curs_vert_status_vals(int win_width)
Sprintf(leadingspace, "%*s", Sprintf(leadingspace, "%*s",
(hp_width + 3) - fld_width, " "); (hp_width + 3) - fld_width, " ");
/*FALLTHRU*/ /*FALLTHRU*/
case BL_VERS:
case BL_EXP: case BL_EXP:
case BL_HUNGER: case BL_HUNGER:
case BL_CAP: case BL_CAP:
@@ -1202,6 +1237,17 @@ curs_vert_status_vals(int win_width)
Sprintf(status_vals_long[fldidx], "%*.*s: %s%s", Sprintf(status_vals_long[fldidx], "%*.*s: %s%s",
-lbl_width, lbl_width, lbl, leadingspace, text); -lbl_width, lbl_width, lbl, leadingspace, text);
*status_vals_long[fldidx] = highc(*status_vals_long[fldidx]); *status_vals_long[fldidx] = highc(*status_vals_long[fldidx]);
} else if (fldidx == BL_VERS && *text) {
int txtlen = (int) strlen(text);
/* right justify without "Version :" prefix; if longer than
width, keep only the *end* of the value */
if (txtlen >= win_width)
Strcpy(status_vals_long[BL_VERS],
eos((char *) text) - win_width);
else
Sprintf(status_vals_long[BL_VERS],
"%*s%s", win_width - txtlen, " ", text);
} else if ((fldidx == BL_HUNGER || fldidx == BL_CAP) && *text) { } else if ((fldidx == BL_HUNGER || fldidx == BL_CAP) && *text) {
/* hunger and enbumbrance are shown side-by-side in /* hunger and enbumbrance are shown side-by-side in
a 26 character or wider window; if leading space is a 26 character or wider window; if leading space is

View File

@@ -4192,28 +4192,28 @@ static const char *const encvals[3][6] = {
{ "", "Brd", "Strs", "Strn", "Ovtx", "Ovld" } { "", "Brd", "Strs", "Strn", "Ovtx", "Ovld" }
}; };
#define blPAD BL_FLUSH #define blPAD BL_FLUSH
#define MAX_PER_ROW 15 #define MAX_PER_ROW 16
/* 2 or 3 status lines */ /* 2 or 3 status lines */
static const enum statusfields static const enum statusfields
twolineorder[3][MAX_PER_ROW] = { twolineorder[3][MAX_PER_ROW] = {
{ BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN,
BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD }, BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD },
{ BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER,
BL_CAP, BL_CONDITION, BL_FLUSH }, BL_CAP, BL_CONDITION, BL_VERS, BL_FLUSH },
/* third row of array isn't used for twolineorder */ /* third row of array isn't used for twolineorder */
{ BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, { BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD,
blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }
}, },
/* Align moved from 1 to 2, Leveldesc+Time+Condition moved from 2 to 3 */ /* Align moved from 1 to 2, Leveldesc+Time+Cond+Vers moved from 2 to 3 */
threelineorder[3][MAX_PER_ROW] = { threelineorder[3][MAX_PER_ROW] = {
{ BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }, BL_SCORE, BL_FLUSH, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD },
{ BL_ALIGN, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, { BL_ALIGN, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX,
BL_AC, BL_XP, BL_EXP, BL_HD, BL_HUNGER, BL_AC, BL_XP, BL_EXP, BL_HD, BL_HUNGER,
BL_CAP, BL_FLUSH, blPAD, blPAD }, BL_CAP, BL_FLUSH, blPAD, blPAD, blPAD },
{ BL_LEVELDESC, BL_TIME, BL_CONDITION, BL_FLUSH, blPAD, blPAD, { BL_LEVELDESC, BL_TIME, BL_CONDITION, BL_VERS, BL_FLUSH, blPAD,
blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD } blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD, blPAD }
}; };
static const enum statusfields (*fieldorder)[MAX_PER_ROW]; static const enum statusfields (*fieldorder)[MAX_PER_ROW];
#undef MAX_PER_ROW #undef MAX_PER_ROW
@@ -4299,7 +4299,7 @@ tty_status_enablefield(
* BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, * BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH,
* BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, * 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_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX,
* BL_LEVELDESC, BL_EXP, BL_CONDITION * BL_LEVELDESC, BL_EXP, BL_CONDITION, BL_VERS
* -- fldindex could also be BL_FLUSH (-1), which is not really * -- 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 * windowport that it should output all changes received
@@ -4664,6 +4664,7 @@ status_sanity_check(void)
"BL_ENE", "BL_ENEMAX", "BL_XP", "BL_AC", "BL_HD", /* 11..15 */ "BL_ENE", "BL_ENEMAX", "BL_XP", "BL_AC", "BL_HD", /* 11..15 */
"BL_TIME", "BL_HUNGER", "BL_HP", "BL_HPMAX", /* 16..19 */ "BL_TIME", "BL_HUNGER", "BL_HP", "BL_HPMAX", /* 16..19 */
"BL_LEVELDESC", "BL_EXP", "BL_CONDITION", /* 20..22 */ "BL_LEVELDESC", "BL_EXP", "BL_CONDITION", /* 20..22 */
"BL_VERS", /* 23 */
}; };
static boolean in_sanity_check = FALSE; static boolean in_sanity_check = FALSE;
int i; int i;
@@ -4902,7 +4903,8 @@ static void
render_status(void) render_status(void)
{ {
long mask, bits; long mask, bits;
int i, x, y, idx, c, ci, row, tlth, num_rows, coloridx = 0, attrmask = 0; int i, x, y, idx, c, ci, row, tlth, num_rows,
coloridx = 0, attrmask = 0;
char *text; char *text;
struct WinDesc *cw = 0; struct WinDesc *cw = 0;
@@ -4935,13 +4937,24 @@ render_status(void)
* +-----------------+ * +-----------------+
*/ */
bits = tty_condition_bits; bits = tty_condition_bits;
/* if no bits are set, we can fall through condition /*
rendering code to finalx[] handling (and subsequent * If no bits are set, we can fall through condition
rest-of-line erasure if line is shorter than before) */ * rendering code to finalx[] handling (and subsequent
if (num_rows == MAX_STATUS_ROWS && bits != 0L) { * rest-of-line erasure if line is shorter than before).
int k; *
* First, when conditions are on 3rd row, they might
* be indented to line up with a position on 2nd row.
*/
if (row == MAX_STATUS_ROWS - 1 && bits != 0L) {
int cstart, last_col = cw->cols;
char *dat = &cw->data[y][0]; char *dat = &cw->data[y][0];
/* 'version' might follow conditions; if so, adjust
expectations for where conditions should end;
only matters when conditions are being indented */
if (status_activefields[BL_VERS]
&& fieldorder[row][i + 1] == BL_VERS)
last_col -= (int) tty_status[NOW][BL_VERS].lth;
/* line up with hunger (or where it would have /* line up with hunger (or where it would have
been when currently omitted); if there isn't been when currently omitted); if there isn't
enough room for that, right justify; or place enough room for that, right justify; or place
@@ -4951,20 +4964,23 @@ render_status(void)
if (tty_status[BEFORE][BL_HUNGER].y < row if (tty_status[BEFORE][BL_HUNGER].y < row
&& x < tty_status[BEFORE][BL_HUNGER].x && x < tty_status[BEFORE][BL_HUNGER].x
&& (tty_status[BEFORE][BL_HUNGER].x + tlth && (tty_status[BEFORE][BL_HUNGER].x + tlth
< cw->cols - 1)) < last_col - 1))
k = tty_status[BEFORE][BL_HUNGER].x; cstart = tty_status[BEFORE][BL_HUNGER].x;
else if (x + tlth < cw->cols - 1) else if (x + tlth < cw->cols - 1)
k = cw->cols - tlth; cstart = last_col - tlth;
else else
k = x; cstart = x;
while (x < k) { /* indent conditions to line them up with 2nd row */
if (dat[x - 1] != ' ') if (x < cstart) {
tty_putstatusfield(" ", x, y); do {
++x; if (dat[x - 1] != ' ')
tty_putstatusfield(" ", x, y);
} while (++x < cstart);
tty_status[NOW][BL_CONDITION].x = x;
tty_curs(WIN_STATUS, x, y);
} }
tty_status[NOW][BL_CONDITION].x = x;
tty_curs(WIN_STATUS, x, y);
} }
/* actually draw condition words */
for (c = 0; c < SIZE(conditions) && bits != 0L; ++c) { for (c = 0; c < SIZE(conditions) && bits != 0L; ++c) {
ci = cond_idx[c]; ci = cond_idx[c];
mask = conditions[ci].mask; mask = conditions[ci].mask;
@@ -5067,6 +5083,34 @@ render_status(void)
* | in a special case above | * | in a special case above |
* +-----------------------------+ * +-----------------------------+
*/ */
if (idx == BL_VERS
/* if 'version' is the last field in its row, right
justify it (otherwise just treat it as ordinary) */
&& fieldorder[row][i + 1] == BL_FLUSH) {
int vstart;
char *dat = &cw->data[y][0];
/* FIXME: there's something fishy going on here;
'x' ends up out of synch when conditions have
3rd row indentation and the indenting of version
overwrites them with spaces; this hides that */
int vx = tty_status[BEFORE][BL_CONDITION].x
+ tty_status[BEFORE][BL_CONDITION].lth;
if (i > 0 && fieldorder[row][i - 1] == BL_CONDITION
&& x != vx) {
x = vx;
tty_curs(WIN_STATUS, x, y);
}
/* indent version to right justify it */
vstart = cw->cols - (int) tty_status[NOW][idx].lth;
if (x < vstart) {
do {
if (dat[x - 1] != ' ')
tty_putstatusfield(" ", x, y);
} while (++x < vstart);
tty_status[NOW][BL_VERS].x = x;
}
}
if (iflags.hilite_delta) { if (iflags.hilite_delta) {
while (*text == ' ') { while (*text == ' ') {
tty_putstatusfield(" ", x++, y); tty_putstatusfield(" ", x++, y);
@@ -5104,7 +5148,7 @@ render_status(void)
* - Copy the entire tty_status struct. * - Copy the entire tty_status struct.
*/ */
tty_status[BEFORE][idx] = tty_status[NOW][idx]; tty_status[BEFORE][idx] = tty_status[NOW][idx];
} } /* for i=..., idx=fieldorder[][i] */
x = finalx[row][NOW]; x = finalx[row][NOW];
if ((x < finalx[row][BEFORE] || !finalx[row][BEFORE]) if ((x < finalx[row][BEFORE] || !finalx[row][BEFORE])
&& x + 1 < cw->cols) { && x + 1 < cw->cols) {
@@ -5116,7 +5160,7 @@ render_status(void)
* - Copy the last written column number on the row. * - Copy the last written column number on the row.
*/ */
finalx[row][BEFORE] = finalx[row][NOW]; finalx[row][BEFORE] = finalx[row][NOW];
} } /* for row=... */
return; return;
} }