gcc warned about comparing signed with unsigned for one particular write() that used an expression for the size argument, and there was already conditional code to try to handle it for a couple of other compilers. But this simpler fix should handle it for everybody.
1581 lines
36 KiB
C
1581 lines
36 KiB
C
/* NetHack 3.5 lev_main.c $Date$ $Revision$ */
|
|
/* SCCS Id: @(#)lev_main.c 3.5 2007/01/17 */
|
|
/* Copyright (c) 1989 by Jean-Christophe Collet */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
/*
|
|
* This file contains the main function for the parser
|
|
* and some useful functions needed by yacc
|
|
*/
|
|
#define SPEC_LEV /* for MPW */
|
|
/* although, why don't we move those special defines here.. and in dgn_main? */
|
|
|
|
#include "hack.h"
|
|
#include "date.h"
|
|
#include "sp_lev.h"
|
|
#ifdef STRICT_REF_DEF
|
|
#include "tcap.h"
|
|
#endif
|
|
|
|
#ifdef MAC
|
|
# if defined(__SC__) || defined(__MRC__)
|
|
# define MPWTOOL
|
|
# define PREFIX ":dungeon:" /* place output files here */
|
|
# include <CursorCtl.h>
|
|
# else
|
|
# if !defined(__MACH__)
|
|
# define PREFIX ":lib:" /* place output files here */
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef WIN_CE
|
|
#define PREFIX "\\nethack\\dat\\"
|
|
#endif
|
|
|
|
#ifndef MPWTOOL
|
|
# define SpinCursor(x)
|
|
#endif
|
|
|
|
#if defined(AMIGA) && defined(DLB)
|
|
# define PREFIX "NH:slib/"
|
|
#endif
|
|
|
|
#ifndef O_WRONLY
|
|
#include <fcntl.h>
|
|
#endif
|
|
#ifndef O_CREAT /* some older BSD systems do not define O_CREAT in <fcntl.h> */
|
|
#include <sys/file.h>
|
|
#endif
|
|
#ifndef O_BINARY /* used for micros, no-op for others */
|
|
# define O_BINARY 0
|
|
#endif
|
|
|
|
#if defined(MICRO) || defined(WIN32)
|
|
# define OMASK FCMASK
|
|
#else
|
|
# define OMASK 0644
|
|
#endif
|
|
|
|
#define ERR (-1)
|
|
|
|
#define NewTab(type, size) (type **) alloc(sizeof(type *) * size)
|
|
#define Free(ptr) if(ptr) free((genericptr_t) (ptr))
|
|
/* write() returns a signed value but its size argument is unsigned;
|
|
types might be int and unsigned or ssize_t and size_t; casting
|
|
to long should be safe for all permutations (even if size_t is
|
|
bigger, since the values involved won't be too big for long) */
|
|
#define Write(fd, item, size) if ((long)write(fd, (genericptr_t)(item), size) \
|
|
!= (long)(size)) return FALSE;
|
|
|
|
#if defined(__BORLANDC__) && !defined(_WIN32)
|
|
extern unsigned _stklen = STKSIZ;
|
|
#endif
|
|
#define MAX_ERRORS 25
|
|
|
|
extern int NDECL (yyparse);
|
|
extern void FDECL (init_yyin, (FILE *));
|
|
extern void FDECL (init_yyout, (FILE *));
|
|
|
|
int FDECL (main, (int, char **));
|
|
void FDECL (yyerror, (const char *));
|
|
void FDECL (yywarning, (const char *));
|
|
int NDECL (yywrap);
|
|
int FDECL(get_floor_type, (CHAR_P));
|
|
int FDECL(get_room_type, (char *));
|
|
int FDECL(get_trap_type, (char *));
|
|
int FDECL(get_monster_id, (char *,CHAR_P));
|
|
int FDECL(get_object_id, (char *,CHAR_P));
|
|
boolean FDECL(check_monster_char, (CHAR_P));
|
|
boolean FDECL(check_object_char, (CHAR_P));
|
|
char FDECL(what_map_char, (CHAR_P));
|
|
void FDECL(scan_map, (char *));
|
|
void NDECL(wallify_map);
|
|
boolean NDECL(check_subrooms);
|
|
void FDECL(check_coord, (int,int,const char *));
|
|
void NDECL(store_part);
|
|
void NDECL(store_room);
|
|
boolean FDECL(write_level_file, (char *,splev *,specialmaze *));
|
|
void FDECL(free_rooms, (splev *));
|
|
|
|
extern void NDECL(monst_init);
|
|
extern void NDECL(objects_init);
|
|
extern void NDECL(decl_init);
|
|
|
|
static boolean FDECL(write_common_data, (int,int,lev_init *,long));
|
|
static boolean FDECL(write_monsters, (int,char *,monster ***));
|
|
static boolean FDECL(write_objects, (int,char *,object ***));
|
|
static boolean FDECL(write_engravings, (int,char *,engraving ***));
|
|
static boolean FDECL(write_maze, (int,specialmaze *));
|
|
static boolean FDECL(write_rooms, (int,splev *));
|
|
static void NDECL(init_obj_classes);
|
|
|
|
static struct {
|
|
const char *name;
|
|
int type;
|
|
} trap_types[] = {
|
|
{ "arrow", ARROW_TRAP },
|
|
{ "dart", DART_TRAP },
|
|
{ "falling rock", ROCKTRAP },
|
|
{ "board", SQKY_BOARD },
|
|
{ "bear", BEAR_TRAP },
|
|
{ "land mine", LANDMINE },
|
|
{ "rolling boulder", ROLLING_BOULDER_TRAP },
|
|
{ "sleep gas", SLP_GAS_TRAP },
|
|
{ "rust", RUST_TRAP },
|
|
{ "fire", FIRE_TRAP },
|
|
{ "pit", PIT },
|
|
{ "spiked pit", SPIKED_PIT },
|
|
{ "hole", HOLE },
|
|
{ "trap door", TRAPDOOR },
|
|
{ "teleport", TELEP_TRAP },
|
|
{ "level teleport", LEVEL_TELEP },
|
|
{ "magic portal", MAGIC_PORTAL },
|
|
{ "web", WEB },
|
|
{ "statue", STATUE_TRAP },
|
|
{ "magic", MAGIC_TRAP },
|
|
{ "anti magic", ANTI_MAGIC },
|
|
{ "polymorph", POLY_TRAP },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
static struct {
|
|
const char *name;
|
|
int type;
|
|
} room_types[] = {
|
|
/* for historical reasons, room types are not contiguous numbers */
|
|
/* (type 1 is skipped) */
|
|
{ "ordinary", OROOM },
|
|
{ "throne", COURT },
|
|
{ "swamp", SWAMP },
|
|
{ "vault", VAULT },
|
|
{ "beehive", BEEHIVE },
|
|
{ "morgue", MORGUE },
|
|
{ "barracks", BARRACKS },
|
|
{ "zoo", ZOO },
|
|
{ "delphi", DELPHI },
|
|
{ "temple", TEMPLE },
|
|
{ "anthole", ANTHOLE },
|
|
{ "cocknest", COCKNEST },
|
|
{ "leprehall", LEPREHALL },
|
|
{ "shop", SHOPBASE },
|
|
{ "armor shop", ARMORSHOP },
|
|
{ "scroll shop", SCROLLSHOP },
|
|
{ "potion shop", POTIONSHOP },
|
|
{ "weapon shop", WEAPONSHOP },
|
|
{ "food shop", FOODSHOP },
|
|
{ "ring shop", RINGSHOP },
|
|
{ "wand shop", WANDSHOP },
|
|
{ "tool shop", TOOLSHOP },
|
|
{ "book shop", BOOKSHOP },
|
|
{ "health food shop", FODDERSHOP },
|
|
{ "candle shop", CANDLESHOP },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
const char *fname = "(stdin)";
|
|
int fatal_error = 0;
|
|
int want_warnings = 0;
|
|
|
|
#ifdef FLEX23_BUG
|
|
/* Flex 2.3 bug work around; not needed for 2.3.6 or later */
|
|
int yy_more_len = 0;
|
|
#endif
|
|
|
|
extern char tmpmessage[];
|
|
extern altar *tmpaltar[];
|
|
extern lad *tmplad[];
|
|
extern stair *tmpstair[];
|
|
extern digpos *tmpdig[];
|
|
extern digpos *tmppass[];
|
|
extern char *tmpmap[];
|
|
extern region *tmpreg[];
|
|
extern lev_region *tmplreg[];
|
|
extern door *tmpdoor[];
|
|
extern room_door *tmprdoor[];
|
|
extern trap *tmptrap[];
|
|
extern monster *tmpmonst[];
|
|
extern object *tmpobj[];
|
|
extern drawbridge *tmpdb[];
|
|
extern walk *tmpwalk[];
|
|
extern gold *tmpgold[];
|
|
extern fountain *tmpfountain[];
|
|
extern sink *tmpsink[];
|
|
extern pool *tmppool[];
|
|
extern engraving *tmpengraving[];
|
|
extern mazepart *tmppart[];
|
|
extern room *tmproom[];
|
|
|
|
extern int n_olist, n_mlist, n_plist;
|
|
|
|
extern unsigned int nlreg, nreg, ndoor, ntrap, nmons, nobj;
|
|
extern unsigned int ndb, nwalk, npart, ndig, npass, nlad, nstair;
|
|
extern unsigned int naltar, ncorridor, nrooms, ngold, nengraving;
|
|
extern unsigned int nfountain, npool, nsink;
|
|
|
|
extern unsigned int max_x_map, max_y_map;
|
|
|
|
extern int nh_line_number, colon_line_number;
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
FILE *fin;
|
|
int i;
|
|
boolean errors_encountered = FALSE;
|
|
#if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__))
|
|
static char *mac_argv[] = { "lev_comp", /* dummy argv[0] */
|
|
":dat:Arch.des",
|
|
":dat:Barb.des",
|
|
":dat:Caveman.des",
|
|
":dat:Healer.des",
|
|
":dat:Knight.des",
|
|
":dat:Monk.des",
|
|
":dat:Priest.des",
|
|
":dat:Ranger.des",
|
|
":dat:Rogue.des",
|
|
":dat:Samurai.des",
|
|
":dat:Tourist.des",
|
|
":dat:Valkyrie.des",
|
|
":dat:Wizard.des",
|
|
":dat:bigroom.des",
|
|
":dat:castle.des",
|
|
":dat:endgame.des",
|
|
":dat:gehennom.des",
|
|
":dat:knox.des",
|
|
":dat:medusa.des",
|
|
":dat:mines.des",
|
|
":dat:oracle.des",
|
|
":dat:sokoban.des",
|
|
":dat:tower.des",
|
|
":dat:yendor.des"
|
|
};
|
|
|
|
argc = SIZE(mac_argv);
|
|
argv = mac_argv;
|
|
#endif
|
|
/* Note: these initializers don't do anything except guarantee that
|
|
we're linked properly.
|
|
*/
|
|
monst_init();
|
|
objects_init();
|
|
decl_init();
|
|
/* this one does something... */
|
|
init_obj_classes();
|
|
|
|
init_yyout(stdout);
|
|
if (argc == 1) { /* Read standard input */
|
|
init_yyin(stdin);
|
|
(void) yyparse();
|
|
if (fatal_error > 0) {
|
|
errors_encountered = TRUE;
|
|
}
|
|
} else { /* Otherwise every argument is a filename */
|
|
for(i=1; i<argc; i++) {
|
|
fname = argv[i];
|
|
if(!strcmp(fname, "-w")) {
|
|
want_warnings++;
|
|
continue;
|
|
}
|
|
fin = freopen(fname, "r", stdin);
|
|
if (!fin) {
|
|
(void) fprintf(stderr,"Can't open \"%s\" for input.\n",
|
|
fname);
|
|
perror(fname);
|
|
errors_encountered = TRUE;
|
|
} else {
|
|
init_yyin(fin);
|
|
(void) yyparse();
|
|
nh_line_number = 1;
|
|
if (fatal_error > 0) {
|
|
errors_encountered = TRUE;
|
|
fatal_error = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS);
|
|
/*NOTREACHED*/
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Each time the parser detects an error, it uses this function.
|
|
* Here we take count of the errors. To continue farther than
|
|
* MAX_ERRORS wouldn't be reasonable.
|
|
* Assume that explicit calls from lev_comp.y have the 1st letter
|
|
* capitalized, to allow printing of the line containing the start of
|
|
* the current declaration, instead of the beginning of the next declaration.
|
|
*/
|
|
void
|
|
yyerror(s)
|
|
const char *s;
|
|
{
|
|
(void) fprintf(stderr, "%s: line %d : %s\n", fname,
|
|
(*s >= 'A' && *s <= 'Z') ? colon_line_number : nh_line_number, s);
|
|
if (++fatal_error > MAX_ERRORS) {
|
|
(void) fprintf(stderr,"Too many errors, good bye!\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Just display a warning (that is : a non fatal error)
|
|
*/
|
|
void
|
|
yywarning(s)
|
|
const char *s;
|
|
{
|
|
(void) fprintf(stderr, "%s: line %d : WARNING : %s\n",
|
|
fname, colon_line_number, s);
|
|
}
|
|
|
|
/*
|
|
* Stub needed for lex interface.
|
|
*/
|
|
int
|
|
yywrap()
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Find the type of floor, knowing its char representation.
|
|
*/
|
|
int
|
|
get_floor_type(c)
|
|
char c;
|
|
{
|
|
int val;
|
|
|
|
SpinCursor(3);
|
|
val = what_map_char(c);
|
|
if(val == INVALID_TYPE) {
|
|
val = ERR;
|
|
yywarning("Invalid fill character in MAZE declaration");
|
|
}
|
|
return val;
|
|
}
|
|
|
|
/*
|
|
* Find the type of a room in the table, knowing its name.
|
|
*/
|
|
int
|
|
get_room_type(s)
|
|
char *s;
|
|
{
|
|
register int i;
|
|
|
|
SpinCursor(3);
|
|
for(i=0; room_types[i].name; i++)
|
|
if (!strcmp(s, room_types[i].name))
|
|
return ((int) room_types[i].type);
|
|
return ERR;
|
|
}
|
|
|
|
/*
|
|
* Find the type of a trap in the table, knowing its name.
|
|
*/
|
|
int
|
|
get_trap_type(s)
|
|
char *s;
|
|
{
|
|
register int i;
|
|
|
|
SpinCursor(3);
|
|
for (i=0; trap_types[i].name; i++)
|
|
if(!strcmp(s,trap_types[i].name))
|
|
return trap_types[i].type;
|
|
return ERR;
|
|
}
|
|
|
|
/*
|
|
* Find the index of a monster in the table, knowing its name.
|
|
*/
|
|
int
|
|
get_monster_id(s, c)
|
|
char *s;
|
|
char c;
|
|
{
|
|
register int i, class;
|
|
|
|
SpinCursor(3);
|
|
class = c ? def_char_to_monclass(c) : 0;
|
|
if (class == MAXMCLASSES) return ERR;
|
|
|
|
for (i = LOW_PM; i < NUMMONS; i++)
|
|
if (!class || class == mons[i].mlet)
|
|
if (!strcmp(s, mons[i].mname)) return i;
|
|
return ERR;
|
|
}
|
|
|
|
/*
|
|
* Find the index of an object in the table, knowing its name.
|
|
*/
|
|
int
|
|
get_object_id(s, c)
|
|
char *s;
|
|
char c; /* class */
|
|
{
|
|
int i, class;
|
|
const char *objname;
|
|
|
|
SpinCursor(3);
|
|
class = (c > 0) ? def_char_to_objclass(c) : 0;
|
|
if (class == MAXOCLASSES) return ERR;
|
|
|
|
for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) {
|
|
if (class && objects[i].oc_class != class) break;
|
|
objname = obj_descr[i].oc_name;
|
|
if (objname && !strcmp(s, objname))
|
|
return i;
|
|
}
|
|
return ERR;
|
|
}
|
|
|
|
static void
|
|
init_obj_classes()
|
|
{
|
|
int i, class, prev_class;
|
|
|
|
prev_class = -1;
|
|
for (i = 0; i < NUM_OBJECTS; i++) {
|
|
class = objects[i].oc_class;
|
|
if (class != prev_class) {
|
|
bases[class] = i;
|
|
prev_class = class;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Is the character 'c' a valid monster class ?
|
|
*/
|
|
boolean
|
|
check_monster_char(c)
|
|
char c;
|
|
{
|
|
return (def_char_to_monclass(c) != MAXMCLASSES);
|
|
}
|
|
|
|
/*
|
|
* Is the character 'c' a valid object class ?
|
|
*/
|
|
boolean
|
|
check_object_char(c)
|
|
char c;
|
|
{
|
|
return (def_char_to_objclass(c) != MAXOCLASSES);
|
|
}
|
|
|
|
/*
|
|
* Convert .des map letter into floor type.
|
|
*/
|
|
char
|
|
what_map_char(c)
|
|
char c;
|
|
{
|
|
SpinCursor(3);
|
|
switch(c) {
|
|
case ' ' : return(STONE);
|
|
case '#' : return(CORR);
|
|
case '.' : return(ROOM);
|
|
case '-' : return(HWALL);
|
|
case '|' : return(VWALL);
|
|
case '+' : return(DOOR);
|
|
case 'A' : return(AIR);
|
|
case 'B' : return(CROSSWALL); /* hack: boundary location */
|
|
case 'C' : return(CLOUD);
|
|
case 'S' : return(SDOOR);
|
|
case 'H' : return(SCORR);
|
|
case '{' : return(FOUNTAIN);
|
|
case '\\' : return(THRONE);
|
|
case 'K' :
|
|
#ifdef SINKS
|
|
return(SINK);
|
|
#else
|
|
yywarning("Sinks are not allowed in this version! Ignoring...");
|
|
return(ROOM);
|
|
#endif
|
|
case '}' : return(MOAT);
|
|
case 'P' : return(POOL);
|
|
case 'L' : return(LAVAPOOL);
|
|
case 'I' : return(ICE);
|
|
case 'W' : return(WATER);
|
|
case 'T' : return (TREE);
|
|
case 'F' : return (IRONBARS); /* Fe = iron */
|
|
}
|
|
return(INVALID_TYPE);
|
|
}
|
|
|
|
/*
|
|
* Yep! LEX gives us the map in a raw mode.
|
|
* Just analyze it here.
|
|
*/
|
|
void
|
|
scan_map(map)
|
|
char *map;
|
|
{
|
|
register int i, len;
|
|
register char *s1, *s2;
|
|
int max_len = 0;
|
|
int max_hig = 0;
|
|
char msg[256];
|
|
|
|
/* First, strip out digits 0-9 (line numbering) */
|
|
for (s1 = s2 = map; *s1; s1++)
|
|
if (*s1 < '0' || *s1 > '9')
|
|
*s2++ = *s1;
|
|
*s2 = '\0';
|
|
|
|
/* Second, find the max width of the map */
|
|
s1 = map;
|
|
while (s1 && *s1) {
|
|
s2 = index(s1, '\n');
|
|
if (s2) {
|
|
len = (int) (s2 - s1);
|
|
s1 = s2 + 1;
|
|
} else {
|
|
len = (int) strlen(s1);
|
|
s1 = (char *) 0;
|
|
}
|
|
if (len > max_len) max_len = len;
|
|
}
|
|
|
|
/* Then parse it now */
|
|
while (map && *map) {
|
|
tmpmap[max_hig] = (char *) alloc(max_len);
|
|
s1 = index(map, '\n');
|
|
if (s1) {
|
|
len = (int) (s1 - map);
|
|
s1++;
|
|
} else {
|
|
len = (int) strlen(map);
|
|
s1 = map + len;
|
|
}
|
|
for(i=0; i<len; i++)
|
|
if((tmpmap[max_hig][i] = what_map_char(map[i])) == INVALID_TYPE) {
|
|
Sprintf(msg,
|
|
"Invalid character @ (%d, %d) - replacing with stone",
|
|
max_hig, i);
|
|
yywarning(msg);
|
|
tmpmap[max_hig][i] = STONE;
|
|
}
|
|
while(i < max_len)
|
|
tmpmap[max_hig][i++] = STONE;
|
|
map = s1;
|
|
max_hig++;
|
|
}
|
|
|
|
/* Memorize boundaries */
|
|
|
|
max_x_map = max_len - 1;
|
|
max_y_map = max_hig - 1;
|
|
|
|
/* Store the map into the mazepart structure */
|
|
|
|
if(max_len > MAP_X_LIM || max_hig > MAP_Y_LIM) {
|
|
Sprintf(msg, "Map too large! (max %d x %d)", MAP_X_LIM, MAP_Y_LIM);
|
|
yyerror(msg);
|
|
}
|
|
|
|
tmppart[npart]->xsize = max_len;
|
|
tmppart[npart]->ysize = max_hig;
|
|
tmppart[npart]->map = (char **) alloc(max_hig*sizeof(char *));
|
|
for(i = 0; i< max_hig; i++)
|
|
tmppart[npart]->map[i] = tmpmap[i];
|
|
}
|
|
|
|
/*
|
|
* If we have drawn a map without walls, this allows us to
|
|
* auto-magically wallify it.
|
|
*/
|
|
#define Map_point(x,y) *(tmppart[npart]->map[y] + x)
|
|
|
|
void
|
|
wallify_map()
|
|
{
|
|
unsigned int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy;
|
|
|
|
for (y = 0; y <= max_y_map; y++) {
|
|
SpinCursor(3);
|
|
lo_yy = (y > 0) ? y - 1 : 0;
|
|
hi_yy = (y < max_y_map) ? y + 1 : max_y_map;
|
|
for (x = 0; x <= max_x_map; x++) {
|
|
if (Map_point(x,y) != STONE) continue;
|
|
lo_xx = (x > 0) ? x - 1 : 0;
|
|
hi_xx = (x < max_x_map) ? x + 1 : max_x_map;
|
|
for (yy = lo_yy; yy <= hi_yy; yy++)
|
|
for (xx = lo_xx; xx <= hi_xx; xx++)
|
|
if (IS_ROOM(Map_point(xx,yy)) ||
|
|
Map_point(xx,yy) == CROSSWALL) {
|
|
Map_point(x,y) = (yy != y) ? HWALL : VWALL;
|
|
yy = hi_yy; /* end `yy' loop */
|
|
break; /* end `xx' loop */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We need to check the subrooms apartenance to an existing room.
|
|
*/
|
|
boolean
|
|
check_subrooms()
|
|
{
|
|
unsigned i, j, n_subrooms;
|
|
boolean found, ok = TRUE;
|
|
char *last_parent, msg[256];
|
|
|
|
for (i = 0; i < nrooms; i++)
|
|
if (tmproom[i]->parent) {
|
|
found = FALSE;
|
|
for(j = 0; j < nrooms; j++)
|
|
if (tmproom[j]->name &&
|
|
!strcmp(tmproom[i]->parent, tmproom[j]->name)) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
if (!found) {
|
|
Sprintf(msg,
|
|
"Subroom error : parent room '%s' not found!",
|
|
tmproom[i]->parent);
|
|
yyerror(msg);
|
|
ok = FALSE;
|
|
}
|
|
}
|
|
|
|
msg[0] = '\0';
|
|
last_parent = msg;
|
|
for (i = 0; i < nrooms; i++)
|
|
if (tmproom[i]->parent) {
|
|
n_subrooms = 0;
|
|
for(j = i; j < nrooms; j++) {
|
|
/*
|
|
* This is by no means perfect, but should cut down the duplicate error
|
|
* messages by over 90%. The only problem will be when either subrooms
|
|
* are mixed in the level definition (not likely but possible) or rooms
|
|
* have subrooms that have subrooms.
|
|
*/
|
|
if (!strcmp(tmproom[i]->parent, last_parent)) continue;
|
|
if (tmproom[j]->parent &&
|
|
!strcmp(tmproom[i]->parent, tmproom[j]->parent)) {
|
|
n_subrooms++;
|
|
if(n_subrooms > MAX_SUBROOMS) {
|
|
|
|
Sprintf(msg,
|
|
"Subroom error: too many subrooms attached to parent room '%s'!",
|
|
tmproom[i]->parent);
|
|
yyerror(msg);
|
|
last_parent = tmproom[i]->parent;
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
/*
|
|
* Check that coordinates (x,y) are roomlike locations.
|
|
* Print warning "str" if they aren't.
|
|
*/
|
|
void
|
|
check_coord(x, y, str)
|
|
int x, y;
|
|
const char *str;
|
|
{
|
|
char ebuf[60];
|
|
|
|
if (x >= 0 && y >= 0 && x <= (int)max_x_map && y <= (int)max_y_map &&
|
|
(IS_ROCK(tmpmap[y][x]) || IS_DOOR(tmpmap[y][x]))) {
|
|
Sprintf(ebuf, "%s placed in wall at (%02d,%02d)?!", str, x, y);
|
|
yywarning(ebuf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Here we want to store the maze part we just got.
|
|
*/
|
|
void
|
|
store_part()
|
|
{
|
|
register unsigned i;
|
|
|
|
/* Ok, We got the whole part, now we store it. */
|
|
|
|
/* The Regions */
|
|
|
|
if ((tmppart[npart]->nreg = nreg) != 0) {
|
|
tmppart[npart]->regions = NewTab(region, nreg);
|
|
for(i=0;i<nreg;i++)
|
|
tmppart[npart]->regions[i] = tmpreg[i];
|
|
}
|
|
nreg = 0;
|
|
|
|
/* The Level Regions */
|
|
|
|
if ((tmppart[npart]->nlreg = nlreg) != 0) {
|
|
tmppart[npart]->lregions = NewTab(lev_region, nlreg);
|
|
for(i=0;i<nlreg;i++)
|
|
tmppart[npart]->lregions[i] = tmplreg[i];
|
|
}
|
|
nlreg = 0;
|
|
|
|
/* the doors */
|
|
|
|
if ((tmppart[npart]->ndoor = ndoor) != 0) {
|
|
tmppart[npart]->doors = NewTab(door, ndoor);
|
|
for(i=0;i<ndoor;i++)
|
|
tmppart[npart]->doors[i] = tmpdoor[i];
|
|
}
|
|
ndoor = 0;
|
|
|
|
/* the drawbridges */
|
|
|
|
if ((tmppart[npart]->ndrawbridge = ndb) != 0) {
|
|
tmppart[npart]->drawbridges = NewTab(drawbridge, ndb);
|
|
for(i=0;i<ndb;i++)
|
|
tmppart[npart]->drawbridges[i] = tmpdb[i];
|
|
}
|
|
ndb = 0;
|
|
|
|
/* The walkmaze directives */
|
|
|
|
if ((tmppart[npart]->nwalk = nwalk) != 0) {
|
|
tmppart[npart]->walks = NewTab(walk, nwalk);
|
|
for(i=0;i<nwalk;i++)
|
|
tmppart[npart]->walks[i] = tmpwalk[i];
|
|
}
|
|
nwalk = 0;
|
|
|
|
/* The non_diggable directives */
|
|
|
|
if ((tmppart[npart]->ndig = ndig) != 0) {
|
|
tmppart[npart]->digs = NewTab(digpos, ndig);
|
|
for(i=0;i<ndig;i++)
|
|
tmppart[npart]->digs[i] = tmpdig[i];
|
|
}
|
|
ndig = 0;
|
|
|
|
/* The non_passwall directives */
|
|
|
|
if ((tmppart[npart]->npass = npass) != 0) {
|
|
tmppart[npart]->passs = NewTab(digpos, npass);
|
|
for(i=0;i<npass;i++)
|
|
tmppart[npart]->passs[i] = tmppass[i];
|
|
}
|
|
npass = 0;
|
|
|
|
/* The ladders */
|
|
|
|
if ((tmppart[npart]->nlad = nlad) != 0) {
|
|
tmppart[npart]->lads = NewTab(lad, nlad);
|
|
for(i=0;i<nlad;i++)
|
|
tmppart[npart]->lads[i] = tmplad[i];
|
|
}
|
|
nlad = 0;
|
|
|
|
/* The stairs */
|
|
|
|
if ((tmppart[npart]->nstair = nstair) != 0) {
|
|
tmppart[npart]->stairs = NewTab(stair, nstair);
|
|
for(i=0;i<nstair;i++)
|
|
tmppart[npart]->stairs[i] = tmpstair[i];
|
|
}
|
|
nstair = 0;
|
|
|
|
/* The altars */
|
|
if ((tmppart[npart]->naltar = naltar) != 0) {
|
|
tmppart[npart]->altars = NewTab(altar, naltar);
|
|
for(i=0;i<naltar;i++)
|
|
tmppart[npart]->altars[i] = tmpaltar[i];
|
|
}
|
|
naltar = 0;
|
|
|
|
/* The fountains */
|
|
|
|
if ((tmppart[npart]->nfountain = nfountain) != 0) {
|
|
tmppart[npart]->fountains = NewTab(fountain, nfountain);
|
|
for(i=0;i<nfountain;i++)
|
|
tmppart[npart]->fountains[i] = tmpfountain[i];
|
|
}
|
|
nfountain = 0;
|
|
|
|
/* the traps */
|
|
|
|
if ((tmppart[npart]->ntrap = ntrap) != 0) {
|
|
tmppart[npart]->traps = NewTab(trap, ntrap);
|
|
for(i=0;i<ntrap;i++)
|
|
tmppart[npart]->traps[i] = tmptrap[i];
|
|
}
|
|
ntrap = 0;
|
|
|
|
/* the monsters */
|
|
|
|
if ((tmppart[npart]->nmonster = nmons) != 0) {
|
|
tmppart[npart]->monsters = NewTab(monster, nmons);
|
|
for(i=0;i<nmons;i++)
|
|
tmppart[npart]->monsters[i] = tmpmonst[i];
|
|
} else
|
|
tmppart[npart]->monsters = 0;
|
|
nmons = 0;
|
|
|
|
/* the objects */
|
|
|
|
if ((tmppart[npart]->nobject = nobj) != 0) {
|
|
tmppart[npart]->objects = NewTab(object, nobj);
|
|
for(i=0;i<nobj;i++)
|
|
tmppart[npart]->objects[i] = tmpobj[i];
|
|
} else
|
|
tmppart[npart]->objects = 0;
|
|
nobj = 0;
|
|
|
|
/* The gold piles */
|
|
|
|
if ((tmppart[npart]->ngold = ngold) != 0) {
|
|
tmppart[npart]->golds = NewTab(gold, ngold);
|
|
for(i=0;i<ngold;i++)
|
|
tmppart[npart]->golds[i] = tmpgold[i];
|
|
}
|
|
ngold = 0;
|
|
|
|
/* The engravings */
|
|
|
|
if ((tmppart[npart]->nengraving = nengraving) != 0) {
|
|
tmppart[npart]->engravings = NewTab(engraving, nengraving);
|
|
for(i=0;i<nengraving;i++)
|
|
tmppart[npart]->engravings[i] = tmpengraving[i];
|
|
} else
|
|
tmppart[npart]->engravings = 0;
|
|
nengraving = 0;
|
|
|
|
npart++;
|
|
n_plist = n_mlist = n_olist = 0;
|
|
}
|
|
|
|
/*
|
|
* Here we want to store the room part we just got.
|
|
*/
|
|
void
|
|
store_room()
|
|
{
|
|
register unsigned i;
|
|
|
|
/* Ok, We got the whole room, now we store it. */
|
|
|
|
/* the doors */
|
|
|
|
if ((tmproom[nrooms]->ndoor = ndoor) != 0) {
|
|
tmproom[nrooms]->doors = NewTab(room_door, ndoor);
|
|
for(i=0;i<ndoor;i++)
|
|
tmproom[nrooms]->doors[i] = tmprdoor[i];
|
|
}
|
|
ndoor = 0;
|
|
|
|
/* The stairs */
|
|
|
|
if ((tmproom[nrooms]->nstair = nstair) != 0) {
|
|
tmproom[nrooms]->stairs = NewTab(stair, nstair);
|
|
for(i=0;i<nstair;i++)
|
|
tmproom[nrooms]->stairs[i] = tmpstair[i];
|
|
}
|
|
nstair = 0;
|
|
|
|
/* The altars */
|
|
if ((tmproom[nrooms]->naltar = naltar) != 0) {
|
|
tmproom[nrooms]->altars = NewTab(altar, naltar);
|
|
for(i=0;i<naltar;i++)
|
|
tmproom[nrooms]->altars[i] = tmpaltar[i];
|
|
}
|
|
naltar = 0;
|
|
|
|
/* The fountains */
|
|
|
|
if ((tmproom[nrooms]->nfountain = nfountain) != 0) {
|
|
tmproom[nrooms]->fountains = NewTab(fountain, nfountain);
|
|
for(i=0;i<nfountain;i++)
|
|
tmproom[nrooms]->fountains[i] = tmpfountain[i];
|
|
}
|
|
nfountain = 0;
|
|
|
|
/* The sinks */
|
|
|
|
if ((tmproom[nrooms]->nsink = nsink) != 0) {
|
|
tmproom[nrooms]->sinks = NewTab(sink, nsink);
|
|
for(i=0;i<nsink;i++)
|
|
tmproom[nrooms]->sinks[i] = tmpsink[i];
|
|
}
|
|
nsink = 0;
|
|
|
|
/* The pools */
|
|
|
|
if ((tmproom[nrooms]->npool = npool) != 0) {
|
|
tmproom[nrooms]->pools = NewTab(pool, npool);
|
|
for(i=0;i<npool;i++)
|
|
tmproom[nrooms]->pools[i] = tmppool[i];
|
|
}
|
|
npool = 0;
|
|
|
|
/* the traps */
|
|
|
|
if ((tmproom[nrooms]->ntrap = ntrap) != 0) {
|
|
tmproom[nrooms]->traps = NewTab(trap, ntrap);
|
|
for(i=0;i<ntrap;i++)
|
|
tmproom[nrooms]->traps[i] = tmptrap[i];
|
|
}
|
|
ntrap = 0;
|
|
|
|
/* the monsters */
|
|
|
|
if ((tmproom[nrooms]->nmonster = nmons) != 0) {
|
|
tmproom[nrooms]->monsters = NewTab(monster, nmons);
|
|
for(i=0;i<nmons;i++)
|
|
tmproom[nrooms]->monsters[i] = tmpmonst[i];
|
|
} else
|
|
tmproom[nrooms]->monsters = 0;
|
|
nmons = 0;
|
|
|
|
/* the objects */
|
|
|
|
if ((tmproom[nrooms]->nobject = nobj) != 0) {
|
|
tmproom[nrooms]->objects = NewTab(object, nobj);
|
|
for(i=0;i<nobj;i++)
|
|
tmproom[nrooms]->objects[i] = tmpobj[i];
|
|
} else
|
|
tmproom[nrooms]->objects = 0;
|
|
nobj = 0;
|
|
|
|
/* The gold piles */
|
|
|
|
if ((tmproom[nrooms]->ngold = ngold) != 0) {
|
|
tmproom[nrooms]->golds = NewTab(gold, ngold);
|
|
for(i=0;i<ngold;i++)
|
|
tmproom[nrooms]->golds[i] = tmpgold[i];
|
|
}
|
|
ngold = 0;
|
|
|
|
/* The engravings */
|
|
|
|
if ((tmproom[nrooms]->nengraving = nengraving) != 0) {
|
|
tmproom[nrooms]->engravings = NewTab(engraving, nengraving);
|
|
for(i=0;i<nengraving;i++)
|
|
tmproom[nrooms]->engravings[i] = tmpengraving[i];
|
|
} else
|
|
tmproom[nrooms]->engravings = 0;
|
|
nengraving = 0;
|
|
|
|
nrooms++;
|
|
}
|
|
|
|
/*
|
|
* Output some info common to all special levels.
|
|
*/
|
|
static boolean
|
|
write_common_data(fd, typ, init, flgs)
|
|
int fd, typ;
|
|
lev_init *init;
|
|
long flgs;
|
|
{
|
|
char c;
|
|
uchar len;
|
|
static struct version_info version_data = {
|
|
VERSION_NUMBER, VERSION_FEATURES,
|
|
VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3
|
|
};
|
|
|
|
Write(fd, &version_data, sizeof version_data);
|
|
c = typ;
|
|
Write(fd, &c, sizeof(c)); /* 1 byte header */
|
|
Write(fd, init, sizeof(lev_init));
|
|
Write(fd, &flgs, sizeof flgs);
|
|
|
|
len = (uchar) strlen(tmpmessage);
|
|
Write(fd, &len, sizeof len);
|
|
if (len) Write(fd, tmpmessage, (int) len);
|
|
tmpmessage[0] = '\0';
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Output monster info, which needs string fixups, then release memory.
|
|
*/
|
|
static boolean
|
|
write_monsters(fd, nmonster_p, monsters_p)
|
|
int fd;
|
|
char *nmonster_p;
|
|
monster ***monsters_p;
|
|
{
|
|
monster *m;
|
|
char *name, *appr;
|
|
int j, n = (int)*nmonster_p;
|
|
|
|
Write(fd, nmonster_p, sizeof *nmonster_p);
|
|
for (j = 0; j < n; j++) {
|
|
m = (*monsters_p)[j];
|
|
name = m->name.str;
|
|
appr = m->appear_as.str;
|
|
m->name.str = m->appear_as.str = 0;
|
|
m->name.len = name ? strlen(name) : 0;
|
|
m->appear_as.len = appr ? strlen(appr) : 0;
|
|
Write(fd, m, sizeof *m);
|
|
if (name) {
|
|
Write(fd, name, m->name.len);
|
|
Free(name);
|
|
}
|
|
if (appr) {
|
|
Write(fd, appr, m->appear_as.len);
|
|
Free(appr);
|
|
}
|
|
Free(m);
|
|
}
|
|
if (*monsters_p) {
|
|
Free(*monsters_p);
|
|
*monsters_p = 0;
|
|
}
|
|
*nmonster_p = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Output object info, which needs string fixup, then release memory.
|
|
*/
|
|
static boolean
|
|
write_objects(fd, nobject_p, objects_p)
|
|
int fd;
|
|
char *nobject_p;
|
|
object ***objects_p;
|
|
{
|
|
object *o;
|
|
char *name;
|
|
int j, n = (int)*nobject_p;
|
|
|
|
Write(fd, nobject_p, sizeof *nobject_p);
|
|
for (j = 0; j < n; j++) {
|
|
o = (*objects_p)[j];
|
|
name = o->name.str;
|
|
o->name.str = 0; /* reset in case `len' is narrower */
|
|
o->name.len = name ? strlen(name) : 0;
|
|
Write(fd, o, sizeof *o);
|
|
if (name) {
|
|
Write(fd, name, o->name.len);
|
|
Free(name);
|
|
}
|
|
Free(o);
|
|
}
|
|
if (*objects_p) {
|
|
Free(*objects_p);
|
|
*objects_p = 0;
|
|
}
|
|
*nobject_p = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Output engraving info, which needs string fixup, then release memory.
|
|
*/
|
|
static boolean
|
|
write_engravings(fd, nengraving_p, engravings_p)
|
|
int fd;
|
|
char *nengraving_p;
|
|
engraving ***engravings_p;
|
|
{
|
|
engraving *e;
|
|
char *engr;
|
|
int j, n = (int)*nengraving_p;
|
|
|
|
Write(fd, nengraving_p, sizeof *nengraving_p);
|
|
for (j = 0; j < n; j++) {
|
|
e = (*engravings_p)[j];
|
|
engr = e->engr.str;
|
|
e->engr.str = 0; /* reset in case `len' is narrower */
|
|
e->engr.len = strlen(engr);
|
|
Write(fd, e, sizeof *e);
|
|
Write(fd, engr, e->engr.len);
|
|
Free(engr);
|
|
Free(e);
|
|
}
|
|
if (*engravings_p) {
|
|
Free(*engravings_p);
|
|
*engravings_p = 0;
|
|
}
|
|
*nengraving_p = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Open and write maze or rooms file, based on which pointer is non-null.
|
|
* Return TRUE on success, FALSE on failure.
|
|
*/
|
|
boolean
|
|
write_level_file(filename, room_level, maze_level)
|
|
char *filename;
|
|
splev *room_level;
|
|
specialmaze *maze_level;
|
|
{
|
|
int fout;
|
|
char lbuf[60];
|
|
|
|
lbuf[0] = '\0';
|
|
#ifdef PREFIX
|
|
Strcat(lbuf, PREFIX);
|
|
#endif
|
|
Strcat(lbuf, filename);
|
|
Strcat(lbuf, LEV_EXT);
|
|
|
|
#if defined(MAC) && (defined(__SC__) || defined(__MRC__))
|
|
fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY);
|
|
#else
|
|
fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK);
|
|
#endif
|
|
if (fout < 0) return FALSE;
|
|
|
|
if (room_level) {
|
|
if (!write_rooms(fout, room_level))
|
|
return FALSE;
|
|
} else if (maze_level) {
|
|
if (!write_maze(fout, maze_level))
|
|
return FALSE;
|
|
} else
|
|
panic("write_level_file");
|
|
|
|
(void) close(fout);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Here we write the structure of the maze in the specified file (fd).
|
|
* Also, we have to free the memory allocated via alloc().
|
|
*/
|
|
static boolean
|
|
write_maze(fd, maze)
|
|
int fd;
|
|
specialmaze *maze;
|
|
{
|
|
short i,j;
|
|
mazepart *pt;
|
|
|
|
if (!write_common_data(fd, SP_LEV_MAZE, &(maze->init_lev), maze->flags))
|
|
return FALSE;
|
|
|
|
Write(fd, &(maze->filling), sizeof(maze->filling));
|
|
Write(fd, &(maze->numpart), sizeof(maze->numpart));
|
|
/* Number of parts */
|
|
for(i=0;i<maze->numpart;i++) {
|
|
pt = maze->parts[i];
|
|
|
|
/* First, write the map */
|
|
|
|
Write(fd, &(pt->halign), sizeof(pt->halign));
|
|
Write(fd, &(pt->valign), sizeof(pt->valign));
|
|
Write(fd, &(pt->xsize), sizeof(pt->xsize));
|
|
Write(fd, &(pt->ysize), sizeof(pt->ysize));
|
|
for(j=0;j<pt->ysize;j++) {
|
|
if(!maze->init_lev.init_present ||
|
|
pt->xsize > 1 || pt->ysize > 1) {
|
|
Write(fd, pt->map[j], pt->xsize * sizeof *pt->map[j]);
|
|
}
|
|
Free(pt->map[j]);
|
|
}
|
|
Free(pt->map);
|
|
|
|
/* level region stuff */
|
|
Write(fd, &pt->nlreg, sizeof pt->nlreg);
|
|
for (j = 0; j < pt->nlreg; j++) {
|
|
lev_region *l = pt->lregions[j];
|
|
char *rname = l->rname.str;
|
|
l->rname.str = 0; /* reset in case `len' is narrower */
|
|
l->rname.len = rname ? strlen(rname) : 0;
|
|
Write(fd, l, sizeof *l);
|
|
if (rname) {
|
|
Write(fd, rname, l->rname.len);
|
|
Free(rname);
|
|
}
|
|
Free(l);
|
|
}
|
|
if (pt->nlreg > 0)
|
|
Free(pt->lregions);
|
|
|
|
/* The random registers */
|
|
Write(fd, &(pt->nrobjects), sizeof(pt->nrobjects));
|
|
if(pt->nrobjects) {
|
|
Write(fd, pt->robjects, pt->nrobjects);
|
|
Free(pt->robjects);
|
|
}
|
|
Write(fd, &(pt->nloc), sizeof(pt->nloc));
|
|
if(pt->nloc) {
|
|
Write(fd, pt->rloc_x, pt->nloc);
|
|
Write(fd, pt->rloc_y, pt->nloc);
|
|
Free(pt->rloc_x);
|
|
Free(pt->rloc_y);
|
|
}
|
|
Write(fd, &(pt->nrmonst), sizeof(pt->nrmonst));
|
|
if(pt->nrmonst) {
|
|
Write(fd, pt->rmonst, pt->nrmonst);
|
|
Free(pt->rmonst);
|
|
}
|
|
|
|
/* subrooms */
|
|
Write(fd, &(pt->nreg), sizeof(pt->nreg));
|
|
for(j=0;j<pt->nreg;j++) {
|
|
Write(fd, pt->regions[j], sizeof(region));
|
|
Free(pt->regions[j]);
|
|
}
|
|
if(pt->nreg > 0)
|
|
Free(pt->regions);
|
|
|
|
/* the doors */
|
|
Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
|
|
for(j=0;j<pt->ndoor;j++) {
|
|
Write(fd, pt->doors[j], sizeof(door));
|
|
Free(pt->doors[j]);
|
|
}
|
|
if (pt->ndoor > 0)
|
|
Free(pt->doors);
|
|
|
|
/* The drawbridges */
|
|
Write(fd, &(pt->ndrawbridge), sizeof(pt->ndrawbridge));
|
|
for(j=0;j<pt->ndrawbridge;j++) {
|
|
Write(fd, pt->drawbridges[j], sizeof(drawbridge));
|
|
Free(pt->drawbridges[j]);
|
|
}
|
|
if(pt->ndrawbridge > 0)
|
|
Free(pt->drawbridges);
|
|
|
|
/* The mazewalk directives */
|
|
Write(fd, &(pt->nwalk), sizeof(pt->nwalk));
|
|
for(j=0; j<pt->nwalk; j++) {
|
|
Write(fd, pt->walks[j], sizeof(walk));
|
|
Free(pt->walks[j]);
|
|
}
|
|
if (pt->nwalk > 0)
|
|
Free(pt->walks);
|
|
|
|
/* The non_diggable directives */
|
|
Write(fd, &(pt->ndig), sizeof(pt->ndig));
|
|
for(j=0;j<pt->ndig;j++) {
|
|
Write(fd, pt->digs[j], sizeof(digpos));
|
|
Free(pt->digs[j]);
|
|
}
|
|
if (pt->ndig > 0)
|
|
Free(pt->digs);
|
|
|
|
/* The non_passwall directives */
|
|
Write(fd, &(pt->npass), sizeof(pt->npass));
|
|
for(j=0;j<pt->npass;j++) {
|
|
Write(fd, pt->passs[j], sizeof(digpos));
|
|
Free(pt->passs[j]);
|
|
}
|
|
if (pt->npass > 0)
|
|
Free(pt->passs);
|
|
|
|
/* The ladders */
|
|
Write(fd, &(pt->nlad), sizeof(pt->nlad));
|
|
for(j=0;j<pt->nlad;j++) {
|
|
Write(fd, pt->lads[j], sizeof(lad));
|
|
Free(pt->lads[j]);
|
|
}
|
|
if (pt->nlad > 0)
|
|
Free(pt->lads);
|
|
|
|
/* The stairs */
|
|
Write(fd, &(pt->nstair), sizeof(pt->nstair));
|
|
for(j=0;j<pt->nstair;j++) {
|
|
Write(fd, pt->stairs[j], sizeof(stair));
|
|
Free(pt->stairs[j]);
|
|
}
|
|
if (pt->nstair > 0)
|
|
Free(pt->stairs);
|
|
|
|
/* The altars */
|
|
Write(fd, &(pt->naltar), sizeof(pt->naltar));
|
|
for(j=0;j<pt->naltar;j++) {
|
|
Write(fd, pt->altars[j], sizeof(altar));
|
|
Free(pt->altars[j]);
|
|
}
|
|
if (pt->naltar > 0)
|
|
Free(pt->altars);
|
|
|
|
/* The fountains */
|
|
Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
|
|
for(j=0;j<pt->nfountain;j++) {
|
|
Write(fd, pt->fountains[j], sizeof(fountain));
|
|
Free(pt->fountains[j]);
|
|
}
|
|
if (pt->nfountain > 0)
|
|
Free(pt->fountains);
|
|
|
|
/* The traps */
|
|
Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
|
|
for(j=0;j<pt->ntrap;j++) {
|
|
Write(fd, pt->traps[j], sizeof(trap));
|
|
Free(pt->traps[j]);
|
|
}
|
|
if (pt->ntrap)
|
|
Free(pt->traps);
|
|
|
|
/* The monsters */
|
|
if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
|
|
return FALSE;
|
|
|
|
/* The objects */
|
|
if (!write_objects(fd, &pt->nobject, &pt->objects))
|
|
return FALSE;
|
|
|
|
/* The gold piles */
|
|
Write(fd, &(pt->ngold), sizeof(pt->ngold));
|
|
for(j=0;j<pt->ngold;j++) {
|
|
Write(fd, pt->golds[j], sizeof(gold));
|
|
Free(pt->golds[j]);
|
|
}
|
|
if (pt->ngold > 0)
|
|
Free(pt->golds);
|
|
|
|
/* The engravings */
|
|
if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
|
|
return FALSE;
|
|
|
|
Free(pt);
|
|
}
|
|
|
|
Free(maze->parts);
|
|
maze->parts = (mazepart **)0;
|
|
maze->numpart = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Here we write the structure of the room level in the specified file (fd).
|
|
*/
|
|
static boolean
|
|
write_rooms(fd, lev)
|
|
int fd;
|
|
splev *lev;
|
|
{
|
|
short i,j, size;
|
|
room *pt;
|
|
|
|
if (!write_common_data(fd, SP_LEV_ROOMS, &(lev->init_lev), lev->flags))
|
|
return FALSE;
|
|
|
|
/* Random registers */
|
|
|
|
Write(fd, &lev->nrobjects, sizeof(lev->nrobjects));
|
|
if (lev->nrobjects)
|
|
Write(fd, lev->robjects, lev->nrobjects);
|
|
Write(fd, &lev->nrmonst, sizeof(lev->nrmonst));
|
|
if (lev->nrmonst)
|
|
Write(fd, lev->rmonst, lev->nrmonst);
|
|
|
|
Write(fd, &(lev->nroom), sizeof(lev->nroom));
|
|
/* Number of rooms */
|
|
for(i=0;i<lev->nroom;i++) {
|
|
pt = lev->rooms[i];
|
|
|
|
/* Room characteristics */
|
|
|
|
size = (short) (pt->name ? strlen(pt->name) : 0);
|
|
Write(fd, &size, sizeof(size));
|
|
if (size)
|
|
Write(fd, pt->name, size);
|
|
|
|
size = (short) (pt->parent ? strlen(pt->parent) : 0);
|
|
Write(fd, &size, sizeof(size));
|
|
if (size)
|
|
Write(fd, pt->parent, size);
|
|
|
|
Write(fd, &(pt->x), sizeof(pt->x));
|
|
Write(fd, &(pt->y), sizeof(pt->y));
|
|
Write(fd, &(pt->w), sizeof(pt->w));
|
|
Write(fd, &(pt->h), sizeof(pt->h));
|
|
Write(fd, &(pt->xalign), sizeof(pt->xalign));
|
|
Write(fd, &(pt->yalign), sizeof(pt->yalign));
|
|
Write(fd, &(pt->rtype), sizeof(pt->rtype));
|
|
Write(fd, &(pt->chance), sizeof(pt->chance));
|
|
Write(fd, &(pt->rlit), sizeof(pt->rlit));
|
|
Write(fd, &(pt->filled), sizeof(pt->filled));
|
|
|
|
/* the doors */
|
|
Write(fd, &(pt->ndoor), sizeof(pt->ndoor));
|
|
for(j=0;j<pt->ndoor;j++)
|
|
Write(fd, pt->doors[j], sizeof(room_door));
|
|
|
|
/* The stairs */
|
|
Write(fd, &(pt->nstair), sizeof(pt->nstair));
|
|
for(j=0;j<pt->nstair;j++)
|
|
Write(fd, pt->stairs[j], sizeof(stair));
|
|
|
|
/* The altars */
|
|
Write(fd, &(pt->naltar), sizeof(pt->naltar));
|
|
for(j=0;j<pt->naltar;j++)
|
|
Write(fd, pt->altars[j], sizeof(altar));
|
|
|
|
/* The fountains */
|
|
Write(fd, &(pt->nfountain), sizeof(pt->nfountain));
|
|
for(j=0;j<pt->nfountain;j++)
|
|
Write(fd, pt->fountains[j], sizeof(fountain));
|
|
|
|
/* The sinks */
|
|
Write(fd, &(pt->nsink), sizeof(pt->nsink));
|
|
for(j=0;j<pt->nsink;j++)
|
|
Write(fd, pt->sinks[j], sizeof(sink));
|
|
|
|
/* The pools */
|
|
Write(fd, &(pt->npool), sizeof(pt->npool));
|
|
for(j=0;j<pt->npool;j++)
|
|
Write(fd, pt->pools[j], sizeof(pool));
|
|
|
|
/* The traps */
|
|
Write(fd, &(pt->ntrap), sizeof(pt->ntrap));
|
|
for(j=0;j<pt->ntrap;j++)
|
|
Write(fd, pt->traps[j], sizeof(trap));
|
|
|
|
/* The monsters */
|
|
if (!write_monsters(fd, &pt->nmonster, &pt->monsters))
|
|
return FALSE;
|
|
|
|
/* The objects */
|
|
if (!write_objects(fd, &pt->nobject, &pt->objects))
|
|
return FALSE;
|
|
|
|
/* The gold piles */
|
|
Write(fd, &(pt->ngold), sizeof(pt->ngold));
|
|
for(j=0;j<pt->ngold;j++)
|
|
Write(fd, pt->golds[j], sizeof(gold));
|
|
|
|
/* The engravings */
|
|
if (!write_engravings(fd, &pt->nengraving, &pt->engravings))
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/* The corridors */
|
|
Write(fd, &lev->ncorr, sizeof(lev->ncorr));
|
|
for (i=0; i < lev->ncorr; i++)
|
|
Write(fd, lev->corrs[i], sizeof(corridor));
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Release memory allocated to a rooms-style special level; maze-style
|
|
* levels have the fields freed as they're written; monsters, objects, and
|
|
* engravings are freed as written for both styles, so not handled here.
|
|
*/
|
|
void
|
|
free_rooms(lev)
|
|
splev *lev;
|
|
{
|
|
room *r;
|
|
int j, n = lev->nroom;
|
|
|
|
while(n--) {
|
|
r = lev->rooms[n];
|
|
Free(r->name);
|
|
Free(r->parent);
|
|
if ((j = r->ndoor) != 0) {
|
|
while(j--)
|
|
Free(r->doors[j]);
|
|
Free(r->doors);
|
|
}
|
|
if ((j = r->nstair) != 0) {
|
|
while(j--)
|
|
Free(r->stairs[j]);
|
|
Free(r->stairs);
|
|
}
|
|
if ((j = r->naltar) != 0) {
|
|
while (j--)
|
|
Free(r->altars[j]);
|
|
Free(r->altars);
|
|
}
|
|
if ((j = r->nfountain) != 0) {
|
|
while(j--)
|
|
Free(r->fountains[j]);
|
|
Free(r->fountains);
|
|
}
|
|
if ((j = r->nsink) != 0) {
|
|
while(j--)
|
|
Free(r->sinks[j]);
|
|
Free(r->sinks);
|
|
}
|
|
if ((j = r->npool) != 0) {
|
|
while(j--)
|
|
Free(r->pools[j]);
|
|
Free(r->pools);
|
|
}
|
|
if ((j = r->ntrap) != 0) {
|
|
while (j--)
|
|
Free(r->traps[j]);
|
|
Free(r->traps);
|
|
}
|
|
if ((j = r->ngold) != 0) {
|
|
while(j--)
|
|
Free(r->golds[j]);
|
|
Free(r->golds);
|
|
}
|
|
Free(r);
|
|
lev->rooms[n] = (room *)0;
|
|
}
|
|
Free(lev->rooms);
|
|
lev->rooms = (room **)0;
|
|
lev->nroom = 0;
|
|
|
|
for (j = 0; j < lev->ncorr; j++) {
|
|
Free(lev->corrs[j]);
|
|
lev->corrs[j] = (corridor *)0;
|
|
}
|
|
Free(lev->corrs);
|
|
lev->corrs = (corridor **)0;
|
|
lev->ncorr = 0;
|
|
|
|
Free(lev->robjects);
|
|
lev->robjects = (char *)0;
|
|
lev->nrobjects = 0;
|
|
Free(lev->rmonst);
|
|
lev->rmonst = (char *)0;
|
|
lev->nrmonst = 0;
|
|
}
|
|
|
|
#ifdef STRICT_REF_DEF
|
|
/*
|
|
* Any globals declared in hack.h and descendents which aren't defined
|
|
* in the modules linked into lev_comp should be defined here. These
|
|
* definitions can be dummies: their sizes shouldn't matter as long as
|
|
* as their types are correct; actual values are irrelevant.
|
|
*/
|
|
#define ARBITRARY_SIZE 1
|
|
/* attrib.c */
|
|
struct attribs attrmax, attrmin;
|
|
/* files.c */
|
|
const char *configfile;
|
|
char lock[ARBITRARY_SIZE];
|
|
char SAVEF[ARBITRARY_SIZE];
|
|
# ifdef MICRO
|
|
char SAVEP[ARBITRARY_SIZE];
|
|
# endif
|
|
/* termcap.c */
|
|
struct tc_lcl_data tc_lcl_data;
|
|
# ifdef TEXTCOLOR
|
|
# ifdef TOS
|
|
const char *hilites[CLR_MAX];
|
|
# else
|
|
char NEARDATA *hilites[CLR_MAX];
|
|
# endif
|
|
# endif
|
|
/* trap.c */
|
|
const char *traps[TRAPNUM];
|
|
/* window.c */
|
|
# ifdef HANGUPHANDLING
|
|
volatile
|
|
# endif
|
|
struct window_procs windowprocs;
|
|
/* xxxtty.c */
|
|
# ifdef DEFINE_OSPEED
|
|
short ospeed;
|
|
# endif
|
|
#endif /* STRICT_REF_DEF */
|
|
|
|
/*lev_main.c*/
|