nakedmudv3.3/
nakedmudv3.3/lib/
nakedmudv3.3/lib/logs/
nakedmudv3.3/lib/misc/
nakedmudv3.3/lib/players/
nakedmudv3.3/lib/txt/
nakedmudv3.3/lib/world/
nakedmudv3.3/lib/world/examples/
nakedmudv3.3/lib/world/examples/mproto/
nakedmudv3.3/lib/world/examples/oproto/
nakedmudv3.3/lib/world/examples/reset/
nakedmudv3.3/lib/world/examples/rproto/
nakedmudv3.3/lib/world/examples/trigger/
nakedmudv3.3/lib/world/limbo/
nakedmudv3.3/lib/world/limbo/room/
nakedmudv3.3/lib/world/limbo/rproto/
nakedmudv3.3/src/alias/
nakedmudv3.3/src/char_vars/
nakedmudv3.3/src/editor/
nakedmudv3.3/src/example_module/
nakedmudv3.3/src/help/
nakedmudv3.3/src/set_val/
nakedmudv3.3/src/socials/
nakedmudv3.3/src/time/
//*****************************************************************************
//
// object.c
//
// this contains the basic implementation of the object data structure, and all
// of the functions needed to interact with it. If you plan on adding any other
// information to objects, it is strongly suggested you do so through auxiliary
// data (see auxiliary.h).
//
// For a recap, IF YOU PLAN ON ADDING ANY OTHER INFORMATION TO OBJECTS, IT
// IS STRONGLY SUGGESTED YOU DO SO THROUGH AUXILIARY DATA (see auxiliary.h).
//
//*****************************************************************************
#include "mud.h"
#include "extra_descs.h"
#include "utils.h"
#include "handler.h"
#include "storage.h"
#include "auxiliary.h"
#include "object.h"


// obj UIDs (unique IDs) start at a million and go 
// up by one every time a new object is created
int next_obj_uid = 1000000;


struct object_data {
  int      uid;                  // our unique identifier
  double   weight;               // how much do we weigh, minus contents
  
  char *name;                    // our name - e.g. "a shirt"
  char *prototypes;              // a list of the types we're instances of
  char *class;                   // the prototype we most directly inherit from
  char *keywords;                // words to reference us by
  char *rdesc;                   // our room description
  char *multi_name;              // our name when more than 1 appears
  char *multi_rdesc;             // our rdesc when more than 1 appears
  BUFFER *desc;                  // the description when we are looked at
  BITVECTOR *bits;               // the object bits we have turned on

  // only one of these should be set at a time
  OBJ_DATA  *container;          // the thing we are in
  ROOM_DATA *room;               // the room we are in
  CHAR_DATA *carrier;            // who has us in their inventory 
  CHAR_DATA *wearer;             // who is wearing us

  LIST      *contents;           // other objects within us
  LIST      *users;              // the people using us (furniture and stuff)

  EDESC_SET  *edescs;            // special descriptions that can be seen on us

  HASHTABLE  *auxiliary_data;    // data modules have installed in us
};


OBJ_DATA *newObj() {
  OBJ_DATA *obj = calloc(1, sizeof(OBJ_DATA));
  obj->uid            = next_obj_uid++;

  obj->weight         = 0.1;

  obj->bits           = bitvectorInstanceOf("obj_bits");
  obj->prototypes     = strdup("");
  obj->class          = strdup("");
  obj->name           = strdup("");
  obj->keywords       = strdup("");
  obj->rdesc          = strdup("");
  obj->multi_name     = strdup("");
  obj->multi_rdesc    = strdup("");
  obj->desc           = newBuffer(1);

  obj->contents       = newList();
  obj->users          = newList();

  obj->edescs         = newEdescSet();
  obj->auxiliary_data = newAuxiliaryData(AUXILIARY_TYPE_OBJ);

  return obj;
}


void deleteObj(OBJ_DATA *obj) {
  // don't remove the objects from this container.
  // it is assumed this has been done already (extract_obj)
  deleteList(obj->contents);
  // same goes for users
  deleteList(obj->users);

  if(obj->class)      free(obj->class);
  if(obj->prototypes) free(obj->prototypes);
  if(obj->name)       free(obj->name);
  if(obj->keywords)   free(obj->keywords);
  if(obj->rdesc)      free(obj->rdesc);
  if(obj->desc)       deleteBuffer(obj->desc);
  if(obj->multi_name) free(obj->multi_name);
  if(obj->multi_rdesc)free(obj->multi_rdesc);
  if(obj->bits)     deleteBitvector(obj->bits);
  if(obj->edescs)   deleteEdescSet(obj->edescs);
  deleteAuxiliaryData(obj->auxiliary_data);

  free(obj);
}


