]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:06:00 +0000 (21:06 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:06:00 +0000 (21:06 +0000)
util/lev_main.c [new file with mode: 0644]

diff --git a/util/lev_main.c b/util/lev_main.c
new file mode 100644 (file)
index 0000000..8c9ee01
--- /dev/null
@@ -0,0 +1,1554 @@
+/*     SCCS Id: @(#)lev_main.c 3.3     2000/08/01      */
+/*     Copyright (c) 1989 by Jean-Christophe Collet */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ * This file contains the main function for the parser
+ * and some useful functions needed by yacc
+ */
+
+#include "hack.h"
+#include "date.h"
+#include "sp_lev.h"
+#ifdef STRICT_REF_DEF
+#include "tcap.h"
+#endif
+
+#ifdef MAC
+# ifdef applec
+#  define MPWTOOL
+#include <CursorCtl.h>
+# else
+#  define PREFIX ":lib:"       /* place output files here */
+# endif
+#endif
+
+#ifndef MPWTOOL
+# define SpinCursor(x)
+#endif
+
+#if defined(AMIGA) && defined(DLB)
+# define PREFIX "NH:slib/"
+#endif
+
+#ifndef O_WRONLY
+#include <fcntl.h>
+#endif
+#ifndef O_CREAT        /* some older BSD systems do not define O_CREAT in <fcntl.h> */
+#include <sys/file.h>
+#endif
+#ifndef O_BINARY       /* used for micros, no-op for others */
+# define O_BINARY 0
+#endif
+
+#ifdef MICRO
+# define OMASK FCMASK
+#else
+# define OMASK 0644
+#endif
+
+#define NEWLINE        10      /* under Mac MPW C '\n' is 13 so don't use it. */
+
+#define ERR            (-1)
+
+#define NewTab(type, size)     (type **) alloc(sizeof(type *) * size)
+#define Free(ptr)              if(ptr) free((genericptr_t) (ptr))
+#define Write(fd, item, size)  if (write(fd, (genericptr_t)(item), size) != size) return FALSE;
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+extern unsigned _stklen = STKSIZ;
+#endif
+#define MAX_ERRORS     25
+
+extern int  NDECL (yyparse);
+extern void FDECL (init_yyin, (FILE *));
+extern void FDECL (init_yyout, (FILE *));
+
+int  FDECL (main, (int, char **));
+void FDECL (yyerror, (const char *));
+void FDECL (yywarning, (const char *));
+int  NDECL (yywrap);
+int FDECL(get_floor_type, (CHAR_P));
+int FDECL(get_room_type, (char *));
+int FDECL(get_trap_type, (char *));
+int FDECL(get_monster_id, (char *,CHAR_P));
+int FDECL(get_object_id, (char *,CHAR_P));
+boolean FDECL(check_monster_char, (CHAR_P));
+boolean FDECL(check_object_char, (CHAR_P));
+char FDECL(what_map_char, (CHAR_P));
+void FDECL(scan_map, (char *));
+void NDECL(wallify_map);
+boolean NDECL(check_subrooms);
+void FDECL(check_coord, (int,int,const char *));
+void NDECL(store_part);
+void NDECL(store_room);
+boolean FDECL(write_level_file, (char *,splev *,specialmaze *));
+void FDECL(free_rooms, (splev *));
+
+extern void NDECL(monst_init);
+extern void NDECL(objects_init);
+extern void NDECL(decl_init);
+
+static boolean FDECL(write_common_data, (int,int,lev_init *,long));
+static boolean FDECL(write_monsters, (int,char *,monster ***));
+static boolean FDECL(write_objects, (int,char *,object ***));
+static boolean FDECL(write_engravings, (int,char *,engraving ***));
+static boolean FDECL(write_maze, (int,specialmaze *));
+static boolean FDECL(write_rooms, (int,splev *));
+static void NDECL(init_obj_classes);
+
+static struct {
+       const char *name;
+       int type;
+} trap_types[] = {
+       { "arrow",      ARROW_TRAP },
+       { "dart",       DART_TRAP },
+       { "falling rock", ROCKTRAP },
+       { "board",      SQKY_BOARD },
+       { "bear",       BEAR_TRAP },
+       { "land mine",  LANDMINE },
+       { "rolling boulder",    ROLLING_BOULDER_TRAP },
+       { "sleep gas",  SLP_GAS_TRAP },
+       { "rust",       RUST_TRAP },
+       { "fire",       FIRE_TRAP },
+       { "pit",        PIT },
+       { "spiked pit", SPIKED_PIT },
+       { "hole",       HOLE },
+       { "trap door",  TRAPDOOR },
+       { "teleport",   TELEP_TRAP },
+       { "level teleport", LEVEL_TELEP },
+       { "magic portal",   MAGIC_PORTAL },
+       { "web",        WEB },
+       { "statue",     STATUE_TRAP },
+       { "magic",      MAGIC_TRAP },
+       { "anti magic", ANTI_MAGIC },
+       { "polymorph",  POLY_TRAP },
+       { 0, 0 }
+};
+
+static struct {
+       const char *name;
+       int type;
+} room_types[] = {
+       /* for historical reasons, room types are not contiguous numbers */
+       /* (type 1 is skipped) */
+       { "ordinary",    OROOM },
+       { "throne",      COURT },
+       { "swamp",       SWAMP },
+       { "vault",       VAULT },
+       { "beehive",     BEEHIVE },
+       { "morgue",      MORGUE },
+       { "barracks",    BARRACKS },
+       { "zoo",         ZOO },
+       { "delphi",      DELPHI },
+       { "temple",      TEMPLE },
+       { "anthole",     ANTHOLE },
+       { "cocknest",    COCKNEST },
+       { "leprehall",   LEPREHALL },
+       { "shop",        SHOPBASE },
+       { "armor shop",  ARMORSHOP },
+       { "scroll shop", SCROLLSHOP },
+       { "potion shop", POTIONSHOP },
+       { "weapon shop", WEAPONSHOP },
+       { "food shop",   FOODSHOP },
+       { "ring shop",   RINGSHOP },
+       { "wand shop",   WANDSHOP },
+       { "tool shop",   TOOLSHOP },
+       { "book shop",   BOOKSHOP },
+       { "candle shop", CANDLESHOP },
+       { 0, 0 }
+};
+
+const char *fname = "(stdin)";
+int fatal_error = 0;
+int want_warnings = 0;
+
+#ifdef FLEX23_BUG
+/* Flex 2.3 bug work around; not needed for 2.3.6 or later */
+int yy_more_len = 0;
+#endif
+
+extern char tmpmessage[];
+extern altar *tmpaltar[];
+extern lad *tmplad[];
+extern stair *tmpstair[];
+extern digpos *tmpdig[];
+extern digpos *tmppass[];
+extern char *tmpmap[];
+extern region *tmpreg[];
+extern lev_region *tmplreg[];
+extern door *tmpdoor[];
+extern room_door *tmprdoor[];
+extern trap *tmptrap[];
+extern monster *tmpmonst[];
+extern object *tmpobj[];
+extern drawbridge *tmpdb[];
+extern walk *tmpwalk[];
+extern gold *tmpgold[];
+extern fountain *tmpfountain[];
+extern sink *tmpsink[];
+extern pool *tmppool[];
+extern engraving *tmpengraving[];
+extern mazepart *tmppart[];
+extern room *tmproom[];
+
+extern int n_olist, n_mlist, n_plist;
+
+extern unsigned int nlreg, nreg, ndoor, ntrap, nmons, nobj;
+extern unsigned int ndb, nwalk, npart, ndig, npass, nlad, nstair;
+extern unsigned int naltar, ncorridor, nrooms, ngold, nengraving;
+extern unsigned int nfountain, npool, nsink;
+
+extern unsigned int max_x_map, max_y_map;
+
+extern int line_number, colon_line_number;
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+       FILE *fin;
+       int i;
+       boolean errors_encountered = FALSE;
+#if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
+       static char *mac_argv[] = {     "lev_comp",     /* dummy argv[0] */
+                               ":dat:Arch.des",
+                               ":dat:Barb.des",
+                               ":dat:Caveman.des",
+                               ":dat:Healer.des",
+                               ":dat:Knight.des",
+                               ":dat:Monk.des",
+                               ":dat:Priest.des",
+                               ":dat:Ranger.des",
+                               ":dat:Rogue.des",
+                               ":dat:Samurai.des",
+                               ":dat:Tourist.des",
+                               ":dat:Valkyrie.des",
+                               ":dat:Wizard.des",
+                               ":dat:bigroom.des",
+                               ":dat:castle.des",
+                               ":dat:endgame.des",
+                               ":dat:gehennom.des",
+                               ":dat:knox.des",
+                               ":dat:medusa.des",
+                               ":dat:mines.des",
+                               ":dat:oracle.des",
+                               ":dat:sokoban.des",
+                               ":dat:tower.des",
+                               ":dat:yendor.des"
+                               };
+
+       argc = SIZE(mac_argv);
+       argv = mac_argv;
+#endif
+       /* Note:  these initializers don't do anything except guarantee that
+               we're linked properly.
+       */
+       monst_init();
+       objects_init();
+       decl_init();
+       /* this one does something... */
+       init_obj_classes();
+
+       init_yyout(stdout);
+       if (argc == 1) {                /* Read standard input */
+           init_yyin(stdin);
+           (void) yyparse();
+           if (fatal_error > 0) {
+                   errors_encountered = TRUE;
+           }
+       } else {                        /* Otherwise every argument is a filename */
+           for(i=1; i<argc; i++) {
+                   fname = argv[i];
+                   if(!strcmp(fname, "-w")) {
+                       want_warnings++;
+                       continue;
+                   }
+                   fin = freopen(fname, "r", stdin);
+                   if (!fin) {
+                       (void) fprintf(stderr,"Can't open \"%s\" for input.\n",
+                                               fname);
+                       perror(fname);
+                       errors_encountered = TRUE;
+                   } else {
+                       init_yyin(fin);
+                       (void) yyparse();
+                       line_number = 1;
+                       if (fatal_error > 0) {
+                               errors_encountered = TRUE;
+                               fatal_error = 0;
+                       }
+                   }
+           }
+       }
+       exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+/*
+ * Each time the parser detects an error, it uses this function.
+ * Here we take count of the errors. To continue farther than
+ * MAX_ERRORS wouldn't be reasonable.
+ * Assume that explicit calls from lev_comp.y have the 1st letter
+ * capitalized, to allow printing of the line containing the start of
+ * the current declaration, instead of the beginning of the next declaration.
+ */
+void
+yyerror(s)
+const char *s;
+{
+       (void) fprintf(stderr, "%s: line %d : %s\n", fname,
+               (*s >= 'A' && *s <= 'Z') ? colon_line_number : line_number, s);
+       if (++fatal_error > MAX_ERRORS) {
+               (void) fprintf(stderr,"Too many errors, good bye!\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+/*
+ * Just display a warning (that is : a non fatal error)
+ */
+void
+yywarning(s)
+const char *s;
+{
+       (void) fprintf(stderr, "%s: line %d : WARNING : %s\n",
+                               fname, colon_line_number, s);
+}
+
+/*
+ * Stub needed for lex interface.
+ */
+int
+yywrap()
+{
+       return 1;
+}
+
+/*
+ * Find the type of floor, knowing its char representation.
+ */
+int
+get_floor_type(c)
+char c;
+{
+       int val;
+
+       SpinCursor(3);
+       val = what_map_char(c);
+       if(val == INVALID_TYPE) {
+           val = ERR;
+           yywarning("Invalid fill character in MAZE declaration");
+       }
+       return val;
+}
+
+/*
+ * Find the type of a room in the table, knowing its name.
+ */
+int
+get_room_type(s)
+char *s;
+{
+       register int i;
+
+       SpinCursor(3);
+       for(i=0; room_types[i].name; i++)
+           if (!strcmp(s, room_types[i].name))
+               return ((int) room_types[i].type);
+       return ERR;
+}
+
+/*
+ * Find the type of a trap in the table, knowing its name.
+ */
+int
+get_trap_type(s)
+char *s;
+{
+       register int i;
+
+       SpinCursor(3);
+       for (i=0; trap_types[i].name; i++)
+           if(!strcmp(s,trap_types[i].name))
+               return trap_types[i].type;
+       return ERR;
+}
+
+/*
+ * Find the index of a monster in the table, knowing its name.
+ */
+int
+get_monster_id(s, c)
+char *s;
+char c;
+{
+       register int i, class;
+
+       SpinCursor(3);
+       class = c ? def_char_to_monclass(c) : 0;
+       if (class == MAXMCLASSES) return ERR;
+
+       for (i = LOW_PM; i < NUMMONS; i++)
+           if (!class || class == mons[i].mlet)
+               if (!strcmp(s, mons[i].mname)) return i;
+       return ERR;
+}
+
+/*
+ * Find the index of an object in the table, knowing its name.
+ */
+int
+get_object_id(s, c)
+char *s;
+char c;                /* class */
+{
+       int i, class;
+       const char *objname;
+
+       SpinCursor(3);
+       class = (c > 0) ? def_char_to_objclass(c) : 0;
+       if (class == MAXOCLASSES) return ERR;
+
+       for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) {
+           if (class && objects[i].oc_class != class) break;
+           objname = obj_descr[i].oc_name;
+           if (objname && !strcmp(s, objname))
+               return i;
+       }
+       return ERR;
+}
+
+static void
+init_obj_classes()
+{
+       int i, class, prev_class;
+
+       prev_class = -1;
+       for (i = 0; i < NUM_OBJECTS; i++) {
+           class = objects[i].oc_class;
+           if (class != prev_class) {
+               bases[class] = i;
+               prev_class = class;
+           }
+       }
+}
+
+/*
+ * Is the character 'c' a valid monster class ?
+ */
+boolean
+check_monster_char(c)
+char c;
+{
+       return (def_char_to_monclass(c) != MAXMCLASSES);
+}
+
+/*
+ * Is the character 'c' a valid object class ?
+ */
+boolean
+check_object_char(c)
+char c;
+{
+       return (def_char_to_objclass(c) != MAXOCLASSES);
+}
+
+/*
+ * Convert .des map letter into floor type.
+ */
+char
+what_map_char(c)
+char c;
+{
+       SpinCursor(3);
+       switch(c) {
+                 case ' '  : return(STONE);
+                 case '#'  : return(CORR);
+                 case '.'  : return(ROOM);
+                 case '-'  : return(HWALL);
+                 case '|'  : return(VWALL);
+                 case '+'  : return(DOOR);
+                 case 'A'  : return(AIR);
+                 case 'B'  : return(CROSSWALL); /* hack: boundary location */
+                 case 'C'  : return(CLOUD);
+                 case 'S'  : return(SDOOR);
+                 case 'H'  : return(SCORR);
+                 case '{'  : return(FOUNTAIN);
+                 case '\\' : return(THRONE);
+                 case 'K'  :
+#ifdef SINKS
+                     return(SINK);
+#else
+                     yywarning("Sinks are not allowed in this version!  Ignoring...");
+                     return(ROOM);
+#endif
+                 case '}'  : return(MOAT);
+                 case 'P'  : return(POOL);
+                 case 'L'  : return(LAVAPOOL);
+                 case 'I'  : return(ICE);
+                 case 'W'  : return(WATER);
+                 case 'T'      : return (TREE);
+                 case 'F'      : return (IRONBARS);    /* Fe = iron */
+           }
+       return(INVALID_TYPE);
+}
+
+/*
+ * Yep! LEX gives us the map in a raw mode.
+ * Just analyze it here.
+ */
+void
+scan_map(map)
+char *map;
+{
+       register int i, len;
+       register char *s1, *s2;
+       int max_len = 0;
+       int max_hig = 0;
+       char msg[256];
+
+       /* First : find the max width of the map */
+
+       s1 = map;
+       while (s1 && *s1) {
+               s2 = index(s1, NEWLINE);
+               if (s2) {
+                       len = (int) (s2 - s1);
+                       s1 = s2 + 1;
+               } else {
+                       len = (int) strlen(s1);
+                       s1 = (char *) 0;
+               }
+               if (len > max_len) max_len = len;
+       }
+
+       /* Then parse it now */
+
+       while (map && *map) {
+               tmpmap[max_hig] = (char *) alloc(max_len);
+               s1 = index(map, NEWLINE);
+               if (s1) {
+                       len = (int) (s1 - map);
+                       s1++;
+               } else {
+                       len = (int) strlen(map);
+                       s1 = map + len;
+               }
+               for(i=0; i<len; i++)
+                 if((tmpmap[max_hig][i] = what_map_char(map[i])) == INVALID_TYPE) {
+                     Sprintf(msg,
+                        "Invalid character @ (%d, %d) - replacing with stone",
+                             max_hig, i);
+                     yywarning(msg);
+                     tmpmap[max_hig][i] = STONE;
+                   }
+               while(i < max_len)
+                   tmpmap[max_hig][i++] = STONE;
+               map = s1;
+               max_hig++;
+       }
+
+       /* Memorize boundaries */
+
+       max_x_map = max_len - 1;
+       max_y_map = max_hig - 1;
+
+       /* Store the map into the mazepart structure */
+
+       if(max_len > MAP_X_LIM || max_hig > MAP_Y_LIM) {
+           Sprintf(msg, "Map too large! (max %d x %d)", MAP_X_LIM, MAP_Y_LIM);
+           yyerror(msg);
+       }
+
+       tmppart[npart]->xsize = max_len;
+       tmppart[npart]->ysize = max_hig;
+       tmppart[npart]->map = (char **) alloc(max_hig*sizeof(char *));
+       for(i = 0; i< max_hig; i++)
+           tmppart[npart]->map[i] = tmpmap[i];
+}
+
+/*
+ *     If we have drawn a map without walls, this allows us to
+ *     auto-magically wallify it.
+ */
+#define Map_point(x,y) *(tmppart[npart]->map[y] + x)
+
+void
+wallify_map()
+{
+       unsigned int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy;
+
+       for (y = 0; y <= max_y_map; y++) {
+           SpinCursor(3);
+           lo_yy = (y > 0) ? y - 1 : 0;
+           hi_yy = (y < max_y_map) ? y + 1 : max_y_map;
+           for (x = 0; x <= max_x_map; x++) {
+               if (Map_point(x,y) != STONE) continue;
+               lo_xx = (x > 0) ? x - 1 : 0;
+               hi_xx = (x < max_x_map) ? x + 1 : max_x_map;
+               for (yy = lo_yy; yy <= hi_yy; yy++)
+                   for (xx = lo_xx; xx <= hi_xx; xx++)
+                       if (IS_ROOM(Map_point(xx,yy)) ||
+                               Map_point(xx,yy) == CROSSWALL) {
+                           Map_point(x,y) = (yy != y) ? HWALL : VWALL;
+                           yy = hi_yy;         /* end `yy' loop */
+                           break;              /* end `xx' loop */
+                       }
+           }
+       }
+}
+
+/*
+ * We need to check the subrooms apartenance to an existing room.
+ */
+boolean
+check_subrooms()
+{
+       unsigned i, j, n_subrooms;
+       boolean found, ok = TRUE;
+       char    *last_parent, msg[256];
+
+       for (i = 0; i < nrooms; i++)
+           if (tmproom[i]->parent) {
+               found = FALSE;
+               for(j = 0; j < nrooms; j++)
+                   if (tmproom[j]->name &&
+                           !strcmp(tmproom[i]->parent, tmproom[j]->name)) {
+                       found = TRUE;
+                       break;
+                   }
+               if (!found) {
+                   Sprintf(msg,
+                           "Subroom error : parent room '%s' not found!",
+                           tmproom[i]->parent);
+                   yyerror(msg);
+                   ok = FALSE;
+               }
+           }
+
+       msg[0] = '\0';
+       last_parent = msg;
+       for (i = 0; i < nrooms; i++)
+           if (tmproom[i]->parent) {
+               n_subrooms = 0;
+               for(j = i; j < nrooms; j++) {
+/*
+ *     This is by no means perfect, but should cut down the duplicate error
+ *     messages by over 90%.  The only problem will be when either subrooms
+ *     are mixed in the level definition (not likely but possible) or rooms
+ *     have subrooms that have subrooms.
+ */
+                   if (!strcmp(tmproom[i]->parent, last_parent)) continue;
+                   if (tmproom[j]->parent &&
+                           !strcmp(tmproom[i]->parent, tmproom[j]->parent)) {
+                       n_subrooms++;
+                       if(n_subrooms > MAX_SUBROOMS) {
+
+                           Sprintf(msg,
+             "Subroom error: too many subrooms attached to parent room '%s'!",
+                                   tmproom[i]->parent);
+                           yyerror(msg);
+                           last_parent = tmproom[i]->parent;
+                           ok = FALSE;
+                           break;
+                       }
+                   }
+               }
+           }
+       return ok;
+}
+
+/*
+ * Check that coordinates (x,y) are roomlike locations.
+ * Print warning "str" if they aren't.
+ */
+void
+check_coord(x, y, str)
+int x, y;
+const char *str;
+{
+    char ebuf[60];
+
+    if (x >= 0 && y >= 0 && x <= (int)max_x_map && y <= (int)max_y_map &&
+       (IS_ROCK(tmpmap[y][x]) || IS_DOOR(tmpmap[y][x]))) {
+       Sprintf(ebuf, "%s placed in wall at (%02d,%02d)?!", str, x, y);
+       yywarning(ebuf);
+    }
+}
+
+/*
+ * Here we want to store the maze part we just got.
+ */
+void
+store_part()
+{
+       register unsigned i;
+
+       /* Ok, We got the whole part, now we store it. */
+
+       /* The Regions */
+
+       if ((tmppart[npart]->nreg = nreg) != 0) {
+               tmppart[npart]->regions = NewTab(region, nreg);
+               for(i=0;i<nreg;i++)
+                   tmppart[npart]->regions[i] = tmpreg[i];
+       }
+       nreg = 0;
+
+       /* The Level Regions */
+
+       if ((tmppart[npart]->nlreg = nlreg) != 0) {
+               tmppart[npart]->lregions = NewTab(lev_region, nlreg);
+               for(i=0;i<nlreg;i++)
+                   tmppart[npart]->lregions[i] = tmplreg[i];
+       }
+       nlreg = 0;
+
+       /* the doors */
+
+       if ((tmppart[npart]->ndoor = ndoor) != 0) {
+               tmppart[npart]->doors = NewTab(door, ndoor);
+               for(i=0;i<ndoor;i++)
+                   tmppart[npart]->doors[i] = tmpdoor[i];
+       }
+       ndoor = 0;
+
+       /* the drawbridges */
+
+       if ((tmppart[npart]->ndrawbridge = ndb) != 0) {
+               tmppart[npart]->drawbridges = NewTab(drawbridge, ndb);
+               for(i=0;i<ndb;i++)
+                   tmppart[npart]->drawbridges[i] = tmpdb[i];
+       }
+       ndb = 0;
+
+       /* The walkmaze directives */
+
+       if ((tmppart[npart]->nwalk = nwalk) != 0) {
+               tmppart[npart]->walks = NewTab(walk, nwalk);
+               for(i=0;i<nwalk;i++)
+                   tmppart[npart]->walks[i] = tmpwalk[i];
+       }
+       nwalk = 0;
+
+       /* The non_diggable directives */
+
+       if ((tmppart[npart]->ndig = ndig) != 0) {
+               tmppart[npart]->digs = NewTab(digpos, ndig);
+               for(i=0;i<ndig;i++)
+                   tmppart[npart]->digs[i] = tmpdig[i];
+       }
+       ndig = 0;
+
+       /* The non_passwall directives */
+
+       if ((tmppart[npart]->npass = npass) != 0) {
+               tmppart[npart]->passs = NewTab(digpos, npass);
+               for(i=0;i<npass;i++)
+                   tmppart[npart]->passs[i] = tmppass[i];
+       }
+       npass = 0;
+
+       /* The ladders */
+
+       if ((tmppart[npart]->nlad = nlad) != 0) {
+               tmppart[npart]->lads = NewTab(lad, nlad);
+               for(i=0;i<nlad;i++)
+                   tmppart[npart]->lads[i] = tmplad[i];
+       }
+       nlad = 0;
+
+       /* The stairs */
+
+       if ((tmppart[npart]->nstair = nstair) != 0) {
+               tmppart[npart]->stairs = NewTab(stair, nstair);
+               for(i=0;i<nstair;i++)
+                   tmppart[npart]->stairs[i] = tmpstair[i];
+       }
+       nstair = 0;
+
+       /* The altars */
+       if ((tmppart[npart]->naltar = naltar) != 0) {
+               tmppart[npart]->altars = NewTab(altar, naltar);
+               for(i=0;i<naltar;i++)
+                   tmppart[npart]->altars[i] = tmpaltar[i];
+       }
+       naltar = 0;
+
+       /* The fountains */
+
+       if ((tmppart[npart]->nfountain = nfountain) != 0) {
+               tmppart[npart]->fountains = NewTab(fountain, nfountain);
+               for(i=0;i<nfountain;i++)
+                   tmppart[npart]->fountains[i] = tmpfountain[i];
+       }
+       nfountain = 0;
+
+       /* the traps */
+
+       if ((tmppart[npart]->ntrap = ntrap) != 0) {
+               tmppart[npart]->traps = NewTab(trap, ntrap);
+               for(i=0;i<ntrap;i++)
+                   tmppart[npart]->traps[i] = tmptrap[i];
+       }
+       ntrap = 0;
+
+       /* the monsters */
+
+       if ((tmppart[npart]->nmonster = nmons) != 0) {
+               tmppart[npart]->monsters = NewTab(monster, nmons);
+               for(i=0;i<nmons;i++)
+                   tmppart[npart]->monsters[i] = tmpmonst[i];
+       } else
+               tmppart[npart]->monsters = 0;
+       nmons = 0;
+
+       /* the objects */
+
+       if ((tmppart[npart]->nobject = nobj) != 0) {
+               tmppart[npart]->objects = NewTab(object, nobj);
+               for(i=0;i<nobj;i++)
+                   tmppart[npart]->objects[i] = tmpobj[i];
+       } else
+               tmppart[npart]->objects = 0;
+       nobj = 0;
+
+       /* The gold piles */
+
+       if ((tmppart[npart]->ngold = ngold) != 0) {
+               tmppart[npart]->golds = NewTab(gold, ngold);
+               for(i=0;i<ngold;i++)
+                   tmppart[npart]->golds[i] = tmpgold[i];
+       }
+       ngold = 0;
+
+       /* The engravings */
+
+       if ((tmppart[npart]->nengraving = nengraving) != 0) {
+               tmppart[npart]->engravings = NewTab(engraving, nengraving);
+               for(i=0;i<nengraving;i++)
+                   tmppart[npart]->engravings[i] = tmpengraving[i];
+       } else
+               tmppart[npart]->engravings = 0;
+       nengraving = 0;
+
+       npart++;
+       n_plist = n_mlist = n_olist = 0;
+}
+
+/*
+ * Here we want to store the room part we just got.
+ */
+void
+store_room()
+{
+       register unsigned i;
+
+       /* Ok, We got the whole room, now we store it. */
+
+       /* the doors */
+
+       if ((tmproom[nrooms]->ndoor = ndoor) != 0) {
+               tmproom[nrooms]->doors = NewTab(room_door, ndoor);
+               for(i=0;i<ndoor;i++)
+                   tmproom[nrooms]->doors[i] = tmprdoor[i];
+       }
+       ndoor = 0;
+
+       /* The stairs */
+
+       if ((tmproom[nrooms]->nstair = nstair) != 0) {
+               tmproom[nrooms]->stairs = NewTab(stair, nstair);
+               for(i=0;i<nstair;i++)
+                   tmproom[nrooms]->stairs[i] = tmpstair[i];
+       }
+       nstair = 0;
+
+       /* The altars */
+       if ((tmproom[nrooms]->naltar = naltar) != 0) {
+               tmproom[nrooms]->altars = NewTab(altar, naltar);
+               for(i=0;i<naltar;i++)
+                   tmproom[nrooms]->altars[i] = tmpaltar[i];
+       }
+       naltar = 0;
+
+       /* The fountains */
+
+       if ((tmproom[nrooms]->nfountain = nfountain) != 0) {
+               tmproom[nrooms]->fountains = NewTab(fountain, nfountain);
+               for(i=0;i<nfountain;i++)
+                   tmproom[nrooms]->fountains[i] = tmpfountain[i];
+       }
+       nfountain = 0;
+
+       /* The sinks */
+
+       if ((tmproom[nrooms]->nsink = nsink) != 0) {
+               tmproom[nrooms]->sinks = NewTab(sink, nsink);
+               for(i=0;i<nsink;i++)
+                   tmproom[nrooms]->sinks[i] = tmpsink[i];
+       }
+       nsink = 0;
+
+       /* The pools */
+
+       if ((tmproom[nrooms]->npool = npool) != 0) {
+               tmproom[nrooms]->pools = NewTab(pool, npool);
+               for(i=0;i<npool;i++)
+                   tmproom[nrooms]->pools[i] = tmppool[i];
+       }
+       npool = 0;
+
+       /* the traps */
+
+       if ((tmproom[nrooms]->ntrap = ntrap) != 0) {
+               tmproom[nrooms]->traps = NewTab(trap, ntrap);
+               for(i=0;i<ntrap;i++)
+                   tmproom[nrooms]->traps[i] = tmptrap[i];
+       }
+       ntrap = 0;
+
+       /* the monsters */
+
+       if ((tmproom[nrooms]->nmonster = nmons) != 0) {
+               tmproom[nrooms]->monsters = NewTab(monster, nmons);
+               for(i=0;i<nmons;i++)
+                   tmproom[nrooms]->monsters[i] = tmpmonst[i];
+       } else
+               tmproom[nrooms]->monsters = 0;
+       nmons = 0;
+
+       /* the objects */
+
+       if ((tmproom[nrooms]->nobject = nobj) != 0) {
+               tmproom[nrooms]->objects = NewTab(object, nobj);
+               for(i=0;i<nobj;i++)
+                   tmproom[nrooms]->objects[i] = tmpobj[i];
+       } else
+               tmproom[nrooms]->objects = 0;
+       nobj = 0;
+
+       /* The gold piles */
+
+       if ((tmproom[nrooms]->ngold = ngold) != 0) {
+               tmproom[nrooms]->golds = NewTab(gold, ngold);
+               for(i=0;i<ngold;i++)
+                   tmproom[nrooms]->golds[i] = tmpgold[i];
+       }
+       ngold = 0;
+
+       /* The engravings */
+
+       if ((tmproom[nrooms]->nengraving = nengraving) != 0) {
+               tmproom[nrooms]->engravings = NewTab(engraving, nengraving);
+               for(i=0;i<nengraving;i++)
+                   tmproom[nrooms]->engravings[i] = tmpengraving[i];
+       } else
+               tmproom[nrooms]->engravings = 0;
+       nengraving = 0;
+
+       nrooms++;
+}
+
+/*
+ * Output some info common to all special levels.
+ */
+static boolean
+write_common_data(fd, typ, init, flgs)
+int fd, typ;
+lev_init *init;
+long flgs;
+{
+       char c;
+       uchar len;
+       static struct version_info version_data = {
+                       VERSION_NUMBER, VERSION_FEATURES,
+                       VERSION_SANITY1, VERSION_SANITY2
+       };
+
+       Write(fd, &version_data, sizeof version_data);
+       c = typ;
+       Write(fd, &c, sizeof(c));       /* 1 byte header */
+       Write(fd, init, sizeof(lev_init));
+       Write(fd, &flgs, sizeof flgs);
+
+       len = (uchar) strlen(tmpmessage);
+       Write(fd, &len, sizeof len);
+       if (len) Write(fd, tmpmessage, (int) len);
+       tmpmessage[0] = '\0';
+       return TRUE;
+}
+
+/*
+ * Output monster info, which needs string fixups, then release memory.
+ */
+static boolean
+write_monsters(fd, nmonster_p, monsters_p)
+int fd;
+char *nmonster_p;
+monster ***monsters_p;
+{
+       monster *m;
+       char *name, *appr;
+       int j, n = (int)*nmonster_p;
+
+       Write(fd, nmonster_p, sizeof *nmonster_p);
+       for (j = 0; j < n; j++) {
+           m = (*monsters_p)[j];
+           name = m->name.str;
+           appr = m->appear_as.str;
+           m->name.str = m->appear_as.str = 0;
+           m->name.len = name ? strlen(name) : 0;
+           m->appear_as.len = appr ? strlen(appr) : 0;
+           Write(fd, m, sizeof *m);
+           if (name) {
+               Write(fd, name, m->name.len);
+               Free(name);
+           }
+           if (appr) {
+               Write(fd, appr, m->appear_as.len);
+               Free(appr);
+           }
+           Free(m);
+       }
+       if (*monsters_p) {
+           Free(*monsters_p);
+           *monsters_p = 0;
+       }
+       *nmonster_p = 0;
+       return TRUE;
+}
+
+/*
+ * Output object info, which needs string fixup, then release memory.
+ */
+static boolean
+write_objects(fd, nobject_p, objects_p)
+int fd;
+char *nobject_p;
+object ***objects_p;
+{
+       object *o;
+       char *name;
+       int j, n = (int)*nobject_p;
+
+       Write(fd, nobject_p, sizeof *nobject_p);
+       for (j = 0; j < n; j++) {
+           o = (*objects_p)[j];
+           name = o->name.str;
+           o->name.str = 0;    /* reset in case `len' is narrower */
+           o->name.len = name ? strlen(name) : 0;
+           Write(fd, o, sizeof *o);
+           if (name) {
+               Write(fd, name, o->name.len);
+               Free(name);
+           }
+           Free(o);
+       }
+       if (*objects_p) {
+           Free(*objects_p);
+           *objects_p = 0;
+       }
+       *nobject_p = 0;
+       return TRUE;
+}
+
+/*
+ * Output engraving info, which needs string fixup, then release memory.
+ */
+static boolean
+write_engravings(fd, nengraving_p, engravings_p)
+int fd;
+char *nengraving_p;
+engraving ***engravings_p;
+{
+       engraving *e;
+       char *engr;
+       int j, n = (int)*nengraving_p;
+
+       Write(fd, nengraving_p, sizeof *nengraving_p);
+       for (j = 0; j < n; j++) {
+           e = (*engravings_p)[j];
+           engr = e->engr.str;
+           e->engr.str = 0;    /* reset in case `len' is narrower */
+           e->engr.len = strlen(engr);
+           Write(fd, e, sizeof *e);
+           Write(fd, engr, e->engr.len);
+           Free(engr);
+           Free(e);
+       }
+       if (*engravings_p) {
+           Free(*engravings_p);
+           *engravings_p = 0;
+       }
+       *nengraving_p = 0;
+       return TRUE;
+}
+
+/*
+ * Open and write maze or rooms file, based on which pointer is non-null.
+ * Return TRUE on success, FALSE on failure.
+ */
+boolean
+write_level_file(filename, room_level, maze_level)
+char *filename;
+splev *room_level;
+specialmaze *maze_level;
+{
+       int fout;
+       char lbuf[60];
+
+       lbuf[0] = '\0';
+#ifdef PREFIX
+       Strcat(lbuf, PREFIX);
+#endif
+       Strcat(lbuf, filename);
+       Strcat(lbuf, LEV_EXT);
+
+       fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
+       if (fout < 0) return FALSE;
+
+       if (room_level) {
+           if (!write_rooms(fout, room_level))
+               return FALSE;
+       } else if (maze_level) {
+           if (!write_maze(fout, maze_level))
+               return FALSE;
+       } else
+           panic("write_level_file");
+
+       (void) close(fout);
+       return TRUE;
+}
+
+/*
+ * Here we write the structure of the maze in the specified file (fd).
+ * Also, we have to free the memory allocated via alloc().
+ */
+static boolean
+write_maze(fd, maze)
+int fd;
+specialmaze *maze;
+{
+       short i,j;
+       mazepart *pt;
+
+       if (!write_common_data(fd, SP_LEV_MAZE, &(maze->init_lev), maze->flags))
+           return FALSE;
+
+       Write(fd, &(maze->filling), sizeof(maze->filling));
+       Write(fd, &(maze->numpart), sizeof(maze->numpart));
+                                        /* Number of parts */
+       for(i=0;i<maze->numpart;i++) {
+           pt = maze->parts[i];
+
+           /* First, write the map */
+
+           Write(fd, &(pt->halign), sizeof(pt->halign));
+           Write(fd, &(pt->valign), sizeof(pt->valign));
+           Write(fd, &(pt->xsize), sizeof(pt->xsize));
+           Write(fd, &(pt->ysize), sizeof(pt->ysize));
+           for(j=0;j<pt->ysize;j++) {
+               if(!maze->init_lev.init_present ||
+                  pt->xsize > 1 || pt->ysize > 1)
+                   Write(fd, pt->map[j], pt->xsize * sizeof *pt->map[j]);
+               Free(pt->map[j]);
+           }
+           Free(pt->map);
+
+           /* level region stuff */
+           Write(fd, &pt->nlreg, sizeof pt->nlreg);
+           for (j = 0; j < pt->nlreg; j++) {
+               lev_region *l = pt->lregions[j];
+               char *rname = l->rname.str;
+               l->rname.str = 0;       /* reset in case `len' is narrower */
+               l->rname.len = rname ? strlen(rname) : 0;
+               Write(fd, l, sizeof *l);
+               if (rname) {
+                   Write(fd, rname, l->rname.len);
+                   Free(rname);
+               }
+               Free(l);
+           }
+           if (pt->nlreg > 0)
+               Free(pt->lregions);
+
+           /* The random registers */
+           Write(fd, &(pt->nrobjects), sizeof(pt->nrobjects));
+           if(pt->nrobjects) {
+                   Write(fd, pt->robjects, pt->nrobjects);
+                   Free(pt->robjects);
+           }
+           Write(fd, &(pt->nloc), sizeof(pt->nloc));
+           if(pt->nloc) {
+                   Write(fd, pt->rloc_x, pt->nloc);
+                   Write(fd, pt->rloc_y, pt->nloc);
+                   Free(pt->rloc_x);
+                   Free(pt->rloc_y);
+           }
+           Write(fd, &(pt->nrmonst), sizeof(pt->nrmonst));
+           if(pt->nrmonst) {
+                   Write(fd, pt->rmonst, pt->nrmonst);
+                   Free(pt->rmonst);
+           }
+
+           /* subrooms */
+           Write(fd, &(pt->nreg), sizeof(pt->nreg));
+           for(j=0;j<pt->nreg;j++) {
+                   Write(fd, pt->regions[j], sizeof(region));
+                   Free(pt->regions[j]);
+           }
+           if(pt->nreg > 0)
+                   Free(pt->regions);
+
+           /* the doors */
+           Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
+           for(j=0;j<pt->ndoor;j++) {
+                   Write(fd, pt->doors[j], sizeof(door));
+                   Free(pt->doors[j]);
+           }
+           if (pt->ndoor > 0)
+                   Free(pt->doors);
+
+           /* The drawbridges */
+           Write(fd, &(pt->ndrawbridge), sizeof(pt->ndrawbridge));
+           for(j=0;j<pt->ndrawbridge;j++) {
+                   Write(fd, pt->drawbridges[j], sizeof(drawbridge));
+                   Free(pt->drawbridges[j]);
+           }
+           if(pt->ndrawbridge > 0)
+                   Free(pt->drawbridges);
+
+           /* The mazewalk directives */
+           Write(fd, &(pt->nwalk), sizeof(pt->nwalk));
+           for(j=0; j<pt->nwalk; j++) {
+                   Write(fd, pt->walks[j], sizeof(walk));
+                   Free(pt->walks[j]);
+           }
+           if (pt->nwalk > 0)
+                   Free(pt->walks);
+
+           /* The non_diggable directives */
+           Write(fd, &(pt->ndig), sizeof(pt->ndig));
+           for(j=0;j<pt->ndig;j++) {
+                   Write(fd, pt->digs[j], sizeof(digpos));
+                   Free(pt->digs[j]);
+           }
+           if (pt->ndig > 0)
+                   Free(pt->digs);
+
+           /* The non_passwall directives */
+           Write(fd, &(pt->npass), sizeof(pt->npass));
+           for(j=0;j<pt->npass;j++) {
+                   Write(fd, pt->passs[j], sizeof(digpos));
+                   Free(pt->passs[j]);
+           }
+           if (pt->npass > 0)
+                   Free(pt->passs);
+
+           /* The ladders */
+           Write(fd, &(pt->nlad), sizeof(pt->nlad));
+           for(j=0;j<pt->nlad;j++) {
+                   Write(fd, pt->lads[j], sizeof(lad));
+                   Free(pt->lads[j]);
+           }
+           if (pt->nlad > 0)
+                   Free(pt->lads);
+
+           /* The stairs */
+           Write(fd, &(pt->nstair), sizeof(pt->nstair));
+           for(j=0;j<pt->nstair;j++) {
+                   Write(fd, pt->stairs[j], sizeof(stair));
+                   Free(pt->stairs[j]);
+           }
+           if (pt->nstair > 0)
+                   Free(pt->stairs);
+
+           /* The altars */
+           Write(fd, &(pt->naltar), sizeof(pt->naltar));
+           for(j=0;j<pt->naltar;j++) {
+                   Write(fd, pt->altars[j], sizeof(altar));
+                   Free(pt->altars[j]);
+           }
+           if (pt->naltar > 0)
+                   Free(pt->altars);
+
+           /* The fountains */
+           Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
+           for(j=0;j<pt->nfountain;j++) {
+               Write(fd, pt->fountains[j], sizeof(fountain));
+               Free(pt->fountains[j]);
+           }
+           if (pt->nfountain > 0)
+                   Free(pt->fountains);
+
+           /* The traps */
+           Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
+           for(j=0;j<pt->ntrap;j++) {
+                   Write(fd, pt->traps[j], sizeof(trap));
+                   Free(pt->traps[j]);
+           }
+           if (pt->ntrap)
+                   Free(pt->traps);
+
+           /* The monsters */
+           if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
+                   return FALSE;
+
+           /* The objects */
+           if (!write_objects(fd, &pt->nobject, &pt->objects))
+                   return FALSE;
+
+           /* The gold piles */
+           Write(fd, &(pt->ngold), sizeof(pt->naltar));
+           for(j=0;j<pt->ngold;j++) {
+                   Write(fd, pt->golds[j], sizeof(gold));
+                   Free(pt->golds[j]);
+           }
+           if (pt->ngold > 0)
+                   Free(pt->golds);
+
+           /* The engravings */
+           if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
+                   return FALSE;
+
+           Free(pt);
+       }
+
+       Free(maze->parts);
+       maze->parts = (mazepart **)0;
+       maze->numpart = 0;
+       return TRUE;
+}
+
+/*
+ * Here we write the structure of the room level in the specified file (fd).
+ */
+static boolean
+write_rooms(fd, lev)
+int fd;
+splev *lev;
+{
+       short i,j, size;
+       room *pt;
+
+       if (!write_common_data(fd, SP_LEV_ROOMS, &(lev->init_lev), lev->flags))
+               return FALSE;
+
+       /* Random registers */
+
+       Write(fd, &lev->nrobjects, sizeof(lev->nrobjects));
+       if (lev->nrobjects)
+               Write(fd, lev->robjects, lev->nrobjects);
+       Write(fd, &lev->nrmonst, sizeof(lev->nrmonst));
+       if (lev->nrmonst)
+               Write(fd, lev->rmonst, lev->nrmonst);
+
+       Write(fd, &(lev->nroom), sizeof(lev->nroom));
+                                                       /* Number of rooms */
+       for(i=0;i<lev->nroom;i++) {
+               pt = lev->rooms[i];
+
+               /* Room characteristics */
+
+               size = (short) (pt->name ? strlen(pt->name) : 0);
+               Write(fd, &size, sizeof(size));
+               if (size)
+                       Write(fd, pt->name, size);
+
+               size = (short) (pt->parent ? strlen(pt->parent) : 0);
+               Write(fd, &size, sizeof(size));
+               if (size)
+                       Write(fd, pt->parent, size);
+
+               Write(fd, &(pt->x), sizeof(pt->x));
+               Write(fd, &(pt->y), sizeof(pt->y));
+               Write(fd, &(pt->w), sizeof(pt->w));
+               Write(fd, &(pt->h), sizeof(pt->h));
+               Write(fd, &(pt->xalign), sizeof(pt->xalign));
+               Write(fd, &(pt->yalign), sizeof(pt->yalign));
+               Write(fd, &(pt->rtype), sizeof(pt->rtype));
+               Write(fd, &(pt->chance), sizeof(pt->chance));
+               Write(fd, &(pt->rlit), sizeof(pt->rlit));
+               Write(fd, &(pt->filled), sizeof(pt->filled));
+
+               /* the doors */
+               Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
+               for(j=0;j<pt->ndoor;j++)
+                       Write(fd, pt->doors[j], sizeof(room_door));
+
+               /* The stairs */
+               Write(fd, &(pt->nstair), sizeof(pt->nstair));
+               for(j=0;j<pt->nstair;j++)
+                       Write(fd, pt->stairs[j], sizeof(stair));
+
+               /* The altars */
+               Write(fd, &(pt->naltar), sizeof(pt->naltar));
+               for(j=0;j<pt->naltar;j++)
+                       Write(fd, pt->altars[j], sizeof(altar));
+
+               /* The fountains */
+               Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
+               for(j=0;j<pt->nfountain;j++)
+                       Write(fd, pt->fountains[j], sizeof(fountain));
+
+               /* The sinks */
+               Write(fd, &(pt->nsink), sizeof(pt->nsink));
+               for(j=0;j<pt->nsink;j++)
+                       Write(fd, pt->sinks[j], sizeof(sink));
+
+               /* The pools */
+               Write(fd, &(pt->npool), sizeof(pt->npool));
+               for(j=0;j<pt->npool;j++)
+                       Write(fd, pt->pools[j], sizeof(pool));
+
+               /* The traps */
+               Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
+               for(j=0;j<pt->ntrap;j++)
+                       Write(fd, pt->traps[j], sizeof(trap));
+
+               /* The monsters */
+               if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
+                       return FALSE;
+
+               /* The objects */
+               if (!write_objects(fd, &pt->nobject, &pt->objects))
+                       return FALSE;
+
+               /* The gold piles */
+               Write(fd, &(pt->ngold), sizeof(pt->ngold));
+               for(j=0;j<pt->ngold;j++)
+                       Write(fd, pt->golds[j], sizeof(gold));
+
+               /* The engravings */
+               if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
+                       return FALSE;
+
+       }
+
+       /* The corridors */
+       Write(fd, &lev->ncorr, sizeof(lev->ncorr));
+       for (i=0; i < lev->ncorr; i++)
+               Write(fd, lev->corrs[i], sizeof(corridor));
+       return TRUE;
+}
+
+/*
+ * Release memory allocated to a rooms-style special level; maze-style
+ * levels have the fields freed as they're written; monsters, objects, and
+ * engravings are freed as written for both styles, so not handled here.
+ */
+void
+free_rooms(lev)
+splev *lev;
+{
+       room *r;
+       int j, n = lev->nroom;
+
+       while(n--) {
+               r = lev->rooms[n];
+               Free(r->name);
+               Free(r->parent);
+               if ((j = r->ndoor) != 0) {
+                       while(j--)
+                               Free(r->doors[j]);
+                       Free(r->doors);
+               }
+               if ((j = r->nstair) != 0) {
+                       while(j--)
+                               Free(r->stairs[j]);
+                       Free(r->stairs);
+               }
+               if ((j = r->naltar) != 0) {
+                       while (j--)
+                               Free(r->altars[j]);
+                       Free(r->altars);
+               }
+               if ((j = r->nfountain) != 0) {
+                       while(j--)
+                               Free(r->fountains[j]);
+                       Free(r->fountains);
+               }
+               if ((j = r->nsink) != 0) {
+                       while(j--)
+                               Free(r->sinks[j]);
+                       Free(r->sinks);
+               }
+               if ((j = r->npool) != 0) {
+                       while(j--)
+                               Free(r->pools[j]);
+                       Free(r->pools);
+               }
+               if ((j = r->ntrap) != 0) {
+                       while (j--)
+                               Free(r->traps[j]);
+                       Free(r->traps);
+               }
+               if ((j = r->ngold) != 0) {
+                       while(j--)
+                               Free(r->golds[j]);
+                       Free(r->golds);
+               }
+               Free(r);
+               lev->rooms[n] = (room *)0;
+       }
+       Free(lev->rooms);
+       lev->rooms = (room **)0;
+       lev->nroom = 0;
+
+       for (j = 0; j < lev->ncorr; j++) {
+               Free(lev->corrs[j]);
+               lev->corrs[j] = (corridor *)0;
+       }
+       Free(lev->corrs);
+       lev->corrs = (corridor **)0;
+       lev->ncorr = 0;
+
+       Free(lev->robjects);
+       lev->robjects = (char *)0;
+       lev->nrobjects = 0;
+       Free(lev->rmonst);
+       lev->rmonst = (char *)0;
+       lev->nrmonst = 0;
+}
+
+#ifdef STRICT_REF_DEF
+/*
+ * Any globals declared in hack.h and descendents which aren't defined
+ * in the modules linked into lev_comp should be defined here.  These
+ * definitions can be dummies:  their sizes shouldn't matter as long as
+ * as their types are correct; actual values are irrelevant.
+ */
+#define ARBITRARY_SIZE 1
+/* attrib.c */
+struct attribs attrmax, attrmin;
+/* files.c */
+const char *configfile;
+char lock[ARBITRARY_SIZE];
+char SAVEF[ARBITRARY_SIZE];
+# ifdef MICRO
+char SAVEP[ARBITRARY_SIZE];
+# endif
+/* termcap.c */
+struct tc_lcl_data tc_lcl_data;
+# ifdef TEXTCOLOR
+#  ifdef TOS
+const char *hilites[CLR_MAX];
+#  else
+char NEARDATA *hilites[CLR_MAX];
+#  endif
+# endif
+/* trap.c */
+const char *traps[TRAPNUM];
+/* window.c */
+struct window_procs windowprocs;
+/* xxxtty.c */
+# ifdef DEFINE_OSPEED
+short ospeed;
+# endif
+#endif /* STRICT_REF_DEF */
+
+/*lev_main.c*/