/
dirt31/
dirt31/bin/
/*
 *  Alf Salte  (Alf)  June 1990
 */

#include <stdio.h>
#include <ctype.h>

#include "kernel.h"

#ifdef VARGS
#include <stdarg.h>
#endif

#define get_oref(z,F) ((XOBJ *)get_ref('O',z,F))
#define get_lref(z,F) get_ref('L', z, F)
#define get_mref(z,F) ((XMOB *)get_ref('M', z, F))

#include "cflags.h"

#include "mflagnames.h"
#include "pflagnames.h"
#include "sflagnames.h"
#include "lflagnames.h"
#include "oflagnames.h"
#include "exitnames.h"
#include "lflags.h"

#define UNKNOWN         ((XOBJ *)(-1))
#define BAD             ((XOBJ *)(-2))
#define GOOD            ((XOBJ *)(-3))
#define REFERRED        ((XOBJ *)(-4))
#define DEFINED         ((XOBJ *)(-5))

#define IS_LINK         0
#define IS_CONTAINED    1
#define IS_CHECK        2

typedef struct _XZON {
    char                *name;
    char                *fname;
    int                 zone;   /* This zone's number */
    int                 loc;    /* The loc number of room ZONE0 */
    int                 n_loc;  /* Number of locations in this zone */
    int                 mob;    /* The mob number of first mobile in zone */
    int                 n_mob;  /* Number of mobiles in this zone */
    struct _XLOC        *locs;
    struct _XOBJ        *objs;
    struct _XMOB        *mobs;
    struct _XLOC        *rlocs;
    struct _XMOB        *rmobs;
} XZON;

typedef struct _XMOB {
    struct _XOBJ        *aux;
    struct _XZON        *zone;
    struct _XMOB        *next;
    char                *name;
    char                *pname;
    int                 mob;
    struct _XLOC        *loc;
    int                 str;
    int                 armor;
    int                 damage;
    int			agg;
    int                 speed;
    int                 vis;
    int                 wimpy;
    PFLAGS              pflags;
    SFLAGS              sflags;
    MFLAGS              mflags;
    int                 attitude;
    int                 att_param;
    char                *desc;
    char                *exam;
} XMOB;

typedef struct _XOBJ {
    struct _XOBJ        *aux;
    struct _XZON        *zone;
    struct _XOBJ        *next;
    char                *name;
    struct _XOBJ        *the_next;
    struct _XOBJ        *linked;
    char                *pname;
    char                *aname;
    int                 obj;
    int                 cflag;
    struct _XLOC        *loc;
    unsigned char       damage;
    unsigned char       armor;
    OFLAGS              oflags;
    int                 state;
    int                 mstate;
    int                 bvalue;
    int                 osize;
    int                 oweight;
    char                *desc[4];
    char                *examine;
    int                 vis;
} XOBJ;

typedef struct _XLOC {
    struct _XOBJ        *aux;
    struct _XZON        *zone;
    struct _XLOC        *next;
    char                *name;
    char                *pname;
    int                 loc;
    LFLAGS              lflags;
    char                exit_types[NEXITS];
    struct _XLOC        *exits[NEXITS];
    char                *description;
} XLOC;

char *strchr();

char    *main_file;
char    *log_file;
char    *zone_file;
char    *mobh_file;
char    *mob_file;
char    *objh_file;
char    *obj_file;
char    *reset_list;
char    *loch_file;
char    *loc_file;
FILE    *LogFile;
int     n_logs;

char    dir[512];
XZON    zones[400];
XMOB    mobs[500];
XOBJ    objs[2000];
XLOC    locs[5000];
char    texts[350000];

char    *textsp = texts;
int     num_z = 0;
int     num_m = 0;
int     num_o = 0;
int     num_l = 0;
int     num_linked = 0;
int     num_unlinked = 0;

/*
XOBJ    *not_linked_l = (XOBJ *)NULL;
XOBJ    *linked_objs_l = (XOBJ *)NULL;
XOBJ    *not_linked = (XOBJ *)NULL;
XOBJ    *linked_objs = (XOBJ *)NULL;
*/
XOBJ    *obj_list = NULL;
XOBJ    *obj_list_l = NULL; /* last */

#define T_NAME 0
#define T_PNAME 1
#define T_LOC 2
#define T_DESC 3
#define T_END 4

#define TMOB_STR 5
#define TMOB_DAM 6
#define TMOB_ARMOR 7
#define TMOB_AGG 8
#define TMOB_SFLAGS 9
#define TMOB_PFLAGS 10
#define TMOB_MFLAGS 11
#define TMOB_SPEED 12
#define TMOB_EXAM  13
#define TMOB_VIS  14
#define TMOB_WIMPY 15

#define TOBJ_ANAME 5
#define TOBJ_OFLAGS 6
#define TOBJ_ARMOR 7
#define TOBJ_DAMAGE 8
#define TOBJ_MAX_STATE 9
#define TOBJ_STATE 10
#define TOBJ_BVALUE 11
#define TOBJ_SIZE 12
#define TOBJ_WEIGHT 13
#define TOBJ_EXAM 14
#define TOBJ_LINKED 15
#define TOBJ_VIS 16

char *Mob_tab[] = {
    "Name",     "Pname",        "Location",     "Description",  "End",
    "Strength", "Damage",	"Armor",        "Aggression",   "SFlags",
    "PFlags",   "MFlags",       "Speed",        "Examine",      "Visibility",
    "Wimpy",    TABLE_END
};

char *Obj_tab[] = {
    "Name",     "Pname",        "Location",     "Description", "End",
    "AltName",  "Oflags",       "Armor",        "Damage",
    "MaxState", "State",        "BValue",       "Size",
    "Weight",   "Examine",      "Linked",       "Visibility",
    TABLE_END
};


char *Cflags[] = {
    "In room", "In container", "Carried by", "Worn by",
    "Wielded by", "Both worn and wielded by"
};

void xexit(code)
    int code;
{
    printf("\n\n");
    exit(code);
}

#ifdef VARGS
void log(char t,XOBJ *O,XZON *Z,char *f, ...);
#endif


/*
**  Open file for read/write or die trying
*/
static FILE    *
Do_fopen(char *name, char *mode)
{
    char           *m;
    FILE           *file;
    Boolean            b;

    b = False;
    if (*(m = mode) == 'p') {
        b = True;
        ++m;
    }
    if (*name == '-' && !name[1])
        return *mode == 'w' ? stdout : stdin;
    file = (b ? popen(name, m) : fopen(name, m));
    if (!file) {
        perror(name);
        (void) fprintf(stderr, "Unable to open file for %s(%s)\n",
           (*m == 'w' ? "write" : "read"), mode);
        xexit(1);
    }
    return file;
}

char *xfgets(char *b,int s, FILE *f)
{
    int k;
    int c;
    char *t;

    for (t = b, k = s; --k >= 0 && (c = fgetc(f)) != EOF && c != '\n';)
        *t++ = c;
    if (c == EOF && t == b)
        return NULL;
    *t = 0;
    return b;
}

char *alloc_text(int s)
{
    char *p;

    textsp = (p = textsp) + s;
    return p;
}

char *save_text(char *t)
{
    int s;
    char *u;

    s = strlen(t) + 1;
    u = alloc_text(s);
    bcopy(t,u,s);
    return u;
}

