diff -c -N frotz-2.32/Makefile frotz-2.32+sz/Makefile
*** frotz-2.32/Makefile Fri Oct 17 22:11:10 1997
--- frotz-2.32+sz/Makefile      Fri Nov 27 02:17:14 1998
***************
*** 33,38 ****
--- 33,40 ----
 #                     than curses.h.
 #
 # These defines add various cosmetic features to the interpreter:
+ #    -DSTRICTZ:       Do stricter error checking. Adapted from Andrew
+ #                   Plotkin's zip_zstrict_patch.
 #    -DCOLOR_SUPPORT: If the terminal you're using has color support, frotz
 #                     will use the curses color routines...if your curses
 #                     library supports color.
***************
*** 42,48 ****
 #                     to define it--it can't hurt anything--but you do
 #                     have that option.
 #
! #DEFS = -DUSE_GETOPT_H -DCOLOR_SUPPORT -DEMACS_EDITING
 DEFS =

 # This should point to the location of your curses or ncurses include file
--- 44,50 ----
 #                     to define it--it can't hurt anything--but you do
 #                     have that option.
 #
! #DEFS = -DUSE_GETOPT_H -DSTRICTZ -DCOLOR_SUPPORT -DEMACS_EDITING
 DEFS =

 # This should point to the location of your curses or ncurses include file
***************
*** 62,70 ****
 # Nothing under this line should need to be changed.

 OBJECTS = buffer.o fastmem.o files.o hotkey.o input.o main.o math.o object.o \
!           process.o random.o redirect.o screen.o sound.o stream.o table.o \
!           text.o ux_init.o ux_input.o ux_pic.o ux_screen.o ux_sample.o \
!           ux_text.o variable.o

 CFLAGS = $(OPTS) $(DEFS) $(INCL)

--- 64,72 ----
 # Nothing under this line should need to be changed.

 OBJECTS = buffer.o fastmem.o files.o hotkey.o input.o main.o math.o object.o \
!           process.o random.o redirect.o screen.o sound.o stream.o strictz.o \
!           table.o text.o ux_init.o ux_input.o ux_pic.o ux_screen.o \
!           ux_sample.o ux_text.o variable.o

 CFLAGS = $(OPTS) $(DEFS) $(INCL)

diff -c -N frotz-2.32/frotz.h frotz-2.32+sz/frotz.h
*** frotz-2.32/frotz.h  Fri Oct  3 22:04:52 1997
--- frotz-2.32+sz/frotz.h       Fri Nov 27 01:24:38 1998
***************
*** 546,551 ****
--- 546,597 ----
 void  z_window_size (void);
 void  z_window_style (void);

+ #ifdef STRICTZ
+
+ /* Definitions for STRICTZ functions and error codes. */
+
+ extern int strictz_report_mode;
+
+ void  init_strictz (void);
+ void  report_strictz_error (int, const char *);
+
+ /* Error codes */
+ #define STRZERR_NO_ERROR (0)
+ #define STRZERR_JIN (1)
+ #define STRZERR_GET_CHILD (2)
+ #define STRZERR_GET_PARENT (3)
+ #define STRZERR_GET_SIBLING (4)
+ #define STRZERR_GET_PROP_ADDR (5)
+ #define STRZERR_GET_PROP (6)
+ #define STRZERR_PUT_PROP (7)
+ #define STRZERR_CLEAR_ATTR (8)
+ #define STRZERR_SET_ATTR (9)
+ #define STRZERR_TEST_ATTR (10)
+ #define STRZERR_MOVE_OBJECT (11)
+ #define STRZERR_MOVE_OBJECT_2 (12)
+ #define STRZERR_REMOVE_OBJECT (13)
+ #define STRZERR_GET_NEXT_PROP (14)
+ #define STRICTZ_NUM_ERRORS (15)
+
+ /* There are four error reporting modes: never report errors;
+   report only the first time a given error type occurs; report
+   every time an error occurs; or treat all errors as fatal
+   errors, killing the interpreter. I strongly recommend
+   "report once" as the default. But you can compile in a
+   different default by changing the definition of
+   STRICTZ_DEFAULT_REPORT_MODE. In any case, the player can
+   specify a report mode on the command line by typing "-Z 0"
+   through "-Z 3". */
+
+ #define STRICTZ_REPORT_NEVER (0)
+ #define STRICTZ_REPORT_ONCE (1)
+ #define STRICTZ_REPORT_ALWAYS (2)
+ #define STRICTZ_REPORT_FATAL (3)
+
+ #define STRICTZ_DEFAULT_REPORT_MODE STRICTZ_REPORT_ONCE
+
+ #endif /* STRICTZ */
+
 /*** Various global functions ***/

 zchar translate_from_zscii (zbyte);
