diff --git a/dat/opthelp b/dat/opthelp index 560acc463..ee9092ede 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -17,7 +17,7 @@ cmdassist give help for errors on direction & other commands [TRUE] confirm ask before hitting tame or peaceful monsters [TRUE] dark_room show floor not in sight in different color [TRUE] eight_bit_tty send 8-bit characters straight to terminal [FALSE] -extmenu tty: use a menu for selecting extended commands (#)[FALSE] +extmenu tty, curses: use menu for # (extended commands) [FALSE] X11: menu has all commands (T) or traditional subset (F) fixinv try to retain the same letter for the same object [TRUE] force_invmenu commands asking for inventory item show a menu [FALSE] diff --git a/doc/fixes36.2 b/doc/fixes36.2 index ea7eab82d..68709069d 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.296 $ $NHDT-Date: 1554136021 2019/04/01 16:27:01 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.298 $ $NHDT-Date: 1554425733 2019/04/05 00:55:33 $ This fixes36.2 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.1 in April 2018. Please note, however, @@ -535,6 +535,9 @@ curses: highlighting of status conditions was broken by the fix for timing out curses: if player pressed ESC at More>> prompt to suppress remaining messages for the current move and then hero got another move on the same turn, messages and most prompts would stay suppressed during that extra move +curses: don't let MSGTYPE=hide block prompts from being shown +curses: the --More-- prompt (">>") wasn't always placed in a visible location, + especially when window borders were displayed vms: add compile of isaac64.c to Makefile.src and vmsbuild.com vms+curses: add compile support but it is known to fail to build diff --git a/include/wincurs.h b/include/wincurs.h index 1dc6400d5..18b3be289 100644 --- a/include/wincurs.h +++ b/include/wincurs.h @@ -213,6 +213,7 @@ extern void curses_cleanup(void); /* cursmesg.c */ extern void curses_message_win_puts(const char *message, boolean recursed); +extern void curses_got_input(void); extern int curses_block(boolean require_tab); /* for MSGTYPE=STOP */ extern int curses_more(void); extern void curses_clear_unhighlight_message_window(void); diff --git a/sys/unix/hints/solaris b/sys/unix/hints/solaris new file mode 100644 index 000000000..2140330dd --- /dev/null +++ b/sys/unix/hints/solaris @@ -0,0 +1,44 @@ +# +# NetHack 3.6 unix $NHDT-Date: 1554411633 2019/04/04 21:00:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.0 $ +# Copyright (c) Kevin Smolkowski "Snivik", Elgin Oregon 2019. +# NetHack may be freely redistributed. See license for details. +# +#-PRE +# solaris hints file +# This hints file provides a single-user x11 build for Solaris, specifically +# for Solaris 10 and 11, but should work just fine on older versions + +# Build using using included gcc and gmake, optional flex and bison come from csw for solaris 10 and included +# with Solaris 11 + +# Build NetHack off your home directory +HACKDIR=$(HOME)/nethackdir +INSTDIR=$(HACKDIR) +VARDIR=$(HACKDIR) +SHELLDIR=$(HOME) + +POSTINSTALL= cp sys/unix/sysconf $(INSTDIR)/sysconf; + +CC=gcc +CFLAGS=-O -I../include +LINK=$(CC) + +WINSRC = $(WINTTYSRC) +WINOBJ = $(WINTTYOBJ) +WINLIB = $(WINTTYLIB) + +WINTTYLIB=-ltermlib + +CHOWN=true +CHGRP=true + +GAMEUID = games +GAMEGRP = bin + +GAMEPERM = 04755 +VARFILEPERM = 0644 +VARDIRPERM = 0755 + +# Optional Tools to build level compiler +#LEX=flex +#YACC=bison -y diff --git a/sys/unix/hints/solaris-playground b/sys/unix/hints/solaris-playground new file mode 100644 index 000000000..5e51df6f2 --- /dev/null +++ b/sys/unix/hints/solaris-playground @@ -0,0 +1,48 @@ +# +# NetHack 3.6 unix $NHDT-Date: 1554411633 2019/04/04 21:00:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.0 $ +# Copyright (c) Kevin Smolkowski "Snivik", Elgin Oregon 2019. +# NetHack may be freely redistributed. See license for details. +# +#-PRE +# This hints file provides a shared playground build for Solaris, specifically +# for Solaris 10 and 11, but should work just fine on older versions + +# Nethack will install suid games, and will expect to read a users .nethackrc file from +# their home directory which may be a problem on secure systems with read restricted home +# directories, not that you would problably run NetHack on such a system anyway. :) + +# Build using using included gcc and gmake, optional flex and bison come from csw for solaris 10 +# and included on Solaris 11 + + +PREFIX=/usr +HACKDIR=$(PREFIX)/games/lib/$(GAME)dir +INSTDIR=$(HACKDIR) +VARDIR=$(HACKDIR) +SHELLDIR=$(PREFIX)/games + +POSTINSTALL= cp sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf;$(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; + +CC=gcc +CFLAGS=-O -I../include +LINK=$(CC) + +WINSRC = $(WINTTYSRC) +WINOBJ = $(WINTTYOBJ) +WINLIB = $(WINTTYLIB) + +WINTTYLIB=-ltermlib + +CHOWN=chown +CHGRP=chgrp + +GAMEUID = games +GAMEGRP = bin + +GAMEPERM = 04755 +VARFILEPERM = 0644 +VARDIRPERM = 0755 + +# Optional Tools to build level compiler +#LEX=flex +#YACC=bison -y \ No newline at end of file diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 8ec5d20b5..fd5385b90 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -17,8 +17,6 @@ #define strncasecmp strncmpi #endif -extern long curs_mesg_suppress_turn; /* from cursmesg.c */ - /* * Note: * @@ -127,7 +125,7 @@ curses_line_input_dialog(const char *prompt, char *answer, int buffer) /* if messages were being suppressed for the remainder of the turn, re-activate them now that input is being requested */ - curs_mesg_suppress_turn = -1; + curses_got_input(); if (buffer >= (int) sizeof input) buffer = (int) sizeof input - 1; @@ -212,7 +210,7 @@ curses_character_input_dialog(const char *prompt, const char *choices, /* if messages were being suppressed for the remainder of the turn, re-activate them now that input is being requested */ - curs_mesg_suppress_turn = -1; + curses_got_input(); if (invent || (moves > 1)) { curses_get_window_size(MAP_WIN, &map_height, &map_width); @@ -276,7 +274,9 @@ curses_character_input_dialog(const char *prompt, const char *choices, wrefresh(askwin); } else { - pline("%s", askstr); + /* TODO: add SUPPRESS_HISTORY flag, then after getting a response, + append it and use put_msghistory() on combined prompt+answer */ + custompline(OVERRIDE_MSGTYPE, "%s", askstr); curs_set(1); } @@ -348,7 +348,7 @@ curses_character_input_dialog(const char *prompt, const char *choices, /* Kludge to make prompt visible after window is dismissed when inputting a number */ if (digit(answer)) { - pline("%s", askstr); + custompline(OVERRIDE_MSGTYPE, "%s", askstr); curs_set(1); } @@ -403,7 +403,7 @@ curses_ext_cmd() extwin = newwin(1, messagew - 2, winy, winx); if (messagew - 4 < maxlen) maxlen = messagew - 4; - pline("#"); + custompline(OVERRIDE_MSGTYPE, "#"); } cur_choice[0] = '\0'; diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index c3cceb1f7..9757e111a 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -232,6 +232,7 @@ curses_get_nh_event() if (do_reset) { getmaxyx(base_term, term_rows, term_cols); + curses_got_input(); /* reset More>> */ /* status_initialize, create_main_windows, last_messages, doredraw */ curs_reset_windows(TRUE, TRUE); } @@ -689,9 +690,6 @@ curses_nhgetch() { int ch; - /* if messages are being suppressed, reenable them */ - curs_mesg_suppress_turn = -1; - curses_prehousekeeping(); ch = curses_read_char(); curses_posthousekeeping(); diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 2c1decb9a..656dce57d 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -9,10 +9,14 @@ #include "cursmesg.h" #include +/* + * Note: references to "More>>" mean ">>", the curses rendition of "--More--". + */ + /* player can type ESC at More>> prompt to avoid seeing more messages for the current move; but hero might get more than one move per turn, so the input routines need to be able to cancel this */ -long curs_mesg_suppress_turn = -1; /* also used in cursdial.c && cursmain.c */ +long curs_mesg_suppress_turn = -1; /* Message window routines for curses interface */ @@ -31,30 +35,30 @@ static void directional_scroll(winid wid, int nlines); static void mesg_add_line(const char *mline); static nhprev_mesg *get_msg_line(boolean reverse, int mindex); -static int turn_lines = 1; +static int turn_lines = 0; static int mx = 0; static int my = 0; /* message window text location */ static nhprev_mesg *first_mesg = NULL; static nhprev_mesg *last_mesg = NULL; static int max_messages; static int num_messages = 0; +static int last_messages = 0; /* Write string to the message window. Attributes set by calling function. */ void curses_message_win_puts(const char *message, boolean recursed) { - int height, width, linespace; + int height, width, border_space, linespace; char *tmpstr; WINDOW *win = curses_get_nhwin(MESSAGE_WIN); - boolean border = curses_window_has_border(MESSAGE_WIN); - int message_length = strlen(message); - int border_space = 0; + boolean bold, border = curses_window_has_border(MESSAGE_WIN); + int message_length = (int) strlen(message); #if 0 /* * This was useful when curses used genl_putmsghistory() but is not - * needed now that it has its own curses_putmsghistory() that's + * needed now that it has its own curses_putmsghistory() which is * capable of putting something into the ^P recall history without * displaying it at the same time. */ @@ -69,17 +73,11 @@ curses_message_win_puts(const char *message, boolean recursed) } curses_get_window_size(MESSAGE_WIN, &height, &width); - if (border) { - border_space = 1; - if (mx < 1) { - mx = 1; - } - if (my < 1) { - my = 1; - } - } - - linespace = ((width + border_space) - 3) - mx; + border_space = (border ? 1 : 0); + if (mx < border_space) + mx = border_space; + if (my < border_space) + my = border_space; if (strcmp(message, "#") == 0) { /* Extended command or Count: */ if ((strcmp(toplines, "#") != 0) @@ -90,7 +88,6 @@ curses_message_win_puts(const char *message, boolean recursed) my--; strcpy(toplines, message); } - return; } @@ -99,88 +96,142 @@ curses_message_win_puts(const char *message, boolean recursed) mesg_add_line(message); } + linespace = width - 3 - (mx - border_space); + if (linespace < message_length) { - if (my >= (height - 1 + border_space)) { + if (my - border_space >= height - 1) { /* bottom of message win */ - if ((turn_lines > height) || (height == 1)) { + if (++turn_lines >= height) { /* || height == 1) */ /* Pause until key is hit - Esc suppresses any further messages that turn */ if (curses_more() == '\033') { curs_mesg_suppress_turn = moves; return; } + /* turn_lines reset to 0 by more()->block()->got_input() */ } else { scroll_window(MESSAGE_WIN); - turn_lines++; } } else { if (mx != border_space) { my++; mx = border_space; + ++turn_lines; } } } - if (height > 1) { + bold = (height > 1 && !last_messages); + if (bold) curses_toggle_color_attr(win, NONE, A_BOLD, ON); - } - if ((mx == border_space) && ((message_length + 2) > width)) { + /* will this message fit as-is or do we need to split it? */ + if (mx == border_space && message_length > width - 2) { + /* split needed */ tmpstr = curses_break_str(message, (width - 2), 1); - mvwprintw(win, my, mx, "%s", tmpstr); - mx += strlen(tmpstr); - if (strlen(tmpstr) < (size_t) (width - 2)) { - mx++; - } + mvwprintw(win, my, mx, "%s", tmpstr), mx += (int) strlen(tmpstr); + /* one space to separate first part of message from rest [is this + actually useful?] */ + if (mx < width - 2) + ++mx; free(tmpstr); - if (height > 1) { + if (bold) curses_toggle_color_attr(win, NONE, A_BOLD, OFF); - } tmpstr = curses_str_remainder(message, (width - 2), 1); curses_message_win_puts(tmpstr, TRUE); free(tmpstr); } else { - mvwprintw(win, my, mx, "%s", message); - curses_toggle_color_attr(win, NONE, A_BOLD, OFF); - mx += message_length + 1; + mvwprintw(win, my, mx, "%s", message), mx += message_length; + /* two spaces to separate this message from next one if they happen + to fit on the same line; (FIXME: it would be better if this was + done at start of next message rather than end of this one since + it impacts placement of "More>>") */ + if (mx < width - 2) { + if (++mx < width - 2) + ++mx; + } + if (bold) + curses_toggle_color_attr(win, NONE, A_BOLD, OFF); } wrefresh(win); } +void +curses_got_input(void) +{ + /* if messages are being suppressed, reenable them */ + curs_mesg_suppress_turn = -1; + + /* misleadingly named; represents number of lines delivered since + player was sure to have had a chance to read them; if player + has just given input then there aren't any such lines right; + that includes responding to More>> even though it stays same turn */ + turn_lines = 0; +} int curses_block(boolean noscroll) /* noscroll - blocking because of msgtype * = stop/alert else blocking because * window is full, so need to scroll after */ { - int height, width, ret = 0; + static const char resp[] = " \r\n\033"; /* space, enter, esc */ + static int prev_x = -1, prev_y = -1, blink = 0; + int height, width, moreattr, oldcrsr, ret = 0, + brdroffset = curses_window_has_border(MESSAGE_WIN) ? 1 : 0; WINDOW *win = curses_get_nhwin(MESSAGE_WIN); - const char *resp = " \r\n\033"; /* space, enter, esc */ - - /* if messages are being suppressed, reenable them */ - curs_mesg_suppress_turn = -1; curses_get_window_size(MESSAGE_WIN, &height, &width); - curses_toggle_color_attr(win, MORECOLOR, NONE, ON); - mvwprintw(win, my, mx, ">>"); - curses_toggle_color_attr(win, MORECOLOR, NONE, OFF); + if (mx - brdroffset > width - 3) { /* -3: room for ">>_" */ + if (my - brdroffset < height - 1) + ++my, mx = brdroffset; + else + mx = width - 3 + brdroffset; + } + /* if ">>" (--More--) is being rendered at the same spot as before, + toggle attributes so that the first '>' starts blinking if it wasn't + or stops blinking if it was */ + if (mx == prev_x && my == prev_y) { + blink = 1 - blink; + } else { + prev_x = mx, prev_y = my; + blink = 0; + } + moreattr = !iflags.wc2_guicolor ? A_REVERSE : NONE; + curses_toggle_color_attr(win, MORECOLOR, moreattr, ON); + if (blink) { + wattron(win, A_BLINK); + mvwprintw(win, my, mx, ">"), mx += 1; + wattroff(win, A_BLINK); + waddstr(win, ">"), mx += 1; + } else { + mvwprintw(win, my, mx, ">>"), mx += 2; + } + curses_toggle_color_attr(win, MORECOLOR, moreattr, OFF); wrefresh(win); - /* msgtype=stop should require space/enter rather than - * just any key, as we want to prevent YASD from - * riding direction keys. */ - while ((ret = wgetch(win)) != 0 && !index(resp, (char) ret)) - continue; + + /* cancel mesg suppression; all messages will have had chance to be read */ + curses_got_input(); + + oldcrsr = curs_set(1); + do { + ret = wgetch(win); + if (ret == ERR || ret == '\0') + ret = '\n'; + /* msgtype=stop should require space/enter rather than any key, + as we want to prevent YASD from direction keys. */ + } while (!index(resp, (char) ret)); + if (oldcrsr >= 0) + (void) curs_set(oldcrsr); + if (height == 1) { curses_clear_unhighlight_message_window(); } else { - mvwprintw(win, my, mx, " "); + mx -= 2, mvwprintw(win, my, mx, " "); /* back up and blank out ">>" */ if (!noscroll) { scroll_window(MESSAGE_WIN); - turn_lines = 1; } wrefresh(win); } - return ret; } @@ -196,34 +247,25 @@ curses_more() void curses_clear_unhighlight_message_window() { - int mh, mw, count; - boolean border = curses_window_has_border(MESSAGE_WIN); + int mh, mw, count, + brdroffset = curses_window_has_border(MESSAGE_WIN) ? 1 : 0; WINDOW *win = curses_get_nhwin(MESSAGE_WIN); - turn_lines = 1; + turn_lines = 0; curses_get_window_size(MESSAGE_WIN, &mh, &mw); - mx = 0; - if (border) { - mx++; - } - if (mh == 1) { curses_clear_nhwin(MESSAGE_WIN); + mx = my = brdroffset; } else { - mx += mw; /* Force new line on new turn */ + mx = mw + brdroffset; /* Force new line on new turn */ - if (border) { - for (count = 0; count < mh; count++) { - mvwchgat(win, count + 1, 1, mw, COLOR_PAIR(8), A_NORMAL, NULL); - } - } else { - for (count = 0; count < mh; count++) { - mvwchgat(win, count, 0, mw, COLOR_PAIR(8), A_NORMAL, NULL); - } - } + for (count = 0; count < mh; count++) + mvwchgat(win, count + brdroffset, brdroffset, + mw, COLOR_PAIR(8), A_NORMAL, NULL); wnoutrefresh(win); } + wmove(win, my, mx); } @@ -235,19 +277,23 @@ curses_last_messages() { boolean border = curses_window_has_border(MESSAGE_WIN); nhprev_mesg *mesg; - int i; + int i, j, height, width; + + curses_get_window_size(MESSAGE_WIN, &height, &width); if (border) mx = my = 1; else mx = my = 0; - for (i = (num_messages - 1); i > 0; i--) { + ++last_messages; + for (j = 0, i = num_messages - 1; i > 0 && j < height; --i, ++j) { mesg = get_msg_line(TRUE, i); if (mesg && mesg->str && *mesg->str) curses_message_win_puts(mesg->str, TRUE); } curses_message_win_puts(toplines, TRUE); + --last_messages; } @@ -402,7 +448,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer) maxlines = buffer / width * 2; Strcpy(tmpbuf, prompt); Strcat(tmpbuf, " "); - nlines = curses_num_lines(tmpbuf,width); + nlines = curses_num_lines(tmpbuf, width); maxlines += nlines * 2; linestarts = (char **) alloc((unsigned) (maxlines * sizeof (char *))); p_answer = tmpbuf + strlen(tmpbuf); @@ -463,6 +509,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer) wmove(win, my, mx); curs_set(1); wrefresh(win); + curses_got_input(); /* despite its name, before rathre than after... */ #ifdef PDCURSES ch = wgetch(win); #else @@ -786,6 +833,7 @@ boolean restoring_msghist; --stash_count; mesg_turn = mesg->turn; mesg_add_line(mesg->str); + /* added line became new tail */ last_mesg->turn = mesg_turn; free((genericptr_t) mesg->str); free((genericptr_t) mesg); diff --git a/win/curses/cursmesg.h b/win/curses/cursmesg.h index 803b0fb5b..ca0752eea 100644 --- a/win/curses/cursmesg.h +++ b/win/curses/cursmesg.h @@ -10,6 +10,7 @@ /* Global declarations */ void curses_message_win_puts(const char *message, boolean recursed); +void curses_got_input(void); int curses_block(boolean require_tab); int curses_more(void); void curses_clear_unhighlight_message_window(void); diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index fd712fac6..223a8be82 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -42,6 +42,9 @@ curses_read_char() { int ch, tmpch; + /* cancel message suppression; all messages have had a chance to be read */ + curses_got_input(); + ch = getch(); tmpch = ch; ch = curses_convert_keys(ch);