char *get_fname(FILE *a,char *d)
{
  char *p;
  register char *q;
  int   c, k;
    
  while ((c = getc(a)) == ' ' || c == '\t');
  q = (p = textsp);
  if (c != '/') {
    k = strlen(d);
    bcopy(d,q,k);
    q += k;
  }
  do {
    *q++ = c;
    c = getc(a);
  } while (!isspace(c));
  while (c != '\n') c = getc(a);
  *q++ = 0;
  textsp = q;
  return p;
}

char *get_text(FILE *a)
{
    char *p;
    register char *q;
    int   c, d;

    q = (p = textsp);
    while ((c = getc(a)) == ' ' || c == '\t');
    if (ispunct(c)) {
        d = c;
    } else {
        d = 0;
        ungetc(c,a);
    }
    if ((c = getc(a)) != '\n')
        ungetc(c,a);
    while((c = getc(a)) != d) {
        if (d == 0 && isspace(c))
            break;
        *q++ = c;
    }
    if (d == 0)
        ungetc(c,a);
    *q++ = 0;
    textsp = q;
    return p;
}

char *get_exam(FILE *a)
{
    char *p;
    register char *q;
    int   c, d;

    q = (p = textsp);
    c = getc(a);
    while (isspace(c)) c = getc(a);
    d = c;
    if ((c = getc(a)) != '\n') ungetc(c,a);
    while((c = getc(a)) != d && c != EOF) *q++ = c;
    if (q[-1] != '\n') *q++ = '\n';
    *q++ = 0;
    textsp = q;
    return p;
}

char *get_description(FILE *a)
{
    char *p;
    register char *q;
    int   c, d;

    q = (p = textsp);
    while (True) {
        while ((c = getc(a)) != '^') {
            do {
                *q++ = c;
            } while ((c = getc(a)) != '\n');
            *q++ = '\n';
        }
        if ((c = getc(a)) == '\n')
            break;
        *q++ = '^';
        *q++ = c;
        while ((*q++ = c = getc(a)) != '\n');
    }
    *q++ = 0;
    textsp = q;
    return p;
}

FILE *xopen(char *f,char *m)
{
    FILE *x;

    if ((x = fopen(f,m)) == 0) {
        perror(f);
        xexit(1);
    }
    return x;
}


int read_main(char *mf)
{
    char b[128];
    char n[128];
    FILE *f;
    XZON *p;
    int c;
    int z;
    int k;
    char *s;
    char *t;
    char *u;

    f = xopen(mf,"r");
    main_file = mf;
    for (s = dir, t = main_file, u = NULL; *t != 0;++s, ++t) {
      if ((*s = *t) == '/')
	u = s;
    }
    if (u == NULL)
      *(u = s = dir) = 0;
    else
      *++u = 0;
    log_file = get_fname(f,dir);
    zone_file = get_fname(f,dir);
    mobh_file = get_fname(f,dir);
    mob_file = get_fname(f,dir);
    objh_file = get_fname(f,dir);
    obj_file = get_fname(f,dir);
    reset_list = get_fname(f,dir);
    loch_file = get_fname(f,dir);
    loc_file = get_fname(f,dir);
    if ((LogFile = fopen(log_file,"w")) == NULL) {
        perror(log_file);
        exit(1);
    }
    n_logs = 0;

    for (z = 0, p = zones;xfgets(b,sizeof(b),f) != NULL;) {
        for (s = b; isalpha(*s); ++s);
        if ((k = s - b) == 0)
            continue;
        t = alloc_text(k + 1);
        bcopy(b,t,k);
        t[k] = 0;
        p->name = t;
        while (*s == ' ' || *s == '\t') ++s;
        if (isalpha(*s) || *s == '/' || *s == '.') {
            for (t = s; isalpha(*s) || *s == '/' || *s == '.'; ++s);
            *s = 0;
	    if (*t != '/') {
	        sprintf(n, "%s%s", dir, t);
		t = n;
	    }
        } else {
            sprintf(n,"%s%s.zone", dir, t);
            t = n;
        }
        k = strlen(t);
        s = alloc_text(k+1);
        bcopy(t,s,k);
        s[k] = 0;
        p->fname = s;
        p->loc = 0;
        p->locs = (XLOC *)0;
        p->mobs = (XMOB *)0;
        p->objs = (XOBJ *)0;
	p->zone = z;
        ++z;
        ++p;
    }
    fclose(f);
    return num_z = z;
}


FILE *zopen(char *fn, char *zn, Boolean *m, char *b, int bs)
{
    FILE *f;
    char *s;
    char *t;
    char buff[128];

    sprintf( buff, "/lib/cpp -P -R -I../include %s", fn);
    f = popen(buff, "r");
    if (f == NULL) {
        fprintf(stderr, "\nError when opening file %s for zone %s\n",
                fn, zn);
        perror(fn);
        xexit(1);
    }
    *m = False;
    do {
        if (xfgets(b,bs,f) == NULL) {
            pclose(f);
            return NULL;
        }
    } while (b[0] != '%');
    if (strncasecmp(&b[1],"zone:",5) == 0) {
        *m = True;
        for (;;) {
            for (s = &b[6]; *s == ' ' || *s == '\t'; ++s);
            for (t = s; isalpha(*t); ++t);
            *t = 0;
            if (strcasecmp(s,zn) == 0) {
                while (xfgets(b,bs,f)) {
                    if (b[0] == '%')
                        return f;
                }
                pclose(f);
                return NULL;
            }
            do {
                if (xfgets(b,bs,f) == NULL) {
                    pclose(f);
                    return NULL;
                }
            } while (strncasecmp(b,"%zone:",6) != 0);
        }
    }
    return f;
}

int lookup(char *s, char **t)
{
    char **u;
    int l;
    int x;

    l = strlen(s);
    for (u = t, x = 0; *u != TABLE_END; u++, x++) {
        if (*u == NULL)
            continue;
        if (strncasecmp(s,*u,l) == 0)
            return x;
    }
    return -1;
}

XMOB *find_mob(XZON *z, char *name)
{
    XMOB *m, *q = NULL;
    char *s;

    for (m = z->mobs; m != NULL; m = m->next) {
        if (strcasecmp(m->name,name) == 0)
            return m;
    }
    for (m = z->rmobs; m != NULL; m = m->next) {
        if (strcasecmp(m->name,name) == 0)
            return m;
        q = m;
    }
    m = &mobs[num_m++];
    bzero((char *)m,sizeof(XMOB));
    m->next = NULL;
    if (q == NULL)
        z->rmobs = m;
    else
        q->next = m;

    m->name = s = save_text(name);
    lowercase(s);
    *s = toupper(*s);
    if (strncmp(m->name,"The ", 4) == 0) {
        s += 4;
        *s = toupper(*s);
    }
    m->zone = z;
    m->mob = -1;
    m->aux = REFERRED;
    return m;
}

XOBJ *find_obj(XZON *z, char *name)
{
    XOBJ *o, *q = NULL;
    char *s;

    for (o = z->objs; o != NULL; o = o->next) {
        if (strcasecmp(o->name,name) == 0)
            return o;
        q = o;
    }
    o = &objs[num_o++];
    bzero((char *)o,sizeof(XOBJ));
    o->next = NULL;
    if (q == NULL)
        z->objs = o;
    else
        q->next = o;

    o->name = s = save_text(name);
    lowercase(s);
    o->zone = z;
    o->obj  = -1;
    o->aux = REFERRED;
    return o;
}

