/* $Header: db.h,v 2.0 90/05/05 12:45:34 lachesis Exp $
 * $Log:    db.h,v $
 * Revision 2.0  90/05/05  12:45:34  lachesis
 * Incorporated ABODE and HAVEN flags (remembering to convert FireFoot's
 * usage of those flags to ours).
 * Added Examine of objects that don't belong to you, added GOD_PRIV.
 *
 * Revision 1.4  90/04/24  14:46:30  lachesis
 * Fixed the @odrop on rooms to links.
 *
 * Revision 1.3  90/04/21  17:20:43  lachesis
 * Added property lists.
 *
 * Revision 1.2  90/04/20  14:06:26  lachesis
 * Added @odrop && @drop.
 *
 * Revision 1.1  90/04/14  14:56:34  lachesis
 * Initial revision
 *
 */
#include "copyright.h"

#ifndef __DB_H
#define __DB_H

#ifdef TEST_MALLOC
extern int malloc_count;
#define malloc(x) (malloc_count++, malloc(x))
#define free(x) (malloc_count--, free(x))
#endif /* TEST_MALLOC */

typedef int dbref;              /* offset into db */

#define TYPE_ROOM   0x0
#define TYPE_THING  0x1
#define TYPE_EXIT   0x2
#define TYPE_PLAYER     0x3
#ifdef RECYCLE
#define TYPE_GARBAGE    0x6
#endif
#define NOTYPE      0x7         /* no particular type */
#define TYPE_MASK   0x7         /* room for expansion */
#define ANTILOCK    0x8         /* negates key (*OBSOLETE*) */
#define WIZARD      0x10        /* gets automatic control */
#define LINK_OK     0x20        /* anybody can link to this room */
#define DARK        0x40        /* contents of room are not printed */
#define TEMPLE      0x80        /* objects dropped in this room go home */
#define STICKY      0x100       /* this object goes home when dropped */

#ifdef RESTRICTED_BUILDING
#define BUILDER     0x200       /* this player can use construction commands */
#endif /* RESTRICTED_BUILDING */

#define CHOWN_OK    0x400       /* this player can be @chowned to */

#define JUMP_OK     0x800       /* A room which can be Trumped from, or */
                /* a player who can be Trumped to */
#ifdef GENDER
#define GENDER_MASK 0x3000      /* 2 bits of gender */
#define GENDER_SHIFT    12      /* 0x1000 is 12 bits over (for shifting) */
#define GENDER_UNASSIGNED   0x0 /* unassigned - the default */
#define GENDER_NEUTER   0x1     /* neuter */
#define GENDER_FEMALE   0x2     /* for women */
#define GENDER_MALE 0x3         /* for men */

#define Genderof(x) ((db[(x)].flags & GENDER_MASK) >> GENDER_SHIFT)
#endif /* GENDER */

#ifdef HAVEN
#undef HAVEN
#define HAVEN         0x10000   /* can't kill in here */
#endif /* HAVEN */

#ifdef ABODE
#undef ABODE
#define ABODE         0x20000   /* can set home here */
#endif /* ABODE */

/* GOD_PRIV implementation */
/* GOD can't be subverted. */
#ifdef GOD_PRIV
#define GOD ((dbref) 1)
#define God(x) ((x) == (GOD))
#endif /* GOD_PRIV */

typedef int object_flag_type;

#define Typeof(x) (x == HOME ? TYPE_ROOM : (db[(x)].flags & TYPE_MASK))
#define Wizard(x) ((db[(x)].flags & WIZARD) != 0)
#define Dark(x) ((db[(x)].flags & DARK) != 0)

#ifdef RESTRICTED_BUILDING
#define Builder(x) ((db[(x)].flags & (WIZARD|BUILDER)) != 0)
#endif /* RESTRICTED_BUILDING */

typedef void *voidptr;

/* Properties lists */
struct plist {
  const char *type;             /* kind of property -- e.g. "sex" */
  const char *class;            /* value of this property  -- e.g. "male" */
#ifdef NUMBER_PROPS
  int value;                    /* for integer property types like "dollars" */
#endif
  struct plist *next;           /* next item on property list */
};

/* property lists are used thus:

   @set me=property:class

   As of right now, the value field is not used, but it is there for later
   expansion.

   SEX is no longer going to be a flag, it's going to be a property, so that
   locks can lock against the sex of the character.                         */