diff -c -N frotz-2.32/main.c frotz-2.32+sz/main.c
*** frotz-2.32/main.c   Wed Sep 10 15:07:58 1997
--- frotz-2.32+sz/main.c        Fri Nov 27 01:26:34 1998
***************
*** 160,165 ****
--- 160,169 ----
 int cdecl main (int argc, char *argv[])
 {

+ #ifdef STRICTZ
+     init_strictz ();
+ #endif
+
     os_process_arguments (argc, argv);

     init_memory ();
diff -c -N frotz-2.32/object.c frotz-2.32+sz/object.c
*** frotz-2.32/object.c Thu Sep 18 14:44:44 1997
--- frotz-2.32+sz/object.c      Fri Nov 27 01:54:25 1998
***************
*** 149,154 ****
--- 149,162 ----
     zword parent_addr;
     zword sibling_addr;

+ #ifdef STRICTZ
+     if (object == 0) {
+       report_strictz_error (STRZERR_REMOVE_OBJECT,
+           "@remove_object called with object 0");
+       return;
+     }
+ #endif
+
     obj_addr = object_address (object);

     if (h_version <= V3) {
***************
*** 264,269 ****
--- 272,285 ----
       stream_mssg_off ();
     }

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_CLEAR_ATTR,
+           "@clear_attr called with object 0");
+       return;
+     }
+ #endif
+
     /* Get attribute address */

     obj_addr = object_address (zargs[0]) + zargs[1] / 8;
***************
*** 299,304 ****
--- 315,329 ----
       stream_mssg_off ();
     }

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_JIN,
+           "@jin called with object 0");
+       branch (0 == zargs[1]);
+       return;
+     }
+ #endif
+
     obj_addr = object_address (zargs[0]);

     if (h_version <= V3) {
***************
*** 351,356 ****
--- 376,391 ----
       stream_mssg_off ();
     }

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_GET_CHILD,
+           "@get_child called with object 0");
+       store (0);
+       branch (FALSE);
+       return;
+     }
+ #endif
+
     obj_addr = object_address (zargs[0]);

     if (h_version <= V3) {
***************
*** 399,404 ****
--- 434,448 ----
     zbyte value;
     zbyte mask;

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_GET_NEXT_PROP,
+           "@get_next_prop called with object 0");
+       store (0);
+       return;
+     }
+ #endif
+
     /* Property id is in bottom five (six) bits */

     mask = (h_version <= V3) ? 0x1f : 0x3f;
***************
*** 450,455 ****
--- 494,508 ----
       stream_mssg_off ();
     }

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_GET_PARENT,
+           "@get_parent called with object 0");
+       store (0);
+       return;
+     }
+ #endif
+
     obj_addr = object_address (zargs[0]);

     if (h_version <= V3) {
***************
*** 498,503 ****
--- 551,565 ----
     zbyte value;
     zbyte mask;

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_GET_PROP,
+           "@get_prop called with object 0");
+       store (0);
+       return;
+     }
+ #endif
+
     /* Property id is in bottom five (six) bits */

     mask = (h_version <= V3) ? 0x1f : 0x3f;
***************
*** 557,562 ****
--- 619,633 ----
     zbyte value;
     zbyte mask;

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_GET_PROP_ADDR,
+           "@get_prop_addr called with object 0");
+       store (0);
+       return;
+     }
+ #endif
+
     if (story_id == BEYOND_ZORK)
       if (zargs[0] > MAX_OBJECT)
           { store (0); return; }
***************
*** 638,643 ****
--- 709,724 ----
 {
     zword obj_addr;

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_GET_SIBLING,
+           "@get_sibling called with object 0");
+       store (0);
+       branch (FALSE);
+       return;
+     }
+ #endif
+
     obj_addr = object_address (zargs[0]);

     if (h_version <= V3) {
***************
*** 698,703 ****
--- 779,798 ----
       stream_mssg_off ();
     }

+ #ifdef STRICTZ
+     if (obj1 == 0) {
+       report_strictz_error (STRZERR_MOVE_OBJECT,
+           "@move_object called moving object 0");
+       return;
+     }
+
+     if (obj2 == 0) {
+       report_strictz_error (STRZERR_MOVE_OBJECT_2,
+           "@move_object called moving into object 0");
+       return;
+     }
+ #endif
+
     /* Get addresses of both objects */

     obj1_addr = object_address (obj1);
***************
*** 752,757 ****
--- 847,860 ----
     zword value;
     zbyte mask;

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_PUT_PROP,
+           "@put_prop called with object 0");
+       return;
+     }
+ #endif
+
     /* Property id is in bottom five or six bits */

     mask = (h_version <= V3) ? 0x1f : 0x3f;
***************
*** 844,849 ****
--- 947,960 ----
       stream_mssg_off ();
     }

+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_SET_ATTR,
+           "@set_attr called with object 0");
+       return;
+     }
+ #endif
+
     /* Get attribute address */

     obj_addr = object_address (zargs[0]) + zargs[1] / 8;
***************
*** 888,893 ****
--- 999,1013 ----
       print_num (zargs[1]);
       stream_mssg_off ();
     }
+
+ #ifdef STRICTZ
+     if (zargs[0] == 0) {
+       report_strictz_error (STRZERR_TEST_ATTR,
+           "@test_attr called with object 0");
+       branch (FALSE);
+       return;
+     }
+ #endif

     /* Get attribute address */

