]> granicus.if.org Git - nethack/commitdiff
Re: [NetHack/NetHack] Prompts can overwrite copyright notice on the
authornhmall <nhmall@nethack.org>
Thu, 9 Jun 2022 03:41:45 +0000 (23:41 -0400)
committernhmall <nhmall@nethack.org>
Thu, 9 Jun 2022 03:41:45 +0000 (23:41 -0400)
starting screen (Issue #783)

On 2022-06-01 12:22 p.m., NetSysFire wrote:
> Steps to reproduce:
>
>1. Get any prompt and answer it. In my case it was a horribly old
>   save I forgot about or when I wiztested something and forgot
>   about that save, too.
>2. See that the copyright information got overwritten by the prompt:
>
>There is already a game in progress under your name. Destroy old game? [yn] (n)
>         By Stichting Mathematisch Centrum and M. Stephenson.
>         Version 3.7.0-59 Unix Work-in-progress, built May 31 2022 12:28:31.
>         See license for details.
>
>
> Shall I pick character's race, role, gender and alignment for you? [ynaq]
>
> Expected behavior:
>
> Redraw after a prompt was answered, so the prompt vanishes and the
> entirety of the starting screen will be shown.
>
> NetHack, Copyright 1985-2022
>          By Stichting Mathematisch Centrum and M. Stephenson.
>          Version 3.7.0-59 Unix Work-in-progress, built May 31 2022 12:28:31.
>          See license for details.
>
>
> Shall I pick character's race, role, gender and alignment for you? [ynaq]
>
> Proposed severity: low. Not gamebreaking, it is cosmetic only and does
> not have any other consequences.
>

The Copyright notice is placed by tty internal routines writing onto
the BASE_WINDOW fairly early in the startup sequence.

The prompt to "Destroy old game? [yn] (n)" is using the in-game
routine to write to the message window at the top of the screen and
prompt there, just like in-game prompts and messages.

If the player answered 'y' to that, the prompt for
"Shall I pick character's race, role, gender and alignment..."
appeared immediately after. That one, however, is written using
the BASE_WINDOW routines in tty, like the copyright notice.

This change does the following:

It moves the copyright lines down a little bit leaving room for the
"Destroy.." prompts.

It places the "Shall I pick characters's..." prompt further down the
screen by default, leaving some room for about 3 raw_print startup
messages after the copyright notice, just in case there are any.
The "Shall I pick character's..." prompt will still appear immediately
if there is a prompt such as "Destroy old game?..."

There were a couple of other issues around raw_print startup messages
too. Those are delivered using a raw_print mechanism to ensure they
are written even if the window-port is not fully operational. However,
they were only on the screen for the blink of an eye. This call
sequence in restore.c made them disappear almost immediately:
     docrt() -> cls()

Put in a mechanism to detect the presence of raw_print messages
from the early startup, and if there were some, wait for a
keypress before obliterating the unread notifications.

include/decl.h
src/decl.c
src/pline.c
src/restore.c
sys/unix/unixmain.c
sys/unix/unixunix.c
sys/windows/windmain.c
sys/windows/windsys.c
win/tty/wintty.c

index 6628212877d4b41e53a9cbceba6e53afd11e34b0..642989027bebd6a1cb58ab0f89bdc32ef328d78f 100644 (file)
@@ -101,6 +101,7 @@ struct sinfo {
     int in_self_recover;
     int in_parseoptions;        /* in parseoptions */
     int config_error_ready;     /* config_error_add is ready, available */
+    int beyond_savefile_load;   /* set when past savefile loading */
 #ifdef PANICLOG
     int in_paniclog;
 #endif
@@ -1262,6 +1263,8 @@ struct instance_globals {
 
     /* per-level glyph mapping flags */
     long glyphmap_perlevel_flags;
+    int early_raw_messages;   /* if raw_prints occurred early prior
+                                 to g.beyond_savefile_load */
 
     unsigned long magic; /* validate that structure layout is preserved */
 };
index 5cf81733a5c8b5fda2b8b89f4f498785c01147a1..a380958765cedb92bb52991db7d6cb89e85fc4b6 100644 (file)
@@ -693,6 +693,7 @@ const struct instance_globals g_init = {
 
     /* per-level glyph mapping flags */
     0L,     /* glyphmap_perlevel_flags */
+    0,      /* early_raw_messages */
 
     IVMAGIC  /* used to validate that structure layout has been preserved */
 };
index 3fac368d86acd9e874b457afe0005808eecb4343..24dcc49a89577ac7096a8866f65f348dc8533252 100644 (file)
@@ -462,6 +462,8 @@ raw_printf(const char *line, ...)
     va_start(the_args, line);
     vraw_printf(line, the_args);
     va_end(the_args);
+    if (!g.program_state.beyond_savefile_load)
+        g.early_raw_messages++;
 }
 
 DISABLE_WARNING_FORMAT_NONLITERAL
@@ -489,6 +491,8 @@ vraw_printf(const char *line, va_list the_args)
 #if defined(MSGHANDLER)
     execplinehandler(line);
 #endif
+    if (!g.program_state.beyond_savefile_load)
+        g.early_raw_messages++;
 }
 
 void
index 51d068656fe8359333d7c232d885c447bcb967a4..31d07b141556864ad8ab7eba2573d3d05b75b0c1 100644 (file)
@@ -870,6 +870,17 @@ dorecover(NHFILE* nhfp)
 
     run_timers(); /* expire all timers that have gone off while away */
     g.program_state.restoring = 0; /* affects bot() so clear before docrt() */