XLOC *find_loc(XZON *z, char *name)
{
    XLOC *l, *q = NULL;

    for (l = z->locs; l != NULL; l = l->next) {
        if (strcasecmp(l->name,name) == 0)
            return l;
    }
    for (l = z->rlocs; l != NULL; l = l->next) {
        if (strcasecmp(l->name,name) == 0)
            return l;
        q = l;
    }
    l = &locs[num_l++];
    bzero((char *)l,sizeof(XLOC));
    l->next = NULL;
    if (q == NULL)
        z->rlocs = l;
    else
        q->next = l;

    l->name = save_text(name);
    l->zone = z;
    l->loc = -1;
    l->aux = REFERRED;
    return l;
}

XLOC *get_ref(char t, XZON *zo, FILE *F)
{
    char n[128];
    char zone[128];
    char *s;
    XZON *z;
    int c;
    int x;

    for (s = n, c = getc(F); isalnum(c) || c == '_'; c = getc(F)) {
        *s++ = c;
    }
    *s = 0;
    z = zo;
    if (c == '@') {
        for (s = zone, c = getc(F); isalpha(c); c = getc(F)) {
            *s++ = c;
        }
        *s = 0;
        for (z = zones, x = 0; x < num_z; ++z, ++x) {
            if (strcasecmp(z->name,zone) == 0)
                break;
        }
        if (x == num_z) {
            ungetc(c,F);
            return 0;   /* Couldn't find entry */
        }
    }
    ungetc(c,F);

    switch(t) {
    case 'L': return (XLOC *)find_loc(z,n); break;
    case 'O': return (XLOC *)find_obj(z,n); break;
    case 'M': return (XLOC *)find_mob(z,n); break;
    }
    return 0;
}

int get_int(FILE *F)
{
    int i;
    int c;
    Boolean neg;

    c = getc(F);
    while (c == ' ' || c == '\t')
        c = getc(F);
    i = 0;
    if (neg = c == '-') {
        c = getc(F);
    }
    while (isdigit(c)) {
        i = i * 10 + (c - '0');
        c = getc(F);
    }
    ungetc(c,F);
    if (neg)
        i = -i;
    return i;
}

void get_flags(XZON *z, XMOB *m, char ty, int *f, int s, char **t, FILE *F)
{
    char n[128];
    int c;
    int light = -1;
    int temp = -1;
    char *p;
    int k;
    int bno;
    int cno;

    c = getc(F);
    while (c != '{')
        c = getc(F);
    bzero(f,s);

    for (c = getc(F);c != '}';c = getc(F)) {
        if (!isalpha(c)) {
            continue;
        }
        for (p = n; isalpha(c); c = getc(F)) {
            *p++ = c;
        }
        ungetc(c,F);

        *p = 0;
        if (ty == 'L') {
            if ((k = lookup(n,L_Light)) >= 0) {
                light = k;
                continue;
            } else if ((k = lookup(n,L_Temp)) >= 0) {
                temp = k;
                continue;
            }
        }
        if ((k = lookup(n,t)) == -1) {
            fprintf(stderr,
                    "\nError in %s@%s, %cFLAGS: unknown flag %s.\n",
                    m->name, z->name, ty, n);
            xexit(1);
        }
        f[s-k/32-1] |= (1<< (k%32));
    }
    if (temp >= 0) temp <<= LFL_T_SHIFT;
    else temp = LFL_T_ORDINARY;
    if (light >= 0) light <<= LFL_L_SHIFT;
    else light = LFL_LIGHT;

    *f |= temp|light;
}

void mkdef_mob(XZON *z, XMOB *m)
{
    XMOB *p;

    if (m->aux != REFERRED) {
        fprintf(stderr,"\nMobile %s@%s is defined twice!\n", m->name, z->name);
        xexit(1);
    }
    if ((p = z->rmobs) == m) {
        z->rmobs = m->next;
    } else {
        while (p->next != m) p = p->next;
        p->next = m->next;
    }
    m->aux = DEFINED;
    m->mob = -1;
    m->pname = m->name;
    m->next = NULL;
    if ((p = z->mobs) == NULL) z->mobs = m;
    else {
        while (p->next != NULL) p = p->next;
        p->next = m;
    }
}

Boolean read_mob(FILE *F, XZON *z, char *b, int bs)
{
    XMOB *m;
    char s[128];
    char n[128];
    char r[128];
    int c;
    int d;
    char *t;
    char *v;
    int k;
    int i;

    m = NULL;
    for (;;) {
        do {
            c = getc(F);
        }
        while (isspace(c));
        for (t = s; isalnum(c) || c == '_';c = getc(F))
            *t++ = c;
        *t = 0;
        if (t == s) {
            if (c == EOF) {
                return False;
            }
            if (c != '%')
                continue;
            ungetc(c,F);
            break;
        }
        i = -1;
        while (c == ' ' || c == '\t' || c == '=')
            c = getc(F);
        ungetc(c,F);
        k = lookup(s,Mob_tab);
        if (k != T_NAME && m == NULL) {
            fprintf(stderr,
                    "\nError in zone mob:%s: Entry %s is out of sequence.\n",
                    z->name, s);
            xexit(1);
        }
        switch (k) {
        case T_NAME:
            d = 0;
            c = getc(F);
            for (t = n; isalnum(c) || c == '_'; c = getc(F)) {
                *t++ = c;
            }
            *t = 0;
            ungetc(c,F);
            m = find_mob(z,n);
            mkdef_mob(z,m);
            m->mob = -1;
            m->pname = m->name;
            m->loc = 0;
            m->str = 0;
            m->armor = 0;
            m->damage = 10;
	    m->vis = 0;
	    m->agg = 0;
	    m->speed = -1;
	    m->wimpy = 0;
            m->pflags.h = 0;
            m->pflags.l = 0;
            m->mflags.h = 0;
            m->mflags.l = 0;
            m->sflags = 0;
            m->attitude = 0;
            m->att_param = 0;
            m->desc = NULL;
	    m->exam = NULL;
            break;
        case T_PNAME:
            m->pname = v = get_text(F);
            lowercase(v);
            *v = toupper(*v);
            if (strncmp(m->pname,"The ", 4) == 0) {
                v += 4;
                *v = toupper(*v);
            }
            break;
        case T_LOC:
            m->loc = get_lref(z, F);
            break;
        case T_DESC:
            m->desc = get_text(F);
            break;
        case T_END:
            d = 0;
            c = getc(F);
            for (t = n; isalnum(c) || c == '_'; c = getc(F)) {
                *t++ = c;
            }
            *t = 0;
            ungetc(c,F);
	    if (strcasecmp(n,m->name) != 0) {
	      log( 'M', (XOBJ *)m,z,"Wrong arg to end: %s.", n);
	      m->aux = BAD;
	    }
	    m = NULL;
	    break;
        case TMOB_STR:
            m->str = get_int(F);
            break;
        case TMOB_ARMOR:
            m->armor = get_int(F);
            break;
        case TMOB_DAM:
            m->damage = get_int(F);
            break;
        case TMOB_WIMPY:
            m->wimpy = get_int(F);
            break;
        case TMOB_VIS:
            m->vis = get_int(F);
            break;
        case TMOB_AGG:
            m->agg = get_int(F);
            break;
	case TMOB_SPEED:
	    m->speed = get_int(F);
	    break;
	case TMOB_EXAM:
	    m->exam  = get_exam(F);
	    break;
        case TMOB_SFLAGS:
            get_flags(z,m,'S', (int *)&(m->sflags), 
                      sizeof(SFLAGS)/sizeof(int),Sflags,F);
            break;
        case TMOB_PFLAGS:
            get_flags(z,m,'P', (int *)&(m->pflags), 
                      sizeof(PFLAGS)/sizeof(int),Pflags,F);
            break;
        case TMOB_MFLAGS:
            get_flags(z,m,'M', (int *)&(m->mflags), 
                      sizeof(MFLAGS)/sizeof(int),Mflags,F);
            break;
        case -1:
            fprintf(stderr,
                    "\nError in zone mob:%s: %s is not a legal entry.\n",
                    z->name, s);
            xexit(1);
        default:
            fprintf(stderr,
                    "\nError in zone mob:%s: %s isn't implemented yet.\n",
                    z->name, s);
            xexit(1);
        }
        while ((c = getc(F)) != '\n') {
            if (c == EOF)
                return False;
        }
    }
    xfgets(b,bs,F);
    return True;
}

