--- /dev/null
+/* 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*/