+
+    if (g.early_raw_messages && !g.program_state.beyond_savefile_load) {
+        /*
+         * We're about to obliterate some potentially important
+         * startup messages, so give the player a chance to see them.
+         */
+        g.early_raw_messages = 0;
+        wait_synch();
+    }
+    g.program_state.beyond_savefile_load = 0;
+
     docrt();
     clear_nhwindow(WIN_MESSAGE);
 
index 53fe67df1e64f6612007c90e618e994f3d87a9fc..6f9dc42e04d0ea8af4081048882b1f1550ca239d 100644 (file)
@@ -235,7 +235,12 @@ main(int argc, char *argv[])
             iflags.news = FALSE; /* in case dorecover() fails */
         }
 #endif
-        pline("Restoring save file...");
+        /* if there are early trouble-messages issued, let's
+         * not go overtop of them with a pline just yet */
+        if (g.early_raw_messages)
+            raw_print("Restoring save file...");
+        else
+            pline("Restoring save file...");
         mark_synch(); /* flush output */
         if (dorecover(nhfp)) {
             resuming = TRUE; /* not starting new game */
index cd8a7daa8473db82528ea7205260dcf6152268c8..c44da845be123fb98dff31cf92808e4b916ccc39 100644 (file)
@@ -171,7 +171,7 @@ getlock(void)
             /* this is a candidate for paranoid_confirmation */
             c = yn(destroy_old_game_prompt);
         } else {
-            (void) printf("\n%s [yn] ", destroy_old_game_prompt);
+            (void) raw_printf("\n%s [yn] ", destroy_old_game_prompt);
             (void) fflush(stdout);
             if ((c = getchar()) != EOF) {
                 int tmp;
index ec0ca58c174fdfb02c84117a0dfe5e2d42596b98..f67826287b086a66ce36b924d173f4fac7e00fba 100644 (file)
@@ -625,7 +625,10 @@ attempt_restore:
             iflags.news = FALSE;
         }
 #endif
-        pline("Restoring save file...");
+        if (g.early_raw_messages)
+            raw_print("Restoring save file...");
+        else
+            pline("Restoring save file...");
         mark_synch(); /* flush output */
         if (dorecover(nhfp)) {
             resuming = TRUE; /* not starting new game */
@@ -1193,7 +1196,7 @@ getlock(void)
                         : "not start a new game");
     if (istty)
         clear_screen();
-    pline(oops);
+    raw_printf("%s", oops);
     if (prompt_result == 1) {          /* recover */
         if (recover_savefile()) {
 #if 0
index b6185801aac8243811480a3601e645bef9a86f45..78125da756eb20d2d492397952baa8b62435b1d4 100644 (file)
@@ -469,6 +469,7 @@ windows_console_custom_nhgetch(void)
     return _getch();
 }
 
+extern int windows_console_custom_nhgetch(void);
 
 void
 getreturn(const char *str)
@@ -481,6 +482,8 @@ getreturn(const char *str)
     in_getreturn = TRUE;
     Sprintf(buf,"Hit <Enter> %s.", str);
     raw_print(buf);
+    if (WINDOWPORT("tty"))
+        windows_console_custom_nhgetch();
     wait_synch();
     in_getreturn = FALSE;
     return;
index 89ad67f1bd7483873e9ec5d4784cc1d477357ced..f7c22458e0570f3b15e42f606a8e84d4e7a6a02b 100644 (file)
@@ -115,12 +115,12 @@ struct window_procs tty_procs = {
      | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS
      | WC2_RESET_STATUS
 #endif
-     | WC2_DARKGRAY | WC2_SUPPRESS_HIST | WC2_URGENT_MESG | WC2_STATUSLINES)
+     | WC2_DARKGRAY | WC2_SUPPRESS_HIST | WC2_URGENT_MESG | WC2_STATUSLINES
      | WC2_U_UTF8STR
 #if !defined(NO_TERMS) || defined(WIN32)
      | WC2_U_24BITCOLOR
 #endif
-    ,
+    ),
 #ifdef TEXTCOLOR
     {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
 #else
@@ -481,12 +481,29 @@ tty_init_nhwindows(int *argcp UNUSED, char **argv UNUSED)
 
     tty_clear_nhwindow(BASE_WINDOW);
 
-    tty_putstr(BASE_WINDOW, 0, "");
+    /* Once pline() is functional, error-related prompts such as
+     * those relating to save files etc. can intrude on the
+     * copyright information display because their prompts are
+     * up at the very top in the message window.
+     * Move the copyright information a little further down to
+     * row 3, out of the way. */
+
+    tty_curs(BASE_WINDOW, 1, 4);
     for (i = 1; i <= 4; ++i)
         tty_putstr(BASE_WINDOW, 0, copyright_banner_line(i));
     tty_putstr(BASE_WINDOW, 0, "");
     tty_display_nhwindow(BASE_WINDOW, FALSE);
 
+    /* Move to a default location for the "Shall I pick .." player
+     * selection prompts, which also use the BASE_WINDOW. Leave
+     * room for as many as 3 unexpected raw_prints early startup
+     * messages above that.
+     * If there is a topline message prompt, before the
+     * "Shall I pick ..." prompt, the latter will end up appearing
+     * immediately after the topline message prompt. There should
+     * now be room. */
+    tty_curs(BASE_WINDOW, 1, 11);
+
     /* 'statuslines' defaults to set_in_config, allowed but invisible;
        make it dynamically settable if feasible, otherwise visible */
     if (tty_procs.wincap2 & WC2_STATUSLINES)