OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / util / lev_main.c
1 /*      SCCS Id: @(#)lev_main.c 3.4     2002/03/27      */
2 /*      Copyright (c) 1989 by Jean-Christophe Collet */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /*
6  * This file contains the main function for the parser
7  * and some useful functions needed by yacc
8  */
9 #define SPEC_LEV        /* for MPW */
10 /* although, why don't we move those special defines here.. and in dgn_main? */
11
12 #include "hack.h"
13 #include "date.h"
14 #include "sp_lev.h"
15 #ifdef STRICT_REF_DEF
16 #include "tcap.h"
17 #endif
18
19 #ifdef MAC
20 # if defined(__SC__) || defined(__MRC__)
21 #  define MPWTOOL
22 #  define PREFIX ":dungeon:"    /* place output files here */
23 #  include <CursorCtl.h>
24 # else
25 #  if !defined(__MACH__)
26 #   define PREFIX ":lib:"       /* place output files here */
27 #  endif
28 # endif
29 #endif
30
31 #ifdef WIN_CE
32 #define PREFIX "\\nethack\\dat\\"
33 #endif
34
35 #ifndef MPWTOOL
36 # define SpinCursor(x)
37 #endif
38
39 #if defined(AMIGA) && defined(DLB)
40 # define PREFIX "NH:slib/"
41 #endif
42
43 #ifndef O_WRONLY
44 #include <fcntl.h>
45 #endif
46 #ifndef O_CREAT /* some older BSD systems do not define O_CREAT in <fcntl.h> */
47 #include <sys/file.h>
48 #endif
49 #ifndef O_BINARY        /* used for micros, no-op for others */
50 # define O_BINARY 0
51 #endif
52
53 #if defined(MICRO) || defined(WIN32)
54 # define OMASK FCMASK
55 #else
56 # define OMASK 0644
57 #endif
58
59 #define ERR             (-1)
60
61 #define NewTab(type, size)      (type **) alloc(sizeof(type *) * size)
62 #define Free(ptr)               if(ptr) free((genericptr_t) (ptr))
63 #define Write(fd, item, size)   if (write(fd, (genericptr_t)(item), size) != size) return FALSE;
64
65 #if defined(__BORLANDC__) && !defined(_WIN32)
66 extern unsigned _stklen = STKSIZ;
67 #endif
68 #define MAX_ERRORS      25
69
70 extern int  NDECL (yyparse);
71 extern void FDECL (init_yyin, (FILE *));
72 extern void FDECL (init_yyout, (FILE *));
73
74 int  FDECL (main, (int, char **));
75 void FDECL (yyerror, (const char *));
76 void FDECL (yywarning, (const char *));
77 int  NDECL (yywrap);
78 int FDECL(get_floor_type, (CHAR_P));
79 int FDECL(get_room_type, (char *));
80 int FDECL(get_trap_type, (char *));
81 int FDECL(get_monster_id, (char *,CHAR_P));
82 int FDECL(get_object_id, (char *,CHAR_P));
83 boolean FDECL(check_monster_char, (CHAR_P));
84 boolean FDECL(check_object_char, (CHAR_P));
85 char FDECL(what_map_char, (CHAR_P));
86 void FDECL(scan_map, (char *));
87 void NDECL(wallify_map);
88 boolean NDECL(check_subrooms);
89 void FDECL(check_coord, (int,int,const char *));
90 void NDECL(store_part);
91 void NDECL(store_room);
92 boolean FDECL(write_level_file, (char *,splev *,specialmaze *));
93 void FDECL(free_rooms, (splev *));
94
95 extern void NDECL(monst_init);
96 extern void NDECL(objects_init);
97 extern void NDECL(decl_init);
98
99 static boolean FDECL(write_common_data, (int,int,lev_init *,long));
100 static boolean FDECL(write_monsters, (int,char *,monster ***));
101 static boolean FDECL(write_objects, (int,char *,object ***));
102 static boolean FDECL(write_engravings, (int,char *,engraving ***));
103 static boolean FDECL(write_maze, (int,specialmaze *));
104 static boolean FDECL(write_rooms, (int,splev *));
105 static void NDECL(init_obj_classes);
106
107 static struct {
108         const char *name;
109         int type;
110 } trap_types[] = {
111         { "arrow",      ARROW_TRAP },
112         { "dart",       DART_TRAP },
113         { "falling rock", ROCKTRAP },
114         { "board",      SQKY_BOARD },
115         { "bear",       BEAR_TRAP },
116         { "land mine",  LANDMINE },
117         { "rolling boulder",    ROLLING_BOULDER_TRAP },
118         { "sleep gas",  SLP_GAS_TRAP },
119         { "rust",       RUST_TRAP },
120         { "fire",       FIRE_TRAP },
121         { "pit",        PIT },
122         { "spiked pit", SPIKED_PIT },
123         { "hole",       HOLE },
124         { "trap door",  TRAPDOOR },
125         { "teleport",   TELEP_TRAP },
126         { "level teleport", LEVEL_TELEP },
127         { "magic portal",   MAGIC_PORTAL },
128         { "web",        WEB },
129         { "statue",     STATUE_TRAP },
130         { "magic",      MAGIC_TRAP },
131         { "anti magic", ANTI_MAGIC },
132         { "polymorph",  POLY_TRAP },
133         { 0, 0 }
134 };
135
136 static struct {
137         const char *name;
138         int type;
139 } room_types[] = {
140         /* for historical reasons, room types are not contiguous numbers */
141         /* (type 1 is skipped) */
142         { "ordinary",    OROOM },
143         { "throne",      COURT },
144         { "swamp",       SWAMP },
145         { "vault",       VAULT },
146         { "beehive",     BEEHIVE },
147         { "morgue",      MORGUE },
148         { "barracks",    BARRACKS },
149         { "zoo",         ZOO },
150         { "delphi",      DELPHI },
151         { "temple",      TEMPLE },
152         { "anthole",     ANTHOLE },
153         { "cocknest",    COCKNEST },
154         { "leprehall",   LEPREHALL },
155         { "shop",        SHOPBASE },
156         { "armor shop",  ARMORSHOP },
157         { "scroll shop", SCROLLSHOP },
158         { "potion shop", POTIONSHOP },
159         { "weapon shop", WEAPONSHOP },
160         { "food shop",   FOODSHOP },
161         { "ring shop",   RINGSHOP },
162         { "wand shop",   WANDSHOP },
163         { "tool shop",   TOOLSHOP },
164         { "book shop",   BOOKSHOP },
165         { "candle shop", CANDLESHOP },
166         { 0, 0 }
167 };
168
169 const char *fname = "(stdin)";
170 int fatal_error = 0;
171 int want_warnings = 0;
172
173 #ifdef FLEX23_BUG
174 /* Flex 2.3 bug work around; not needed for 2.3.6 or later */
175 int yy_more_len = 0;
176 #endif
177
178 extern char tmpmessage[];
179 extern altar *tmpaltar[];
180 extern lad *tmplad[];
181 extern stair *tmpstair[];
182 extern digpos *tmpdig[];
183 extern digpos *tmppass[];
184 extern char *tmpmap[];
185 extern region *tmpreg[];
186 extern lev_region *tmplreg[];
187 extern door *tmpdoor[];
188 extern room_door *tmprdoor[];
189 extern trap *tmptrap[];
190 extern monster *tmpmonst[];
191 extern object *tmpobj[];
192 extern drawbridge *tmpdb[];
193 extern walk *tmpwalk[];
194 extern gold *tmpgold[];
195 extern fountain *tmpfountain[];
196 extern sink *tmpsink[];
197 extern pool *tmppool[];
198 extern engraving *tmpengraving[];
199 extern mazepart *tmppart[];
200 extern room *tmproom[];
201
202 extern int n_olist, n_mlist, n_plist;
203
204 extern unsigned int nlreg, nreg, ndoor, ntrap, nmons, nobj;
205 extern unsigned int ndb, nwalk, npart, ndig, npass, nlad, nstair;
206 extern unsigned int naltar, ncorridor, nrooms, ngold, nengraving;
207 extern unsigned int nfountain, npool, nsink;
208
209 extern unsigned int max_x_map, max_y_map;
210
211 extern int line_number, colon_line_number;
212
213 int
214 main(argc, argv)
215 int argc;
216 char **argv;
217 {
218         FILE *fin;
219         int i;
220         boolean errors_encountered = FALSE;
221 #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
222         static char *mac_argv[] = {     "lev_comp",     /* dummy argv[0] */
223                                 ":dat:Arch.des",
224                                 ":dat:Barb.des",
225                                 ":dat:Caveman.des",
226                                 ":dat:Healer.des",
227                                 ":dat:Knight.des",
228                                 ":dat:Monk.des",
229                                 ":dat:Priest.des",
230                                 ":dat:Ranger.des",
231                                 ":dat:Rogue.des",
232                                 ":dat:Samurai.des",
233                                 ":dat:Tourist.des",
234                                 ":dat:Valkyrie.des",
235                                 ":dat:Wizard.des",
236                                 ":dat:bigroom.des",
237                                 ":dat:castle.des",
238                                 ":dat:endgame.des",
239                                 ":dat:gehennom.des",
240                                 ":dat:knox.des",
241                                 ":dat:medusa.des",
242                                 ":dat:mines.des",
243                                 ":dat:oracle.des",
244                                 ":dat:sokoban.des",
245                                 ":dat:tower.des",
246                                 ":dat:yendor.des"
247                                 };
248
249         argc = SIZE(mac_argv);
250         argv = mac_argv;
251 #endif
252         /* Note:  these initializers don't do anything except guarantee that
253                 we're linked properly.
254         */
255         monst_init();
256         objects_init();
257         decl_init();
258         /* this one does something... */
259         init_obj_classes();
260
261         init_yyout(stdout);
262         if (argc == 1) {                /* Read standard input */
263             init_yyin(stdin);
264             (void) yyparse();
265             if (fatal_error > 0) {
266                     errors_encountered = TRUE;
267             }
268         } else {                        /* Otherwise every argument is a filename */
269             for(i=1; i<argc; i++) {
270                     fname = argv[i];
271                     if(!strcmp(fname, "-w")) {
272                         want_warnings++;
273                         continue;
274                     }
275                     fin = freopen(fname, "r", stdin);
276                     if (!fin) {
277                         (void) fprintf(stderr,"Can't open \"%s\" for input.\n",
278                                                 fname);
279                         perror(fname);
280                         errors_encountered = TRUE;
281                     } else {
282                         init_yyin(fin);
283                         (void) yyparse();
284                         line_number = 1;
285                         if (fatal_error > 0) {
286                                 errors_encountered = TRUE;
287                                 fatal_error = 0;
288                         }
289                     }
290             }
291         }
292         exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS);
293         /*NOTREACHED*/
294         return 0;
295 }
296
297 /*
298  * Each time the parser detects an error, it uses this function.
299  * Here we take count of the errors. To continue farther than
300  * MAX_ERRORS wouldn't be reasonable.
301  * Assume that explicit calls from lev_comp.y have the 1st letter
302  * capitalized, to allow printing of the line containing the start of
303  * the current declaration, instead of the beginning of the next declaration.
304  */
305 void
306 yyerror(s)
307 const char *s;
308 {
309         (void) fprintf(stderr, "%s: line %d : %s\n", fname,
310                 (*s >= 'A' && *s <= 'Z') ? colon_line_number : line_number, s);
311         if (++fatal_error > MAX_ERRORS) {
312                 (void) fprintf(stderr,"Too many errors, good bye!\n");
313                 exit(EXIT_FAILURE);
314         }
315 }
316
317 /*
318  * Just display a warning (that is : a non fatal error)
319  */
320 void
321 yywarning(s)
322 const char *s;
323 {
324         (void) fprintf(stderr, "%s: line %d : WARNING : %s\n",
325                                 fname, colon_line_number, s);
326 }
327
328 /*
329  * Stub needed for lex interface.
330  */
331 int
332 yywrap()
333 {
334         return 1;
335 }
336
337 /*
338  * Find the type of floor, knowing its char representation.
339  */
340 int
341 get_floor_type(c)
342 char c;
343 {
344         int val;
345
346         SpinCursor(3);
347         val = what_map_char(c);
348         if(val == INVALID_TYPE) {
349             val = ERR;
350             yywarning("Invalid fill character in MAZE declaration");
351         }
352         return val;
353 }
354
355 /*
356  * Find the type of a room in the table, knowing its name.
357  */
358 int
359 get_room_type(s)
360 char *s;
361 {
362         register int i;
363
364         SpinCursor(3);
365         for(i=0; room_types[i].name; i++)
366             if (!strcmp(s, room_types[i].name))
367                 return ((int) room_types[i].type);
368         return ERR;
369 }
370
371 /*
372  * Find the type of a trap in the table, knowing its name.
373  */
374 int
375 get_trap_type(s)
376 char *s;
377 {
378         register int i;
379
380         SpinCursor(3);
381         for (i=0; trap_types[i].name; i++)
382             if(!strcmp(s,trap_types[i].name))
383                 return trap_types[i].type;
384         return ERR;
385 }
386
387 /*
388  * Find the index of a monster in the table, knowing its name.
389  */
390 int
391 get_monster_id(s, c)
392 char *s;
393 char c;
394 {
395         register int i, class;
396
397         SpinCursor(3);
398         class = c ? def_char_to_monclass(c) : 0;
399         if (class == MAXMCLASSES) return ERR;
400
401         for (i = LOW_PM; i < NUMMONS; i++)
402             if (!class || class == mons[i].mlet)
403                 if (!strcmp(s, mons[i].mname)) return i;
404         return ERR;
405 }
406
407 /*
408  * Find the index of an object in the table, knowing its name.
409  */
410 int
411 get_object_id(s, c)
412 char *s;
413 char c;         /* class */
414 {
415         int i, class;
416         const char *objname;
417
418         SpinCursor(3);
419         class = (c > 0) ? def_char_to_objclass(c) : 0;
420         if (class == MAXOCLASSES) return ERR;
421
422         for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) {
423             if (class && objects[i].oc_class != class) break;
424             objname = obj_descr[i].oc_name;
425             if (objname && !strcmp(s, objname))
426                 return i;
427         }
428         return ERR;
429 }
430
431 static void
432 init_obj_classes()
433 {
434         int i, class, prev_class;
435
436         prev_class = -1;
437         for (i = 0; i < NUM_OBJECTS; i++) {
438             class = objects[i].oc_class;
439             if (class != prev_class) {
440                 bases[class] = i;
441                 prev_class = class;
442             }
443         }
444 }
445
446 /*
447  * Is the character 'c' a valid monster class ?
448  */
449 boolean
450 check_monster_char(c)
451 char c;
452 {
453         return (def_char_to_monclass(c) != MAXMCLASSES);
454 }
455
456 /*
457  * Is the character 'c' a valid object class ?
458  */
459 boolean
460 check_object_char(c)
461 char c;
462 {
463         return (def_char_to_objclass(c) != MAXOCLASSES);
464 }
465
466 /*
467  * Convert .des map letter into floor type.
468  */
469 char
470 what_map_char(c)
471 char c;
472 {
473         SpinCursor(3);
474         switch(c) {
475                   case ' '  : return(STONE);
476                   case '#'  : return(CORR);
477                   case '.'  : return(ROOM);
478                   case '-'  : return(HWALL);
479                   case '|'  : return(VWALL);
480                   case '+'  : return(DOOR);
481                   case 'A'  : return(AIR);
482                   case 'B'  : return(CROSSWALL); /* hack: boundary location */
483                   case 'C'  : return(CLOUD);
484                   case 'S'  : return(SDOOR);
485                   case 'H'  : return(SCORR);
486                   case '{'  : return(FOUNTAIN);
487                   case '\\' : return(THRONE);
488                   case 'K'  :
489 #ifdef SINKS
490                       return(SINK);
491 #else
492                       yywarning("Sinks are not allowed in this version!  Ignoring...");
493                       return(ROOM);
494 #endif
495                   case '}'  : return(MOAT);
496                   case 'P'  : return(POOL);
497                   case 'L'  : return(LAVAPOOL);
498                   case 'I'  : return(ICE);
499                   case 'W'  : return(WATER);
500                   case 'T'      : return (TREE);
501                   case 'F'      : return (IRONBARS);    /* Fe = iron */
502             }
503         return(INVALID_TYPE);
504 }
505
506 /*
507  * Yep! LEX gives us the map in a raw mode.
508  * Just analyze it here.
509  */
510 void
511 scan_map(map)
512 char *map;
513 {
514         register int i, len;
515         register char *s1, *s2;
516         int max_len = 0;
517         int max_hig = 0;
518         char msg[256];
519
520         /* First, strip out digits 0-9 (line numbering) */
521         for (s1 = s2 = map; *s1; s1++)
522             if (*s1 < '0' || *s1 > '9')
523                 *s2++ = *s1;
524         *s2 = '\0';
525
526         /* Second, find the max width of the map */
527         s1 = map;
528         while (s1 && *s1) {
529                 s2 = index(s1, '\n');
530                 if (s2) {
531                         len = (int) (s2 - s1);
532                         s1 = s2 + 1;
533                 } else {
534                         len = (int) strlen(s1);
535                         s1 = (char *) 0;
536                 }
537                 if (len > max_len) max_len = len;
538         }
539
540         /* Then parse it now */
541         while (map && *map) {
542                 tmpmap[max_hig] = (char *) alloc(max_len);
543                 s1 = index(map, '\n');
544                 if (s1) {
545                         len = (int) (s1 - map);
546                         s1++;
547                 } else {
548                         len = (int) strlen(map);
549                         s1 = map + len;
550                 }
551                 for(i=0; i<len; i++)
552                   if((tmpmap[max_hig][i] = what_map_char(map[i])) == INVALID_TYPE) {
553                       Sprintf(msg,
554                          "Invalid character @ (%d, %d) - replacing with stone",
555                               max_hig, i);
556                       yywarning(msg);
557                       tmpmap[max_hig][i] = STONE;
558                     }
559                 while(i < max_len)
560                     tmpmap[max_hig][i++] = STONE;
561                 map = s1;
562                 max_hig++;
563         }
564
565         /* Memorize boundaries */
566
567         max_x_map = max_len - 1;
568         max_y_map = max_hig - 1;
569
570         /* Store the map into the mazepart structure */
571
572         if(max_len > MAP_X_LIM || max_hig > MAP_Y_LIM) {
573             Sprintf(msg, "Map too large! (max %d x %d)", MAP_X_LIM, MAP_Y_LIM);
574             yyerror(msg);
575         }
576
577         tmppart[npart]->xsize = max_len;
578         tmppart[npart]->ysize = max_hig;
579         tmppart[npart]->map = (char **) alloc(max_hig*sizeof(char *));
580         for(i = 0; i< max_hig; i++)
581             tmppart[npart]->map[i] = tmpmap[i];
582 }
583
584 /*
585  *      If we have drawn a map without walls, this allows us to
586  *      auto-magically wallify it.
587  */
588 #define Map_point(x,y) *(tmppart[npart]->map[y] + x)
589
590 void
591 wallify_map()
592 {
593         unsigned int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy;
594
595         for (y = 0; y <= max_y_map; y++) {
596             SpinCursor(3);
597             lo_yy = (y > 0) ? y - 1 : 0;
598             hi_yy = (y < max_y_map) ? y + 1 : max_y_map;
599             for (x = 0; x <= max_x_map; x++) {
600                 if (Map_point(x,y) != STONE) continue;
601                 lo_xx = (x > 0) ? x - 1 : 0;
602                 hi_xx = (x < max_x_map) ? x + 1 : max_x_map;
603                 for (yy = lo_yy; yy <= hi_yy; yy++)
604                     for (xx = lo_xx; xx <= hi_xx; xx++)
605                         if (IS_ROOM(Map_point(xx,yy)) ||
606                                 Map_point(xx,yy) == CROSSWALL) {
607                             Map_point(x,y) = (yy != y) ? HWALL : VWALL;
608                             yy = hi_yy;         /* end `yy' loop */
609                             break;              /* end `xx' loop */
610                         }
611             }
612         }
613 }
614
615 /*
616  * We need to check the subrooms apartenance to an existing room.
617  */
618 boolean
619 check_subrooms()
620 {
621         unsigned i, j, n_subrooms;
622         boolean found, ok = TRUE;
623         char    *last_parent, msg[256];
624
625         for (i = 0; i < nrooms; i++)
626             if (tmproom[i]->parent) {
627                 found = FALSE;
628                 for(j = 0; j < nrooms; j++)
629                     if (tmproom[j]->name &&
630                             !strcmp(tmproom[i]->parent, tmproom[j]->name)) {
631                         found = TRUE;
632                         break;
633                     }
634                 if (!found) {
635                     Sprintf(msg,
636                             "Subroom error : parent room '%s' not found!",
637                             tmproom[i]->parent);
638                     yyerror(msg);
639                     ok = FALSE;
640                 }
641             }
642
643         msg[0] = '\0';
644         last_parent = msg;
645         for (i = 0; i < nrooms; i++)
646             if (tmproom[i]->parent) {
647                 n_subrooms = 0;
648                 for(j = i; j < nrooms; j++) {
649 /*
650  *      This is by no means perfect, but should cut down the duplicate error
651  *      messages by over 90%.  The only problem will be when either subrooms
652  *      are mixed in the level definition (not likely but possible) or rooms
653  *      have subrooms that have subrooms.
654  */
655                     if (!strcmp(tmproom[i]->parent, last_parent)) continue;
656                     if (tmproom[j]->parent &&
657                             !strcmp(tmproom[i]->parent, tmproom[j]->parent)) {
658                         n_subrooms++;
659                         if(n_subrooms > MAX_SUBROOMS) {
660
661                             Sprintf(msg,
662               "Subroom error: too many subrooms attached to parent room '%s'!",
663                                     tmproom[i]->parent);
664                             yyerror(msg);
665                             last_parent = tmproom[i]->parent;
666                             ok = FALSE;
667                             break;
668                         }
669                     }
670                 }
671             }
672         return ok;
673 }
674
675 /*
676  * Check that coordinates (x,y) are roomlike locations.
677  * Print warning "str" if they aren't.
678  */
679 void
680 check_coord(x, y, str)
681 int x, y;
682 const char *str;
683 {
684     char ebuf[60];
685
686     if (x >= 0 && y >= 0 && x <= (int)max_x_map && y <= (int)max_y_map &&
687         (IS_ROCK(tmpmap[y][x]) || IS_DOOR(tmpmap[y][x]))) {
688         Sprintf(ebuf, "%s placed in wall at (%02d,%02d)?!", str, x, y);
689         yywarning(ebuf);
690     }
691 }
692
693 /*
694  * Here we want to store the maze part we just got.
695  */
696 void
697 store_part()
698 {
699         register unsigned i;
700
701         /* Ok, We got the whole part, now we store it. */
702
703         /* The Regions */
704
705         if ((tmppart[npart]->nreg = nreg) != 0) {
706                 tmppart[npart]->regions = NewTab(region, nreg);
707                 for(i=0;i<nreg;i++)
708                     tmppart[npart]->regions[i] = tmpreg[i];
709         }
710         nreg = 0;
711
712         /* The Level Regions */
713
714         if ((tmppart[npart]->nlreg = nlreg) != 0) {
715                 tmppart[npart]->lregions = NewTab(lev_region, nlreg);
716                 for(i=0;i<nlreg;i++)
717                     tmppart[npart]->lregions[i] = tmplreg[i];
718         }
719         nlreg = 0;
720
721         /* the doors */
722
723         if ((tmppart[npart]->ndoor = ndoor) != 0) {
724                 tmppart[npart]->doors = NewTab(door, ndoor);
725                 for(i=0;i<ndoor;i++)
726                     tmppart[npart]->doors[i] = tmpdoor[i];
727         }
728         ndoor = 0;
729
730         /* the drawbridges */
731
732         if ((tmppart[npart]->ndrawbridge = ndb) != 0) {
733                 tmppart[npart]->drawbridges = NewTab(drawbridge, ndb);
734                 for(i=0;i<ndb;i++)
735                     tmppart[npart]->drawbridges[i] = tmpdb[i];
736         }
737         ndb = 0;
738
739         /* The walkmaze directives */
740
741         if ((tmppart[npart]->nwalk = nwalk) != 0) {
742                 tmppart[npart]->walks = NewTab(walk, nwalk);
743                 for(i=0;i<nwalk;i++)
744                     tmppart[npart]->walks[i] = tmpwalk[i];
745         }
746         nwalk = 0;
747
748         /* The non_diggable directives */
749
750         if ((tmppart[npart]->ndig = ndig) != 0) {
751                 tmppart[npart]->digs = NewTab(digpos, ndig);
752                 for(i=0;i<ndig;i++)
753                     tmppart[npart]->digs[i] = tmpdig[i];
754         }
755         ndig = 0;
756
757         /* The non_passwall directives */
758
759         if ((tmppart[npart]->npass = npass) != 0) {
760                 tmppart[npart]->passs = NewTab(digpos, npass);
761                 for(i=0;i<npass;i++)
762                     tmppart[npart]->passs[i] = tmppass[i];
763         }
764         npass = 0;
765
766         /* The ladders */
767
768         if ((tmppart[npart]->nlad = nlad) != 0) {
769                 tmppart[npart]->lads = NewTab(lad, nlad);
770                 for(i=0;i<nlad;i++)
771                     tmppart[npart]->lads[i] = tmplad[i];
772         }
773         nlad = 0;
774
775         /* The stairs */
776
777         if ((tmppart[npart]->nstair = nstair) != 0) {
778                 tmppart[npart]->stairs = NewTab(stair, nstair);
779                 for(i=0;i<nstair;i++)
780                     tmppart[npart]->stairs[i] = tmpstair[i];
781         }
782         nstair = 0;
783
784         /* The altars */
785         if ((tmppart[npart]->naltar = naltar) != 0) {
786                 tmppart[npart]->altars = NewTab(altar, naltar);
787                 for(i=0;i<naltar;i++)
788                     tmppart[npart]->altars[i] = tmpaltar[i];
789         }
790         naltar = 0;
791
792         /* The fountains */
793
794         if ((tmppart[npart]->nfountain = nfountain) != 0) {
795                 tmppart[npart]->fountains = NewTab(fountain, nfountain);
796                 for(i=0;i<nfountain;i++)
797                     tmppart[npart]->fountains[i] = tmpfountain[i];
798         }
799         nfountain = 0;
800
801         /* the traps */
802
803         if ((tmppart[npart]->ntrap = ntrap) != 0) {
804                 tmppart[npart]->traps = NewTab(trap, ntrap);
805                 for(i=0;i<ntrap;i++)
806                     tmppart[npart]->traps[i] = tmptrap[i];
807         }
808         ntrap = 0;
809
810         /* the monsters */
811
812         if ((tmppart[npart]->nmonster = nmons) != 0) {
813                 tmppart[npart]->monsters = NewTab(monster, nmons);
814                 for(i=0;i<nmons;i++)
815                     tmppart[npart]->monsters[i] = tmpmonst[i];
816         } else
817                 tmppart[npart]->monsters = 0;
818         nmons = 0;
819
820         /* the objects */
821
822         if ((tmppart[npart]->nobject = nobj) != 0) {
823                 tmppart[npart]->objects = NewTab(object, nobj);
824                 for(i=0;i<nobj;i++)
825                     tmppart[npart]->objects[i] = tmpobj[i];
826         } else
827                 tmppart[npart]->objects = 0;
828         nobj = 0;
829
830         /* The gold piles */
831
832         if ((tmppart[npart]->ngold = ngold) != 0) {
833                 tmppart[npart]->golds = NewTab(gold, ngold);
834                 for(i=0;i<ngold;i++)
835                     tmppart[npart]->golds[i] = tmpgold[i];
836         }
837         ngold = 0;
838
839         /* The engravings */
840
841         if ((tmppart[npart]->nengraving = nengraving) != 0) {
842                 tmppart[npart]->engravings = NewTab(engraving, nengraving);
843                 for(i=0;i<nengraving;i++)
844                     tmppart[npart]->engravings[i] = tmpengraving[i];
845         } else
846                 tmppart[npart]->engravings = 0;
847         nengraving = 0;
848
849         npart++;
850         n_plist = n_mlist = n_olist = 0;
851 }
852
853 /*
854  * Here we want to store the room part we just got.
855  */
856 void
857 store_room()
858 {
859         register unsigned i;
860
861         /* Ok, We got the whole room, now we store it. */
862
863         /* the doors */
864
865         if ((tmproom[nrooms]->ndoor = ndoor) != 0) {
866                 tmproom[nrooms]->doors = NewTab(room_door, ndoor);
867                 for(i=0;i<ndoor;i++)
868                     tmproom[nrooms]->doors[i] = tmprdoor[i];
869         }
870         ndoor = 0;
871
872         /* The stairs */
873
874         if ((tmproom[nrooms]->nstair = nstair) != 0) {
875                 tmproom[nrooms]->stairs = NewTab(stair, nstair);
876                 for(i=0;i<nstair;i++)
877                     tmproom[nrooms]->stairs[i] = tmpstair[i];
878         }
879         nstair = 0;
880
881         /* The altars */
882         if ((tmproom[nrooms]->naltar = naltar) != 0) {
883                 tmproom[nrooms]->altars = NewTab(altar, naltar);
884                 for(i=0;i<naltar;i++)
885                     tmproom[nrooms]->altars[i] = tmpaltar[i];
886         }
887         naltar = 0;
888
889         /* The fountains */
890
891         if ((tmproom[nrooms]->nfountain = nfountain) != 0) {
892                 tmproom[nrooms]->fountains = NewTab(fountain, nfountain);
893                 for(i=0;i<nfountain;i++)
894                     tmproom[nrooms]->fountains[i] = tmpfountain[i];
895         }
896         nfountain = 0;
897
898         /* The sinks */
899
900         if ((tmproom[nrooms]->nsink = nsink) != 0) {
901                 tmproom[nrooms]->sinks = NewTab(sink, nsink);
902                 for(i=0;i<nsink;i++)
903                     tmproom[nrooms]->sinks[i] = tmpsink[i];
904         }
905         nsink = 0;
906
907         /* The pools */
908
909         if ((tmproom[nrooms]->npool = npool) != 0) {
910                 tmproom[nrooms]->pools = NewTab(pool, npool);
911                 for(i=0;i<npool;i++)
912                     tmproom[nrooms]->pools[i] = tmppool[i];
913         }
914         npool = 0;
915
916         /* the traps */
917
918         if ((tmproom[nrooms]->ntrap = ntrap) != 0) {
919                 tmproom[nrooms]->traps = NewTab(trap, ntrap);
920                 for(i=0;i<ntrap;i++)
921                     tmproom[nrooms]->traps[i] = tmptrap[i];
922         }
923         ntrap = 0;
924
925         /* the monsters */
926
927         if ((tmproom[nrooms]->nmonster = nmons) != 0) {
928                 tmproom[nrooms]->monsters = NewTab(monster, nmons);
929                 for(i=0;i<nmons;i++)
930                     tmproom[nrooms]->monsters[i] = tmpmonst[i];
931         } else
932                 tmproom[nrooms]->monsters = 0;
933         nmons = 0;
934
935         /* the objects */
936
937         if ((tmproom[nrooms]->nobject = nobj) != 0) {
938                 tmproom[nrooms]->objects = NewTab(object, nobj);
939                 for(i=0;i<nobj;i++)
940                     tmproom[nrooms]->objects[i] = tmpobj[i];
941         } else
942                 tmproom[nrooms]->objects = 0;
943         nobj = 0;
944
945         /* The gold piles */
946
947         if ((tmproom[nrooms]->ngold = ngold) != 0) {
948                 tmproom[nrooms]->golds = NewTab(gold, ngold);
949                 for(i=0;i<ngold;i++)
950                     tmproom[nrooms]->golds[i] = tmpgold[i];
951         }
952         ngold = 0;
953
954         /* The engravings */
955
956         if ((tmproom[nrooms]->nengraving = nengraving) != 0) {
957                 tmproom[nrooms]->engravings = NewTab(engraving, nengraving);
958                 for(i=0;i<nengraving;i++)
959                     tmproom[nrooms]->engravings[i] = tmpengraving[i];
960         } else
961                 tmproom[nrooms]->engravings = 0;
962         nengraving = 0;
963
964         nrooms++;
965 }
966
967 /*
968  * Output some info common to all special levels.
969  */
970 static boolean
971 write_common_data(fd, typ, init, flgs)
972 int fd, typ;
973 lev_init *init;
974 long flgs;
975 {
976         char c;
977         uchar len;
978         static struct version_info version_data = {
979                         VERSION_NUMBER, VERSION_FEATURES,
980                         VERSION_SANITY1, VERSION_SANITY2
981         };
982
983         Write(fd, &version_data, sizeof version_data);
984         c = typ;
985         Write(fd, &c, sizeof(c));       /* 1 byte header */
986         Write(fd, init, sizeof(lev_init));
987         Write(fd, &flgs, sizeof flgs);
988
989         len = (uchar) strlen(tmpmessage);
990         Write(fd, &len, sizeof len);
991         if (len) Write(fd, tmpmessage, (int) len);
992         tmpmessage[0] = '\0';
993         return TRUE;
994 }
995
996 /*
997  * Output monster info, which needs string fixups, then release memory.
998  */
999 static boolean
1000 write_monsters(fd, nmonster_p, monsters_p)
1001 int fd;
1002 char *nmonster_p;
1003 monster ***monsters_p;
1004 {
1005         monster *m;
1006         char *name, *appr;
1007         int j, n = (int)*nmonster_p;
1008
1009         Write(fd, nmonster_p, sizeof *nmonster_p);
1010         for (j = 0; j < n; j++) {
1011             m = (*monsters_p)[j];
1012             name = m->name.str;
1013             appr = m->appear_as.str;
1014             m->name.str = m->appear_as.str = 0;
1015             m->name.len = name ? strlen(name) : 0;
1016             m->appear_as.len = appr ? strlen(appr) : 0;
1017             Write(fd, m, sizeof *m);
1018             if (name) {
1019                 Write(fd, name, m->name.len);
1020                 Free(name);
1021             }
1022             if (appr) {
1023                 Write(fd, appr, m->appear_as.len);
1024                 Free(appr);
1025             }
1026             Free(m);
1027         }
1028         if (*monsters_p) {
1029             Free(*monsters_p);
1030             *monsters_p = 0;
1031         }
1032         *nmonster_p = 0;
1033         return TRUE;
1034 }
1035
1036 /*
1037  * Output object info, which needs string fixup, then release memory.
1038  */
1039 static boolean
1040 write_objects(fd, nobject_p, objects_p)
1041 int fd;
1042 char *nobject_p;
1043 object ***objects_p;
1044 {
1045         object *o;
1046         char *name;
1047         int j, n = (int)*nobject_p;
1048
1049         Write(fd, nobject_p, sizeof *nobject_p);
1050         for (j = 0; j < n; j++) {
1051             o = (*objects_p)[j];
1052             name = o->name.str;
1053             o->name.str = 0;    /* reset in case `len' is narrower */
1054             o->name.len = name ? strlen(name) : 0;
1055             Write(fd, o, sizeof *o);
1056             if (name) {
1057                 Write(fd, name, o->name.len);
1058                 Free(name);
1059             }
1060             Free(o);
1061         }
1062         if (*objects_p) {
1063             Free(*objects_p);
1064             *objects_p = 0;
1065         }
1066         *nobject_p = 0;
1067         return TRUE;
1068 }
1069
1070 /*
1071  * Output engraving info, which needs string fixup, then release memory.
1072  */
1073 static boolean
1074 write_engravings(fd, nengraving_p, engravings_p)
1075 int fd;
1076 char *nengraving_p;
1077 engraving ***engravings_p;
1078 {
1079         engraving *e;
1080         char *engr;
1081         int j, n = (int)*nengraving_p;
1082
1083         Write(fd, nengraving_p, sizeof *nengraving_p);
1084         for (j = 0; j < n; j++) {
1085             e = (*engravings_p)[j];
1086             engr = e->engr.str;
1087             e->engr.str = 0;    /* reset in case `len' is narrower */
1088             e->engr.len = strlen(engr);
1089             Write(fd, e, sizeof *e);
1090             Write(fd, engr, e->engr.len);
1091             Free(engr);
1092             Free(e);
1093         }
1094         if (*engravings_p) {
1095             Free(*engravings_p);
1096             *engravings_p = 0;
1097         }
1098         *nengraving_p = 0;
1099         return TRUE;
1100 }
1101
1102 /*
1103  * Open and write maze or rooms file, based on which pointer is non-null.
1104  * Return TRUE on success, FALSE on failure.
1105  */
1106 boolean
1107 write_level_file(filename, room_level, maze_level)
1108 char *filename;
1109 splev *room_level;
1110 specialmaze *maze_level;
1111 {
1112         int fout;
1113         char lbuf[60];
1114
1115         lbuf[0] = '\0';
1116 #ifdef PREFIX
1117         Strcat(lbuf, PREFIX);
1118 #endif
1119         Strcat(lbuf, filename);
1120         Strcat(lbuf, LEV_EXT);
1121
1122 #if defined(MAC) && (defined(__SC__) || defined(__MRC__))
1123         fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
1124 #else
1125         fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
1126 #endif
1127         if (fout < 0) return FALSE;
1128
1129         if (room_level) {
1130             if (!write_rooms(fout, room_level))
1131                 return FALSE;
1132         } else if (maze_level) {
1133             if (!write_maze(fout, maze_level))
1134                 return FALSE;
1135         } else
1136             panic("write_level_file");
1137
1138         (void) close(fout);
1139         return TRUE;
1140 }
1141
1142 /*
1143  * Here we write the structure of the maze in the specified file (fd).
1144  * Also, we have to free the memory allocated via alloc().
1145  */
1146 static boolean
1147 write_maze(fd, maze)
1148 int fd;
1149 specialmaze *maze;
1150 {
1151         short i,j;
1152         mazepart *pt;
1153
1154         if (!write_common_data(fd, SP_LEV_MAZE, &(maze->init_lev), maze->flags))
1155             return FALSE;
1156
1157         Write(fd, &(maze->filling), sizeof(maze->filling));
1158         Write(fd, &(maze->numpart), sizeof(maze->numpart));
1159                                          /* Number of parts */
1160         for(i=0;i<maze->numpart;i++) {
1161             pt = maze->parts[i];
1162
1163             /* First, write the map */
1164
1165             Write(fd, &(pt->halign), sizeof(pt->halign));
1166             Write(fd, &(pt->valign), sizeof(pt->valign));
1167             Write(fd, &(pt->xsize), sizeof(pt->xsize));
1168             Write(fd, &(pt->ysize), sizeof(pt->ysize));
1169             for(j=0;j<pt->ysize;j++) {
1170                 if(!maze->init_lev.init_present ||
1171                    pt->xsize > 1 || pt->ysize > 1) {
1172 #if !defined(_MSC_VER) && !defined(__BORLANDC__)
1173                         Write(fd, pt->map[j], pt->xsize * sizeof *pt->map[j]);
1174 #else
1175                         /*
1176                          * On MSVC and Borland C compilers the Write macro above caused:
1177                          * warning '!=' : signed/unsigned mismatch
1178                          */
1179                         unsigned reslt, sz = pt->xsize * sizeof *pt->map[j];
1180                         reslt = write(fd, (genericptr_t)(pt->map[j]), sz);
1181                         if (reslt != sz) return FALSE;
1182 #endif
1183                 }
1184                 Free(pt->map[j]);
1185             }
1186             Free(pt->map);
1187
1188             /* level region stuff */
1189             Write(fd, &pt->nlreg, sizeof pt->nlreg);
1190             for (j = 0; j < pt->nlreg; j++) {
1191                 lev_region *l = pt->lregions[j];
1192                 char *rname = l->rname.str;
1193                 l->rname.str = 0;       /* reset in case `len' is narrower */
1194                 l->rname.len = rname ? strlen(rname) : 0;
1195                 Write(fd, l, sizeof *l);
1196                 if (rname) {
1197                     Write(fd, rname, l->rname.len);
1198                     Free(rname);
1199                 }
1200                 Free(l);
1201             }
1202             if (pt->nlreg > 0)
1203                 Free(pt->lregions);
1204
1205             /* The random registers */
1206             Write(fd, &(pt->nrobjects), sizeof(pt->nrobjects));
1207             if(pt->nrobjects) {
1208                     Write(fd, pt->robjects, pt->nrobjects);
1209                     Free(pt->robjects);
1210             }
1211             Write(fd, &(pt->nloc), sizeof(pt->nloc));
1212             if(pt->nloc) {
1213                     Write(fd, pt->rloc_x, pt->nloc);
1214                     Write(fd, pt->rloc_y, pt->nloc);
1215                     Free(pt->rloc_x);
1216                     Free(pt->rloc_y);
1217             }
1218             Write(fd, &(pt->nrmonst), sizeof(pt->nrmonst));
1219             if(pt->nrmonst) {
1220                     Write(fd, pt->rmonst, pt->nrmonst);
1221                     Free(pt->rmonst);
1222             }
1223
1224             /* subrooms */
1225             Write(fd, &(pt->nreg), sizeof(pt->nreg));
1226             for(j=0;j<pt->nreg;j++) {
1227                     Write(fd, pt->regions[j], sizeof(region));
1228                     Free(pt->regions[j]);
1229             }
1230             if(pt->nreg > 0)
1231                     Free(pt->regions);
1232
1233             /* the doors */
1234             Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
1235             for(j=0;j<pt->ndoor;j++) {
1236                     Write(fd, pt->doors[j], sizeof(door));
1237                     Free(pt->doors[j]);
1238             }
1239             if (pt->ndoor > 0)
1240                     Free(pt->doors);
1241
1242             /* The drawbridges */
1243             Write(fd, &(pt->ndrawbridge), sizeof(pt->ndrawbridge));
1244             for(j=0;j<pt->ndrawbridge;j++) {
1245                     Write(fd, pt->drawbridges[j], sizeof(drawbridge));
1246                     Free(pt->drawbridges[j]);
1247             }
1248             if(pt->ndrawbridge > 0)
1249                     Free(pt->drawbridges);
1250
1251             /* The mazewalk directives */
1252             Write(fd, &(pt->nwalk), sizeof(pt->nwalk));
1253             for(j=0; j<pt->nwalk; j++) {
1254                     Write(fd, pt->walks[j], sizeof(walk));
1255                     Free(pt->walks[j]);
1256             }
1257             if (pt->nwalk > 0)
1258                     Free(pt->walks);
1259
1260             /* The non_diggable directives */
1261             Write(fd, &(pt->ndig), sizeof(pt->ndig));
1262             for(j=0;j<pt->ndig;j++) {
1263                     Write(fd, pt->digs[j], sizeof(digpos));
1264                     Free(pt->digs[j]);
1265             }
1266             if (pt->ndig > 0)
1267                     Free(pt->digs);
1268
1269             /* The non_passwall directives */
1270             Write(fd, &(pt->npass), sizeof(pt->npass));
1271             for(j=0;j<pt->npass;j++) {
1272                     Write(fd, pt->passs[j], sizeof(digpos));
1273                     Free(pt->passs[j]);
1274             }
1275             if (pt->npass > 0)
1276                     Free(pt->passs);
1277
1278             /* The ladders */
1279             Write(fd, &(pt->nlad), sizeof(pt->nlad));
1280             for(j=0;j<pt->nlad;j++) {
1281                     Write(fd, pt->lads[j], sizeof(lad));
1282                     Free(pt->lads[j]);
1283             }
1284             if (pt->nlad > 0)
1285                     Free(pt->lads);
1286
1287             /* The stairs */
1288             Write(fd, &(pt->nstair), sizeof(pt->nstair));
1289             for(j=0;j<pt->nstair;j++) {
1290                     Write(fd, pt->stairs[j], sizeof(stair));
1291                     Free(pt->stairs[j]);
1292             }
1293             if (pt->nstair > 0)
1294                     Free(pt->stairs);
1295
1296             /* The altars */
1297             Write(fd, &(pt->naltar), sizeof(pt->naltar));
1298             for(j=0;j<pt->naltar;j++) {
1299                     Write(fd, pt->altars[j], sizeof(altar));
1300                     Free(pt->altars[j]);
1301             }
1302             if (pt->naltar > 0)
1303                     Free(pt->altars);
1304
1305             /* The fountains */
1306             Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
1307             for(j=0;j<pt->nfountain;j++) {
1308                 Write(fd, pt->fountains[j], sizeof(fountain));
1309                 Free(pt->fountains[j]);
1310             }
1311             if (pt->nfountain > 0)
1312                     Free(pt->fountains);
1313
1314             /* The traps */
1315             Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
1316             for(j=0;j<pt->ntrap;j++) {
1317                     Write(fd, pt->traps[j], sizeof(trap));
1318                     Free(pt->traps[j]);
1319             }
1320             if (pt->ntrap)
1321                     Free(pt->traps);
1322
1323             /* The monsters */
1324             if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
1325                     return FALSE;
1326
1327             /* The objects */
1328             if (!write_objects(fd, &pt->nobject, &pt->objects))
1329                     return FALSE;
1330
1331             /* The gold piles */
1332             Write(fd, &(pt->ngold), sizeof(pt->ngold));
1333             for(j=0;j<pt->ngold;j++) {
1334                     Write(fd, pt->golds[j], sizeof(gold));
1335                     Free(pt->golds[j]);
1336             }
1337             if (pt->ngold > 0)
1338                     Free(pt->golds);
1339
1340             /* The engravings */
1341             if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
1342                     return FALSE;
1343
1344             Free(pt);
1345         }
1346
1347         Free(maze->parts);
1348         maze->parts = (mazepart **)0;
1349         maze->numpart = 0;
1350         return TRUE;
1351 }
1352
1353 /*
1354  * Here we write the structure of the room level in the specified file (fd).
1355  */
1356 static boolean
1357 write_rooms(fd, lev)
1358 int fd;
1359 splev *lev;
1360 {
1361         short i,j, size;
1362         room *pt;
1363
1364         if (!write_common_data(fd, SP_LEV_ROOMS, &(lev->init_lev), lev->flags))
1365                 return FALSE;
1366
1367         /* Random registers */
1368
1369         Write(fd, &lev->nrobjects, sizeof(lev->nrobjects));
1370         if (lev->nrobjects)
1371                 Write(fd, lev->robjects, lev->nrobjects);
1372         Write(fd, &lev->nrmonst, sizeof(lev->nrmonst));
1373         if (lev->nrmonst)
1374                 Write(fd, lev->rmonst, lev->nrmonst);
1375
1376         Write(fd, &(lev->nroom), sizeof(lev->nroom));
1377                                                         /* Number of rooms */
1378         for(i=0;i<lev->nroom;i++) {
1379                 pt = lev->rooms[i];
1380
1381                 /* Room characteristics */
1382
1383                 size = (short) (pt->name ? strlen(pt->name) : 0);
1384                 Write(fd, &size, sizeof(size));
1385                 if (size)
1386                         Write(fd, pt->name, size);
1387
1388                 size = (short) (pt->parent ? strlen(pt->parent) : 0);
1389                 Write(fd, &size, sizeof(size));
1390                 if (size)
1391                         Write(fd, pt->parent, size);
1392
1393                 Write(fd, &(pt->x), sizeof(pt->x));
1394                 Write(fd, &(pt->y), sizeof(pt->y));
1395                 Write(fd, &(pt->w), sizeof(pt->w));
1396                 Write(fd, &(pt->h), sizeof(pt->h));
1397                 Write(fd, &(pt->xalign), sizeof(pt->xalign));
1398                 Write(fd, &(pt->yalign), sizeof(pt->yalign));
1399                 Write(fd, &(pt->rtype), sizeof(pt->rtype));
1400                 Write(fd, &(pt->chance), sizeof(pt->chance));
1401                 Write(fd, &(pt->rlit), sizeof(pt->rlit));
1402                 Write(fd, &(pt->filled), sizeof(pt->filled));
1403
1404                 /* the doors */
1405                 Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
1406                 for(j=0;j<pt->ndoor;j++)
1407                         Write(fd, pt->doors[j], sizeof(room_door));
1408
1409                 /* The stairs */
1410                 Write(fd, &(pt->nstair), sizeof(pt->nstair));
1411                 for(j=0;j<pt->nstair;j++)
1412                         Write(fd, pt->stairs[j], sizeof(stair));
1413
1414                 /* The altars */
1415                 Write(fd, &(pt->naltar), sizeof(pt->naltar));
1416                 for(j=0;j<pt->naltar;j++)
1417                         Write(fd, pt->altars[j], sizeof(altar));
1418
1419                 /* The fountains */
1420                 Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
1421                 for(j=0;j<pt->nfountain;j++)
1422                         Write(fd, pt->fountains[j], sizeof(fountain));
1423
1424                 /* The sinks */
1425                 Write(fd, &(pt->nsink), sizeof(pt->nsink));
1426                 for(j=0;j<pt->nsink;j++)
1427                         Write(fd, pt->sinks[j], sizeof(sink));
1428
1429                 /* The pools */
1430                 Write(fd, &(pt->npool), sizeof(pt->npool));
1431                 for(j=0;j<pt->npool;j++)
1432                         Write(fd, pt->pools[j], sizeof(pool));
1433
1434                 /* The traps */
1435                 Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
1436                 for(j=0;j<pt->ntrap;j++)
1437                         Write(fd, pt->traps[j], sizeof(trap));
1438
1439                 /* The monsters */
1440                 if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
1441                         return FALSE;
1442
1443                 /* The objects */
1444                 if (!write_objects(fd, &pt->nobject, &pt->objects))
1445                         return FALSE;
1446
1447                 /* The gold piles */
1448                 Write(fd, &(pt->ngold), sizeof(pt->ngold));
1449                 for(j=0;j<pt->ngold;j++)
1450                         Write(fd, pt->golds[j], sizeof(gold));
1451
1452                 /* The engravings */
1453                 if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
1454                         return FALSE;
1455
1456         }
1457
1458         /* The corridors */
1459         Write(fd, &lev->ncorr, sizeof(lev->ncorr));
1460         for (i=0; i < lev->ncorr; i++)
1461                 Write(fd, lev->corrs[i], sizeof(corridor));
1462         return TRUE;
1463 }
1464
1465 /*
1466  * Release memory allocated to a rooms-style special level; maze-style
1467  * levels have the fields freed as they're written; monsters, objects, and
1468  * engravings are freed as written for both styles, so not handled here.
1469  */
1470 void
1471 free_rooms(lev)
1472 splev *lev;
1473 {
1474         room *r;
1475         int j, n = lev->nroom;
1476
1477         while(n--) {
1478                 r = lev->rooms[n];
1479                 Free(r->name);
1480                 Free(r->parent);
1481                 if ((j = r->ndoor) != 0) {
1482                         while(j--)
1483                                 Free(r->doors[j]);
1484                         Free(r->doors);
1485                 }
1486                 if ((j = r->nstair) != 0) {
1487                         while(j--)
1488                                 Free(r->stairs[j]);
1489                         Free(r->stairs);
1490                 }
1491                 if ((j = r->naltar) != 0) {
1492                         while (j--)
1493                                 Free(r->altars[j]);
1494                         Free(r->altars);
1495                 }
1496                 if ((j = r->nfountain) != 0) {
1497                         while(j--)
1498                                 Free(r->fountains[j]);
1499                         Free(r->fountains);
1500                 }
1501                 if ((j = r->nsink) != 0) {
1502                         while(j--)
1503                                 Free(r->sinks[j]);
1504                         Free(r->sinks);
1505                 }
1506                 if ((j = r->npool) != 0) {
1507                         while(j--)
1508                                 Free(r->pools[j]);
1509                         Free(r->pools);
1510                 }
1511                 if ((j = r->ntrap) != 0) {
1512                         while (j--)
1513                                 Free(r->traps[j]);
1514                         Free(r->traps);
1515                 }
1516                 if ((j = r->ngold) != 0) {
1517                         while(j--)
1518                                 Free(r->golds[j]);
1519                         Free(r->golds);
1520                 }
1521                 Free(r);
1522                 lev->rooms[n] = (room *)0;
1523         }
1524         Free(lev->rooms);
1525         lev->rooms = (room **)0;
1526         lev->nroom = 0;
1527
1528         for (j = 0; j < lev->ncorr; j++) {
1529                 Free(lev->corrs[j]);
1530                 lev->corrs[j] = (corridor *)0;
1531         }
1532         Free(lev->corrs);
1533         lev->corrs = (corridor **)0;
1534         lev->ncorr = 0;
1535
1536         Free(lev->robjects);
1537         lev->robjects = (char *)0;
1538         lev->nrobjects = 0;
1539         Free(lev->rmonst);
1540         lev->rmonst = (char *)0;
1541         lev->nrmonst = 0;
1542 }
1543
1544 #ifdef STRICT_REF_DEF
1545 /*
1546  * Any globals declared in hack.h and descendents which aren't defined
1547  * in the modules linked into lev_comp should be defined here.  These
1548  * definitions can be dummies:  their sizes shouldn't matter as long as
1549  * as their types are correct; actual values are irrelevant.
1550  */
1551 #define ARBITRARY_SIZE 1
1552 /* attrib.c */
1553 struct attribs attrmax, attrmin;
1554 /* files.c */
1555 const char *configfile;
1556 char lock[ARBITRARY_SIZE];
1557 char SAVEF[ARBITRARY_SIZE];
1558 # ifdef MICRO
1559 char SAVEP[ARBITRARY_SIZE];
1560 # endif
1561 /* termcap.c */
1562 struct tc_lcl_data tc_lcl_data;
1563 # ifdef TEXTCOLOR
1564 #  ifdef TOS
1565 const char *hilites[CLR_MAX];
1566 #  else
1567 char NEARDATA *hilites[CLR_MAX];
1568 #  endif
1569 # endif
1570 /* trap.c */
1571 const char *traps[TRAPNUM];
1572 /* window.c */
1573 struct window_procs windowprocs;
1574 /* xxxtty.c */
1575 # ifdef DEFINE_OSPEED
1576 short ospeed;
1577 # endif
1578 #endif  /* STRICT_REF_DEF */
1579
1580 /*lev_main.c*/