Boolean read_obj(FILE *F, XZON *z, char *b, int bs)
{
    XOBJ *o;
    XOBJ *g;
    char s[128];
    char n[128];
    char r[128];
    int c;
    int d;
    char *t;
    int k;
    int i;
    int cf;
    char cft;
    int x;

    o = NULL;
    for (;;) {
        do {
            c = getc(F);
        }
        while (isspace(c));
        for (t = s; isalnum(c) || c == '_';c = getc(F))
            *t++ = c;
        *t = 0;
        if (t == s) {
            if (c == EOF) {
                return False;
            }
            if (c != '%')
                continue;
            ungetc(c,F);
            break;
        }
        i = -1;
        if (c == '[') {
            c = getc(F);
            for (i = 0;isdigit(c);i = i * 10 + (c - '0'), c = getc(F));
            if (c != ']') {
                fprintf(stderr,
                        "\nError in zone obj:%s: not number in [..]\n",
                        z->name);
            }
            c = getc(F);
        }
        while (c == ' ' || c == '\t' || c == '=')
            c = getc(F);
        ungetc(c,F);
        k = lookup(s,Obj_tab);
        if (k != T_NAME && o == NULL) {
            fprintf(stderr,
                    "\nError in zone obj:%s: Entry %s is out of sequence.\n",
                    z->name, s);
            xexit(1);
        }
        switch (k) {
        case T_NAME:
            d = 0;
            c = getc(F);
            for (t = n; isalnum(c) || c == '_'; c = getc(F)) {
                *t++ = c;
            }
            *t = 0;
            ungetc(c,F);
            o = find_obj(z,n);
            if (o->aux != REFERRED) {
                fprintf(stderr, "\nObject %s@%s is defined twice!\n",
                        n, z->name);
                xexit(1);
            }
            o->aux = DEFINED;
            o->obj = -1;
            o->pname = o->name;
            o->linked = NULL;
            o->aname = NULL;
            o->cflag = -1;
            o->loc = 0;
            o->damage = 0;
            o->armor = 0;
            o->oflags = 0;
            o->state = -1;
            o->mstate = 0;
            o->bvalue = 0;
            o->osize = 0;
            o->oweight = 0;
            o->desc[0] = NULL;
            o->desc[1] = NULL;
            o->desc[2] = NULL;
            o->desc[3] = NULL;
            o->examine = NULL;
	    o->vis = 0;
            break;
        case T_PNAME:
            o->pname = get_text(F);
            lowercase(o->pname);
            break;
        case T_LOC:

	    fscanf(F, "%d\t:", &cf); /* */
	    /* fscanf(F, "%d%*[\t ]:", &cf); */

            switch(cf) {
            case IN_ROOM: cft = 'L'; break;
            case IN_CONTAINER: cft = 'O'; break;
            case CARRIED_BY:
            case WIELDED_BY:
            case WORN_BY:
            case BOTH_BY:
                cft = 'M';
                break;
            default:
                fprintf(stderr,
                        "\nError in obj:%s@%s: Illegal carry flag %d.\n",
                        o->name, z->name, cf);
                xexit(1);
            }
            o->cflag = cf;
            o->loc = get_ref(cft, z, F);
            break;
        case T_DESC:
            if (i < 0 || i >= 4) {
                fprintf(stderr,
                        "\nError in obj:%s@%s: Illegal index in Desc %d.\n",
                        o->name, z->name, i);
            }
            o->desc[i] = get_text(F);
            break;
        case T_END:
            d = 0;
            c = getc(F);
            for (t = n; isalnum(c) || c == '_'; c = getc(F)) {
                *t++ = c;
            }
            *t = 0;
            ungetc(c,F);
	    if (strcasecmp(n,o->name) != 0) {
	      log( 'O', o, z,"Wrong arg to end: %s.", n);
	      o->aux = BAD;
	    }
	    o = NULL;
	    break;
        case TOBJ_ANAME:
            o->aname = get_text(F);
            break;
        case TOBJ_OFLAGS:
            get_flags(z,(XMOB *)o,'O',
                     (int *)&(o->oflags), sizeof(OFLAGS)/sizeof(int),Oflags,F);
            break;
        case TOBJ_ARMOR:
            o->armor = get_int(F);
            break;
        case TOBJ_DAMAGE:
            o->damage = get_int(F);
            break;
        case TOBJ_MAX_STATE:
            o->mstate = get_int(F);
            break;
        case TOBJ_STATE:
            o->state = get_int(F);
            break;
        case TOBJ_BVALUE:
            o->bvalue = get_int(F);
            break;
        case TOBJ_SIZE:
            o->osize = get_int(F);
            break;
        case TOBJ_WEIGHT:
            o->oweight = get_int(F);
            break;
        case TOBJ_LINKED:
            if ((o->linked = get_oref(z,F)) == NULL)
                o->linked = (XOBJ *)(-1);
            break;
        case TOBJ_EXAM:
            o->examine = get_exam(F);
            break;
        case TOBJ_VIS:
            o->vis = get_int(F);
            break;
        case -1:
            fprintf(stderr,
                    "\nError in zone obj:%s: %s is not a legal entry.\n",
                    z->name, s);
            xexit(1);
        default:
            fprintf(stderr,
                    "\nError in zone obj:%s: %s isn't implemented yet.\n",
                    z->name, s);
            xexit(1);
        }
        while ((c = getc(F)) != '\n') {
            if (c == EOF)
                return False;
        }
    }
    xfgets(b,bs,F);
    return True;
}

void mkdef_loc(XZON *z, XLOC *l)
{
    XLOC *p, *q;

    if (l->aux != REFERRED) {
        fprintf(stderr,"\nRoom %s@%s is defined twice!\n", l->name, z->name);
        xexit(1);
    }
    if ((p = z->rlocs) == l) {
        z->rlocs = l->next;
    } else {
        while (p->next != l) p = p->next;
        p->next = l->next;
    }
    l->aux = DEFINED;
    l->loc = 0;
    l->next = NULL;
    if ((p = z->locs) == NULL) z->locs = l;
    else {
        while (p->next != NULL) p = p->next;
        p->next = l;
    }
}

