From e240efa10b63662509034901bfb02e973b3a22d0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 12 Jul 2025 18:21:09 +0300 Subject: [PATCH] Restoring a game can return to the wishing prompt In TTY or curses, if the terminal goes away while you're in the wishing prompt, return to the prompt when the game is restored. Breaks saves. --- doc/fixes3-7-0.txt | 2 ++ include/context.h | 1 + include/flag.h | 1 + include/patchlevel.h | 2 +- src/allmain.c | 3 +++ src/zap.c | 7 +++++++ win/curses/cursdial.c | 4 ++++ win/curses/cursmesg.c | 3 +++ win/curses/cursmisc.c | 1 + win/tty/getline.c | 2 ++ win/tty/wintty.c | 4 +++- 11 files changed, 28 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 8bb097002..5bd8ab8ca 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2453,6 +2453,8 @@ tty: hide cursor unless waiting for user input; now extended to include tty platforms that define NO_TERMS, rather than just on those using termcap/terminfo, namely Windows console and msdos (text-mode implemented; vga and vesa just have stubs currently) +tty+curses: if terminal goes away while in the wishing prompt, return to the + wish prompt when game is restored Unix: when user name is used as default character name, keep hyphenated value intact instead stripping off dash and whatever follows as if that specified role/race/&c (worked once upon a time; broken since 3.3.0) diff --git a/include/context.h b/include/context.h index d98ada70e..73fee29bc 100644 --- a/include/context.h +++ b/include/context.h @@ -161,6 +161,7 @@ struct context_info { boolean mv; boolean bypasses; /* bypass flag is set on at least one fobj */ boolean door_opened; /* set to true if door was opened during test_move */ + boolean resume_wish; /* game was exited while in wish prompt */ boolean tips[NUM_TIPS]; struct dig_info digging; struct victual_info victual; diff --git a/include/flag.h b/include/flag.h index d586f3c5f..bd6a5dc58 100644 --- a/include/flag.h +++ b/include/flag.h @@ -246,6 +246,7 @@ struct instance_flags { boolean invis_goldsym; /* gold symbol is ' '? */ boolean in_lua; /* executing a lua script */ boolean lua_testing; /* doing lua tests */ + boolean term_gone; /* terminal is gone, abort abort abort */ boolean nofollowers; /* level change ignores pets (for tutorial) */ boolean partly_eaten_hack; /* extra flag for xname() used when it's called * indirectly so we can't use xname_flags() */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 4992b7f3a..1de0380b0 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 127 +#define EDITLEVEL 128 /* * Development status possibilities. diff --git a/src/allmain.c b/src/allmain.c index d80e50a78..a1fad95c9 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -187,6 +187,9 @@ moveloop_core(void) if (iflags.sanity_check || iflags.debug_fuzzer) sanity_check(); + if (svc.context.resume_wish) + makewish(); /* clears resume_wish */ + if (svc.context.move) { /* actual time passed */ u.umovement -= NORMAL_SPEED; diff --git a/src/zap.c b/src/zap.c index 67eac9bbe..efd60f1fe 100644 --- a/src/zap.c +++ b/src/zap.c @@ -6186,6 +6186,7 @@ makewish(void) int tries = 0; long oldwisharti = u.uconduct.wisharti; + svc.context.resume_wish = 0; promptbuf[0] = '\0'; nothing = cg.zeroobj; /* lint suppression; only its address matters */ if (flags.verbose) @@ -6196,6 +6197,12 @@ makewish(void) Strcat(promptbuf, " (enter 'help' for assistance)"); Strcat(promptbuf, "?"); getlin(promptbuf, buf); + + if (iflags.term_gone) { + svc.context.resume_wish = 1; + return; + } + (void) mungspaces(buf); if (buf[0] == '\033') { buf[0] = '\0'; diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 85803a5a8..b6a51eb2a 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -308,6 +308,7 @@ curses_character_input_dialog( answer = curses_read_char(); #endif if (answer == ERR) { + iflags.term_gone = 1; answer = def; break; } @@ -451,6 +452,8 @@ curses_ext_cmd(void) curs_set(0); prompt_width = (int) strlen(cur_choice); + if (letter == ERR) + iflags.term_gone = 1; if (letter == '\033' || letter == ERR) { ret = -1; break; @@ -1518,6 +1521,7 @@ menu_get_selections(WINDOW *win, nhmenu *menu, int how) curletter = curses_getch(); if (curletter == ERR) { + iflags.term_gone = 1; num_selected = -1; dismiss = TRUE; } diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 9608c1158..adc039f52 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -348,6 +348,8 @@ curses_block( ret = '\n'; else ret = curses_read_char(); + if (ret == ERR) + iflags.term_gone = 1; if (ret == ERR || ret == '\0') ret = '\n'; /* msgtype=stop should require space/enter rather than any key, @@ -775,6 +777,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer) switch (ch) { case ERR: /* should not happen */ + iflags.term_gone = 1; *answer = '\0'; goto alldone; case '\033': /* DOESCAPE */ diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index ce02ca435..4b4fe97c1 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -1026,6 +1026,7 @@ parse_escape_sequence(int key, boolean *keypadnum) ret = getch(); if (ret == ERR) { + iflags.term_gone = 1; /* there was no additional char; treat as M-O or M-^O below */ ret = (key == '\033') ? 'O' : C('O'); } else if (ret >= 112 && ret <= 121) { /* 'p'..'y' */ diff --git a/win/tty/getline.c b/win/tty/getline.c index 1a8215c06..acb3f7f14 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -83,6 +83,8 @@ hooked_tty_getlin( c = pgetchar(); term_curs_set(0); if (c == '\033' || c == EOF) { + if (c == EOF) + iflags.term_gone = 1; if (c == '\033' && obufp[0] != '\0') { obufp[0] = '\0'; bufp = obufp; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 4c7a107dc..61338542b 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -4090,8 +4090,10 @@ tty_nhgetch(void) term_curs_set(0); if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ - else if (i == EOF) + else if (i == EOF) { + iflags.term_gone = 1; i = '\033'; /* same for EOF */ + } /* topline has been seen - we can clear the need for --More-- */ if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) ttyDisplay->toplin = TOPLINE_NON_EMPTY;