From 4b87255105a7fe5fab3bab74bf815568098e148e Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 13 Mar 2017 15:43:08 -0700 Subject: [PATCH 1/6] more control key formatting The previous fix to use highc(UNCTRL(x)) worked for ^A through ^Z, but not for NUL (yielded ^` instead of usual ^@) or ^[ through ^_ (yielded lowercase ^{ and so on). The problem was UNCTRL(); it shouldn't have been forcing on the lowercase bit to begin with. Also, the code that used UNMETA() for formatting wouldn't work as intended for M-control char since it stripped off the 8th bit but didn't apply any fixup for control chars. Just get rid of ISCTRL/ISMETA/UNCTRL/UNMETA and use the existing visctrl() routine instead. (Its 3.6.0 edition didn't handle M-control char, but the to-be-3.6.1 branch has done so since a week or two after the 3.6.0 release.) --- src/cmd.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index 79e096249..19dcf6852 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -2737,24 +2737,18 @@ int final; /* Macros for meta and ctrl modifiers: * M and C return the meta/ctrl code for the given character; * e.g., (C('c') is ctrl-c - * ISMETA and ISCTRL return TRUE iff the code is a meta/ctrl code - * UNMETA and UNCTRL are the opposite of M/C and return the key for a given - * meta/ctrl code. */ + */ #ifndef M #ifndef NHSTDC #define M(c) (0x80 | (c)) #else -#define M(c) ((c) -128) +#define M(c) ((c) - 128) #endif /* NHSTDC */ #endif -#define ISMETA(c) (((c) & 0x80) != 0) -#define UNMETA(c) ((c) & 0x7f) #ifndef C #define C(c) (0x1f & (c)) #endif -#define ISCTRL(c) ((uchar)(c) < 0x20) -#define UNCTRL(c) (ISCTRL(c) ? (0x60 | (c)) : (c)) /* ordered by command name */ struct ext_func_tab extcmdlist[] = { @@ -3727,27 +3721,25 @@ char *txt; return '\0'; } -/* returns the text for a one-byte encoding +/* returns the text for a one-byte encoding; * must be shorter than a tab for proper formatting */ char * key2txt(c, txt) uchar c; char *txt; /* sufficiently long buffer */ { + /* should probably switch to "SPC", "ESC", "RET" + since nethack's documentation uses ESC for */ if (c == ' ') Sprintf(txt, ""); else if (c == '\033') Sprintf(txt, ""); else if (c == '\n') Sprintf(txt, ""); - else if (ISCTRL(c)) - Sprintf(txt, "^%c", highc(UNCTRL(c))); - else if (ISMETA(c)) - Sprintf(txt, "M-%c", UNMETA(c)); - else if (c >= 33 && c <= 126) - Sprintf(txt, "%c", c); /* regular keys: ! through ~ */ + else if (c == '\177') + Sprintf(txt, ""); /* "" won't fit */ else - Sprintf(txt, "A-%i", c); /* arbitrary ascii combinations */ + Strcpy(txt, visctrl((char) c)); return txt; } From dd8a95eec43a89757f0ca7ed9ef8fe9c03099419 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 14 Mar 2017 05:27:45 -0700 Subject: [PATCH 2/6] fix #H5188 - getting an artifact break illiterate To-be-3.6.1 bug, caused by a patch (of mine...) incorporated about a week after 3.6.0 was released that was intended to be for naming Sting or Orcist. Any artifact creation ended up breaking illiterate conduct whether user-assigned naming was involved or not (because oname() is always used to apply the name, not just when do_name() is executing). This should be handled differently but I don't want to go through the dozen and half or so calls to oname() to add an extra argument. --- doc/fixes36.1 | 2 ++ src/do_name.c | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 761d1e02e..f0986f9a2 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -398,6 +398,8 @@ DUMPLOG: genocided and extinct species was always a blank line; vanquished creatures was just a blank line if nothing had been killed DUMPLOG: RIP tombstone was printed for characters who survived (ascended, escaped dungeon, quit, trickery or panic) +artifact creation violated illiterate conduct when artifact name was assigned, + behavior intended only for creating Sting or Orcrist via naming Platform- and/or Interface-Specific Fixes diff --git a/src/do_name.c b/src/do_name.c index d494942ce..98293152e 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1452669022 2016/01/13 07:10:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.90 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1489494376 2017/03/14 12:26:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.116 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1011,10 +1011,12 @@ do_mname() (void) christen_monst(mtmp, buf); } +STATIC_VAR int via_naming = 0; + /* - * This routine changes the address of obj. Be careful not to call it - * when there might be pointers around in unknown places. For now: only - * when obj is in the inventory. + * This routine used to change the address of 'obj' so be unsafe if not + * used with extreme care. Applying a name to an object no longer + * allocates a replacement object, so that old risk is gone. */ STATIC_OVL void @@ -1079,7 +1081,9 @@ register struct obj *obj; display_nhwindow(WIN_MESSAGE, FALSE); You("engrave: \"%s\".", buf); } + ++via_naming; /* This ought to be an argument rather than a static... */ obj = oname(obj, buf); + --via_naming; /* ...but oname() is used in a lot of places, so defer. */ } struct obj * @@ -1119,8 +1123,10 @@ const char *name; /* if obj is owned by a shop, increase your bill */ if (obj->unpaid) alter_cost(obj, 0L); - /* violate illiteracy conduct since successfully wrote arti-name */ - u.uconduct.literate++; + if (via_naming) { + /* violate illiteracy conduct since successfully wrote arti-name */ + u.uconduct.literate++; + } } if (carried(obj)) update_inventory(); From a03d20d7abf19fad63df3f920a6ac8d4e51a8d96 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 17 Mar 2017 03:20:11 -0700 Subject: [PATCH 3/6] fix Bell of Opening segfault Noticed on nethack.alt.org; the Bell of Opening could trigger a segfault if applied near a trap door or bear trap (and a few others) that had no monster at the trap location. Reproducible if done while mounted; {open,close}{fall,hold}ingtrap() would try to access monst->mx and monst->my of a Null monst pointer if given one when u.usteed was non-Null. --- doc/fixes36.1 | 2 ++ src/trap.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index f0986f9a2..179ac4fee 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -368,6 +368,8 @@ add option status_updates to prevent bottom of screen status line updates fix achievement recording bug with mines and sokoban prizes g.cubes would eat globs of green slime without harm; engulf those instead fix up true rumor about rock moles vs boots +Bell of Opening could trigger segfault attempting to open some types of traps + if hero was mounted Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/trap.c b/src/trap.c index 0df86b1d7..2c9b4e511 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.c $NHDT-Date: 1473665044 2016/09/12 07:24:04 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.274 $ */ +/* NetHack 3.6 trap.c $NHDT-Date: 1489745987 2017/03/17 10:19:47 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.277 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4420,6 +4420,8 @@ boolean *noticed; /* set to true iff hero notices the effect; */ const char *trapdescr, *which; boolean ishero = (mon == &youmonst); + if (!mon) + return FALSE; if (mon == u.usteed) ishero = TRUE; t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); @@ -4478,6 +4480,8 @@ boolean *noticed; /* set to true iff hero notices the effect; */ unsigned dotrapflags; boolean ishero = (mon == &youmonst), result; + if (!mon) + return FALSE; if (mon == u.usteed) ishero = TRUE; t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); @@ -4521,6 +4525,8 @@ boolean *noticed; /* set to true iff hero notices the effect; */ struct trap *t; boolean ishero = (mon == &youmonst), result; + if (!mon) + return FALSE; if (mon == u.usteed) ishero = TRUE; t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); From 82620d16f54419d10210e2167cbb190359ad0b96 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 20 Mar 2017 19:11:48 -0700 Subject: [PATCH 4/6] tty prompting fix and DUMPLOG of prompts+answers Update DUMPLOG's message history to include player responses to most queries. For tty, both getlin() and yn_function(). For other interfaces, only yn_function() is covered. (It's intercepted by a core routine that can take care of the logging; getlin() isn't.) Also includes saved messages from previous session(s), for the interfaces which support that (tty), to fill out the logging when a game ends shortly after a save/restore cycle. The tty interface was using pline() to display prompt strings. Having 'MSGTYPE=hide "#"' or 'MSGTYPE=hide "yn"' in .nethackrc would suppress many prompt strings (in the two examples mentioned, entering extended commands or the vast majority of yes/no questions, respectively) and generally lead to substantial confusion even if done intentionally, so switch to putstr(WIN_MESSAGE) instead. --- doc/fixes36.1 | 4 +++- include/extern.h | 2 +- src/cmd.c | 37 ++++++++++++++++++++++++++++++++----- src/invent.c | 2 +- win/tty/getline.c | 40 +++++++++++++++++++++++++++++++++------- win/tty/topl.c | 41 ++++++++++++++++++++++++++++++++--------- 6 files changed, 102 insertions(+), 24 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 179ac4fee..63c80b848 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -426,6 +426,7 @@ tty: if "--More--" was written to leftmost column (beginning of second line) of status line instead back on map) after message line was cleared tty: long message lines which wrap when shown on the top line might be re-displayed incorrectly by ^P for msg_window={full,combo,reverse} +tty: MSGTYPE=hide could interfere with display of prompts unix/X11: in top level Makefile, some commented out definitions of VARDATND misspelled pilemark.xbm (as pilemark.xpm) unix: options file with CR+LF line ends and an invalid option line resulted in @@ -570,7 +571,8 @@ Ray Chason's MS-DOS port restored to functionality with credit to Reddit user Ray Chason's MSDOS port support for some VESA modes Darshan Shaligram's pet ranged attack Jason Dorje Short's key rebinding -Maxime Bacoux's new dumplog +Maxime Bacoux's new DUMPLOG: compile-time option to enable logging of + end-of-game information into a text file Code Cleanup and Reorganization diff --git a/include/extern.h b/include/extern.h index 3f5b34971..fb3b7dfa4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -211,7 +211,7 @@ E int FDECL(isok, (int, int)); E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *)); E const char *FDECL(click_to_cmd, (int, int, int)); -E char FDECL(get_count, (char *, CHAR_P, long, long *)); +E char FDECL(get_count, (char *, CHAR_P, long, long *, BOOLEAN_P)); #ifdef HANGUPHANDLING E void FDECL(hangup, (int)); E void NDECL(end_of_input); diff --git a/src/cmd.c b/src/cmd.c index 19dcf6852..f9473e6a7 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -4571,11 +4571,12 @@ int x, y, mod; } char -get_count(allowchars, inkey, maxcount, count) +get_count(allowchars, inkey, maxcount, count, historical) char *allowchars; char inkey; long maxcount; long *count; +boolean historical; /* whether to include in message history: True => yes */ { char qbuf[QBUFSZ]; int key; @@ -4616,10 +4617,19 @@ long *count; Sprintf(qbuf, "Count: %ld", cnt); backspaced = FALSE; } - pline1(qbuf); + /* bypassing pline() keeps intermediate prompt out of + DUMPLOG message history */ + putstr(WIN_MESSAGE, 0, qbuf); mark_synch(); } } + + if (historical) { + Sprintf(qbuf, "Count: %ld ", *count); + (void) key2txt((uchar) key, eos(qbuf)); + putmsghistory(qbuf, FALSE); + } + return key; } @@ -4645,7 +4655,7 @@ parse() if (!Cmd.num_pad || (foo = readchar()) == Cmd.spkeys[NHKF_COUNT]) { long tmpmulti = multi; - foo = get_count((char *) 0, '\0', LARGEST_INT, &tmpmulti); + foo = get_count((char *) 0, '\0', LARGEST_INT, &tmpmulti, FALSE); last_multi = multi = tmpmulti; } #ifdef ALTMETA @@ -4902,7 +4912,13 @@ yn_function(query, resp, def) const char *query, *resp; char def; { - char qbuf[QBUFSZ]; + char res, qbuf[QBUFSZ]; +#ifdef DUMPLOG + extern unsigned saved_pline_index; /* pline.c */ + unsigned idx = saved_pline_index; + /* buffer to hold query+space+formatted_single_char_response */ + char dumplog_buf[QBUFSZ + 1 + 15]; /* [QBUFSZ+1+7] should suffice */ +#endif iflags.last_msg = PLNMSG_UNKNOWN; /* most recent pline is clobbered */ @@ -4914,7 +4930,18 @@ char def; Strcpy(&qbuf[QBUFSZ - 1 - 3], "..."); query = qbuf; } - return (*windowprocs.win_yn_function)(query, resp, def); + res = (*windowprocs.win_yn_function)(query, resp, def); +#ifdef DUMPLOG + if (idx == saved_pline_index) { + /* when idx is still the same as saved_pline_index, the interface + didn't put the prompt into saved_plines[]; we put a simplified + version in there now (without response choices or default) */ + Sprintf(dumplog_buf, "%s ", query); + (void) key2txt((uchar) res, eos(dumplog_buf)); + dumplogmsg(dumplog_buf); + } +#endif + return res; } /* for paranoid_confirm:quit,die,attack prompting */ diff --git a/src/invent.c b/src/invent.c index fb0099bb8..added0caa 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1313,7 +1313,7 @@ register const char *let, *word; pline("No count allowed with this command."); continue; } - ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt); + ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt, TRUE); if (tmpcnt) { cnt = tmpcnt; cntgiven = TRUE; diff --git a/win/tty/getline.c b/win/tty/getline.c index 4d86f9a11..8d61aabfe 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -14,6 +14,7 @@ #include "func_tab.h" char morc = 0; /* tell the outside world what char you chose */ +STATIC_VAR boolean suppress_history; STATIC_DCL boolean FDECL(ext_cmd_getlin_hook, (char *)); typedef boolean FDECL((*getlin_hook_proc), (char *)); @@ -35,6 +36,7 @@ tty_getlin(query, bufp) const char *query; register char *bufp; { + suppress_history = FALSE; hooked_tty_getlin(query, bufp, (getlin_hook_proc) 0); } @@ -48,13 +50,20 @@ getlin_hook_proc hook; register int c; struct WinDesc *cw = wins[WIN_MESSAGE]; boolean doprev = 0; + char tmpbuf[BUFSZ]; /* [QBUFSZ+1] should suffice */ if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; ttyDisplay->toplin = 3; /* special prompt state */ ttyDisplay->inread++; - pline("%s ", query); + /* + * This used to use pline("%s ", query), but that made getline + * prompts be susceptible to suppression via the MSGTYPE mechanism. + * Having 'MSGTYPE=hide "# "' was particularly confusing. + */ + Sprintf(tmpbuf, "%s ", query); + tty_putstr(WIN_MESSAGE, 0, tmpbuf); *obufp = 0; for (;;) { (void) fflush(stdout); @@ -82,6 +91,7 @@ getlin_hook_proc hook; if (c == '\020') { /* ctrl-P */ if (iflags.prevmsg_window != 's') { int sav = ttyDisplay->inread; + ttyDisplay->inread = 0; (void) tty_doprev_message(); ttyDisplay->inread = sav; @@ -136,9 +146,9 @@ getlin_hook_proc hook; #endif /* not NEWAUTOCOMP */ break; } else if (' ' <= (unsigned char) c && c != '\177' + /* avoid isprint() - some people don't have it + ' ' is not always a printing char */ && (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO)) { -/* avoid isprint() - some people don't have it - ' ' is not always a printing char */ #ifdef NEWAUTOCOMP char *i = eos(bufp); @@ -166,7 +176,7 @@ getlin_hook_proc hook; #endif /* NEWAUTOCOMP */ } } else if (c == kill_char || c == '\177') { /* Robert Viduya */ -/* this test last - @ might be the kill_char */ + /* this test last - @ might be the kill_char */ #ifndef NEWAUTOCOMP while (bufp != obufp) { bufp--; @@ -185,6 +195,17 @@ getlin_hook_proc hook; ttyDisplay->toplin = 2; /* nonempty, no --More-- required */ ttyDisplay->inread--; clear_nhwindow(WIN_MESSAGE); /* clean up after ourselves */ + + if (suppress_history) { + /* prevent next message from pushing current query+answer into + tty message history */ + *toplines = '\0'; +#ifdef DUMPLOG + } else { + /* needed because we've bypassed pline() */ + dumplogmsg(toplines); +#endif + } } void @@ -267,9 +288,14 @@ tty_get_ext_cmd() if (iflags.extmenu) return extcmd_via_menu(); - /* maybe a runtime option? */ - /* hooked_tty_getlin("#", buf, flags.cmd_comp ? ext_cmd_getlin_hook : - * (getlin_hook_proc) 0); */ + + suppress_history = TRUE; + /* maybe a runtime option? + * hooked_tty_getlin("#", buf, + * (flags.cmd_comp && !in_doagain) + * ? ext_cmd_getlin_hook + * : (getlin_hook_proc) 0); + */ hooked_tty_getlin("#", buf, in_doagain ? (getlin_hook_proc) 0 : ext_cmd_getlin_hook); (void) mungspaces(buf); diff --git a/win/tty/topl.c b/win/tty/topl.c index dd6758a4e..cefc08f95 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -331,6 +331,7 @@ register int n; extern char erase_char; /* from xxxtty.c; don't need kill_char */ +/* returns a single keystroke; also sets 'yn_number' */ char tty_yn_function(query, resp, def) const char *query, *resp; @@ -354,6 +355,7 @@ char def; boolean doprev = 0; char prompt[BUFSZ]; + yn_number = 0L; if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; @@ -383,11 +385,14 @@ char def; /* not pline("%s ", prompt); trailing space is wanted here in case of reprompt */ Strcat(prompt, " "); - pline("%s", prompt); + /* pline("%s", prompt); -- see comment in hooked_tty_getlin() */ + tty_putstr(WIN_MESSAGE, 0, prompt); } else { /* no restriction on allowed response, so always preserve case */ /* preserve_case = TRUE; -- moot since we're jumping to the end */ - pline("%s ", query); + /* pline("%s ", query); -- see above about tty_getlin() */ + Sprintf(prompt, "%s ", query); + tty_putstr(WIN_MESSAGE, 0, prompt); q = readchar(); goto clean_up; } @@ -444,6 +449,7 @@ char def; char z, digit_string[2]; int n_len = 0; long value = 0; + addtopl("#"), n_len++; digit_string[1] = '\0'; if (q != '#') { @@ -491,11 +497,16 @@ char def; } } while (!q); - if (q != '#') { - Sprintf(rtmp, "%c", q); - addtopl(rtmp); - } -clean_up: + clean_up: + if (yn_number) + Sprintf(rtmp, "#%ld", yn_number); + else + (void) key2txt(q, rtmp); + /* addtopl(rtmp); -- rewrite toplines instead */ + Sprintf(toplines, "%s%s", prompt, rtmp); +#ifdef DUMPLOG + dumplogmsg(toplines); +#endif ttyDisplay->inread--; ttyDisplay->toplin = 2; if (ttyDisplay->intr) @@ -636,6 +647,9 @@ boolean restoring_msghist; { static boolean initd = FALSE; int idx; +#ifdef DUMPLOG + extern unsigned saved_pline_index; /* pline.c */ +#endif if (restoring_msghist && !initd) { /* we're restoring history from the previous session, but new @@ -645,18 +659,27 @@ boolean restoring_msghist; restored ones are being put into place */ msghistory_snapshot(TRUE); initd = TRUE; +#ifdef DUMPLOG + /* this suffices; there's no need to scrub saved_pline[] pointers */ + saved_pline_index = 0; +#endif } if (msg) { - /* move most recent message to history, make this become most recent - */ + /* move most recent message to history, make this become most recent */ remember_topl(); Strcpy(toplines, msg); +#ifdef DUMPLOG + dumplogmsg(toplines); +#endif } else if (snapshot_mesgs) { /* done putting arbitrary messages in; put the snapshot ones back */ for (idx = 0; snapshot_mesgs[idx]; ++idx) { remember_topl(); Strcpy(toplines, snapshot_mesgs[idx]); +#ifdef DUMPLOG + dumplogmsg(toplines); +#endif } /* now release the snapshot */ free_msghistory_snapshot(TRUE); From 6ba906b23443f4c8043fff52cb5e5f9151335a26 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 30 Mar 2017 14:14:38 -0700 Subject: [PATCH 5/6] maybe fix #H5264 - screen clears on prompting I couldn't reproduce the reported problem of the "In what direction?" being issued after the screen was cleared, but bypassing pline() in favor of putstr(WIN_MESSAGE) for tty prompts did also bypass if (vision_full_recalc) vision_recalc(0); if (u.ux) flush_screen(1); done in pline(). Inadvertent loss of the latter could conceivably be responsible for the problem. If so, the escape code used by cl_end() may be broken for somebody's termcap or terminfo setup since clearing to the end of the line in the message window shouldn't erase the rest of the screen. Regardless, the prompting change also bypassed the ability to show the prompt with raw_printf() if the display wasn't fully intialized yet, so some change to the revised prompting was necessary anyway. Switching back from putstr(WIN_MESSAGE) to pline() resulted in duplicated entries in DUMPLOG message history, one with bare prompt followed by another with response appended, so more tweaking was needed. The result is use of new custompline() instead of normal pline(). custompline() accepts some message handling flags to give more control over pline()'s behavior. It's a more general variation of Norep() but its caller needs to specify an extra argument. --- doc/fixes36.1 | 1 + include/extern.h | 3 ++- include/hack.h | 8 +++++++- src/pline.c | 42 ++++++++++++++++++++++++++++++++---------- win/tty/getline.c | 11 ++--------- win/tty/topl.c | 8 +++----- 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 63c80b848..7fa058915 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -402,6 +402,7 @@ DUMPLOG: RIP tombstone was printed for characters who survived (ascended, escaped dungeon, quit, trickery or panic) artifact creation violated illiterate conduct when artifact name was assigned, behavior intended only for creating Sting or Orcrist via naming +tty: revert to pline() for issuing prompts (override MSGTYPE=hide differently) Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index fb3b7dfa4..82765df78 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1489192904 2017/03/11 00:41:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.583 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1490908458 2017/03/30 21:14:18 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.585 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1806,6 +1806,7 @@ E void FDECL(dumplogmsg, (const char *)); E void NDECL(dumplogfreemessages); #endif E void VDECL(pline, (const char *, ...)) PRINTF_F(1, 2); +E void VDECL(custompline, (unsigned, const char *, ...)) PRINTF_F(2, 3); E void VDECL(Norep, (const char *, ...)) PRINTF_F(1, 2); E void NDECL(free_youbuf); E void VDECL(You, (const char *, ...)) PRINTF_F(1, 2); diff --git a/include/hack.h b/include/hack.h index bf2273b2b..b7cf512c7 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.h $NHDT-Date: 1451683048 2016/01/01 21:17:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.68 $ */ +/* NetHack 3.6 hack.h $NHDT-Date: 1490908464 2017/03/30 21:14:24 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.76 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -359,6 +359,12 @@ enum explosion_types { #define XKILL_NOCORPSE 2 #define XKILL_NOCONDUCT 4 +/* pline_flags; mask values for custompline()'s first argument */ +/* #define PLINE_ORDINARY 0 */ +#define PLINE_NOREPEAT 1 +#define OVERRIDE_MSGTYPE 2 +#define SUPPRESS_HISTORY 4 + /* Macros for messages referring to hands, eyes, feet, etc... */ enum bodypart_types { ARM = 0, diff --git a/src/pline.c b/src/pline.c index 2a473625b..118ed82ee 100644 --- a/src/pline.c +++ b/src/pline.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pline.c $NHDT-Date: 1489192905 2017/03/11 00:41:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.57 $ */ +/* NetHack 3.6 pline.c $NHDT-Date: 1490908465 2017/03/30 21:14:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.58 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,7 +6,7 @@ */ #include "hack.h" -static boolean no_repeat = FALSE; +static unsigned pline_flags = 0; static char prevmsg[BUFSZ]; static char *FDECL(You_buf, (int)); @@ -98,7 +98,8 @@ VA_DECL(const char *, line) { /* start of vpline() or of nested block in USE_OLDARG's pline() */ char pbuf[3 * BUFSZ]; int ln; - xchar msgtyp; + int msgtyp; + boolean no_repeat; /* Do NOT use VA_START and VA_END in here... see above */ if (!line || !*line) @@ -134,18 +135,23 @@ VA_DECL(const char *, line) return; } + msgtyp = MSGTYP_NORMAL; + no_repeat = (pline_flags & PLINE_NOREPEAT) ? TRUE : FALSE; #ifdef DUMPLOG /* We hook here early to have options-agnostic output. * Unfortunately, that means Norep() isn't honored (general issue) and * that short lines aren't combined into one longer one (tty behavior). */ - dumplogmsg(line); + if ((pline_flags & SUPPRESS_HISTORY) == 0) + dumplogmsg(line); #endif + if ((pline_flags & OVERRIDE_MSGTYPE) != 0) { + msgtyp = msgtype_type(line, no_repeat); + if (msgtyp == MSGTYP_NOSHOW + || (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg))) + return; + } - msgtyp = msgtype_type(line, no_repeat); - if (msgtyp == MSGTYP_NOSHOW - || (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg))) - return; if (vision_full_recalc) vision_recalc(0); if (u.ux) @@ -170,15 +176,31 @@ VA_DECL(const char *, line) #endif } +/* pline() variant which can override MSGTYPE handling or suppress + message history (tty interface uses pline() to issue prompts and + they shouldn't be blockable via MSGTYPE=hide) */ +/*VARARGS2*/ +void custompline +VA_DECL2(unsigned, pflags, const char *, line) +{ + VA_START(line); + VA_INIT(line, const char *); + pline_flags = pflags; + vpline(line, VA_ARGS); + pline_flags = 0; + VA_END(); + return; +} + /*VARARGS1*/ void Norep VA_DECL(const char *, line) { VA_START(line); VA_INIT(line, const char *); - no_repeat = TRUE; + pline_flags = PLINE_NOREPEAT; vpline(line, VA_ARGS); - no_repeat = FALSE; + pline_flags = 0; VA_END(); return; } diff --git a/win/tty/getline.c b/win/tty/getline.c index 8d61aabfe..f3dd6cbf2 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 getline.c $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.28 $ */ +/* NetHack 3.6 getline.c $NHDT-Date: 1490908467 2017/03/30 21:14:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.31 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -50,20 +50,13 @@ getlin_hook_proc hook; register int c; struct WinDesc *cw = wins[WIN_MESSAGE]; boolean doprev = 0; - char tmpbuf[BUFSZ]; /* [QBUFSZ+1] should suffice */ if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; ttyDisplay->toplin = 3; /* special prompt state */ ttyDisplay->inread++; - /* - * This used to use pline("%s ", query), but that made getline - * prompts be susceptible to suppression via the MSGTYPE mechanism. - * Having 'MSGTYPE=hide "# "' was particularly confusing. - */ - Sprintf(tmpbuf, "%s ", query); - tty_putstr(WIN_MESSAGE, 0, tmpbuf); + custompline(OVERRIDE_MSGTYPE | SUPPRESS_HISTORY, "%s ", query); *obufp = 0; for (;;) { (void) fflush(stdout); diff --git a/win/tty/topl.c b/win/tty/topl.c index cefc08f95..c4a778eef 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 topl.c $NHDT-Date: 1463787697 2016/05/20 23:41:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.33 $ */ +/* NetHack 3.6 topl.c $NHDT-Date: 1490908468 2017/03/30 21:14:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.36 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -385,14 +385,12 @@ char def; /* not pline("%s ", prompt); trailing space is wanted here in case of reprompt */ Strcat(prompt, " "); - /* pline("%s", prompt); -- see comment in hooked_tty_getlin() */ - tty_putstr(WIN_MESSAGE, 0, prompt); + custompline(OVERRIDE_MSGTYPE | SUPPRESS_HISTORY, "%s", prompt); } else { /* no restriction on allowed response, so always preserve case */ /* preserve_case = TRUE; -- moot since we're jumping to the end */ - /* pline("%s ", query); -- see above about tty_getlin() */ Sprintf(prompt, "%s ", query); - tty_putstr(WIN_MESSAGE, 0, prompt); + custompline(OVERRIDE_MSGTYPE | SUPPRESS_HISTORY, "%s", prompt); q = readchar(); goto clean_up; } From b708f8b39b0b5b4f30c38a3cdfeae0d8787ff734 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 30 Mar 2017 16:12:21 -0700 Subject: [PATCH 6/6] partial fix for #H5216 - sortloot inconsistency The tie-breaker for the qsort comparison routine used for 'sortloot' had its logic backwards. Instead of retaining the original relative order for tied items, it inadvertently reversed them. So a chest containing club dagger named A dagger named B dagger named C long sword would alternate between that order and club dagger named C dagger named B dagger named A long sword each time the chest's contents were examined. This fixes that, and also simplifies the unnecessarily convoluted bless/curse state handling. The other half of the report was a request that 'sortloot:n' not do any sorting. Right now, if the player has 'sortpack' set then 'sortloot:n' results in grouping into object classes within pack order rather than not sorting at all. (Also, armor and weapons are further ordered within their groups: armor by slot [helms, gloves, shields, &c] and weapons by function [ammo, launchers, missiles, 'ordinary', pole- arms].) I think the proper fix is to add a new setting for 'sortpack' which yields the current behavior before changing 'n' to leave things in their unsorted order. --- src/invent.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/invent.c b/src/invent.c index added0caa..d79bf1ef5 100644 --- a/src/invent.c +++ b/src/invent.c @@ -166,16 +166,9 @@ const genericptr vptr2; if ((namcmp = strcmpi(nam1, nam2)) != 0) return namcmp; - /* Sort by BUCX. Map blessed to 4, uncursed to 2, cursed to 1, and - unknown to 0. */ - val1 = obj1->bknown - ? (obj1->blessed << 2) - + ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed - : 0; - val2 = obj2->bknown - ? (obj2->blessed << 2) - + ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed - : 0; + /* Sort by BUCX. */ + val1 = obj1->bknown ? (obj1->blessed ? 3 : !obj1->cursed ? 2 : 1) : 0; + val2 = obj2->bknown ? (obj2->blessed ? 3 : !obj2->cursed ? 2 : 1) : 0; if (val1 != val2) return val2 - val1; /* bigger is better */ @@ -216,7 +209,7 @@ tiebreak: /* They're identical, as far as we're concerned. We want to force a deterministic order, and do so by producing a stable sort: maintain the original order of equal items. */ - return (sli2->indx - sli1->indx); + return (sli1->indx - sli2->indx); } void