Boolean read_loc(FILE *F, XZON *z, char *b, int bs)
{
    XLOC *l;
    char s[128];
    char n[128];
    char r[128];
    int c;
    int d;
    int g;
    char *t;
    int k;
    int i;

    l = NULL;
    for (;;) {
        do {
            c = getc(F);
        }
        while (isspace(c));
        for (t = s; isalnum(c) || c == '_';c = getc(F))
            *t++ = c;
        *t = 0;
        if (t == s) {
            if (c == EOF) {
                return False;
            }
            if (c == '%') {
                ungetc(c,F);
                break;
            }
            continue;
        }

        l = find_loc(z,s);
        mkdef_loc(z,l);

        while (c != ';') {
            while (isspace(c))
                c = getc(F);
            for (t = n; isalpha(c); c = getc(F)) {
                *t++ = c;
            }
            *t = 0;
            if (t == n) {
                if (c == ';')
                    break;
                if (t == n && c != ';') {
                    fprintf(stderr,"\n Expected ';' in room %s@%s.\n",
                            s, z->name);
                    xexit(1);
                }
            }
            if (c != ':') {
                fprintf(stderr,"\n Expected ':' in room %s@%s.\n",
                        s, z->name);
                xexit(1);
            }
            if ((k = lookup(n,Exits)) == -1) {
                fprintf(stderr,"\n Illegal exit %s in room %s@%s.\n",
                        n, s, z->name);
                xexit(1);
            }
	    if (l->exit_types[k] != 0) {
	      log('L', (XOBJ *)l, z,
		  "Multiple defineds of exit %s.", Exits[k]);
	    }

            for (c = getc(F);isspace(c); c = getc(F));
            switch(c) {
            case '#':
                l->exit_types[k] = '#';
                l->exits[k] = (XLOC *)get_int(F);
                break;
            case '^':
                l->exit_types[k] = '^';
                l->exits[k] = (XLOC *)get_oref(z, F);
                break;
    default:
                l->exit_types[k] = ' ';
                ungetc(c,F);
                l->exits[k] = get_lref(z, F);
            }
            c = getc(F);
        }
        while (getc(F) != '\n');
        c = getc(F);
        while (isspace(c))
            c = getc(F);
        for (t = n; isalpha(c); c = getc(F)) {
            *t++ = c;
        }
        *t = 0;
        if ((g = t - n) == 0 || strncasecmp(n,"Lflags", g) != 0) {
            fprintf(stderr,"\nError in %s@%s, Lflags entry required.\n",
                    s, z->name);
            xexit(1);
        }
        ungetc(c,F);
        get_flags(z,(XMOB *)l,'L',
                  (int *)&(l->lflags), sizeof(LFLAGS)/sizeof(int),Lflags,F);
        while (getc(F) != '\n');
        c = getc(F);
        t = n;
        while (c != '^') {
            *t++ = c;
            c = getc(F);
        }
        *t = 0;
        while (getc(F) != '\n');
        l->pname = save_text(n);
        l->description = get_description(F);
    }
}

void read_zones(XZON *zo, int nz)
{
    int z;
    XZON *zon;
    FILE *F;
    Boolean multiple;
    char buff[128];
    char buff2[128];

    printf("\n");
    for (z = 0, zon = zo; z < nz; ++z, ++zon, pclose(F)) {
        sprintf(buff2, "Zone %d(%s) from %s", z, zon->name, zon->fname);
        printf("    %-75s\r", buff2);
        fflush(stdout);
        if ((F = zopen(zon->fname,
                       zon->name,&multiple,buff,sizeof(buff))) == NULL) {
            fprintf(stderr,"\nZone not found: %s in file %s.\n",
                    zon->name, zon->fname);
            xexit(1);
        }
        if (strncasecmp(buff,"%mobiles",8) == 0) {
            if (!read_mob(F,zon,buff,sizeof(buff)))
                continue;
        }
        if (strncasecmp(buff, "%objects", 8) == 0) {
            if (!read_obj(F,zon,buff,sizeof(buff)))
                continue;
        }
        if (strncasecmp(buff, "%locations", 10) == 0) {
            read_loc(F,zon,buff,sizeof(buff));
            continue;
        } else if (strncasecmp(buff, "%zone:", 6) == 0) {
            if (!multiple) {
                fprintf(stderr,"\nError in zone file, %s unexpected.\n", buff);
                xexit(1);
            }
            continue;
        } else {
            fprintf(stderr, "\n Error in zone file: unknown sequence %s.",
                    buff);
            xexit(1);
        }

    }
}

Boolean obj_ok(XOBJ *O, XOBJ *F, char t)
{
    XOBJ *L;
    XOBJ *G;
    XLOC *R;
    int k;

    if (O == 0 || O == (XOBJ *)(-1) || O->aux == BAD) {
        return False;
    } else if (O->aux == F && t == IS_LINK) {
        return True;
    } else if (O->aux == F) {
        log('O',O,O->zone,"Recursive contents in object.");
        O->aux = BAD;
        return False;
    } else if (O->loc == NULL) {
        log('O',O,O->zone,"Location does not exist.");
        O->aux = BAD;
        return False;
    } else if (O->obj != -1) {
        log('O',O,O->zone,"O->obj == %d, should be -1");
        O->aux = BAD;
        return False;
    } else if (O->aux != UNKNOWN) {
        return True;
    }

    O->aux = F;
    if (O->cflag == IN_CONTAINER && !obj_ok((XOBJ *)(O->loc),F,IS_CONTAINED)) {
        G = (XOBJ *)(O->loc);
        log('O',O,O->zone,"Container %s@%s[%s] is bad",
            G->name, G->zone->name, G->pname);
        O->aux = BAD;
        return False;
    }

    if ((L = O->linked) != NULL) {
        if (L == (XOBJ *)(-1)) {
            log('O',O,O->zone,"Linked object doesn't exist.");
            O->aux = BAD;
            return False;
        } else if (L == O) {
            log('O',O,O->zone,"Linked object to itself.");
            O->aux = BAD;
            return False;
        } else if (L->linked != O) {
            log('O',O,O->zone,"Linked object %s@%s[%s] isn't linked back.",
                L->name, L->zone->name, L->pname);
            O->aux = BAD;
            return False;
        } else if (L->aux == BAD) {
            log('O',O,O->zone,"Linked object %s@%s[%s] is bad.",
                L->name, L->zone->name, L->pname);
            O->aux = BAD;
            return False;
        } else if ((G = L->aux) != GOOD) {
            if (G == UNKNOWN)
                G = L;

            if (!obj_ok(L,G,IS_LINK)) {
                log('O',O,O->zone,"Error with linked object %s@%s[%s].",
                    L->name, L->zone->name, L->pname);
                L->aux = BAD;
                O->aux = BAD;
                return False;
            }
        }

        if (O->state == -1) {
            if ((O->state = L->state) == -1) {
                O->state = L->state = 0;
            }
        } else if (L->state == -1) {
            L->state = O->state;
        } else if (L->state != O->state) {
            log('O',O,O->zone,
                "Initial states on linked objects %s@%s[%s] are not the same.",
                    L->name, L->zone->name, L->pname);
            L->aux = BAD;
            O->aux = BAD;
            return False;
        }

    } else if (O->state == -1) {
        O->state = 0;
    }

    if ((R = O->loc) != NULL) {
        switch(O->cflag) {
        case IN_ROOM:
            if (((int)(R->loc)) <= 0 || R->aux != GOOD)
                R = NULL;
            break;
        case IN_CONTAINER:
            break;
        case CARRIED_BY:
        case WORN_BY:
        case WIELDED_BY:
        case BOTH_BY:
            if (((XMOB *)R)->mob < 0 || ((XMOB *)R)->aux != GOOD)
                R = NULL;
            break;
        default:
            R = NULL;
        }
    }
    if (R == NULL) {
        log('O',O,O->zone,"Invalid location.");
        O->aux = BAD;
        return False;
    }

/*
    if (O->linked == NULL) {
        if (not_linked_l == NULL) {
            not_linked = not_linked_l = O;
        } else {
            not_linked_l->the_next = O;
            not_linked_l = O;
        }
        ++num_unlinked;
    } else if (O < O->linked) {
        if (linked_objs_l == NULL) {
            linked_objs = linked_objs_l = O;
        } else {
            linked_objs_l->the_next = O;
            linked_objs_l = O;
        }
        ++num_linked;
    }
*/

    if (obj_list == NULL) {
	    obj_list_l = obj_list = O;
    }
    else {
	    obj_list_l->the_next = obj_list_l = O;
    }

    if (O->linked == NULL)
      ++num_unlinked;
    else if (O < O->linked)
      ++num_linked;


    O->aux = GOOD;
    return True;
}

