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. */
6 * This file contains the main function for the parser
7 * and some useful functions needed by yacc
9 #define SPEC_LEV /* for MPW */
10 /* although, why don't we move those special defines here.. and in dgn_main? */
20 # if defined(__SC__) || defined(__MRC__)
22 # define PREFIX ":dungeon:" /* place output files here */
23 # include <CursorCtl.h>
25 # if !defined(__MACH__)
26 # define PREFIX ":lib:" /* place output files here */
32 #define PREFIX "\\nethack\\dat\\"
36 # define SpinCursor(x)
39 #if defined(AMIGA) && defined(DLB)
40 # define PREFIX "NH:slib/"
46 #ifndef O_CREAT /* some older BSD systems do not define O_CREAT in <fcntl.h> */
49 #ifndef O_BINARY /* used for micros, no-op for others */
53 #if defined(MICRO) || defined(WIN32)
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;
65 #if defined(__BORLANDC__) && !defined(_WIN32)
66 extern unsigned _stklen = STKSIZ;
70 extern int NDECL (yyparse);
71 extern void FDECL (init_yyin, (FILE *));
72 extern void FDECL (init_yyout, (FILE *));
74 int FDECL (main, (int, char **));
75 void FDECL (yyerror, (const char *));
76 void FDECL (yywarning, (const char *));
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 *));
95 extern void NDECL(monst_init);
96 extern void NDECL(objects_init);
97 extern void NDECL(decl_init);
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);
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 },
122 { "spiked pit", SPIKED_PIT },
124 { "trap door", TRAPDOOR },
125 { "teleport", TELEP_TRAP },
126 { "level teleport", LEVEL_TELEP },
127 { "magic portal", MAGIC_PORTAL },
129 { "statue", STATUE_TRAP },
130 { "magic", MAGIC_TRAP },
131 { "anti magic", ANTI_MAGIC },
132 { "polymorph", POLY_TRAP },
140 /* for historical reasons, room types are not contiguous numbers */
141 /* (type 1 is skipped) */
142 { "ordinary", OROOM },
146 { "beehive", BEEHIVE },
147 { "morgue", MORGUE },
148 { "barracks", BARRACKS },
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 },
169 const char *fname = "(stdin)";
171 int want_warnings = 0;
174 /* Flex 2.3 bug work around; not needed for 2.3.6 or later */
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[];
202 extern int n_olist, n_mlist, n_plist;
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;
209 extern unsigned int max_x_map, max_y_map;
211 extern int line_number, colon_line_number;
220 boolean errors_encountered = FALSE;
221 #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
222 static char *mac_argv[] = { "lev_comp", /* dummy argv[0] */
249 argc = SIZE(mac_argv);
252 /* Note: these initializers don't do anything except guarantee that
253 we're linked properly.
258 /* this one does something... */
262 if (argc == 1) { /* Read standard input */
265 if (fatal_error > 0) {
266 errors_encountered = TRUE;
268 } else { /* Otherwise every argument is a filename */
269 for(i=1; i<argc; i++) {
271 if(!strcmp(fname, "-w")) {
275 fin = freopen(fname, "r", stdin);
277 (void) fprintf(stderr,"Can't open \"%s\" for input.\n",
280 errors_encountered = TRUE;
285 if (fatal_error > 0) {
286 errors_encountered = TRUE;
292 exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS);
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.
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");
318 * Just display a warning (that is : a non fatal error)
324 (void) fprintf(stderr, "%s: line %d : WARNING : %s\n",
325 fname, colon_line_number, s);
329 * Stub needed for lex interface.
338 * Find the type of floor, knowing its char representation.
347 val = what_map_char(c);
348 if(val == INVALID_TYPE) {
350 yywarning("Invalid fill character in MAZE declaration");
356 * Find the type of a room in the table, knowing its name.
365 for(i=0; room_types[i].name; i++)
366 if (!strcmp(s, room_types[i].name))
367 return ((int) room_types[i].type);
372 * Find the type of a trap in the table, knowing its name.
381 for (i=0; trap_types[i].name; i++)
382 if(!strcmp(s,trap_types[i].name))
383 return trap_types[i].type;
388 * Find the index of a monster in the table, knowing its name.
395 register int i, class;
398 class = c ? def_char_to_monclass(c) : 0;
399 if (class == MAXMCLASSES) return ERR;
401 for (i = LOW_PM; i < NUMMONS; i++)
402 if (!class || class == mons[i].mlet)
403 if (!strcmp(s, mons[i].mname)) return i;
408 * Find the index of an object in the table, knowing its name.
419 class = (c > 0) ? def_char_to_objclass(c) : 0;
420 if (class == MAXOCLASSES) return ERR;
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))
434 int i, class, prev_class;
437 for (i = 0; i < NUM_OBJECTS; i++) {
438 class = objects[i].oc_class;
439 if (class != prev_class) {
447 * Is the character 'c' a valid monster class ?
450 check_monster_char(c)
453 return (def_char_to_monclass(c) != MAXMCLASSES);
457 * Is the character 'c' a valid object class ?
463 return (def_char_to_objclass(c) != MAXOCLASSES);
467 * Convert .des map letter into floor type.
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);
492 yywarning("Sinks are not allowed in this version! Ignoring...");
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 */
503 return(INVALID_TYPE);
507 * Yep! LEX gives us the map in a raw mode.
508 * Just analyze it here.
515 register char *s1, *s2;
520 /* First, strip out digits 0-9 (line numbering) */
521 for (s1 = s2 = map; *s1; s1++)
522 if (*s1 < '0' || *s1 > '9')
526 /* Second, find the max width of the map */
529 s2 = index(s1, '\n');
531 len = (int) (s2 - s1);
534 len = (int) strlen(s1);
537 if (len > max_len) max_len = len;
540 /* Then parse it now */
541 while (map && *map) {
542 tmpmap[max_hig] = (char *) alloc(max_len);
543 s1 = index(map, '\n');
545 len = (int) (s1 - map);
548 len = (int) strlen(map);
552 if((tmpmap[max_hig][i] = what_map_char(map[i])) == INVALID_TYPE) {
554 "Invalid character @ (%d, %d) - replacing with stone",
557 tmpmap[max_hig][i] = STONE;
560 tmpmap[max_hig][i++] = STONE;
565 /* Memorize boundaries */
567 max_x_map = max_len - 1;
568 max_y_map = max_hig - 1;
570 /* Store the map into the mazepart structure */
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);
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];
585 * If we have drawn a map without walls, this allows us to
586 * auto-magically wallify it.
588 #define Map_point(x,y) *(tmppart[npart]->map[y] + x)
593 unsigned int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy;
595 for (y = 0; y <= max_y_map; y++) {
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 */
616 * We need to check the subrooms apartenance to an existing room.
621 unsigned i, j, n_subrooms;
622 boolean found, ok = TRUE;
623 char *last_parent, msg[256];
625 for (i = 0; i < nrooms; i++)
626 if (tmproom[i]->parent) {
628 for(j = 0; j < nrooms; j++)
629 if (tmproom[j]->name &&
630 !strcmp(tmproom[i]->parent, tmproom[j]->name)) {
636 "Subroom error : parent room '%s' not found!",
645 for (i = 0; i < nrooms; i++)
646 if (tmproom[i]->parent) {
648 for(j = i; j < nrooms; j++) {
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.
655 if (!strcmp(tmproom[i]->parent, last_parent)) continue;
656 if (tmproom[j]->parent &&
657 !strcmp(tmproom[i]->parent, tmproom[j]->parent)) {
659 if(n_subrooms > MAX_SUBROOMS) {
662 "Subroom error: too many subrooms attached to parent room '%s'!",
665 last_parent = tmproom[i]->parent;
676 * Check that coordinates (x,y) are roomlike locations.
677 * Print warning "str" if they aren't.
680 check_coord(x, y, str)
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);
694 * Here we want to store the maze part we just got.
701 /* Ok, We got the whole part, now we store it. */
705 if ((tmppart[npart]->nreg = nreg) != 0) {
706 tmppart[npart]->regions = NewTab(region, nreg);
708 tmppart[npart]->regions[i] = tmpreg[i];
712 /* The Level Regions */
714 if ((tmppart[npart]->nlreg = nlreg) != 0) {
715 tmppart[npart]->lregions = NewTab(lev_region, nlreg);
717 tmppart[npart]->lregions[i] = tmplreg[i];
723 if ((tmppart[npart]->ndoor = ndoor) != 0) {
724 tmppart[npart]->doors = NewTab(door, ndoor);
726 tmppart[npart]->doors[i] = tmpdoor[i];
730 /* the drawbridges */
732 if ((tmppart[npart]->ndrawbridge = ndb) != 0) {
733 tmppart[npart]->drawbridges = NewTab(drawbridge, ndb);
735 tmppart[npart]->drawbridges[i] = tmpdb[i];
739 /* The walkmaze directives */
741 if ((tmppart[npart]->nwalk = nwalk) != 0) {
742 tmppart[npart]->walks = NewTab(walk, nwalk);
744 tmppart[npart]->walks[i] = tmpwalk[i];
748 /* The non_diggable directives */
750 if ((tmppart[npart]->ndig = ndig) != 0) {
751 tmppart[npart]->digs = NewTab(digpos, ndig);
753 tmppart[npart]->digs[i] = tmpdig[i];
757 /* The non_passwall directives */
759 if ((tmppart[npart]->npass = npass) != 0) {
760 tmppart[npart]->passs = NewTab(digpos, npass);
762 tmppart[npart]->passs[i] = tmppass[i];
768 if ((tmppart[npart]->nlad = nlad) != 0) {
769 tmppart[npart]->lads = NewTab(lad, nlad);
771 tmppart[npart]->lads[i] = tmplad[i];
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];
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];
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];
803 if ((tmppart[npart]->ntrap = ntrap) != 0) {
804 tmppart[npart]->traps = NewTab(trap, ntrap);
806 tmppart[npart]->traps[i] = tmptrap[i];
812 if ((tmppart[npart]->nmonster = nmons) != 0) {
813 tmppart[npart]->monsters = NewTab(monster, nmons);
815 tmppart[npart]->monsters[i] = tmpmonst[i];
817 tmppart[npart]->monsters = 0;
822 if ((tmppart[npart]->nobject = nobj) != 0) {
823 tmppart[npart]->objects = NewTab(object, nobj);
825 tmppart[npart]->objects[i] = tmpobj[i];
827 tmppart[npart]->objects = 0;
832 if ((tmppart[npart]->ngold = ngold) != 0) {
833 tmppart[npart]->golds = NewTab(gold, ngold);
835 tmppart[npart]->golds[i] = tmpgold[i];
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];
846 tmppart[npart]->engravings = 0;
850 n_plist = n_mlist = n_olist = 0;
854 * Here we want to store the room part we just got.
861 /* Ok, We got the whole room, now we store it. */
865 if ((tmproom[nrooms]->ndoor = ndoor) != 0) {
866 tmproom[nrooms]->doors = NewTab(room_door, ndoor);
868 tmproom[nrooms]->doors[i] = tmprdoor[i];
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];
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];
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];
900 if ((tmproom[nrooms]->nsink = nsink) != 0) {
901 tmproom[nrooms]->sinks = NewTab(sink, nsink);
903 tmproom[nrooms]->sinks[i] = tmpsink[i];
909 if ((tmproom[nrooms]->npool = npool) != 0) {
910 tmproom[nrooms]->pools = NewTab(pool, npool);
912 tmproom[nrooms]->pools[i] = tmppool[i];
918 if ((tmproom[nrooms]->ntrap = ntrap) != 0) {
919 tmproom[nrooms]->traps = NewTab(trap, ntrap);
921 tmproom[nrooms]->traps[i] = tmptrap[i];
927 if ((tmproom[nrooms]->nmonster = nmons) != 0) {
928 tmproom[nrooms]->monsters = NewTab(monster, nmons);
930 tmproom[nrooms]->monsters[i] = tmpmonst[i];
932 tmproom[nrooms]->monsters = 0;
937 if ((tmproom[nrooms]->nobject = nobj) != 0) {
938 tmproom[nrooms]->objects = NewTab(object, nobj);
940 tmproom[nrooms]->objects[i] = tmpobj[i];
942 tmproom[nrooms]->objects = 0;
947 if ((tmproom[nrooms]->ngold = ngold) != 0) {
948 tmproom[nrooms]->golds = NewTab(gold, ngold);
950 tmproom[nrooms]->golds[i] = tmpgold[i];
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];
961 tmproom[nrooms]->engravings = 0;
968 * Output some info common to all special levels.
971 write_common_data(fd, typ, init, flgs)
978 static struct version_info version_data = {
979 VERSION_NUMBER, VERSION_FEATURES,
980 VERSION_SANITY1, VERSION_SANITY2
983 Write(fd, &version_data, sizeof version_data);
985 Write(fd, &c, sizeof(c)); /* 1 byte header */
986 Write(fd, init, sizeof(lev_init));
987 Write(fd, &flgs, sizeof flgs);
989 len = (uchar) strlen(tmpmessage);
990 Write(fd, &len, sizeof len);
991 if (len) Write(fd, tmpmessage, (int) len);
992 tmpmessage[0] = '\0';
997 * Output monster info, which needs string fixups, then release memory.
1000 write_monsters(fd, nmonster_p, monsters_p)
1003 monster ***monsters_p;
1007 int j, n = (int)*nmonster_p;
1009 Write(fd, nmonster_p, sizeof *nmonster_p);
1010 for (j = 0; j < n; j++) {
1011 m = (*monsters_p)[j];
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);
1019 Write(fd, name, m->name.len);
1023 Write(fd, appr, m->appear_as.len);
1037 * Output object info, which needs string fixup, then release memory.
1040 write_objects(fd, nobject_p, objects_p)
1043 object ***objects_p;
1047 int j, n = (int)*nobject_p;
1049 Write(fd, nobject_p, sizeof *nobject_p);
1050 for (j = 0; j < n; j++) {
1051 o = (*objects_p)[j];
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);
1057 Write(fd, name, o->name.len);
1071 * Output engraving info, which needs string fixup, then release memory.
1074 write_engravings(fd, nengraving_p, engravings_p)
1077 engraving ***engravings_p;
1081 int j, n = (int)*nengraving_p;
1083 Write(fd, nengraving_p, sizeof *nengraving_p);
1084 for (j = 0; j < n; j++) {
1085 e = (*engravings_p)[j];
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);
1094 if (*engravings_p) {
1095 Free(*engravings_p);
1103 * Open and write maze or rooms file, based on which pointer is non-null.
1104 * Return TRUE on success, FALSE on failure.
1107 write_level_file(filename, room_level, maze_level)
1110 specialmaze *maze_level;
1117 Strcat(lbuf, PREFIX);
1119 Strcat(lbuf, filename);
1120 Strcat(lbuf, LEV_EXT);
1122 #if defined(MAC) && (defined(__SC__) || defined(__MRC__))
1123 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
1125 fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
1127 if (fout < 0) return FALSE;
1130 if (!write_rooms(fout, room_level))
1132 } else if (maze_level) {
1133 if (!write_maze(fout, maze_level))
1136 panic("write_level_file");
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().
1147 write_maze(fd, maze)
1154 if (!write_common_data(fd, SP_LEV_MAZE, &(maze->init_lev), maze->flags))
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];
1163 /* First, write the map */
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]);
1176 * On MSVC and Borland C compilers the Write macro above caused:
1177 * warning '!=' : signed/unsigned mismatch
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;
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);
1197 Write(fd, rname, l->rname.len);
1205 /* The random registers */
1206 Write(fd, &(pt->nrobjects), sizeof(pt->nrobjects));
1208 Write(fd, pt->robjects, pt->nrobjects);
1211 Write(fd, &(pt->nloc), sizeof(pt->nloc));
1213 Write(fd, pt->rloc_x, pt->nloc);
1214 Write(fd, pt->rloc_y, pt->nloc);
1218 Write(fd, &(pt->nrmonst), sizeof(pt->nrmonst));
1220 Write(fd, pt->rmonst, pt->nrmonst);
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]);
1234 Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
1235 for(j=0;j<pt->ndoor;j++) {
1236 Write(fd, pt->doors[j], sizeof(door));
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]);
1248 if(pt->ndrawbridge > 0)
1249 Free(pt->drawbridges);
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));
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));
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));
1279 Write(fd, &(pt->nlad), sizeof(pt->nlad));
1280 for(j=0;j<pt->nlad;j++) {
1281 Write(fd, pt->lads[j], sizeof(lad));
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]);
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]);
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]);
1311 if (pt->nfountain > 0)
1312 Free(pt->fountains);
1315 Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
1316 for(j=0;j<pt->ntrap;j++) {
1317 Write(fd, pt->traps[j], sizeof(trap));
1324 if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
1328 if (!write_objects(fd, &pt->nobject, &pt->objects))
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));
1340 /* The engravings */
1341 if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
1348 maze->parts = (mazepart **)0;
1354 * Here we write the structure of the room level in the specified file (fd).
1357 write_rooms(fd, lev)
1364 if (!write_common_data(fd, SP_LEV_ROOMS, &(lev->init_lev), lev->flags))
1367 /* Random registers */
1369 Write(fd, &lev->nrobjects, sizeof(lev->nrobjects));
1371 Write(fd, lev->robjects, lev->nrobjects);
1372 Write(fd, &lev->nrmonst, sizeof(lev->nrmonst));
1374 Write(fd, lev->rmonst, lev->nrmonst);
1376 Write(fd, &(lev->nroom), sizeof(lev->nroom));
1377 /* Number of rooms */
1378 for(i=0;i<lev->nroom;i++) {
1381 /* Room characteristics */
1383 size = (short) (pt->name ? strlen(pt->name) : 0);
1384 Write(fd, &size, sizeof(size));
1386 Write(fd, pt->name, size);
1388 size = (short) (pt->parent ? strlen(pt->parent) : 0);
1389 Write(fd, &size, sizeof(size));
1391 Write(fd, pt->parent, size);
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));
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));
1410 Write(fd, &(pt->nstair), sizeof(pt->nstair));
1411 for(j=0;j<pt->nstair;j++)
1412 Write(fd, pt->stairs[j], sizeof(stair));
1415 Write(fd, &(pt->naltar), sizeof(pt->naltar));
1416 for(j=0;j<pt->naltar;j++)
1417 Write(fd, pt->altars[j], sizeof(altar));
1420 Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
1421 for(j=0;j<pt->nfountain;j++)
1422 Write(fd, pt->fountains[j], sizeof(fountain));
1425 Write(fd, &(pt->nsink), sizeof(pt->nsink));
1426 for(j=0;j<pt->nsink;j++)
1427 Write(fd, pt->sinks[j], sizeof(sink));
1430 Write(fd, &(pt->npool), sizeof(pt->npool));
1431 for(j=0;j<pt->npool;j++)
1432 Write(fd, pt->pools[j], sizeof(pool));
1435 Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
1436 for(j=0;j<pt->ntrap;j++)
1437 Write(fd, pt->traps[j], sizeof(trap));
1440 if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
1444 if (!write_objects(fd, &pt->nobject, &pt->objects))
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));
1452 /* The engravings */
1453 if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
1459 Write(fd, &lev->ncorr, sizeof(lev->ncorr));
1460 for (i=0; i < lev->ncorr; i++)
1461 Write(fd, lev->corrs[i], sizeof(corridor));
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.
1475 int j, n = lev->nroom;
1481 if ((j = r->ndoor) != 0) {
1486 if ((j = r->nstair) != 0) {
1491 if ((j = r->naltar) != 0) {
1496 if ((j = r->nfountain) != 0) {
1498 Free(r->fountains[j]);
1501 if ((j = r->nsink) != 0) {
1506 if ((j = r->npool) != 0) {
1511 if ((j = r->ntrap) != 0) {
1516 if ((j = r->ngold) != 0) {
1522 lev->rooms[n] = (room *)0;
1525 lev->rooms = (room **)0;
1528 for (j = 0; j < lev->ncorr; j++) {
1529 Free(lev->corrs[j]);
1530 lev->corrs[j] = (corridor *)0;
1533 lev->corrs = (corridor **)0;
1536 Free(lev->robjects);
1537 lev->robjects = (char *)0;
1540 lev->rmonst = (char *)0;
1544 #ifdef STRICT_REF_DEF
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.
1551 #define ARBITRARY_SIZE 1
1553 struct attribs attrmax, attrmin;
1555 const char *configfile;
1556 char lock[ARBITRARY_SIZE];
1557 char SAVEF[ARBITRARY_SIZE];
1559 char SAVEP[ARBITRARY_SIZE];
1562 struct tc_lcl_data tc_lcl_data;
1565 const char *hilites[CLR_MAX];
1567 char NEARDATA *hilites[CLR_MAX];
1571 const char *traps[TRAPNUM];
1573 struct window_procs windowprocs;
1575 # ifdef DEFINE_OSPEED
1578 #endif /* STRICT_REF_DEF */