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
main(argc,argv)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
yyerror(s)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
yywarning(s)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
yywrap()332 yywrap()
333 {
334 	return 1;
335 }
336 
337 /*
338  * Find the type of floor, knowing its char representation.
339  */
340 int
get_floor_type(c)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
get_room_type(s)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
get_trap_type(s)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
get_monster_id(s,c)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
get_object_id(s,c)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
init_obj_classes()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
check_monster_char(c)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
check_object_char(c)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
what_map_char(c)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
scan_map(map)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
wallify_map()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
check_subrooms()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
check_coord(x,y,str)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
store_part()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
store_room()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
write_common_data(fd,typ,init,flgs)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
write_monsters(fd,nmonster_p,monsters_p)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
write_objects(fd,nobject_p,objects_p)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
write_engravings(fd,nengraving_p,engravings_p)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
write_level_file(filename,room_level,maze_level)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
write_maze(fd,maze)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
write_rooms(fd,lev)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
free_rooms(lev)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*/
1581