OBJ_DATA *objRead(STORAGE_SET *set) {
  OBJ_DATA *obj = newObj();
  objSetClass(obj,           read_string(set, "class"));
  objSetPrototypes(obj,      read_string(set, "prototypes"));
  objSetWeightRaw(obj,       read_double(set, "weight"));
  objSetName(obj,            read_string(set, "name"));
  objSetKeywords(obj,        read_string(set, "keywords"));
  objSetRdesc(obj,           read_string(set, "rdesc"));
  objSetDesc(obj,            read_string(set, "desc"));
  objSetMultiName(obj,       read_string(set, "multiname"));
  objSetMultiRdesc(obj,      read_string(set, "multirdesc"));
  objSetEdescs(obj,   edescSetRead(read_set(set, "edescs")));
  bitSet(obj->bits,read_string(set, "obj_bits"));
  deleteAuxiliaryData(obj->auxiliary_data);
  obj->auxiliary_data = auxiliaryDataRead(read_set(set, "auxiliary"), 
					  AUXILIARY_TYPE_OBJ);

  // parse all of our contents
  STORAGE_SET_LIST *contents = read_list(set, "contents");
  LIST *cont_list = gen_read_list(contents, objRead);
  OBJ_DATA *content = NULL;
  // make sure they're put into us
  while( (content = listPop(cont_list)) != NULL)
    obj_to_obj(content, obj);
  deleteList(cont_list);

  return obj;
}


STORAGE_SET *objStore(OBJ_DATA *obj) {
  STORAGE_SET *set = new_storage_set();
  store_string(set, "class",     obj->class);
  store_string(set, "prototypes",obj->prototypes);
  store_double(set, "weight",    obj->weight);
  store_string(set, "name",      obj->name);
  store_string(set, "keywords",  obj->keywords);
  store_string(set, "rdesc",     obj->rdesc);
  store_string(set, "desc",      bufferString(obj->desc));
  store_string(set, "multiname", obj->multi_name);
  store_string(set, "multirdesc",obj->multi_rdesc);
  store_set   (set, "edescs",    edescSetStore(obj->edescs));
  store_string(set, "obj_bits",  bitvectorGetBits(obj->bits));
  store_set   (set, "auxiliary", auxiliaryDataStore(obj->auxiliary_data));
  store_list  (set, "contents",  gen_store_list(obj->contents, objStore));

  return set;
}


void objCopyTo(OBJ_DATA *from, OBJ_DATA *to) {
  objSetWeightRaw (to, objGetWeightRaw(from));
  objSetClass     (to, objGetClass(from));
  objSetPrototypes(to, objGetPrototypes(from));
  objSetName      (to, objGetName(from));
  objSetKeywords  (to, objGetKeywords(from));
  objSetRdesc     (to, objGetRdesc(from));
  objSetDesc      (to, objGetDesc(from));
  objSetMultiName (to, objGetMultiName(from));
  objSetMultiRdesc(to, objGetMultiRdesc(from));
  edescSetCopyTo  (objGetEdescs(from), objGetEdescs(to));
  bitvectorCopyTo (from->bits, to->bits);
  auxiliaryDataCopyTo(from->auxiliary_data, to->auxiliary_data);
}

OBJ_DATA *objCopy(OBJ_DATA *obj) {
  OBJ_DATA *newobj = newObj();
  objCopyTo(obj, newobj);
  return newobj;
}

bool objIsInstance(OBJ_DATA *obj, const char *prototype) {
  return is_keyword(obj->prototypes, prototype, FALSE);
}

bool objIsName(OBJ_DATA *obj, const char *name) {
  return is_keyword(obj->keywords, name, TRUE);
}

void objAddChar(OBJ_DATA *obj, CHAR_DATA *ch) {
  listPut(obj->users, ch);
}

void objRemoveChar(OBJ_DATA *obj, CHAR_DATA *ch) {
  listRemove(obj->users, ch);
}



//*****************************************************************************
//
// set and get functions
//
//*****************************************************************************
LIST *objGetContents(OBJ_DATA *obj) {
  return obj->contents;
}

LIST *objGetUsers(OBJ_DATA *obj) {
  return obj->users;
}

const char *objGetClass(OBJ_DATA *obj) {
  return obj->class;
}

const char *objGetPrototypes(OBJ_DATA *obj) {
  return obj->prototypes;
}

const char *objGetName(OBJ_DATA *obj) {
  return obj->name;
}