diff -c -N frotz-2.32/strictz.c frotz-2.32+sz/strictz.c
*** frotz-2.32/strictz.c        Thu Jan  1 01:00:00 1970
--- frotz-2.32+sz/strictz.c     Fri Nov 27 01:39:36 1998
***************
*** 0 ****
--- 1,86 ----
+ /*
+  * strictz.c
+  *
+  * Strict Z error reporting functions
+  */
+
+ #include "frotz.h"
+
+ #ifdef STRICTZ
+
+ #include <stdio.h>
+
+ /* Define stuff for stricter Z-code error checking, for the generic
+    Unix/DOS/etc terminal-window interface. Feel free to change the way
+    player prefs are specified, or replace report_zstrict_error()
+    completely if you want to change the way errors are reported. */
+
+ int strictz_report_mode;
+ static int strictz_error_count[STRICTZ_NUM_ERRORS];
+
+ /*
+  * report_strictz_error
+  *
+  * This handles Z-code error conditions which ought to be fatal errors,
+  * but which players might want to ignore for the sake of finishing the
+  * game.
+  *
+  * The error is provided as both a numeric code and a string. This allows
+  * us to print a warning the first time a particular error occurs, and
+  * ignore it thereafter.
+  *
+  * errnum : Numeric code for error (0 to STRICTZ_NUM_ERRORS-1)
+  * errstr : Text description of error
+  *
+  */
+
+ void init_strictz ()
+ {
+     int i;
+
+     /* Initialize the STRICTZ variables. */
+
+     strictz_report_mode = STRICTZ_DEFAULT_REPORT_MODE;
+
+     for (i = 0; i < STRICTZ_NUM_ERRORS; i++) {
+         strictz_error_count[i] = 0;
+     }
+ }
+
+ void report_strictz_error (int errnum, const char *errstr)
+ {
+     int wasfirst;
+
+     if (errnum <= 0 || errnum >= STRICTZ_NUM_ERRORS)
+       return;
+
+     if (strictz_report_mode == STRICTZ_REPORT_FATAL) {
+       flush_buffer ();
+       os_fatal (errstr);
+       return;
+     }
+
+     wasfirst = (strictz_error_count[errnum] == 0);
+     strictz_error_count[errnum]++;
+
+     if ((strictz_report_mode == STRICTZ_REPORT_ALWAYS)
+       || (strictz_report_mode == STRICTZ_REPORT_ONCE && wasfirst)) {
+       char buf[256];
+       long pc;
+
+       GET_PC (pc);
+       sprintf (buf, "Warning: %s (PC = %lx)", errstr, pc);
+       print_string (buf);
+
+       if (strictz_report_mode == STRICTZ_REPORT_ONCE) {
+           print_string(" (will ignore further occurrences)");
+       } else {
+           sprintf (buf, " (occurrence %d)", strictz_error_count[errnum]);
+           print_string(buf);
+       }
+       new_line ();
+     }
+
+ } /* report_strictz_error */
+
+ #endif /* STRICTZ */
diff -c -N frotz-2.32/ux_init.c frotz-2.32+sz/ux_init.c
*** frotz-2.32/ux_init.c        Sat Oct  4 03:12:10 1997
--- frotz-2.32+sz/ux_init.c     Fri Nov 27 01:56:17 1998
***************
*** 139,145 ****

     do {

!       c = getopt(argc, argv, "aAb:c:df:h:il:oOpPr:s:S:tu:w:x");

       switch(c) {
         case 'a': option_attribute_assignment = 1; break;
--- 139,149 ----

     do {

!       c = getopt(argc, argv, "aAb:c:df:h:il:oOpPr:s:S:tu:w:x"
! #ifdef STRICTZ
!                              "Z:"
! #endif
!                 );

       switch(c) {
         case 'a': option_attribute_assignment = 1; break;
***************
*** 170,181 ****
--- 174,200 ----
         case 'u': option_undo_slots = atoi(optarg); break;
         case 'w': user_screen_width = atoi(optarg); break;
         case 'x': option_expand_abbreviations = 1; break;
+ #ifdef STRICTZ
+         case 'Z': strictz_report_mode = atoi(optarg);
+                   if ((strictz_report_mode < STRICTZ_REPORT_NEVER) ||
+                       (strictz_report_mode > STRICTZ_REPORT_FATAL))
+                     strictz_report_mode = STRICTZ_DEFAULT_REPORT_MODE;
+                   break;
+ #endif
       }

     } while (c != EOF);

     if (optind != argc - 1) {
       puts (INFORMATION);
+ #ifdef STRICTZ
+       printf ("  -Z # stricter error checking (default = %d)\n"
+           "\t(%d: none; %d: report first error; %d: report all errors;\n"
+           "\t %d: exit after any error)\n",
+           STRICTZ_DEFAULT_REPORT_MODE, STRICTZ_REPORT_NEVER,
+           STRICTZ_REPORT_ONCE, STRICTZ_REPORT_ALWAYS,
+           STRICTZ_REPORT_FATAL);
+ #endif
       exit (1);
     }