diff -c zip/object.c zip_zs/object.c
*** zip/object.c        Fri Jan  2 13:49:22 1998
--- zip_zs/object.c     Fri Jan  2 15:10:22 1998
***************
*** 66,71 ****
--- 66,84 ----
 {
     zword_t obj1p, obj2p, child2;

+ #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 */

     obj1p = get_object_address (obj1);
***************
*** 111,116 ****
--- 124,137 ----
 {
     zword_t objp, parentp, childp, parent, child;

+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_REMOVE_OBJECT,
+             "@remove_object called with object 0");
+         return;
+     }
+ #endif
+
     /* Get address of object to be removed */

     objp = get_object_address (obj);
***************
*** 169,174 ****
--- 190,204 ----
 zword_t obj;
 #endif
 {
+
+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_GET_PARENT,
+             "@get_parent called with object 0");
+         store_operand(0);
+         return;
+     }
+ #endif

     store_operand (read_object (get_object_address (obj), PARENT));

***************
*** 191,196 ****
--- 221,236 ----
 {
     zword_t child;

+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_GET_CHILD,
+             "@get_child called with object 0");
+         store_operand(0);
+         conditional_jump(FALSE);
+         return;
+     }
+ #endif
+
     child = read_object (get_object_address (obj), CHILD);

     store_operand (child);
***************
*** 216,221 ****
--- 256,271 ----
 {
     zword_t next;

+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_GET_SIBLING,
+             "@get_sibling called with object 0");
+         store_operand(0);
+         conditional_jump(FALSE);
+         return;
+     }
+ #endif
+
     next = read_object (get_object_address (obj), NEXT);

     store_operand (next);
***************
*** 240,245 ****
--- 290,304 ----
 #endif
 {

+ #ifdef STRICTZ
+     if (obj1 == 0) {
+         report_strictz_error(STRZERR_JIN,
+             "@jin called with object 0");
+         conditional_jump(0 == obj2);
+         return;
+     }
+ #endif
+
     conditional_jump (read_object (get_object_address (obj1), PARENT) == obj2);

 }/* compare_parent_object */
***************
*** 264,269 ****
--- 323,337 ----

     assert (O3_ATTRIBUTES == O4_ATTRIBUTES);

+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_TEST_ATTR,
+             "@test_attr called with object 0");
+         conditional_jump(FALSE);
+         return;
+     }
+ #endif
+
     /* Get attribute address */

     objp = get_object_address (obj) + (bit >> 3);
***************
*** 298,303 ****
--- 366,379 ----

     assert (O3_ATTRIBUTES == O4_ATTRIBUTES);

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

     objp = get_object_address (obj) + (bit >> 3);
***************
*** 335,340 ****
--- 411,424 ----
     zbyte_t value;

     assert (O3_ATTRIBUTES == O4_ATTRIBUTES);
+
+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_CLEAR_ATTR,
+             "@clear_attr called with object 0");
+         return;
+     }
+ #endif

     /* Get attribute address */

diff -c zip/osdepend.c zip_zs/osdepend.c
*** zip/osdepend.c      Fri Jan  2 13:49:22 1998
--- zip_zs/osdepend.c   Fri Jan  2 15:40:43 1998
***************
*** 21,26 ****
--- 21,56 ----
 #define RECORD_NAME "record.lis"  /* Default record name */
 #endif /* defined(AMIGA) */

+ #ifdef STRICTZ
+
+ /* 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. */
+
+ /* 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 "-s 0"
+   through "-s 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
+
+ static int strictz_report_mode;
+ static int strictz_error_count[STRICTZ_NUM_ERRORS];
+
+ #endif /* STRICTZ */
+
+
 #if !defined(AMIGA)

 /* getopt linkages */
