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