const char *objGetKeywords(OBJ_DATA *obj) {
  return obj->keywords;
}

const char  *objGetRdesc   (OBJ_DATA *obj) {
  return obj->rdesc;
}

const char  *objGetDesc    (OBJ_DATA *obj) {
  return bufferString(obj->desc);
}

const char  *objGetMultiName(OBJ_DATA *obj) {
  return obj->multi_name;
}

BUFFER *objGetDescBuffer(OBJ_DATA *obj) {
  return obj->desc;
}

const char  *objGetMultiRdesc(OBJ_DATA *obj) {
  return obj->multi_rdesc;
}

EDESC_SET *objGetEdescs(OBJ_DATA *obj) {
  return obj->edescs;
}

const char *objGetEdesc(OBJ_DATA *obj, const char *keyword) {
  EDESC_DATA *edesc = edescSetGet(obj->edescs, keyword);
  if(edesc) return edescSetGetDesc(edesc);
  else return NULL;
}

CHAR_DATA *objGetCarrier(OBJ_DATA *obj) {
  return obj->carrier;
}

CHAR_DATA *objGetWearer(OBJ_DATA *obj) {
  return obj->wearer;
}

OBJ_DATA *objGetContainer(OBJ_DATA *obj) {
  return obj->container;
}

ROOM_DATA *objGetRoom(OBJ_DATA *obj) {
  return obj->room;
}

int objGetUID(OBJ_DATA *obj) {
  return obj->uid;
}

double objGetWeightRaw(OBJ_DATA *obj) {
  return obj->weight;
}

double objGetWeight(OBJ_DATA *obj) {
  double tot_weight = obj->weight;
  if(listSize(obj->contents) > 0) {
    LIST_ITERATOR *cont_i = newListIterator(obj->contents);
    OBJ_DATA *cont = NULL;

    ITERATE_LIST(cont, cont_i)
      tot_weight += objGetWeight(cont);
    deleteListIterator(cont_i);
  }
  return tot_weight;
}

BITVECTOR *objGetBits(OBJ_DATA *obj) {
  return obj->bits;
}

void *objGetAuxiliaryData(const OBJ_DATA *obj, const char *name) {
  return hashGet(obj->auxiliary_data, name);
}

void objSetKeywords(OBJ_DATA *obj, const char *keywords) {
  if(obj->keywords) free(obj->keywords);
  obj->keywords = strdupsafe(keywords);
}

void objSetRdesc(OBJ_DATA *obj, const char *rdesc) {
  if(obj->rdesc) free(obj->rdesc);
  obj->rdesc = strdupsafe(rdesc);
}

void objSetClass(OBJ_DATA *obj, const char *prototype) {
  if(obj->class) free(obj->class);
  obj->class = strdupsafe(prototype);
}

void objSetPrototypes(OBJ_DATA *obj, const char *prototypes) {
  if(obj->prototypes) free(obj->prototypes);
  obj->prototypes = strdupsafe(prototypes);
}

void objAddPrototype(OBJ_DATA *obj, const char *prototype) {
  add_keyword(&obj->prototypes, prototype);
}

void objSetName(OBJ_DATA *obj, const char *name) {
  if(obj->name) free(obj->name);
  obj->name = strdupsafe(name);
}

void objSetDesc(OBJ_DATA *obj, const char *desc) {
  bufferClear(obj->desc);
  bufferCat(obj->desc, (desc ? desc : ""));
}

void objSetMultiName(OBJ_DATA *obj, const char *multi_name) {
  if(obj->multi_name) free(obj->multi_name);
  obj->multi_name = strdupsafe(multi_name);
}

void objSetMultiRdesc(OBJ_DATA *obj, const char *multi_rdesc) {
  if(obj->multi_rdesc) free(obj->multi_rdesc);
  obj->multi_rdesc = strdupsafe(multi_rdesc);
}

void objSetEdescs(OBJ_DATA *obj, EDESC_SET *edescs) {
  if(obj->edescs) deleteEdescSet(obj->edescs);
  obj->edescs = edescs;
}

void objSetCarrier(OBJ_DATA *obj, CHAR_DATA *ch) {
  obj->carrier = ch;
}

void objSetWearer(OBJ_DATA *obj, CHAR_DATA *ch) {
  obj->wearer = ch;
}

void objSetContainer(OBJ_DATA *obj, OBJ_DATA  *cont) {
  obj->container = cont;
}

void objSetRoom(OBJ_DATA *obj, ROOM_DATA *room) {
  obj->room = room;
}

void objSetWeightRaw(OBJ_DATA *obj, double weight) {
  obj->weight = weight;
}