void clean_up(XZON *zon, int nz, int *mm, int *oo, int *lo, int *ll)
{
    XOBJ *O;
    XOBJ *F;
    XMOB *M;
    XLOC *L;
    XLOC *E;
    XZON *Z;
    int x;
    int k;
    int l;
    int m;
    int o;
    int z;
    char et;

    for (M = mobs, x = 0; x < num_m; M++, x++) {
        if (M->aux == BAD)
	  continue;
        if (M->aux != DEFINED) {
            M->aux = BAD;
            log('M',(XOBJ *)M,M->zone,"Mobile isn't properly defined..");
        } else {
	    char *p = M->pname;
            M->aux = UNKNOWN;
	    if (M->agg == -1) {
	      M->agg = 10;     /*((k = abs(M->lev)) <= 200 ? 0 : k%100);*/
	    }
	    if (M->speed == -1) {
	      M->speed = 5;
	    }
	    while (isalpha(*p) || *p == ' ') p++;
	    if (*p != '\0')
	      log('M',(XOBJ *)M,M->zone,
	      "Mobile in-game name must consist of letters only.");
        }
    }
    for (L = locs, x = 0; x < num_l; L++, x++) {
        if (L->aux != DEFINED) {
            log('L',(XOBJ *)L,L->zone,"Location isn't properly defined..");
            L->aux = BAD;
        } else {
            L->aux = UNKNOWN;
            L->loc = -2;
        }
    }
    for (O = objs, x = 0; x < num_o; O++, x++) {
        if (O->aux == BAD)
	    continue;
        if (O->aux != DEFINED) {
            log('O',O,O->zone,"Object isn't properly defined..");
            O->aux = BAD;
        } else {
	    char *p = O->pname;
            O->obj = -2;
            O->the_next = NULL;
            O->aux = UNKNOWN;
	    while (isalpha(*p) || *p == ' ') p++;
	    if (*p != '\0')
	      log('O',O,O->zone,
	      "Object in-game name must consist of letters only.");
        }
    }

    for (Z = zon, z = 0, o = 0; z < nz; ++z, ++Z) {
        Z->n_loc = 0;
        Z->n_mob;
        for (O = Z->objs; O != NULL; O = O->next) {
            if (O->aux == UNKNOWN) {
                O->obj = -1;
                O->zone = Z;
            }
        }

        for (L = Z->locs; L != NULL; L = L->next) {
            if (L->aux == UNKNOWN) {
                L->loc = -1;
            }
        }
    }

    for (Z = zon, z = 0, l = 0; z < nz; ++z, ++Z) {
        Z->loc = l;
        for (L = Z->locs; L != NULL; L = L->next) {
            if (L->aux == UNKNOWN && L->pname != NULL
                && L->description != NULL) {
                L->loc = ++l;
                L->aux = GOOD;
                Z->n_loc++;
            }
        }
    }

    for (Z = zon, z = 0, m = 0; z < nz; ++z, ++Z) {
        Z->mob = m;
        for (M = Z->mobs; M != NULL; M = M->next) {
            if (M->aux == UNKNOWN && M->loc != NULL && M->loc->aux == GOOD) {
                M->mob = m++;
                M->aux = GOOD;
                Z->n_mob++;
            }
        }
    }

    for (Z = zon, z = 0, o = 0; z < nz; ++z, ++Z) {
        for (O = Z->objs; O != NULL; O = O->next) {
            if ((F = O->aux) == BAD || F == GOOD)
                continue;
            if (F ==  REFERRED || F == DEFINED) {
                log('O',O,O->zone,"Object isn't properly checked.");
                O->aux = BAD;
                continue;
            }
            if (F == UNKNOWN)
                F = O;
            if (!obj_ok(O,F,IS_CHECK)) {
                log('O',O,O->zone,"General error with object.");
                O->aux = BAD;
            } else {
                O->aux = GOOD;
            }
        }
    }

    for (Z = zon, z = 0; z < nz; ++z, ++Z) {
        for (L = Z->locs; L != NULL; L = L->next) {
            if (L->aux != GOOD)
                continue;
            for (k = 0; k < NEXITS; k++) {
                E = L->exits[k];
                switch(L->exit_types[k]) {
                case '^':
                    O = (XOBJ *)E;
                    if (O->cflag != IN_ROOM
                        || O->loc != L
                        || O->aux != GOOD
                        || (F = O->linked) == NULL
                        || F->cflag != IN_ROOM) {
                        L->exits[k] = NULL;
                        L->exit_types[k] = 0;
                    }
                    break;
                case '#':
                    break;
                case ' ':
                    if (E == NULL || E->aux != GOOD) {
                        L->exits[k] = NULL;
			L->exit_types[k] = 0;
		    }
                    break;
		case 0:
		    if (L->exits[k] != NULL) {
		      log('L', (XOBJ *)L, L->zone,
			  "Garbage in exit %s, should be none.", Exits[k]);
		      L->exits[k] = NULL;
		    }
		    break;
                default:
		    log('L', (XOBJ *)L, L->zone,
			"Garbage in exit %s, exit type = %c[%03o]",
			Exits[k], L->exit_types[k],  L->exit_types[k]);
                    L->exits[k] = NULL;
                    L->exit_types[k] = 0;
                    break;
               }
            }
        }
    }

/*
    for (O = linked_objs, o = 0; O != NULL; O = O->the_next) {
        if (O->aux != GOOD || O->linked == NULL
            || O->linked->aux != GOOD) {
            printf("\nPanic Object %s@%s were supposed to be good!\n",
                   O->name, O->zone->name);
            xexit(1);
        }
        O->obj = o++;
        O->linked->obj = o++;
    }
    *lo = o;

    for (O = not_linked; O != NULL; O = O->the_next) {
        if (O->aux != GOOD) {
            printf("\nPanic Object %s@%s were supposed to be good!\n",
                   O->name, O->zone->name);
            xexit(1);

        }
        O->obj = o++;
    }
*/

    for (O = obj_list, o = *lo = 0; O != NULL; O = O->the_next) {
	    if (O->aux != GOOD || O->linked != NULL && O->linked->aux != GOOD){
		    printf("\nPanic Object %s@%s were supposed to be good!\n",
			   O->name, O->zone->name);
		    xexit(1);
	    }

	    O->obj = o++;

	    if (O->linked != NULL) (*lo)++;
    }

    *mm = m;
    *oo = o;
    *ll = l;
}

void write_zone(XZON *ZON, int numz)
{
    FILE *F;
    int z;
    XZON *Z;

    F = Do_fopen(zone_file,"w");
    fprintf(F,"%d\n", numz);
    for (Z = ZON, z = 0; z < numz; ++z, ++Z) {
        fprintf(F,"%s\t%d\n", Z->name, Z->loc);
    }
    fclose(F);
}

