smartphone: added Q(quiver) command to "Attack" layout
smartphone: fixed F command to prompt for direction
unix,vms: altmeta option to handle terminals which send "ESC c" for Alt+c
+tty,win32gui,win32tty: add menucolors
NetHack Community Patches (or Variation) Included
#ifndef COLOR_H
#define COLOR_H
+#ifdef MENU_COLOR_REGEX
+#include <regex.h>
+#endif
+
/*
* The color scheme used is tailored for an IBM PC. It consists of the
* standard 8 colors, folowed by their bright counterparts. There are
#define DRAGON_SILVER CLR_BRIGHT_CYAN
#define HI_ZAP CLR_BRIGHT_BLUE
+struct menucoloring {
+# ifdef MENU_COLOR_REGEX
+# ifdef MENU_COLOR_REGEX_POSIX
+ regex_t match;
+# else
+ struct re_pattern_buffer match;
+# endif
+# else
+ char *match;
+# endif
+ int color, attr;
+ struct menucoloring *next;
+};
+
#endif /* COLOR_H */
* bugs left here.
*/
+/* Menucolors */
+# define MENU_COLOR_REGEX /* use GNU regex */
+/*# define MENU_COLOR_REGEX_POSIX*/ /* use POSIX regex */
+/* if neither is defined, uses pmatch()
+ * pmatch() provides basic globbing: '*' and '?' wildcards.
+ */
+
+
#define STATUS_VIA_WINDOWPORT /* re-work of the status line updating process */
#define STATUS_HILITES /* support hilites of status fields */
/* #define WINCHAIN*/ /* stacked window systems */
E struct symparse *FDECL(match_sym, (char *));
E void NDECL(set_playmode);
E int FDECL(sym_val, (char *));
+E boolean FDECL(add_menu_coloring, (char *));
+E boolean FDECL(get_menu_coloring, (char *, int *, int *));
+E void NDECL(free_menu_coloring);
/* ### pager.c ### */
boolean rlecomp; /* run-length comp of levels when writing savefile */
uchar num_pad_mode;
boolean echo; /* 1 to echo characters */
+ boolean use_menu_color; /* use color in menus; only if wc_color */
#if 0
boolean DECgraphics; /* use DEC VT-xxx extended character set */
boolean IBMgraphics; /* use IBM extended character set */
"white"
};
+struct menucoloring *menu_colorings = NULL;
+
const char *c_obj_colors[] = {
"black", /* CLR_BLACK */
"red", /* CLR_RED */
} else if (match_varname(buf, "BOULDER", 3)) {
(void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE,
1, "BOULDER");
+ } else if (match_varname(buf, "MENUCOLOR", 9)) {
+ (void) add_menu_coloring(bufp);
} else if (match_varname(buf, "WARNINGS", 5)) {
(void) get_uchars(fp, buf, bufp, translate, FALSE,
WARNCOUNT, "WARNINGS");
{"mail", (boolean *)0, TRUE, SET_IN_FILE},
#endif
{"mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME},
+ {"menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME},
/* for menu debugging only*/
{"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME},
{"menu_objsyms", &iflags.menu_head_objsym, FALSE, SET_IN_GAME},
{ ~0, "all", 3, 0, 0, 0 }, /* ditto */
};
+
+extern struct menucoloring *menu_colorings;
+
+static const struct {
+ const char *name;
+ const int color;
+} colornames[] = {
+ {"black", CLR_BLACK},
+ {"red", CLR_RED},
+ {"green", CLR_GREEN},
+ {"brown", CLR_BROWN},
+ {"blue", CLR_BLUE},
+ {"magenta", CLR_MAGENTA},
+ {"cyan", CLR_CYAN},
+ {"gray", CLR_GRAY},
+ {"grey", CLR_GRAY},
+ {"orange", CLR_ORANGE},
+ {"lightgreen", CLR_BRIGHT_GREEN},
+ {"yellow", CLR_YELLOW},
+ {"lightblue", CLR_BRIGHT_BLUE},
+ {"lightmagenta", CLR_BRIGHT_MAGENTA},
+ {"lightcyan", CLR_BRIGHT_CYAN},
+ {"white", CLR_WHITE}
+};
+
+static const struct {
+ const char *name;
+ const int attr;
+} attrnames[] = {
+ {"none", ATR_NONE},
+ {"bold", ATR_BOLD},
+ {"dim", ATR_DIM},
+ {"underline", ATR_ULINE},
+ {"blink", ATR_BLINK},
+ {"inverse", ATR_INVERSE}
+};
+
+/* parse '"regex_string"=color&attr' and add it to menucoloring */
+boolean
+add_menu_coloring(str)
+char *str;
+{
+ int i, c = NO_COLOR, a = ATR_NONE;
+ struct menucoloring *tmp;
+ char *tmps, *cs = strchr(str, '=');
+#ifdef MENU_COLOR_REGEX_POSIX
+ int errnum;
+ char errbuf[80];
+#endif
+ const char *err = (char *)0;
+
+ if (!cs || !str) return FALSE;
+
+ tmps = cs;
+ tmps++;
+ while (*tmps && isspace(*tmps)) tmps++;
+
+ for (i = 0; i < SIZE(colornames); i++)
+ if (strstri(tmps, colornames[i].name) == tmps) {
+ c = colornames[i].color;
+ break;
+ }
+ if ((i == SIZE(colornames)) && (*tmps >= '0' && *tmps <='9'))
+ c = atoi(tmps);
+
+ if (c > 15) return FALSE;
+
+ tmps = strchr(str, '&');
+ if (tmps) {
+ tmps++;
+ while (*tmps && isspace(*tmps)) tmps++;
+ for (i = 0; i < SIZE(attrnames); i++)
+ if (strstri(tmps, attrnames[i].name) == tmps) {
+ a = attrnames[i].attr;
+ break;
+ }
+ if ((i == SIZE(attrnames)) && (*tmps >= '0' && *tmps <='9'))
+ a = atoi(tmps);
+ }
+
+ *cs = '\0';
+ tmps = str;
+ if ((*tmps == '"') || (*tmps == '\'')) {
+ cs--;
+ while (isspace(*cs)) cs--;
+ if (*cs == *tmps) {
+ *cs = '\0';
+ tmps++;
+ }
+ }
+
+ tmp = (struct menucoloring *)alloc(sizeof(struct menucoloring));
+#ifdef MENU_COLOR_REGEX
+#ifdef MENU_COLOR_REGEX_POSIX
+ errnum = regcomp(&tmp->match, tmps, REG_EXTENDED | REG_NOSUB);
+ if (errnum != 0)
+ {
+ regerror(errnum, &tmp->match, errbuf, sizeof(errbuf));
+ err = errbuf;
+ }
+#else
+ tmp->match.translate = 0;
+ tmp->match.fastmap = 0;
+ tmp->match.buffer = 0;
+ tmp->match.allocated = 0;
+ tmp->match.regs_allocated = REGS_FIXED;
+ err = re_compile_pattern(tmps, strlen(tmps), &tmp->match);
+#endif
+#else
+ tmp->match = (char *)alloc(strlen(tmps)+1);
+ (void) memcpy((genericptr_t)tmp->match, (genericptr_t)tmps, strlen(tmps)+1);
+#endif
+ if (err) {
+ raw_printf("\nMenucolor regex error: %s\n", err);
+ wait_synch();
+ free(tmp);
+ return FALSE;
+ } else {
+ tmp->next = menu_colorings;
+ tmp->color = c;
+ tmp->attr = a;
+ menu_colorings = tmp;
+ return TRUE;
+ }
+}
+
+boolean
+get_menu_coloring(str, color, attr)
+char *str;
+int *color, *attr;
+{
+ struct menucoloring *tmpmc;
+ if (iflags.use_menu_color)
+ for (tmpmc = menu_colorings; tmpmc; tmpmc = tmpmc->next)
+#ifdef MENU_COLOR_REGEX
+# ifdef MENU_COLOR_REGEX_POSIX
+ if (regexec(&tmpmc->match, str, 0, NULL, 0) == 0) {
+# else
+ if (re_search(&tmpmc->match, str, strlen(str), 0, 9999, 0) >= 0) {
+# endif
+#else
+ if (pmatch(tmpmc->match, str)) {
+#endif
+ *color = tmpmc->color;
+ *attr = tmpmc->attr;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+free_menu_coloring()
+{
+ struct menucoloring *tmp = menu_colorings;
+
+ while (tmp) {
+ struct menucoloring *tmp2 = tmp->next;
+#ifdef MENU_COLOR_REGEX
+ (void) regfree(&tmp->match);
+#else
+ free(tmp->match);
+#endif
+ free(tmp);
+ tmp = tmp2;
+ }
+}
+
+
void
parseoptions(opts, tinitial, tfrom_file)
register char *opts;
return;
}
+ /* menucolor:"regex_string"=color */
+ fullname = "menucolor";
+ if (match_optname(opts, fullname, 9, TRUE)) {
+ if (negated) bad_negation(fullname, FALSE);
+ else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0)
+ if (!add_menu_coloring(op))
+ badoption(opts);
+ return;
+ }
+
fullname = "msghistory";
if (match_optname(opts, fullname, 3, TRUE)) {
if (duplicate) complain_about_duplicate(opts,1);
freedynamicdata()
{
unload_qtlist();
+ free_menu_coloring();
free_invbuf(); /* let_to_name (invent.c) */
free_youbuf(); /* You_buf,&c (pline.c) */
tmp_at(DISP_FREEMEM, 0); /* temporary display effects */
# DEC Rainbows will hang if rawio is set, so they should instead use:
#OPTIONS=BIOS,DECgraphics
+# Colored menus.
+#OPTIONS=menucolors
+# Syntax is: MENUCOLOR="string_to_match"=color&attribute
+# Colors: black, red, green, brown, blue, magenta, cyan, gray, orange,
+# lightgreen, yellow, lightblue, lightmagenta, lightcyan, white.
+# Attributes: none, bold, dim, underline, blink, inverse.
+#MENUCOLOR=" blessed "=green
+#MENUCOLOR=" holy "=green
+#MENUCOLOR=" cursed "=red
+#MENUCOLOR=" unholy "=red
+#MENUCOLOR=" cursed .* (being worn)"=orange&underline
#ifdef NEWS
"news file",
#endif
+#ifdef MENU_COLOR_REGEX
+ "menu colors via regular expressions",
+#else
+ "menu colors via pmatch",
+#endif
#ifdef OVERLAY
# ifdef MOVERLAY
"MOVE overlays",
for (page_lines = 0, curr = page_start;
curr != page_end;
page_lines++, curr = curr->next) {
+ int color = NO_COLOR, attr = ATR_NONE;
+ boolean menucolr = FALSE;
if (curr->selector)
*rp++ = curr->selector;
* actually output the character. We're faster doing
* this.
*/
+ if (iflags.use_menu_color &&
+ (menucolr = get_menu_coloring(curr->str, &color,&attr))) {
+ term_start_attr(attr);
+ if (color != NO_COLOR) term_start_color(color);
+ } else
term_start_attr(curr->attr);
for (n = 0, cp = curr->str;
#ifndef WIN32CON
(void) putchar('#'); /* count selected */
} else
(void) putchar(*cp);
+ if (iflags.use_menu_color && menucolr) {
+ if (color != NO_COLOR) term_end_color();
+ term_end_attr(attr);
+ } else
term_end_attr(curr->attr);
}
} else {
#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2)
static void nhglyph2charcolor(short glyph, uchar* ch, int* color);
#endif
-static COLORREF nhcolor_to_RGB(int c);
HWND mswin_init_map_window () {
static int run_once = 0;
#include "global.h"
+COLORREF nhcolor_to_RGB (int c);
HWND mswin_init_map_window (void);
void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw);
int mswin_map_mode(HWND hWnd, int mode);
int column;
int spacing = 0;
+ int color = NO_COLOR, attr;
+ boolean menucolr = FALSE;
+
lpdis = (LPDRAWITEMSTRUCT) lParam;
/* If there are no list box items, skip this message. */
buf[0] = item->accelerator;
buf[1] = '\x0';
+ if (iflags.use_menu_color &&
+ (menucolr = get_menu_coloring(item->str, &color,&attr))) {
+ /* TODO: use attr too */
+ if (color != NO_COLOR)
+ SetTextColor(lpdis->hDC, nhcolor_to_RGB(color));
+ }
+
SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom );
DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
}