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..."