void write_mob(XZON *ZON, int numz,int m)
{
    FILE *F;
    FILE *H;
    int z;
    int i = 0;
    XZON *Z;
    XMOB *M;
    char zn[32];
    char n[64];
    char b[128];

    F = Do_fopen(mob_file,"w");
    H = Do_fopen(mobh_file, "w");
    fprintf(F,"%d\n", m);

   /* Print out header */
    (void) fprintf(H, "\
/*\n\
**\tMobiles file header generated from %s\n\
**\tDON'T MAKE CHANGES HERE -- THEY WILL GO AWAY!\n\
*/\n\n",
       main_file);

    for (Z = ZON, z = 0; z < numz; ++z, ++Z) {
        strcpy(zn,Z->name);
        uppercase(zn);
        fprintf(H, "#define MOBMIN_%s\t%d\n", zn, Z->mob);
        fprintf(H, "#define MOBMAX_%s\t%d\n", zn, Z->mob + Z->n_mob);
        for (M = Z->mobs; M != NULL; M = M->next, i++) {
            if (M->aux != GOOD) {
	      log('M',(XOBJ *)M,Z,"Mobile not found good.");
	      continue;
            }
            fprintf(F,"%s^\n", M->pname);
            fprintf(F,"%d %d %d %d %d %d %d %d %d %d %d\n",
                    i, i, z, -(M->loc->loc), M->str,
		    M->damage, M->agg, M->armor, M->speed, M->vis, M->wimpy);
            fprintf(F,"0x%08x 0x%08x:0x%08x\n",
                    M->sflags, M->pflags.h, M->pflags.l);
            fprintf(F,"0x%08x:0x%08x\n", M->mflags.h, M->mflags.l);
            fprintf(F, "%s^\n", M->desc);
	    fprintf(F, "%s^\n\n", M->exam == NULL ? "" : M->exam);
            strcpy(n,M->name);
            uppercase(n);
            fprintf(H, "#define MOB_%s_%s\t%d\n", zn, n, M->mob);
        }
    }
    fclose(F);
    fclose(H);
}

void write_xobj(FILE *F, FILE *H, FILE *X, XOBJ *O, int obj_num)
{
    XLOC *L;
    XOBJ *C;
    XMOB *M;
    XZON *Z;
    int x;
    int y;
    int j;
    OFLAGS f;
    char *s;
    int obj_loc;
    char n[64];
    char z[32];
    char b[128];

    char                *name;
    int                 obj;

    L = O->loc;
    switch(O->cflag) {
    case IN_ROOM: Z = L->zone; obj_loc = -(L->loc); break;
    case IN_CONTAINER: C = (XOBJ *)L; Z = C->zone; obj_loc = C->obj; break;
    case CARRIED_BY:
    case WIELDED_BY:
    case WORN_BY:
    case BOTH_BY: M = (XMOB *)L; Z = M->zone; obj_loc = M->mob; break;
    default:
        printf("\nPanic carry flag is %d!\n", O->cflag);
        xexit(1);
    }

    f = O->oflags;


    fprintf(F,"%s %s %d %d %d %d %d %d %d %d %d %d %ld %d %d %d %d\n",
            O->pname, (O->aname == NULL?"<null>":O->aname),
	    O->zone->zone,
	    obj_num, obj_num,
	    O->linked != NULL ? O->linked->obj : -1,
	    O->vis, O->cflag, obj_loc,
            O->state, O->damage,
            O->armor, O->oflags,
            O->mstate, O->bvalue,
            O->osize, O->oweight);
    for (x = 0; x < 4; ++x) {
        if ((s = O->desc[x]) == NULL)
            s = "";
        fprintf(F,"%s^\n", s);
    }
    if ((s = O->examine) == NULL)
        s = "";
    fprintf(F,"%s^\n\n", s);
    strcpy(n,O->name);
    uppercase(n);
    strcpy(z,O->zone->name);
    uppercase(z);

    fprintf(H,"#define OBJ_%s_%s\t%d\n", z, n, O->obj);
    fprintf(X,"\n\nName = %s@%s, PName = %s\nLocation = ",
            O->name, O->zone->name, O->pname);
    switch(O->cflag) {
    case IN_ROOM:
        fprintf(X, "In room %s@%s[%s](%d)",
                L->name, Z->name, L->pname, obj_loc);
        break;
    case IN_CONTAINER:
        fprintf(X, "In container %s@%s[%s](%d)",
                C->name, Z->name, C->pname, obj_loc);
        break;
    case CARRIED_BY:
    case WIELDED_BY:
    case WORN_BY:
    case BOTH_BY:
        fprintf(X, "%s %s@%s[%s](%d)",
                Cflags[O->cflag], M->name, Z->name, M->pname, obj_loc);
        break;
    }

    if (O->linked != NULL)
      fprintf(X, "\nLinked to object %d (%s@%s)\n", O->linked->obj,
	      O->linked->name, O->linked->zone->name);

    fprintf(X,"\nState = %d, Damage = %d, Armor = %d, Flags = 0x%08x\n",
            O->state, O->damage, O->armor, f);
    if (f != 0) {
        fprintf(X,"OFlags:");
        for (y = 31, j = 0; y >= 0; --y, f <<= 1) {
            if (f >= 0)
                continue;
            if (Oflags[y] != NULL)
                fprintf(X, " %s", Oflags[y]);
            else
                fprintf(X, " <spare %d>", y);
            if (++j != 5)
                continue;
            j = 1;
            putc('\n', X);
        }
        putc('\n', X);
    }
}

void write_obj(XZON *ZON, int numz, int o, int l)
{
    FILE *F;
    FILE *H;
    FILE *X;
    int   i, z;
    XZON *Z;
    XOBJ *O;

    F = Do_fopen(obj_file,"w");
    H = Do_fopen(objh_file, "w");
    X = Do_fopen(reset_list, "w");

/*    fprintf(F,"%d/%d\n", o, l);*/
    fprintf(F,"%d\n", o);

   /* Print out header */
    (void) fprintf(H, "\
/*\n\
**\tObject file header generated from %s\n\
**\tDON'T MAKE CHANGES HERE -- THEY WILL GO AWAY!\n\
*/\n\n",
       main_file);

/*
    fprintf(X,"\n**************\n\n Linked objects\n\n**************\n");
    for (O = linked_objs; O != NULL; O = O->the_next) {
        fprintf(X,"\n ===========================\n");
        write_xobj(F,H,X,O);
        write_xobj(F,H,X,O->linked);
    }
    fprintf(X,"\n **************\n\n Unlinked objects\n\n**************\n");
    for (O = not_linked; O != NULL; O = O->the_next) {
        write_xobj(F,H,X,O);
    }
*/
    fprintf(X,"\n**************\n\n Objects\n\n**************\n");
    for (O = obj_list, i = 0; O != NULL; O = O->the_next, i++) {
        fprintf(X,"\n ===========================\n");
        write_xobj(F,H,X,O,i);
    }


    fprintf(X, "\n *************\n\n The End\n\n**************\n");
    fclose(F);
    fclose(H);
    fclose(X);
}