/* Boolean expressions, for locks */
typedef char boolexp_type;

#define BOOLEXP_AND 0
#define BOOLEXP_OR 1
#define BOOLEXP_NOT 2
#define BOOLEXP_CONST 3
#define BOOLEXP_PROP 4

struct boolexp {
  boolexp_type type;
  struct boolexp *sub1;
  struct boolexp *sub2;
  dbref thing;
  struct plist *prop_check;
};

#define TRUE_BOOLEXP ((struct boolexp *) 0)

/* special dbref's */
#define NOTHING (-1)            /* null dbref */
#define AMBIGUOUS (-2)          /* multiple possibilities, for matchers */
#define HOME (-3)               /* virtual room, represents mover's home */

/* union of type-specific fields */

union specific {
  struct {                      /* ROOM-specific fields */
    dbref dropto;
    dbref exits;
    dbref owner;
  } room;
  struct {                      /* THING-specific fields */
    dbref home;
    dbref actions;
    dbref owner;
    int value;
  } thing;
  struct {                      /* EXIT-specific fields */
    int ndest;
    dbref *dest;
    dbref owner;
  } exit;
  struct {                      /* PLAYER-specific fields */
    dbref home;
    dbref actions;
    int pennies;
    const char *password;
  } player;
};

struct object {

  const char *name;
  const char *description;
  dbref location;               /* pointer to container */
  dbref contents;
  dbref next;                   /* pointer to next in contents/exits chain */

  /* the following are used for pickups for things, entry for exits */
  struct boolexp *key;          /* if not NOTHING, must have this to do op */
  const char *fail_message;     /* what you see if op fails */
  const char *succ_message;     /* what you see if op succeeds */
  const char *drop_message;     /* what you see if this thing is dropped */
  /* other messages get your name prepended, so if your name is "Foo", */
  /* and osuccess = "disappears in a blast of gamma radiation." */
  /* then others see "Foo disappears in a blast of gamma radiation." */
  /* (At some point I may put in Maven-style %-substitutions.) */
  const char *ofail;            /* what others see if op fails */
  const char *osuccess;         /* what others see if op succeeds */
  const char *odrop;            /* what others see i this is dropped */

  /* please note that drop && odrop means different things to different TYPEs
     --- for TYPE_THING,
     it is the message printed when that thing is dropped.
     --- for TYPE_EXIT,
     it is the message printed when someone enters.
     --- for TYPE_PLAYER,
     it is the message printed when you get killed.
     drop is the message that the player who killed you sees,
     odrop is the message everyone else sees after they see "someone killed
     someone".
     --- for other types, it does not make sense, though it can still be set.       */

  struct plist *properties;
  object_flag_type flags;
  union specific sp;
};

extern struct object *db;
extern dbref db_top;

extern char *alloc_string (const char *s);

extern dbref new_object (void);     /* return a new object */

extern dbref getref (FILE *);   /* Read a database reference from a file. */

extern void putref (FILE *, dbref);     /* Write one ref to the file */

extern struct boolexp *getboolexp (FILE *);     /* get a boolexp */
extern void putboolexp (FILE *, struct boolexp *);      /* put a boolexp */

extern int db_write_object (FILE *, dbref);     /* write one object to file */

extern dbref db_write (FILE * f);       /* write db to file, return # of objects */

extern dbref db_read (FILE * f);        /* read db from file, return # of objects */
                /* Warning: destroys existing db contents! */

extern void free_boolexp (struct boolexp *);
extern void db_free (void);

extern dbref parse_dbref (const char *);        /* parse a dbref */

extern void db_free_object(dbref i);
extern void db_clear_object(dbref i);

#define DOLIST(var, first) \
  for((var) = (first); (var) != NOTHING; (var) = db[(var)].next)
#define PUSH(thing, locative) \
    ((db[(thing)].next = (locative)), (locative) = (thing))
#define getloc(thing) (db[thing].location)

/*
  Usage guidelines:

  To refer to objects use db[object_ref].  Pointers to objects may
  become invalid after a call to new_object().

  The programmer is responsible for managing storage for string
  components of entries; db_read will produce malloc'd strings.  The
  alloc_string routine is provided for generating malloc'd strings
  duplicates of other strings.  Note that db_free and db_read will
  attempt to free any non-NULL string that exists in db when they are
  invoked.
*/
#endif /* __DB_H */