From d0c4d27a507b390cc13d85a49d5876c3f2428109 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 16 Oct 2019 15:52:00 -0700 Subject: [PATCH] githib pull request #232 - curses symset This time I'm putting things in as-is before making a few tweaks. The pull request was three or four separate changes. I used the patch instead so they've been collected into one commit. --- dat/symbols | 34 +++++++ include/rm.h | 3 +- include/wincurs.h | 2 +- src/drawing.c | 1 + src/options.c | 4 + win/curses/cursinit.c | 5 + win/curses/cursmain.c | 4 +- win/curses/cursmisc.c | 224 +++++++++++++++++------------------------- win/curses/cursmisc.h | 2 +- 9 files changed, 137 insertions(+), 142 deletions(-) diff --git a/dat/symbols b/dat/symbols index be27dad5d..364c6db21 100644 --- a/dat/symbols +++ b/dat/symbols @@ -15,6 +15,11 @@ # NetHack encodes the request to use the alternate font here by # having the high bit set (in hexadecimal, \x80 is combined with # a character code between \x60 and \x7f). +# +# curses is an approximation of IBMgraphics which relies on DEC +# mode of operation, with a few characters missing. It is based +# on an old graphics mode for the Curses mode and is the default +# on that windowport if no symset is specified. start: DECgraphics Handling: DEC @@ -55,6 +60,35 @@ start: DECgraphics S_explode8: \xf3 # meta-s, low horizontal line finish +start: curses + Handling: DEC + S_vwall: \xf8 # meta-x, vertical rule + S_hwall: \xf1 # meta-q, horizontal rule + S_tlcorn: \xec # meta-l, top left corner + S_trcorn: \xeb # meta-k, top right corner + S_blcorn: \xed # meta-m, bottom left + S_brcorn: \xea # meta-j, bottom right + S_crwall: \xee # meta-n, cross + S_tuwall: \xf6 # meta-v, T up + S_tdwall: \xf7 # meta-w, T down + S_tlwall: \xf5 # meta-u, T left + S_trwall: \xf4 # meta-t, T right + S_ndoor: \xfe # meta-z, centered dot + S_tree: \xf1 # plus or minus symbol + S_room: \xfe # meta-z, centered dot + S_corr: \xe1 # meta-a, solid block + S_litcorr: \xe1 # meta-a, solid block + S_ice: \xfe # meta-z, centered dot + S_vodbridge: \xfe # meta-z, centered dot + S_hodbridge: \xfe # meta-z, centered dot + S_vbeam: \xf8 # meta-3, vertical rule + S_hbeam: \xf1 # meta-D, horizontal rule + S_sw_ml: \xf8 # meta-3, vertical rule + S_sw_mr: \xf8 # meta-3, vertical rule + S_explode4: \xf8 # meta-3, vertical rule + S_explode6: \xf8 # meta-3, vertical rule +finish + start: IBMgraphics Handling: IBM S_vwall: \xb3 # meta-3, vertical rule diff --git a/include/rm.h b/include/rm.h index 1190a355b..becdd21a0 100644 --- a/include/rm.h +++ b/include/rm.h @@ -278,7 +278,8 @@ struct symsetentry { Bitfield(nocolor, 1); /* don't use color if set */ Bitfield(primary, 1); /* restricted for use as primary set */ Bitfield(rogue, 1); /* restricted for use as rogue lev set */ - /* 5 free bits */ + Bitfield(fallback, 1); /* no explicit symset set */ + /* 4 free bits */ }; /* diff --git a/include/wincurs.h b/include/wincurs.h index c7d16f9e5..8ae45e10e 100644 --- a/include/wincurs.h +++ b/include/wincurs.h @@ -152,7 +152,7 @@ extern char *curses_break_str(const char *str, int width, int line_num); extern char *curses_str_remainder(const char *str, int width, int line_num); extern boolean curses_is_menu(winid wid); extern boolean curses_is_text(winid wid); -extern int curses_convert_glyph(boolean decgraphics, int ch, int glyph); +extern int curses_convert_glyph(int ch, int glyph); extern void curses_move_cursor(winid wid, int x, int y); extern void curses_prehousekeeping(void); extern void curses_posthousekeeping(void); diff --git a/src/drawing.c b/src/drawing.c index e9a1e08e1..f29dbf3a2 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -543,6 +543,7 @@ boolean name_too; /* initialize restriction bits */ symset[which_set].primary = 0; symset[which_set].rogue = 0; + symset[which_set].fallback = TRUE; if (name_too) { if (symset[which_set].name) diff --git a/src/options.c b/src/options.c index cc39f585b..220f8f483 100644 --- a/src/options.c +++ b/src/options.c @@ -2315,6 +2315,7 @@ boolean tinitial, tfrom_file; } else { if (!initial && Is_rogue_level(&u.uz)) assign_graphics(ROGUESET); + symset[ROGUESET].fallback = FALSE; need_redraw = TRUE; } } else @@ -2339,6 +2340,7 @@ boolean tinitial, tfrom_file; return FALSE; } else { switch_symbols(symset[PRIMARY].name != (char *) 0); + symset[PRIMARY].fallback = FALSE; need_redraw = TRUE; } } else @@ -6008,8 +6010,10 @@ int which_set; if (read_sym_file(which_set)) { switch_symbols(TRUE); + symset[which_set].fallback = FALSE; } else { clear_symsetentry(which_set, TRUE); + symset[which_set].fallback = TRUE; return 0; } return 1; diff --git a/win/curses/cursinit.c b/win/curses/cursinit.c index 7c5ac185b..773334855 100644 --- a/win/curses/cursinit.c +++ b/win/curses/cursinit.c @@ -784,6 +784,11 @@ curses_init_options() /* Remove a few options that are irrelevant to this windowport */ set_option_mod_status("eight_bit_tty", SET_IN_FILE); + /* If we don't have a symset defined, load the curses symset by default */ + if (symset[PRIMARY].fallback) { + load_symset("curses", PRIMARY); + load_symset("default", ROGUESET); + } #ifdef PDCURSES /* PDCurses for SDL, win32 and OS/2 has the ability to set the terminal size programatically. If the user does not specify a diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index d252b5b6d..e0b69b42c 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -660,9 +660,7 @@ curses_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, attr = A_REVERSE; } if (SYMHANDLING(H_DEC)) - ch = curses_convert_glyph(TRUE, ch, glyph); - else if (!symset[PRIMARY].name || !strcmpi(symset[PRIMARY].name, "curses")) - ch = curses_convert_glyph(FALSE, ch, glyph); + ch = curses_convert_glyph(ch, glyph); if (wid == NHW_MAP) { /* hilite stairs not in 3.6, yet diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 2a2dd8a7b..df3316679 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -74,7 +74,7 @@ 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 = C('r'); /* NetHack doesn't know what to do with KEY_RESIZE */ } #endif @@ -467,161 +467,113 @@ curses_is_text(winid wid) cursesgraphics option is enabled, or special curses handling for DECgraphics */ int -curses_convert_glyph(boolean decgraphics, int ch, int glyph) +curses_convert_glyph(int ch, int glyph) { - static int cursesglyphs[MAXPCHARS], cursesglyphsinited = 0; int retch, symbol; /* FIXME? we don't support any special characters in roguesymset */ if (Is_rogue_level(&u.uz)) return ch; - /* Save some processing time by returning if the glyph represents - an object that we don't have custom characters for */ - if (!glyph_is_cmap(glyph)) - return ch; - symbol = glyph_to_cmap(glyph); - /* - * FIXME: - * 'cursesgraphics' should be a symbol set so that users can - * modify it without having to edit this source file and rebuild - * the program. Unfortunately these ACS values are 32-bit ones - * and not user-friendly. - */ - if (!cursesglyphsinited) { /* one-time initialization */ - cursesglyphsinited = 1; - cursesglyphs[S_vwall] = ACS_VLINE; - cursesglyphs[S_hwall] = ACS_HLINE; - cursesglyphs[S_tlcorn] = ACS_ULCORNER; - cursesglyphs[S_trcorn] = ACS_URCORNER; - cursesglyphs[S_blcorn] = ACS_LLCORNER; - cursesglyphs[S_brcorn] = ACS_LRCORNER; - cursesglyphs[S_crwall] = ACS_PLUS; - cursesglyphs[S_tuwall] = ACS_BTEE; - cursesglyphs[S_tdwall] = ACS_TTEE; - /* yes, the left/right Ts are inverted nethack vs curses */ - cursesglyphs[S_tlwall] = ACS_RTEE; - cursesglyphs[S_trwall] = ACS_LTEE; - cursesglyphs[S_tree] = ACS_PLMINUS; - cursesglyphs[S_corr] = ACS_CKBOARD; - cursesglyphs[S_litcorr] = ACS_CKBOARD; - } - /* Curses has complete access to all characters that DECgraphics uses. However, their character value isn't consistent between terminals and implementations. For actual DEC terminals and faithful emulators, line-drawing characters are specified as lowercase letters (mostly) and a control code is sent to the terminal telling it to switch character sets (that's how the tty interface handles them). - Curses remaps the characters instead. */ - if (decgraphics) { - /* the DEC line drawing characters use 0x5f through 0x7e instead - of the much more straightforward 0x60 through 0x7f, possibly - because 0x7f is effectively a control character (Rubout); - nethack ORs 0x80 to flag line drawing--that's stripped below */ - static int decchars[33]; /* for chars 0x5f through 0x7f (95..127) */ + Curses remaps the characters instead. - /* one-time initialization; some ACS_x aren't compile-time constant */ - if (!decchars[0]) { - /* [0] is non-breakable space; irrelevant to nethack */ - decchars[0x5f - 0x5f] = ' '; /* NBSP */ - decchars[0x60 - 0x5f] = ACS_DIAMOND; /* [1] solid diamond */ - decchars[0x61 - 0x5f] = ACS_CKBOARD; /* [2] checkerboard */ - /* several "line drawing" characters are two-letter glyphs - which could be substituted for invisible control codes; - nethack's DECgraphics doesn't use any of them so we're - satisfied with conversion to a simple letter; - [3] "HT" as one char, with small raised upper case H over - and/or preceding small lowered upper case T */ - decchars[0x62 - 0x5f] = 'H'; /* "HT" (horizontal tab) */ - decchars[0x63 - 0x5f] = 'F'; /* "FF" as one char (form feed) */ - decchars[0x64 - 0x5f] = 'C'; /* "CR" as one (carriage return) */ - decchars[0x65 - 0x5f] = 'L'; /* [6] "LF" as one (line feed) */ - decchars[0x66 - 0x5f] = ACS_DEGREE; /* small raised circle */ - /* [8] plus or minus sign, '+' with horizontal line below */ - decchars[0x67 - 0x5f] = ACS_PLMINUS; - decchars[0x68 - 0x5f] = 'N'; /* [9] "NL" as one char (new line) */ - decchars[0x69 - 0x5f] = 'V'; /* [10] "VT" as one (vertical tab) */ - decchars[0x6a - 0x5f] = ACS_LRCORNER; /* lower right corner */ - decchars[0x6b - 0x5f] = ACS_URCORNER; /* upper right corner */ - decchars[0x6c - 0x5f] = ACS_ULCORNER; /* upper left corner */ - decchars[0x6d - 0x5f] = ACS_LLCORNER; /* lower left corner, 'L' */ - /* [15] center cross, like big '+' sign */ - decchars[0x6e - 0x5f] = ACS_PLUS; - decchars[0x6f - 0x5f] = ACS_S1; /* very high horizontal line */ - decchars[0x70 - 0x5f] = ACS_S3; /* medium high horizontal line */ - decchars[0x71 - 0x5f] = ACS_HLINE; /* centered horizontal line */ - decchars[0x72 - 0x5f] = ACS_S7; /* medium low horizontal line */ - decchars[0x73 - 0x5f] = ACS_S9; /* very low horizontal line */ - /* [21] left tee, 'H' with right-hand vertical stroke removed; - note on left vs right: the ACS name (also DEC's terminal - documentation) refers to vertical bar rather than cross stroke, - nethack's left/right refers to direction of the cross stroke */ - decchars[0x74 - 0x5f] = ACS_LTEE; /* ACS left tee, NH right tee */ - /* [22] right tee, 'H' with left-hand vertical stroke removed */ - decchars[0x75 - 0x5f] = ACS_RTEE; /* ACS right tee, NH left tee */ - /* [23] bottom tee, '+' with lower half of vertical stroke - removed and remaining stroke pointed up (unside-down 'T'); - nethack is inconsistent here--unlike with left/right, its - bottom/top directions agree with ACS */ - decchars[0x76 - 0x5f] = ACS_BTEE; /* bottom tee, stroke up */ - /* [24] top tee, '+' with upper half of vertical stroke removed */ - decchars[0x77 - 0x5f] = ACS_TTEE; /* top tee, stroke down, 'T' */ - decchars[0x78 - 0x5f] = ACS_VLINE; /* centered vertical line */ - decchars[0x79 - 0x5f] = ACS_LEQUAL; /* less than or equal to */ - /* [27] greater than or equal to, '>' with underscore */ - decchars[0x7a - 0x5f] = ACS_GEQUAL; - /* [28] Greek pi ('n'-like; case is ambiguous: small size - suggests lower case but flat top suggests upper case) */ - decchars[0x7b - 0x5f] = ACS_PI; - /* [29] not equal sign, combination of '=' and '/' */ - decchars[0x7c - 0x5f] = ACS_NEQUAL; - /* [30] British pound sign (curly 'L' with embellishments) */ - decchars[0x7d - 0x5f] = ACS_STERLING; - decchars[0x7e - 0x5f] = ACS_BULLET; /* [31] centered dot */ - /* [32] is not used for DEC line drawing but is a potential - value for someone who assumes that 0x60..0x7f is the valid - range, so we're prepared to accept--and sanitize--it */ - decchars[0x7f - 0x5f] = '?'; - } + The DEC line drawing characters use 0x5f through 0x7e instead + of the much more straightforward 0x60 through 0x7f, possibly + because 0x7f is effectively a control character (Rubout); + nethack ORs 0x80 to flag line drawing--that's stripped below */ + static int decchars[33]; /* for chars 0x5f through 0x7f (95..127) */ - /* high bit set means special handling */ - if (ch & 0x80) { - int convindx; - - ch &= ~0x80; /* force plain ASCII for last resort */ - convindx = ch - 0x5f; - /* if it's in the lower case block of ASCII (which includes - a few punctuation characters), use the conversion table */ - if (convindx >= 0 && convindx < SIZE(decchars)) { - ch = decchars[convindx]; - /* in case ACS_foo maps to 0 when current terminal is unable - to handle a particular character; if so, revert to default - rather than using DECgr value with high bit stripped */ - if (!ch) - ch = (int) defsyms[symbol].sym; - } - } - return ch; + /* one-time initialization; some ACS_x aren't compile-time constant */ + if (!decchars[0]) { + /* [0] is non-breakable space; irrelevant to nethack */ + decchars[0x5f - 0x5f] = ' '; /* NBSP */ + decchars[0x60 - 0x5f] = ACS_DIAMOND; /* [1] solid diamond */ + decchars[0x61 - 0x5f] = ACS_CKBOARD; /* [2] checkerboard */ + /* several "line drawing" characters are two-letter glyphs + which could be substituted for invisible control codes; + nethack's DECgraphics doesn't use any of them so we're + satisfied with conversion to a simple letter; + [3] "HT" as one char, with small raised upper case H over + and/or preceding small lowered upper case T */ + decchars[0x62 - 0x5f] = 'H'; /* "HT" (horizontal tab) */ + decchars[0x63 - 0x5f] = 'F'; /* "FF" as one char (form feed) */ + decchars[0x64 - 0x5f] = 'C'; /* "CR" as one (carriage return) */ + decchars[0x65 - 0x5f] = 'L'; /* [6] "LF" as one (line feed) */ + decchars[0x66 - 0x5f] = ACS_DEGREE; /* small raised circle */ + /* [8] plus or minus sign, '+' with horizontal line below */ + decchars[0x67 - 0x5f] = ACS_PLMINUS; + decchars[0x68 - 0x5f] = 'N'; /* [9] "NL" as one char (new line) */ + decchars[0x69 - 0x5f] = 'V'; /* [10] "VT" as one (vertical tab) */ + decchars[0x6a - 0x5f] = ACS_LRCORNER; /* lower right corner */ + decchars[0x6b - 0x5f] = ACS_URCORNER; /* upper right corner */ + decchars[0x6c - 0x5f] = ACS_ULCORNER; /* upper left corner */ + decchars[0x6d - 0x5f] = ACS_LLCORNER; /* lower left corner, 'L' */ + /* [15] center cross, like big '+' sign */ + decchars[0x6e - 0x5f] = ACS_PLUS; + decchars[0x6f - 0x5f] = ACS_S1; /* very high horizontal line */ + decchars[0x70 - 0x5f] = ACS_S3; /* medium high horizontal line */ + decchars[0x71 - 0x5f] = ACS_HLINE; /* centered horizontal line */ + decchars[0x72 - 0x5f] = ACS_S7; /* medium low horizontal line */ + decchars[0x73 - 0x5f] = ACS_S9; /* very low horizontal line */ + /* [21] left tee, 'H' with right-hand vertical stroke removed; + note on left vs right: the ACS name (also DEC's terminal + documentation) refers to vertical bar rather than cross stroke, + nethack's left/right refers to direction of the cross stroke */ + decchars[0x74 - 0x5f] = ACS_LTEE; /* ACS left tee, NH right tee */ + /* [22] right tee, 'H' with left-hand vertical stroke removed */ + decchars[0x75 - 0x5f] = ACS_RTEE; /* ACS right tee, NH left tee */ + /* [23] bottom tee, '+' with lower half of vertical stroke + removed and remaining stroke pointed up (unside-down 'T'); + nethack is inconsistent here--unlike with left/right, its + bottom/top directions agree with ACS */ + decchars[0x76 - 0x5f] = ACS_BTEE; /* bottom tee, stroke up */ + /* [24] top tee, '+' with upper half of vertical stroke removed */ + decchars[0x77 - 0x5f] = ACS_TTEE; /* top tee, stroke down, 'T' */ + decchars[0x78 - 0x5f] = ACS_VLINE; /* centered vertical line */ + decchars[0x79 - 0x5f] = ACS_LEQUAL; /* less than or equal to */ + /* [27] greater than or equal to, '>' with underscore */ + decchars[0x7a - 0x5f] = ACS_GEQUAL; + /* [28] Greek pi ('n'-like; case is ambiguous: small size + suggests lower case but flat top suggests upper case) */ + decchars[0x7b - 0x5f] = ACS_PI; + /* [29] not equal sign, combination of '=' and '/' */ + decchars[0x7c - 0x5f] = ACS_NEQUAL; + /* [30] British pound sign (curly 'L' with embellishments) */ + decchars[0x7d - 0x5f] = ACS_STERLING; + decchars[0x7e - 0x5f] = ACS_BULLET; /* [31] centered dot */ + /* [32] is not used for DEC line drawing but is a potential + value for someone who assumes that 0x60..0x7f is the valid + range, so we're prepared to accept--and sanitize--it */ + decchars[0x7f - 0x5f] = '?'; } - /* - * [Is this correct? How did mapglyph() supply the value if it - * isn't coming from showsyms[]? glyph_is_cmap() test commented - * out because of the nothing-else-gets-here optimization above.] - */ - /* If user selected a custom character for this object, don't - override this. */ - if (/*glyph_is_cmap(glyph) &&*/ ch != showsyms[symbol]) { - retch = ch; - } else { - retch = (symbol >= 0 && symbol < MAXPCHARS) ? cursesglyphs[symbol] : 0; - if (!retch) - retch = ch; + /* high bit set means special handling */ + if (ch & 0x80) { + int convindx; + + ch &= ~0x80; /* force plain ASCII for last resort */ + convindx = ch - 0x5f; + /* if it's in the lower case block of ASCII (which includes + a few punctuation characters), use the conversion table */ + if (convindx >= 0 && convindx < SIZE(decchars)) { + ch = decchars[convindx]; + /* in case ACS_foo maps to 0 when current terminal is unable + to handle a particular character; if so, revert to default + rather than using DECgr value with high bit stripped */ + if (!ch) + ch = (int) defsyms[symbol].sym; + } } - return retch; + + return ch; } diff --git a/win/curses/cursmisc.h b/win/curses/cursmisc.h index 9a5b8033b..d76346184 100644 --- a/win/curses/cursmisc.h +++ b/win/curses/cursmisc.h @@ -19,7 +19,7 @@ char *curses_break_str(const char *str, int width, int line_num); char *curses_str_remainder(const char *str, int width, int line_num); boolean curses_is_menu(winid wid); boolean curses_is_text(winid wid); -int curses_convert_glyph(boolean decgraphics, int ch, int glyph); +int curses_convert_glyph(int ch, int glyph); void curses_move_cursor(winid wid, int x, int y); void curses_prehousekeeping(void); void curses_posthousekeeping(void);