static char *c_ex(char *s,int x, int *Ex, Boolean *ex,Boolean neg)
{
    char c;

    if (ex[x]) {
        ex[x] = False;
    } else if ((Ex[x] == 0) == neg) {
        ex[x] = True;
    } else {
        c = s[-1];
        while (*s != 0) {
            if (*s == '^' && s[1] == c)
                return s + 2;
            ++s;
        }
    }
    return s;
}

static char *c_zo(char *s,Boolean neg)
{
    XZON *Z;
    char zname[64];
    char *t, *q;
    int z;

    if (*s != '(')
        return s;
    for (t = zname, q = s; *++q != 0 && *q != ')';)
        *t++ = *q;
    if (*q == 0)
        return s;
    ++q;
    if (t == zname)
        return q;
    *t = 0;
    for (z = 0, Z = zones; z < num_z; ++z, ++Z) {
        if (strcasecmp(zname,Z->name) == 0)
            continue;
        neg = !neg;
        break;
    }
    if (neg)
        return q;
    while (*q != 0 && (*q != '^' || q[1] != 'z')) ++q;
    if (*q == 0)
        return q;
    q += 2;
    if (*q == '(' && q[1] == ')')
        q += 2;
    return q;
}

void write_loc(XZON *ZON,int numz,int l)
{
    FILE *F;
    FILE *H;
    int z;
    int x;
    int y;
    int i = -1;
    Boolean neg;
    Boolean ex[NEXITS];   /* True if in condition ^<exit> */
    int Ex[NEXITS]; /* The calculated exit number.. */
    XZON *Z;
    XLOC *L;
    XLOC *E;
    char *s;
    char c;
    char zn[32];
    char n[64];
    char b[128];

    F = Do_fopen(loc_file,"w");
    H = Do_fopen(loch_file, "w");
    fprintf(F,"%d\n", l);

   /* Print out header */
    (void) fprintf(H, "\
/*\n\
**\tLocations file header generated from %s\n\
**\tDON'T MAKE CHANGES HERE -- THEY WILL GO AWAY!\n\
*/\n\n",
       main_file);

    for (Z = ZON, z = 0; z < numz; ++z, ++Z) {
        strcpy(zn,Z->name);
        uppercase(zn);
        fprintf(H, "#define LOCMIN_%s\t%d\n", zn, -(Z->loc));
        fprintf(H, "#define LOCMAX_%s\t%d\n", zn, -(Z->loc + Z->n_loc));
        for (L = Z->locs; L != NULL; L = L->next, i--) {
            if (L->aux != GOOD) {
                log('L',(XOBJ *)L,Z,"Location not found good.");
                continue;
            }
            fprintf(F,"%d %d", /*L->loc,*/ i, z);
            for (x = 0; x < NEXITS; x++) {
                E = L->exits[x];
                ex[x] = False;
                switch (L->exit_types[x]) {
                case '^': y = DOOR + ((XOBJ *)L->exits[x])->obj; break;
                case '#': y = (int)(L->exits[x]); break;
                case ' ': y = -(L->exits[x]->loc); break;
                case 0: y = 0; break;
                default:
                    printf("\nPanic Room %d has illegal exit type %s: %c!\n",
                           L->loc, Exits[x], L->exit_types[x]);
                    xexit(1);
                }
                Ex[x] = y;
                fprintf( F, " %d", y);
            }
            fprintf(F, "\n0x%08x\n%s^\n", L->lflags, L->pname);
            s = L->description;
            while (*s != 0) {
                if ((c = *s++) != '^') {
                    putc(c,F);
                    continue;
                }
                neg = False;
                if (*s == '!') {
                    neg = True;
                    ++s;
                }

                switch(c = *s++) {
                case 'n':       s = c_ex(s,0,Ex,ex,neg); continue;
                case 'e':       s = c_ex(s,1,Ex,ex,neg); continue;
                case 's':       s = c_ex(s,2,Ex,ex,neg); continue;
                case 'w':       s = c_ex(s,3,Ex,ex,neg); continue;
                case 'u':       s = c_ex(s,4,Ex,ex,neg); continue;
                case 'd':       s = c_ex(s,5,Ex,ex,neg); continue;
                case 'z':       s = c_zo(s,neg); continue;
                default:        putc(c,F); continue;
                }
            }
            fprintf(F,"^\n");

            strcpy(n,L->name);
            uppercase(n);
            fprintf(H, "#define LOC_%s_%s\t%d\n", zn, n, -(L->loc));
        }
    }
    fclose(F);
    fclose(H);
}

void write_files(XZON *ZON, int numz, int l, int o, int lo, int m)
{
    write_zone(ZON,numz);
    write_mob(ZON,numz,m);
    write_obj(ZON,numz,o,lo);
    write_loc(ZON,numz,l);
}

void make_data(int argc,char **argv)
{
    int numz;
    int numl;
    int numo;
    int numm;
    int numlo;

    if (argc < 2) {
        fprintf(stderr,"\nToo few arguments.\n");
        xexit(1);
    }
    numz = read_main(argv[1]);
    read_zones(zones,numz);
    clean_up(zones,numz,&numm,&numo,&numlo,&numl);

    write_files(zones,numz,numl,numo,numlo,numm);
    printf("\nMade %d zones with %d locations,\n%d objects (%d linked) and %d mobiles.\nUsed %d of text space out of a total of %d (%d unused)\n",
           numz, numl, numo, numlo, numm, textsp - texts, sizeof(texts),
           sizeof(texts) - (textsp - texts));
    if (n_logs > 0) {
        printf("\nNumber of errors is %d, check log file %s.\n\n",
               n_logs, log_file);
        fprintf(LogFile, "Total number of logs is %d.\n", n_logs);
    } else {
        printf("\nNo errors, log file %s is empty.\n\n", log_file);
    }
    fclose(LogFile);
}



#ifdef VARGS

void log(char t,XOBJ *O,XZON *Z,char *f, ...)
{
    va_list pvar;
    char *n;
    char *z;
    char *p;
    char *q;
    char b[1024];

    va_start(pvar,f);
    vsprintf(b,f,pvar);
    z = Z->name;
    ++n_logs;
    switch (t) {
    case 'L':
        n = ((XLOC *)O)->name;
        p = ((XLOC *)O)->pname;
        q = "Loc";
        break;
    case 'M':
        n = ((XMOB *)O)->name;
        p = ((XMOB *)O)->pname;
        q = "Mob";
        break;
    case 'O':
        n = O->name;
        p = O->pname;
        q = "Obj";
        break;
    default:
        fprintf(stderr,"\nIllegal type %c.\n", t);
        exit(1);
    }
    fprintf(LogFile,"%s: %s@%s[%s] %s\n", q, n, z, p, b);
}

#else

void log(char t,XOBJ *O,XZON *Z,char *f,
         char *arg1, char *arg2, char *arg3, char *arg4)
{
    char *n;
    char *z;
    char *p;
    char *q;
    char b[1024];

    sprintf(b, f, arg1, arg2, arg3, arg4);

    z = Z->name;
    ++n_logs;
    switch (t) {
    case 'L':
        n = ((XLOC *)O)->name;
        p = ((XLOC *)O)->pname;
        q = "Loc";
        break;
    case 'M':
        n = ((XMOB *)O)->name;
        p = ((XMOB *)O)->pname;
        q = "Mob";
        break;
    case 'O':
        n = O->name;
        p = O->pname;
        q = "Obj";
        break;
    default:
        fprintf(stderr,"\nIllegal type %c.\n", t);
        exit(1);
    }
    fprintf(LogFile,"%s: %s@%s[%s] %s\n", q, n, z, p, b);
}
#endif