Date: Thu, 11 Sep 1997 22:23:25 -0700 (PDT)
From: Andrew Plotkin 
To: Z-Machine List 
Subject: [z-machine] ZIP bug

While updating MaxZip, I came across some places where the original ZIP
source behaves wrong. Other ZIP derivatives may wish to take note. I don't
have patch files but I can describe what to do, I think.

A bunch of header data is supposed to be set when the game is started,
restarted, or restored. ZIP fails to do this after restoring.

Look in control.c, in the restart() procedure. There is a clot of code
commented "Restart the interpreter state"; it sets the scripting flag, the
screen width and heigh fields in the header, and (in V1-3) clears the
status line.

This code should be chopped out into a separate procedure. I have it like
this:

---------------

/*
 * restart_interp
 *
 * Do all the things which need to be done after startup, restart, and
 * restore commands.
 *
 */

#ifdef __STDC__
void restart_interp (int scripting_flag)
#else
void restart_interp ()
#endif
{
    if (scripting_flag)
        set_word (H_FLAGS, (get_word (H_FLAGS) | SCRIPTING_FLAG));

    set_byte (H_INTERPRETER, h_interpreter);
    set_byte (H_INTERPRETER_VERSION, h_interpreter_version);
    set_byte (H_SCREEN_ROWS, screen_rows); /* Screen dimension in 
characters */
    set_byte (H_SCREEN_COLUMNS, screen_cols);

    set_byte (H_SCREEN_LEFT, 0); /* Screen dimension in smallest
addressable units, ie. pixels */
    set_byte (H_SCREEN_RIGHT, screen_cols);
    set_byte (H_SCREEN_TOP, 0);
    set_byte (H_SCREEN_BOTTOM, screen_rows);

    set_byte (H_MAX_CHAR_WIDTH, 1); /* Size of a character in screen units
*/
    set_byte (H_MAX_CHAR_HEIGHT, 1);

    /* Initialise status region */

    if (h_type < V4) {
        set_status_size (0);
        blank_status_line ();
    }

}/* restart_interp */

-----------------

You can then call restart_interp(scripting_flag) from the restart()
procedure, in place of the code you just chopped out.

Then, at the end of save_restore(), change this:

----------------
    /* Close the save file and restore scripting */

    if (flag == GAME_SAVE || flag == GAME_RESTORE) {
        // close file
        if (scripting_flag)
            set_word (H_FLAGS, get_word (H_FLAGS) | SCRIPTING_FLAG);
    }
---------------
to this:
---------------
    /* Close the save file and restore scripting */

    if (flag == GAME_SAVE) {
        // close file
        if (scripting_flag)
            set_word (H_FLAGS, get_word (H_FLAGS) | SCRIPTING_FLAG);
    }
    else if (flag == GAME_RESTORE) {
        // close file
        restart_screen();
        restart_interp(scripting_flag);
    }
----------------

(The "close file" command is fclose() in the original, I guess; I've
changed it to Mac file calls in my source.)

Once this is done, you can remove the set_status_size/blank_status_line
calls from restore(); they have become redundant. 

What good does this do? Well, try running a game with a complicated status
line. Save your game; quit and restart the interpreter with a different
window size; and reload the game. In ZIP, the status line becomes
confused, because the old window size gets loaded in with the saved-game
data. With the above changes, no confusion.

This is particularly noticeable with Martin Frost's Quetzal save examples
(this is of course how I noticed it.) His three sample save files (for
Jigsaw) have different screen widths. When I restored them sequentially,
the status line got messed up. I spent quite a while trying to figure out
what was wrong with his quetzal.c, before I realized that the bug had been
in ZIP all along.

--Z

"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the
borogoves..."

    Source: geocities.com/siliconvalley/vista/6631

               ( geocities.com/siliconvalley/vista)                   ( geocities.com/siliconvalley)