curses run-time options

This started out as an attempt to document the curses options in the
Guidebook, but I didn't actually get that far.  Instead, integrate
the curses options better via more consistent WC/WC2 usage.  This
prevents 'guicolor' from showing up as a boolean option for non-curses
interface in curses+other binary.

For curses itself, let 'petattr' be set/reset via 'O'.  Also, accept
'Dim' as a possible pet highlight attribute since it already handles
all the other ordinary attributes.  I'm not sure what leftline and
rightline highlighting are supposed to do.  They were missing for
ncurses (or maybe they're misspelled for PDcurses?) but adding them
didn't produce any visible effect (using TERM=xterm-256color on OSX
with default font/character set).

Not addressed:
1) general confusion about compile-time vs run-time option filtering;
2) curses pet highlighting only works if 'color' option is enabled.
This commit is contained in:
PatR
2019-02-26 15:16:42 -08:00
parent 5a432d0c97
commit 1a028d1197
5 changed files with 178 additions and 89 deletions

View File

@@ -45,6 +45,12 @@ extern WINDOW *mapwin, *statuswin, *messagewin; /* Main windows */
# endif
#endif
#if !defined(A_LEFTLINE) && defined(A_LEFT)
#define A_LEFTLINE A_LEFT
#endif
#if !defined(A_RIGHTLINE) && defined(A_RIGHT)
#define A_RIGHTLINE A_RIGHT
#endif
typedef enum orient_type
{
@@ -158,6 +164,7 @@ extern void curses_rtrim(char *str);
extern int curses_get_count(int first_digit);
extern int curses_convert_attr(int attr);
extern int curses_read_attrs(char *attrs);
extern char *curses_fmt_attrs(char *);
extern int curses_convert_keys(int key);
extern int curses_get_mouse(int *mousex, int *mousey, int *mod);

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 options.c $NHDT-Date: 1551138503 2019/02/25 23:48:23 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.355 $ */
/* NetHack 3.6 options.c $NHDT-Date: 1551222973 2019/02/26 23:16:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.356 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2008. */
/* NetHack may be freely redistributed. See license for details. */
@@ -29,6 +29,7 @@ NEARDATA struct instance_flags iflags; /* provide linkage */
#ifdef CURSES_GRAPHICS
extern int curses_read_attrs(char *attrs);
extern char *curses_fmt_attrs(char *);
#endif
enum window_option_types {
@@ -131,9 +132,9 @@ static struct Bool_Opt {
{ "flush", (boolean *) 0, FALSE, SET_IN_FILE },
#endif
{ "force_invmenu", &iflags.force_invmenu, FALSE, SET_IN_GAME },
{ "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE },
{ "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE }, /*WC2*/
{ "goldX", &iflags.goldX, FALSE, SET_IN_GAME },
{ "guicolor", &iflags.wc2_guicolor, TRUE, SET_IN_GAME},
{ "guicolor", &iflags.wc2_guicolor, TRUE, SET_IN_GAME}, /*WC2*/
{ "help", &flags.help, TRUE, SET_IN_GAME },
{ "herecmd_menu", &iflags.herecmd_menu, FALSE, SET_IN_GAME },
{ "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/
@@ -209,7 +210,7 @@ static struct Bool_Opt {
{ "showscore", (boolean *) 0, FALSE, SET_IN_FILE },
#endif
{ "silent", &flags.silent, TRUE, SET_IN_GAME },
{ "softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE },
{ "softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE }, /*WC2*/
{ "sortpack", &flags.sortpack, TRUE, SET_IN_GAME },
{ "sparkle", &flags.sparkle, TRUE, SET_IN_GAME },
{ "splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME }, /*WC*/
@@ -228,7 +229,7 @@ static struct Bool_Opt {
#ifdef DEBUG
{ "travel_debug", &iflags.trav_debug, FALSE, SET_IN_WIZGAME }, /*hack.c*/
#endif
{ "use_darkgray", &iflags.wc2_darkgray, TRUE, SET_IN_FILE },
{ "use_darkgray", &iflags.wc2_darkgray, TRUE, SET_IN_FILE }, /*WC2*/
#ifdef WIN32
{ "use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME }, /*WC*/
#else
@@ -243,7 +244,7 @@ static struct Bool_Opt {
{ "whatis_menu", &iflags.getloc_usemenu, FALSE, SET_IN_GAME },
{ "whatis_moveskip", &iflags.getloc_moveskip, FALSE, SET_IN_GAME },
{ "wizweight", &iflags.wizweight, FALSE, SET_IN_WIZGAME },
{ "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME },
{ "wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME }, /*WC2*/
#ifdef ZEROCOMP
{ "zerocomp", &iflags.zerocomp,
#if defined(COMPRESS) || defined(ZLIB_COMP)
@@ -344,19 +345,18 @@ static struct Comp_Opt {
#ifdef CHANGE_COLOR
{ "palette",
#ifndef WIN32
"palette (00c/880/-fff is blue/yellow/reverse white)", 15,
SET_IN_GAME },
"palette (00c/880/-fff is blue/yellow/reverse white)", 15, SET_IN_GAME
#else
"palette (adjust an RGB color in palette (color-R-G-B)", 15,
SET_IN_FILE },
"palette (adjust an RGB color in palette (color-R-G-B)", 15, SET_IN_FILE
#endif
},
#if defined(MAC)
{ "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE },
#endif
#endif
{ "paranoid_confirmation", "extra prompting in certain situations", 28,
SET_IN_GAME },
{ "petattr", "attributes for highlighting pets", 12, SET_IN_FILE },
{ "petattr", "attributes for highlighting pets", 88, SET_IN_GAME },
{ "pettype", "your preferred initial pet type", 4, DISP_IN_GAME },
{ "pickup_burden", "maximum burden picked up before prompt", 20,
SET_IN_GAME },
@@ -409,6 +409,9 @@ static struct Comp_Opt {
#endif
{ "suppress_alert", "suppress alerts about version-specific features", 8,
SET_IN_GAME },
/* term_cols,term_rows -> WC2_TERM_SIZE (6: room to format 1..32767) */
{ "term_cols", "number of columns", 6, SET_IN_FILE }, /*WC2*/
{ "term_rows", "number of rows", 6, SET_IN_FILE }, /*WC2*/
{ "tile_width", "width of tiles", 20, DISP_IN_GAME }, /*WC*/
{ "tile_height", "height of tiles", 20, DISP_IN_GAME }, /*WC*/
{ "tile_file", "name of tile file", 70, DISP_IN_GAME }, /*WC*/
@@ -430,6 +433,7 @@ static struct Comp_Opt {
{ "whatis_filter",
"filter coordinate locations when targeting next or previous",
1, SET_IN_GAME },
{ "windowborders", "1 (on), 2 (off), 3 (auto)", 9, DISP_IN_GAME }, /*WC2*/
{ "windowcolors", "the foreground/background colors of windows", /*WC*/
80, DISP_IN_GAME },
{ "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME },
@@ -3325,6 +3329,7 @@ boolean tinitial, tfrom_file;
return retval;
}
#endif /* VIDEOSHADES */
#ifdef MSDOS
#ifdef NO_TERMS
/* video:string -- must be after longer tests */
@@ -3447,8 +3452,8 @@ boolean tinitial, tfrom_file;
if (negated) {
bad_negation(fullname, FALSE);
return FALSE;
} else {
#if defined(WIN32)
} else {
op = string_for_opt(opts, 0);
if (!op)
return FALSE;
@@ -3593,29 +3598,34 @@ boolean tinitial, tfrom_file;
}
return retval;
}
#ifdef CURSES_GRAPHICS
/* WINCAP2
* term_cols:amount */
* term_cols:amount or term_rows:amount */
fullname = "term_cols";
if (match_optname(opts, fullname, sizeof "term_cols" - 1, TRUE)) {
op = string_for_opt(opts, negated);
iflags.wc2_term_cols = atoi(op);
if (negated) {
bad_negation(fullname, FALSE);
return FALSE;
}
return retval;
}
if (match_optname(opts, fullname, 8, TRUE)
/* alternate spelling */
|| match_optname(opts, "term_columns", 9, TRUE)
/* different option but identical handlng */
|| (fullname = "term_rows", match_optname(opts, fullname, 8, TRUE))) {
long ltmp;
/* WINCAP2
* term_rows:amount */
fullname = "term_rows";
if (match_optname(opts, fullname, sizeof "term_rows" - 1, TRUE)) {
op = string_for_opt(opts, negated);
iflags.wc2_term_rows = atoi(op);
ltmp = atol(op);
if (negated) {
bad_negation(fullname, FALSE);
return FALSE;
retval = FALSE;
/* this just checks atol() sanity, not logical window size sanity */
} else if (ltmp <= 0L || ltmp >= (long) LARGEST_INT) {
config_error_add("Invalid %s: %ld", fullname, ltmp);
retval = FALSE;
} else {
if (!strcmp(fullname, "term_rows"))
iflags.wc2_term_rows = (int) ltmp;
else /* !strcmp(fullname, "term_cols") */
iflags.wc2_term_cols = (int) ltmp;
}
return retval;
}
@@ -3625,22 +3635,31 @@ boolean tinitial, tfrom_file;
fullname = "petattr";
if (match_optname(opts, fullname, sizeof "petattr" - 1, TRUE)) {
op = string_for_opt(opts, negated);
if (op && !negated) {
if (op && negated) {
bad_negation(fullname, TRUE);
retval = FALSE;
} else if (op) {
#ifdef CURSES_GRAPHICS
iflags.wc2_petattr = curses_read_attrs(op);
if (!curses_read_attrs(op)) {
int itmp = curses_read_attrs(op);
if (itmp == -1) {
config_error_add("Unknown %s parameter '%s'", fullname, opts);
return FALSE;
}
retval = FALSE;
} else
iflags.wc2_petattr = itmp;
#else
/* non-curses windowports will not use this flag anyway
* but the above will not compile if we don't have curses.
* Just set it to a sensible default: */
iflags.wc2_petattr = ATR_INVERSE
iflags.wc2_petattr = ATR_INVERSE;
#endif
} else if (negated) {
bad_negation(fullname, TRUE);
return FALSE;
iflags.wc2_petattr = ATR_NONE;
}
if (retval) {
iflags.hilite_pet = (iflags.wc2_petattr != ATR_NONE);
if (!initial)
need_redraw = TRUE;
}
return retval;
}
@@ -3648,28 +3667,31 @@ boolean tinitial, tfrom_file;
/* WINCAP2
* windowborders:n */
fullname = "windowborders";
if (match_optname(opts, fullname, sizeof "windowborders" - 1, TRUE)) {
if (match_optname(opts, fullname, 10, TRUE)) {
op = string_for_opt(opts, negated);
if (negated && op) {
bad_negation(fullname, TRUE);
return FALSE;
retval = FALSE;
} else {
int itmp;
if (negated)
iflags.wc2_windowborders = 2; /* Off */
itmp = 2; /* Off */
else if (!op)
iflags.wc2_windowborders = 1; /* On */
else /* Value supplied */
iflags.wc2_windowborders = atoi(op);
if ((iflags.wc2_windowborders > 3)
|| (iflags.wc2_windowborders < 1)) {
iflags.wc2_windowborders = 0;
config_error_add("Badoption - windowborders %s.", opts);
return FALSE;
itmp = 1; /* On */
else /* Value supplied; expect 1 (on), 2 (off), or 3 (auto) */
itmp = atoi(op);
if (itmp < 1 || itmp > 3) {
config_error_add("Invalid %s: %s.", fullname, opts);
retval = FALSE;
} else {
iflags.wc2_windowborders = itmp;
}
}
return retval;
}
#endif
#endif /* CURSES_GRAPHICS */
/* menustyle:traditional or combination or full or partial */
fullname = "menustyle";
@@ -5592,6 +5614,18 @@ char *buf;
if (flags.paranoia_bits & paranoia[i].flagmask)
Sprintf(eos(tmpbuf), " %s", paranoia[i].argname);
Strcpy(buf, tmpbuf[0] ? &tmpbuf[1] : "none");
} else if (!strcmp(optname, "petattr")) {
#ifdef CURSES_GRAPHICS
if (WINDOWPORT("curses")) {
char tmpbuf[QBUFSZ];
Strcpy(buf, curses_fmt_attrs(tmpbuf));
} else
#endif
if (iflags.wc2_petattr != 0)
Sprintf(buf, "0x%08x", iflags.wc2_petattr);
else
Strcpy(buf, defopt);
} else if (!strcmp(optname, "pettype")) {
Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat"
: (preferred_pet == 'd') ? "dog"
@@ -5674,7 +5708,6 @@ char *buf;
symset[PRIMARY].name ? symset[PRIMARY].name : "default");
if (currentgraphics == PRIMARY && symset[PRIMARY].name)
Strcat(buf, ", active");
#ifdef CURSES_GRAPHICS
} else if (!strcmp(optname, "term_cols")) {
if (iflags.wc2_term_cols)
Sprintf(buf, "%d", iflags.wc2_term_cols);
@@ -5682,10 +5715,9 @@ char *buf;
Strcpy(buf, defopt);
} else if (!strcmp(optname, "term_rows")) {
if (iflags.wc2_term_rows)
Sprintf(buf, "%d",iflags.wc2_term_rows);
Sprintf(buf, "%d", iflags.wc2_term_rows);
else
Strcpy(buf, defopt);
#endif
} else if (!strcmp(optname, "tile_file")) {
Sprintf(buf, "%s",
iflags.wc_tile_file ? iflags.wc_tile_file : defopt);
@@ -6433,9 +6465,11 @@ static struct wc_Opt wc2_options[] = {
{ "status hilite rules", WC2_HILITE_STATUS },
/* statushilites doesn't have its own bit */
{ "statushilites", WC2_HILITE_STATUS },
#ifdef CURSES_GRAPHICS
{"windowborders", WC2_WINDOWBORDERS},
#endif
{ "term_cols", WC2_TERM_SIZE },
{ "term_rows", WC2_TERM_SIZE },
{ "petattr", WC2_PETATTR },
{ "guicolor", WC2_GUICOLOR },
{ "windowborders", WC2_WINDOWBORDERS },
{ (char *) 0, 0L }
};

View File

@@ -835,11 +835,15 @@ curses_init_options()
iflags.wc2_windowborders = 3; /* Set to auto if not specified */
}
if (!iflags.wc2_petattr) {
iflags.wc2_petattr = A_REVERSE;
} else { /* Pet attribute specified, so hilite_pet should be true */
/* fix up pet highlighting */
if (iflags.wc2_petattr == -1) /* shouldn't happen */
iflags.wc2_petattr = A_NORMAL;
if (iflags.wc2_petattr != A_NORMAL) {
/* Pet attribute specified, so hilite_pet should be true */
iflags.hilite_pet = TRUE;
} else if (iflags.hilite_pet) {
/* pet highlighting specified, so don't leave petattr at A_NORMAL */
iflags.wc2_petattr = A_REVERSE;
}
#ifdef NCURSES_MOUSE_VERSION

View File

@@ -47,7 +47,7 @@ curses_read_char()
ch = curses_convert_keys(ch);
if (ch == 0) {
ch = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
ch = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */
}
#if defined(ALT_0) && defined(ALT_9) /* PDCurses, maybe others */
if ((ch >= ALT_0) && (ch <= ALT_9)) {
@@ -66,11 +66,11 @@ curses_read_char()
#ifdef KEY_RESIZE
/* Handle resize events via get_nh_event, not this code */
if (ch == KEY_RESIZE) {
ch = '\033'; /* NetHack doesn't know what to do with KEY_RESIZE */
ch = '\033'; /* NetHack doesn't know what to do with KEY_RESIZE */
}
#endif
if (counting && !isdigit(ch)) { /* Dismiss count window if necissary */
if (counting && !isdigit(ch)) { /* Dismiss count window if necissary */
curses_count_window(NULL);
curses_refresh_nethack_windows();
}
@@ -249,7 +249,7 @@ curses_num_lines(const char *str, int width)
if (last_space == 0) { /* No spaces found */
last_space = count - 1;
}
for (count = (last_space + 1); (size_t) count < strlen(substr); count++) {
for (count = (last_space + 1); count < (int) strlen(substr); count++) {
tmpstr[count - (last_space + 1)] = substr[count];
}
tmpstr[count - (last_space + 1)] = '\0';
@@ -389,7 +389,7 @@ curses_str_remainder(const char *str, int width, int line_num)
if (substr[count] == '\0') {
break;
}
for (count = (last_space + 1); (size_t) count < strlen(substr); count++) {
for (count = (last_space + 1); count < (int) strlen(substr); count++) {
tmpstr[count - (last_space + 1)] = substr[count];
}
tmpstr[count - (last_space + 1)] = '\0';
@@ -682,44 +682,87 @@ curses_convert_attr(int attr)
/* Map letter attributes from a string to bitmask. Return mask on
success, or 0 if not found */
success (might be 0), or -1 if not found. */
int
curses_read_attrs(char *attrs)
{
int retattr = 0;
if (strchr(attrs, 'b') || strchr(attrs, 'B')) {
retattr = retattr | A_BOLD;
}
if (strchr(attrs, 'i') || strchr(attrs, 'I')) {
retattr = retattr | A_REVERSE;
}
if (strchr(attrs, 'u') || strchr(attrs, 'U')) {
retattr = retattr | A_UNDERLINE;
}
if (strchr(attrs, 'k') || strchr(attrs, 'K')) {
retattr = retattr | A_BLINK;
}
if (!attrs || !*attrs)
return A_NORMAL;
if (strchr(attrs, 'b') || strchr(attrs, 'B'))
retattr |= A_BOLD;
if (strchr(attrs, 'i') || strchr(attrs, 'I')) /* inverse */
retattr |= A_REVERSE;
if (strchr(attrs, 'u') || strchr(attrs, 'U'))
retattr |= A_UNDERLINE;
if (strchr(attrs, 'k') || strchr(attrs, 'K'))
retattr |= A_BLINK;
if (strchr(attrs, 'd') || strchr(attrs, 'D'))
retattr |= A_DIM;
#ifdef A_ITALIC
if (strchr(attrs, 't') || strchr(attrs, 'T')) {
retattr = retattr | A_ITALIC;
}
#endif
#ifdef A_RIGHTLINE
if (strchr(attrs, 'r') || strchr(attrs, 'R')) {
retattr = retattr | A_RIGHTLINE;
}
if (strchr(attrs, 't') || strchr(attrs, 'T'))
retattr |= A_ITALIC;
#endif
#ifdef A_LEFTLINE
if (strchr(attrs, 'l') || strchr(attrs, 'L')) {
retattr = retattr | A_LEFTLINE;
}
if (strchr(attrs, 'l') || strchr(attrs, 'L'))
retattr |= A_LEFTLINE;
#endif
#ifdef A_RIGHTLINE
if (strchr(attrs, 'r') || strchr(attrs, 'R'))
retattr |= A_RIGHTLINE;
#endif
if (retattr == 0) {
/* still default; check for none/normal */
if (strchr(attrs, 'n') || strchr(attrs, 'N'))
retattr = A_NORMAL;
else
retattr = -1; /* error */
}
return retattr;
}
/* format iflags.wc2_petattr into "+a+b..." for set bits a, b, ...
(used by core's 'O' command; return value points past leading '+') */
char *
curses_fmt_attrs(outbuf)
char *outbuf;
{
int attr = iflags.wc2_petattr;
outbuf[0] = '\0';
if (attr == A_NORMAL) {
Strcpy(outbuf, "+N(None)");
} else {
if (attr & A_BOLD)
Strcat(outbuf, "+B(Bold)");
if (attr & A_REVERSE)
Strcat(outbuf, "+I(Inverse)");
if (attr & A_UNDERLINE)
Strcat(outbuf, "+U(Underline)");
if (attr & A_BLINK)
Strcat(outbuf, "+K(blinK)");
if (attr & A_DIM)
Strcat(outbuf, "+D(Dim)");
#ifdef A_ITALIC
if (attr & A_ITALIC)
Strcat(outbuf, "+T(iTalic)");
#endif
#ifdef A_LEFTLINE
if (attr & A_LEFTLINE)
Strcat(outbuf, "+L(Left line)");
#endif
#ifdef A_RIGHTLINE
if (attr & A_RIGHTLINE)
Strcat(outbuf, "+R(Right line)");
#endif
}
if (!*outbuf)
Sprintf(outbuf, "+unknown [%d]", attr);
return &outbuf[1];
}
/* Convert special keys into values that NetHack can understand.
Currently this is limited to arrow keys, but this may be expanded. */
@@ -827,7 +870,7 @@ curses_get_mouse(int *mousex, int *mousey, int *mod)
#ifdef NCURSES_MOUSE_VERSION
MEVENT event;
if (getmouse(&event) == OK) { /* When the user clicks left mouse button */
if (getmouse(&event) == OK) { /* When the user clicks left mouse button */
if (event.bstate & BUTTON1_CLICKED) {
/* See if coords are in map window & convert coords */
if (wmouse_trafo(mapwin, &event.y, &event.x, TRUE)) {

View File

@@ -27,6 +27,7 @@ void curses_rtrim(char *str);
int curses_get_count(int first_digit);
int curses_convert_attr(int attr);
int curses_read_attrs(char *attrs);
char *curses_fmt_attrs(char *);
int curses_convert_keys(int key);
int curses_get_mouse(int *mousex, int *mousey, int *mod);