***************
*** 50,59 ****
 #endif
 {
     int c, errflg = 0;

     /* Parse the options */

!     while ((c = getopt (argc, argv, "hl:c:r:t:")) != EOF) {
         switch (c) {
             case 'l': /* lines */
                 screen_rows = atoi (optarg);
--- 80,100 ----
 #endif
 {
     int c, errflg = 0;
+     int num;

+ #ifdef STRICTZ
+     /* Initialize the STRICTZ variables. */
+
+     strictz_report_mode = STRICTZ_DEFAULT_REPORT_MODE;
+
+     for (num=0; num<STRICTZ_NUM_ERRORS; num++) {
+         strictz_error_count[num] = 0;
+     }
+ #endif /* STRICTZ */
+
     /* Parse the options */

!     while ((c = getopt (argc, argv, "hl:c:r:t:s:")) != EOF) {
         switch (c) {
             case 'l': /* lines */
                 screen_rows = atoi (optarg);
***************
*** 67,72 ****
--- 108,122 ----
             case 't': /* top margin */
                 top_margin = atoi (optarg);
                 break;
+ #ifdef STRICTZ
+             case 's': /* strictz reporting mode */
+                 strictz_report_mode = atoi (optarg);
+                 if (strictz_report_mode < STRICTZ_REPORT_NEVER
+                     || strictz_report_mode > STRICTZ_REPORT_FATAL) {
+                     errflg++;
+                 }
+                 break;
+ #endif /* STRICTZ */
             case 'h':
             case '?':
             default:
***************
*** 84,89 ****
--- 134,143 ----
         fprintf (stderr, "\t-c n columns in display\n");
         fprintf (stderr, "\t-r n text right margin (default = %d)\n", DEFAULT_RIGHT_MARGIN);
         fprintf (stderr, "\t-t n text top margin (default = %d)\n", DEFAULT_TOP_MARGIN);
+ #ifdef STRICTZ
+         fprintf (stderr, "\t-s n stricter error checking (default = %d)\n", STRICTZ_DEFAULT_REPORT_MODE);
+         fprintf (stderr, "\t\t(0: none; 1: report first error; 2: report all errors; 3: exit after any error)\n");
+ #endif /* STRICTZ */
         exit (EXIT_FAILURE);
     }

***************
*** 314,319 ****
--- 368,436 ----
     exit (1);

 }/* fatal */
+
+ #endif /* !defined(AMIGA) */
+
+ #if !defined(AMIGA)
+
+ /*
+  * 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
+  *
+  */
+
+ #ifdef STRICTZ
+
+ #ifdef __STDC__
+ void report_strictz_error (int errnum, const char *errstr)
+ #else /* __STDC__ */
+ void report_strictz_error (errnum, errstr)
+ int errnum;
+ const char *errstr;
+ #endif /* __STDC__ */
+ {
+     int wasfirst;
+
+     if (errnum <= 0 || errnum >= STRICTZ_NUM_ERRORS)
+         return;
+
+     if (strictz_report_mode == STRICTZ_REPORT_FATAL) {
+         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];
+         sprintf(buf, "Warning: %s (PC = %lx)", errstr, pc);
+         write_string(buf);
+
+         if (strictz_report_mode == STRICTZ_REPORT_ONCE) {
+             write_string(" (will ignore further occurrences)");
+         }
+         else {
+             sprintf(buf, " (occurrence %d)", strictz_error_count[errnum]);
+             write_string(buf);
+         }
+         new_line();
+     }
+
+ } /* report_strictz_error */
+
+ #endif /* STRICTZ */

 #endif /* !defined(AMIGA) */

diff -c zip/property.c zip_zs/property.c
*** zip/property.c      Fri Jan  2 13:49:22 1998
--- zip_zs/property.c   Fri Jan  2 15:10:22 1998
***************
*** 98,103 ****
--- 98,112 ----
 {
     zword_t propp;

+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_GET_PROP,
+             "@get_prop called with object 0");
+         store_operand (0);
+         return;
+     }
+ #endif
+
     /* Load address of first property */

     propp = get_property_addr (obj);
***************
*** 149,154 ****
--- 158,171 ----
 {
     zword_t propp;

+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_PUT_PROP,
+             "@put_prop called with object 0");
+         return;
+     }
+ #endif
+
     /* Load address of first property */

     propp = get_property_addr (obj);
***************
*** 192,197 ****
--- 209,223 ----
 {
     zword_t propp;

+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_GET_NEXT_PROP,
+             "@get_next_prop called with object 0");
+         store_operand (0);
+         return;
+     }
+ #endif
+
     /* Load address of first property */

     propp = get_property_addr (obj);
***************
*** 236,241 ****
--- 262,276 ----
 #endif
 {
     zword_t propp;
+
+ #ifdef STRICTZ
+     if (obj == 0) {
+         report_strictz_error(STRZERR_GET_PROP_ADDR,
+             "@get_prop_addr called with object 0");
+         store_operand (0);
+         return;
+     }
+ #endif

     /* Load address of first property */

diff -c zip/ztypes.h zip_zs/ztypes.h
*** zip/ztypes.h        Fri Jan  2 13:49:24 1998
--- zip_zs/ztypes.h     Fri Jan  2 15:48:11 1998
***************
*** 27,32 ****
--- 27,48 ----
 #define DEFAULT_RIGHT_MARGIN 0 /* # of characters in right margin */
 #define DEFAULT_TOP_MARGIN 0   /* # of lines left on screen before [MORE] message */

+ /* Perform stricter z-code error checking. If STRICTZ is #defined,
+    the interpreter will check for common opcode errors, such as reading
+    or writing properties of the "nothing" (0) object. When such an
+    error occurs, the opcode will call report_zstrict_error() and
+    then continue in some safe manner. This may mean doing nothing,
+    returning 0, or something like that.
+  See osdepend.c for the definition of report_zstrict_error(). Note that
+    this function may call fatal() to shut down the interpreter.
+  If STRICTZ is not #defined, the STRICTZ patch has no effect at all.
+    It does not even check to continue safely when an error occurs;
+    it just behaves the way ZIP has always behaved. This typically
+    means calling get_property_addr(0) or get_object_address(0),
+    which will return a meaningless value, and continuing on with
+    that. */
+ #define STRICTZ
+
 /* Global defines */

 #ifndef TRUE
***************
*** 353,358 ****
--- 369,404 ----
 extern char *status_line;

 extern char lookup_table[3][26];
+
+ #ifdef STRICTZ
+
+ /* Definitions for STRICTZ functions and error codes. */
+
+ #ifdef __STDC__
+ void report_strictz_error (int, const char *);
+ #else /* __STDC__ */
+ void report_strictz_error ();
+ #endif /* __STDC__ */
+
+ /* 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)
+
+ #endif /* STRICTZ */

 /* Global routines */