//*****************************************************************************
//
// 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;
}