From 24adb1c592a306b67fbb3fa928fbe2fb5497ae79 Mon Sep 17 00:00:00 2001 From: Doktor L Date: Sat, 30 May 2026 18:03:20 +0200 Subject: [PATCH 1/5] curses: use existing background parameter for pile The blue background colour for piles was implemented by changing glyph colour to curses colour pair with the desired background, and then passed to curses_putch which takes character and background colour and makes curses colour pair out of them once again. Pass blue background to curses_putch instead and let it create curses colour pair just once. --- include/wincurs.h | 1 - win/curses/cursmain.c | 6 ++++-- win/curses/curswins.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/wincurs.h b/include/wincurs.h index 0911cf11c..aea0e9ebf 100644 --- a/include/wincurs.h +++ b/include/wincurs.h @@ -145,7 +145,6 @@ extern void curses_puts(winid wid, int attr, const char *text); extern void curses_clear_nhwin(winid wid); extern void curses_alert_win_border(winid wid, boolean onoff); extern void curses_alert_main_borders(boolean onoff); -extern int get_framecolor(int nhcolor, int framecolor); extern void curses_draw_map(int sx, int sy, int ex, int ey); extern boolean curses_map_borders(int *sx, int *sy, int *ex, int *ey, int ux, int uy); diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index 448d8c77d..ee45eb059 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -940,6 +940,7 @@ curses_print_glyph( int glyph; int ch; int color; + int framecolor; int nhcolor = 0; unsigned int special; int attr = -1; @@ -948,6 +949,7 @@ curses_print_glyph( special = glyphinfo->gm.glyphflags; ch = glyphinfo->ttychar; color = glyphinfo->gm.sym.color; + framecolor = bkglyphinfo->framecolor; /* Extra color handling * FIQ: The curses library does not support truecolor, only the more limited 256 * color mode. On top of this, the windowport only supports 16 color mode. @@ -981,7 +983,7 @@ curses_print_glyph( */ if ((special & MG_OBJPILE) && iflags.hilite_pile) { if (iflags.wc_color) - color = get_framecolor(color, CLR_BLUE); + framecolor = CLR_BLUE; else /* if (iflags.use_inverse) */ attr = A_REVERSE; } @@ -1007,7 +1009,7 @@ curses_print_glyph( ? glyphinfo->gm.u : NULL, #endif (nhcolor != 0) ? nhcolor : color, - bkglyphinfo->framecolor, attr); + framecolor, attr); } diff --git a/win/curses/curswins.c b/win/curses/curswins.c index 21e1bae09..50f8f171c 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -763,7 +763,7 @@ is_main_window(winid wid) coordinates without a refresh. Currently only used for the map. */ /* convert nhcolor (fg) and framecolor (bg) to curses colorpair */ -int +static int get_framecolor(int nhcolor, int framecolor) { /* curses_toggle_color_attr() adds the +1 and takes care of COLORS < 16 */ From f3d292e111e509a4ad6e426cc0f00da0238d97c6 Mon Sep 17 00:00:00 2001 From: Doktor L Date: Sat, 30 May 2026 18:13:36 +0200 Subject: [PATCH 2/5] Combine three arguments of curses_putch into one It will need another parameter for 256-colour support. To avoid having too many arguments, put glyph colour, background colour and attributes into a struct and, since to curses library all of that is attributes that are handled by same function, call the struct "gryph attributes". curses_putch was also declared in two different headers, remove one of those declarations. --- include/wincurs.h | 8 -------- win/curses/cursmain.c | 27 +++++++++++++-------------- win/curses/curswins.c | 8 ++++---- win/curses/curswins.h | 13 +++++++++---- 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/include/wincurs.h b/include/wincurs.h index aea0e9ebf..43780e276 100644 --- a/include/wincurs.h +++ b/include/wincurs.h @@ -128,14 +128,6 @@ extern void curses_refresh_nethack_windows(void); extern void curses_del_nhwin(winid wid); extern void curses_del_wid(winid wid); extern void curs_destroy_all_wins(void); -#ifdef ENHANCED_SYMBOLS -extern void curses_putch(winid wid, int x, int y, int ch, - struct unicode_representation *u, int color, - int framecolor, int attrs); -#else -extern void curses_putch(winid wid, int x, int y, int ch, int color, - int framecolor, int attrs); -#endif extern void curses_get_window_size(winid wid, int *height, int *width); extern boolean curses_window_has_border(winid wid); extern boolean curses_window_exists(winid wid); diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index ee45eb059..3966771f6 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -7,6 +7,7 @@ #include "hack.h" #include "color.h" #include "wincurs.h" +#include "curswins.h" #ifdef CURSES_UNICODE #include #endif @@ -939,17 +940,16 @@ curses_print_glyph( { int glyph; int ch; - int color; - int framecolor; + struct glyph_attributes attr; int nhcolor = 0; unsigned int special; - int attr = -1; + attr.attribute_flags = -1; glyph = glyphinfo->glyph; special = glyphinfo->gm.glyphflags; ch = glyphinfo->ttychar; - color = glyphinfo->gm.sym.color; - framecolor = bkglyphinfo->framecolor; + attr.color = glyphinfo->gm.sym.color; + attr.framecolor = bkglyphinfo->framecolor; /* Extra color handling * FIQ: The curses library does not support truecolor, only the more limited 256 * color mode. On top of this, the windowport only supports 16 color mode. @@ -958,7 +958,7 @@ curses_print_glyph( if (glyphinfo->gm.customcolor != 0 && (curses_procs.wincap2 & WC2_EXTRACOLORS) != 0) { if ((glyphinfo->gm.customcolor & NH_BASIC_COLOR) != 0) { - color = COLORVAL(glyphinfo->gm.customcolor); + attr.color = COLORVAL(glyphinfo->gm.customcolor); #if 0 } else { /* 24-bit color, NH_BASIC_COLOR == 0 */ @@ -967,10 +967,10 @@ curses_print_glyph( } } if ((special & MG_PET) && iflags.hilite_pet) { - attr = curses_convert_attr(iflags.wc2_petattr); + attr.attribute_flags = curses_convert_attr(iflags.wc2_petattr); } if ((special & MG_DETECT) && iflags.use_inverse) { - attr = A_REVERSE; + attr.attribute_flags = A_REVERSE; } if (SYMHANDLING(H_DEC)) ch = curses_convert_glyph(ch, glyph); @@ -983,9 +983,9 @@ curses_print_glyph( */ if ((special & MG_OBJPILE) && iflags.hilite_pile) { if (iflags.wc_color) - framecolor = CLR_BLUE; + attr.framecolor = CLR_BLUE; else /* if (iflags.use_inverse) */ - attr = A_REVERSE; + attr.attribute_flags = A_REVERSE; } /* water and lava look the same except for color; when color is off (checked by core), render lava in inverse video so that it looks @@ -994,11 +994,11 @@ curses_print_glyph( if ((special & (MG_BW_LAVA | MG_BW_ICE | MG_BW_SINK | MG_BW_ENGR)) != 0 && iflags.use_inverse) { /* reset_glyphmap() only sets MG_BW_foo if color is off */ - attr = A_REVERSE; + attr.attribute_flags = A_REVERSE; } /* highlight female monsters (wizard mode option) */ if ((special & MG_FEMALE) && wizard && iflags.wizmgender) { - attr = A_REVERSE; + attr.attribute_flags = A_REVERSE; } } @@ -1008,8 +1008,7 @@ curses_print_glyph( && glyphinfo->gm.u && glyphinfo->gm.u->utf8str) ? glyphinfo->gm.u : NULL, #endif - (nhcolor != 0) ? nhcolor : color, - framecolor, attr); + &attr); } diff --git a/win/curses/curswins.c b/win/curses/curswins.c index 50f8f171c..ee28d4508 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -532,7 +532,7 @@ curses_putch(winid wid, int x, int y, int ch, #ifdef ENHANCED_SYMBOLS struct unicode_representation *unicode_representation, #endif - int color, int framecolor, int attr) + const struct glyph_attributes *attr) { static boolean map_initted = FALSE; int sx, sy, ex, ey; @@ -554,9 +554,9 @@ curses_putch(winid wid, int x, int y, int ch, --x; /* map column [0] is not used; draw column [1] in first screen col */ map[y][x].ch = ch; - map[y][x].color = color; - map[y][x].framecolor = framecolor; - map[y][x].attr = attr; + map[y][x].color = attr->color; + map[y][x].framecolor = attr->framecolor; + map[y][x].attr = attr->attribute_flags; #ifdef ENHANCED_SYMBOLS map[y][x].unicode_representation = unicode_representation; #endif diff --git a/win/curses/curswins.h b/win/curses/curswins.h index ebf4c9bb5..992fea55a 100644 --- a/win/curses/curswins.h +++ b/win/curses/curswins.h @@ -6,6 +6,11 @@ #ifndef CURSWIN_H # define CURSWIN_H +struct glyph_attributes { + int color; + int framecolor; + int attribute_flags; +}; /* Global declarations */ @@ -27,11 +32,11 @@ void curses_del_wid(winid wid); void curs_destroy_all_wins(void); #ifdef ENHANCED_SYMBOLS void curses_putch(winid wid, int x, int y, int ch, - struct unicode_representation *ur, int color, - int framecolor, int attrs); + struct unicode_representation *ur, + const struct glyph_attributes *attr); #else -void curses_putch(winid wid, int x, int y, int ch, int color, - int framecolor, int attrs); +void curses_putch(winid wid, int x, int y, int ch, + const struct glyph_attributes *attr); #endif void curses_get_window_xy(winid wid, int *x, int *y); boolean curses_window_has_border(winid wid); From 7036f902d2aabad9d522133509aa9ee59d831398 Mon Sep 17 00:00:00 2001 From: Doktor L Date: Sat, 30 May 2026 18:28:08 +0200 Subject: [PATCH 3/5] Pass base-256 colour index to curses_putch And to its inner function write_char --- src/coloratt.c | 3 ++- win/curses/cursmain.c | 10 ++++------ win/curses/curswins.c | 6 ++++-- win/curses/curswins.h | 3 ++- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/coloratt.c b/src/coloratt.c index 10f216ba6..a5d040fda 100644 --- a/src/coloratt.c +++ b/src/coloratt.c @@ -886,7 +886,8 @@ static struct { int index; uint32 value; } color_256_definitions[] = { - /* color values are from unnethack */ + /* from unnethack - these are the colors used by xterm + when $TERM is set to xterm-256color */ { 16, 0x000000 }, { 17, 0x00005f }, { 18, 0x000087 }, { 19, 0x0000af }, { 20, 0x0000d7 }, { 21, 0x0000ff }, { 22, 0x005f00 }, { 23, 0x005f5f }, { 24, 0x005f87 }, diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index 3966771f6..f6b5e3013 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -941,14 +941,14 @@ curses_print_glyph( int glyph; int ch; struct glyph_attributes attr; - int nhcolor = 0; unsigned int special; attr.attribute_flags = -1; glyph = glyphinfo->glyph; special = glyphinfo->gm.glyphflags; ch = glyphinfo->ttychar; - attr.color = glyphinfo->gm.sym.color; + attr.basic_color = glyphinfo->gm.sym.color; + attr.color256 = 0; attr.framecolor = bkglyphinfo->framecolor; /* Extra color handling * FIQ: The curses library does not support truecolor, only the more limited 256 @@ -958,12 +958,10 @@ curses_print_glyph( if (glyphinfo->gm.customcolor != 0 && (curses_procs.wincap2 & WC2_EXTRACOLORS) != 0) { if ((glyphinfo->gm.customcolor & NH_BASIC_COLOR) != 0) { - attr.color = COLORVAL(glyphinfo->gm.customcolor); -#if 0 + attr.basic_color = COLORVAL(glyphinfo->gm.customcolor); } else { /* 24-bit color, NH_BASIC_COLOR == 0 */ - nhcolor = COLORVAL(glyphinfo->gm.customcolor); -#endif + attr.color256 = glyphinfo->gm.color256idx; } } if ((special & MG_PET) && iflags.hilite_pet) { diff --git a/win/curses/curswins.c b/win/curses/curswins.c index ee28d4508..6ce123c34 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -40,7 +40,8 @@ typedef struct nhwd { typedef struct nhchar { int ch; /* character */ - int color; /* color info for character */ + int color; /* basic color info for character */ + int color256; /* extended color for the character, 0 if none */ int framecolor; /* background color info for character */ int attr; /* attributes of character */ struct unicode_representation *unicode_representation; @@ -554,7 +555,8 @@ curses_putch(winid wid, int x, int y, int ch, --x; /* map column [0] is not used; draw column [1] in first screen col */ map[y][x].ch = ch; - map[y][x].color = attr->color; + map[y][x].color = attr->basic_color; + map[y][x].color256 = attr->color256; map[y][x].framecolor = attr->framecolor; map[y][x].attr = attr->attribute_flags; #ifdef ENHANCED_SYMBOLS diff --git a/win/curses/curswins.h b/win/curses/curswins.h index 992fea55a..13985ce1b 100644 --- a/win/curses/curswins.h +++ b/win/curses/curswins.h @@ -7,7 +7,8 @@ # define CURSWIN_H struct glyph_attributes { - int color; + int basic_color; // basic color + int color256; // extended color (0 if not defined), used when supported int framecolor; int attribute_flags; }; From 19c87585fa5cabb8869bc70e2c65c215a66b981b Mon Sep 17 00:00:00 2001 From: Doktor L Date: Sat, 30 May 2026 19:29:11 +0200 Subject: [PATCH 4/5] Create curses colour pairs for 256 colours Keep only 8 background colours but if curses supports 256 colours and 256*8 colours pairs, create colours pairs for 256 foregrounds rather than just 16. --- win/curses/cursinit.c | 12 +++++++----- win/curses/cursmisc.c | 8 +++++++- win/curses/cursmisc.h | 3 +++ win/curses/curswins.c | 6 +++++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/win/curses/cursinit.c b/win/curses/cursinit.c index 1135d0eb8..523ae92d3 100644 --- a/win/curses/cursinit.c +++ b/win/curses/cursinit.c @@ -7,6 +7,7 @@ #include "hack.h" #include "wincurs.h" #include "cursinit.h" +#include "cursmisc.h" /* Initialization and startup functions for curses interface */ @@ -334,18 +335,18 @@ curses_init_nhcolors(void) /* COLOR_foo + 8 means COLOR | A_BOLD when COLORS < 16 */ /* otherwise assume the terminal has least 16 different colors */ /* these map to the NetHack CLR_ defines */ - static const int fg_clr[16] = { + static const int basic_fg_clr[16] = { COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE, -1, COLOR_RED + 8, COLOR_GREEN + 8, COLOR_YELLOW + 8, COLOR_BLUE + 8, COLOR_MAGENTA + 8, COLOR_CYAN + 8, COLOR_WHITE + 8 }; - static const int bg_clr[8] = { + static const int bg_clr[CURSES_NUM_BACKGROUND_COLORS] = { -1, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE }; int bg, nhclr; - int maxc = (COLORS >= 16) ? 16 : 8; + int maxc = curses_has_256color() ? 256 : (COLORS >= 16) ? 16 : 8; if (!has_colors()) return; @@ -353,8 +354,9 @@ curses_init_nhcolors(void) use_default_colors(); for (nhclr = CLR_BLACK; nhclr < maxc; nhclr++) { - for (bg = 0; bg < 8; bg++) { - init_pair((maxc * bg) + nhclr + 1, fg_clr[nhclr], bg_clr[bg]); + for (bg = 0; bg < CURSES_NUM_BACKGROUND_COLORS; bg++) { + int fg_color = (nhclr < 16) ? basic_fg_clr[nhclr] : nhclr; + init_pair((maxc * bg) + nhclr + 1, fg_color, bg_clr[bg]); } } diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index efa5da83a..30e782411 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -91,6 +91,12 @@ curses_read_char(void) return ch; } +boolean +curses_has_256color(void) +{ + return (COLORS >= 256) && (COLOR_PAIRS >= 256 * CURSES_NUM_BACKGROUND_COLORS); +} + /* Turn on or off the specified color and / or attribute */ void @@ -147,7 +153,7 @@ curses_toggle_color_attr(WINDOW *win, int color, int attr, int onoff) if (use_bold) { wattron(win, A_BOLD); } - wattron(win, COLOR_PAIR(curses_color)); + wcolor_set(win, curses_color, &curses_color); } if (attr != NONE) { diff --git a/win/curses/cursmisc.h b/win/curses/cursmisc.h index dc79ebfbe..81c34135d 100644 --- a/win/curses/cursmisc.h +++ b/win/curses/cursmisc.h @@ -8,8 +8,11 @@ /* Global declarations */ +#define CURSES_NUM_BACKGROUND_COLORS 8 + int curses_getch(void); int curses_read_char(void); +boolean curses_has_256color(void); void curses_toggle_color_attr(WINDOW *win, int color, int attr, int onoff); void curses_menu_color_attr(WINDOW *win, int color, int attr, int onoff); void curses_bail(const char *mesg); diff --git a/win/curses/curswins.c b/win/curses/curswins.c index 6ce123c34..a09b3f3f0 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -769,7 +769,11 @@ static int get_framecolor(int nhcolor, int framecolor) { /* curses_toggle_color_attr() adds the +1 and takes care of COLORS < 16 */ - return (16 * (framecolor % 8)) + (nhcolor % 16); + if (curses_has_256color()) { + return (256 * (framecolor % 8)) + (nhcolor % 256); + } else + return (16 * (framecolor % 8)) + (nhcolor % 16); + } static void From 08ac68b754c1f22ae6e6b7a33d323e682333c5b6 Mon Sep 17 00:00:00 2001 From: Doktor L Date: Sat, 30 May 2026 19:31:37 +0200 Subject: [PATCH 5/5] Use 256 colours in curses window port Only glyphs that are customised via config can have colours different from the basic 16. For such glyphs, when curses supports 256 colours, use them. --- win/curses/curswins.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/win/curses/curswins.c b/win/curses/curswins.c index a09b3f3f0..1044cd61b 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -766,25 +766,26 @@ coordinates without a refresh. Currently only used for the map. */ /* convert nhcolor (fg) and framecolor (bg) to curses colorpair */ static int -get_framecolor(int nhcolor, int framecolor) +get_framecolor(const nethack_char *nch) { + int bgcolor = (nch->framecolor != NO_COLOR) ? nch->framecolor : 0; /* curses_toggle_color_attr() adds the +1 and takes care of COLORS < 16 */ if (curses_has_256color()) { - return (256 * (framecolor % 8)) + (nhcolor % 256); + int color = nch->color256 ? nch->color256 : nch->color; + return (256 * (bgcolor % CURSES_NUM_BACKGROUND_COLORS)) + (color % 256); } else - return (16 * (framecolor % 8)) + (nhcolor % 16); - + return (16 * (bgcolor % CURSES_NUM_BACKGROUND_COLORS)) + (nch->color % 16); } static void write_char(WINDOW * win, int x, int y, nethack_char nch) { - int curscolor = nch.color, cursattr = nch.attr; + int curscolor; + int cursattr = nch.attr; - if (nch.framecolor != NO_COLOR) { - curscolor = get_framecolor(nch.color, nch.framecolor); - if (nch.attr == A_REVERSE) - cursattr = A_NORMAL; /* hilited pet looks odd otherwise */ + curscolor = get_framecolor(&nch); + if ((nch.framecolor != NO_COLOR) && (nch.attr == A_REVERSE)) { + cursattr = A_NORMAL; /* hilited pet looks odd otherwise */ } curses_toggle_color_attr(win, curscolor, cursattr, ON); #if defined(CURSES_UNICODE) && defined(ENHANCED_SYMBOLS)