//*****************************************************************************
//
// items.c
//
// Objects can serve many different functions; they might be containers, they
// might be weapons, they might be pieces of clothing... the list goes on and
// on. The classification of what type of item the object is is what handles
// these sorts of distinctions. This is a general framework for adding new
// item types. Contains functions for storing type data on objects. Item types
// are expected to be able to handle their own subtyping (if neccessary).
// Objects can be multi-typed (e.g. a desk with a drawer can be both a piece
// of furniture and a container).
//
//*****************************************************************************
#include "../mud.h"
#include "../utils.h"
#include "../object.h"
#include "../auxiliary.h"
#include "../storage.h"
#include "items.h"
#include "iedit.h"
//*****************************************************************************
// local functions, datastructures, and defines
//*****************************************************************************
// a table of all our item types, and their assocciated new/delete/etc.. funcs
HASHTABLE *type_table = NULL;
//
// this is what will go into our type_data table
typedef struct item_func_data {
void *(* new)();
void (* delete)(void *data);
void *(* copy)(void *data);
void (* copyto)(void *from, void *to);
STORAGE_SET *(* store)(void *data);
void *(* read)(STORAGE_SET *set);
} ITEM_FUNC_DATA;
//
// create a new structure for holding item type functions
ITEM_FUNC_DATA *newItemFuncData(void *new, void *delete, void *copyTo,
void *copy, void *store, void *read) {
ITEM_FUNC_DATA *data = malloc(sizeof(ITEM_FUNC_DATA));
data->new = new;
data->delete = delete;
data->copy = copy;
data->copyto = copyTo;
data->store = store;
data->read = read;
return data;
}
//
// deletes one structure for holding item type functions
void deleteItemFuncData(ITEM_FUNC_DATA *data) {
free(data);
}
//
// goes through an object's item table and deletes everything in it. Does
// not delete the table itself
void clearItemTable(HASHTABLE *table) {
// if our hashtable isn't empty, we have to make sure
// we delete all of the data within it
if(hashSize(table) > 0) {
HASH_ITERATOR *hash_i = newHashIterator(table);
const char *key = NULL;
void *val = NULL;
// delete the contents of our hashtable
ITERATE_HASH(key, val, hash_i) {
ITEM_FUNC_DATA *funcs = hashGet(type_table, key);
funcs->delete(hashRemove(table, key));
}
deleteHashIterator(hash_i);
}
}
//
// copies the contents of one item table over to another. clears the destination
// table first.
void copyItemTableTo(HASHTABLE *from, HASHTABLE *to) {
clearItemTable(to);
// if the table we're copying has contents, go throug hand copy them all
if(hashSize(from) > 0) {
HASH_ITERATOR *hash_i = newHashIterator(from);
const char *key = NULL;
void *val = NULL;
// copy all the contents
ITERATE_HASH(key, val, hash_i) {
ITEM_FUNC_DATA *funcs = hashGet(type_table, key);
hashPut(to, key, funcs->copy(val));
}
deleteHashIterator(hash_i);
}
}
//
// Creates a new item table and copies the contents of the old one
// over to the new one
HASHTABLE *copyItemTable(HASHTABLE *table) {
HASHTABLE *newtable = newHashtable();
copyItemTableTo(table, newtable);
return newtable;
}
//*****************************************************************************
// auxiliary data
//*****************************************************************************
typedef struct item_data {
HASHTABLE *item_table;
} ITEM_DATA;
ITEM_DATA *newItemData() {
ITEM_DATA *data = malloc(sizeof(ITEM_DATA));
data->item_table = newHashtable();
return data;
}
void deleteItemData(ITEM_DATA *data) {
clearItemTable(data->item_table);
deleteHashtable(data->item_table);
free(data);
}
void itemDataCopyTo(ITEM_DATA *from, ITEM_DATA *to) {
copyItemTableTo(from->item_table, to->item_table);
}
ITEM_DATA *itemDataCopy(ITEM_DATA *data) {
ITEM_DATA *newdata = newItemData();
itemDataCopyTo(data, newdata);
return newdata;
}
STORAGE_SET *itemDataStore(ITEM_DATA *data) {
STORAGE_SET *set = new_storage_set();
// if we have a type or more, go through them all and store 'em
if(hashSize(data->item_table) > 0) {
STORAGE_SET_LIST *list = new_storage_list();
HASH_ITERATOR *hash_i = newHashIterator(data->item_table);
ITEM_FUNC_DATA *funcs = NULL;
const char *key = NULL;
void *val = NULL;
// store all of our item type data
ITERATE_HASH(key, val, hash_i) {
STORAGE_SET *one_set = new_storage_set();
funcs = hashGet(type_table, key);
store_string(one_set, "type", key);
store_set(one_set, "data", funcs->store(val));
storage_list_put(list, one_set);
}
deleteHashIterator(hash_i);
store_list(set, "types", list);
}
return set;
}
ITEM_DATA *itemDataRead(STORAGE_SET *set) {
ITEM_DATA *data = newItemData();
STORAGE_SET_LIST *types = read_list(set, "types");
ITEM_FUNC_DATA *funcs = NULL;
STORAGE_SET *one_entry = NULL;
// go through each entry and parse the item type
while( (one_entry = storage_list_next(types)) != NULL) {
const char *type = read_string(one_entry, "type");
// make sure the type is valid
if((funcs = hashGet(type_table, type)) == NULL)
continue;
STORAGE_SET *type_set = read_set(one_entry, "data");
hashPut(data->item_table, type, funcs->read(type_set));
}
return data;
}
//*****************************************************************************
// implementation of items.h
//*****************************************************************************
void init_items(void) {
type_table = newHashtable();
auxiliariesInstall("type_data",
newAuxiliaryFuncs(AUXILIARY_TYPE_OBJ, newItemData,
deleteItemData, itemDataCopyTo,
itemDataCopy, itemDataStore,
itemDataRead));
// initialize item olc
init_item_olc();
// now, initialize our basic items types
extern void init_container(); init_container();
extern void init_portal(); init_portal();
extern void init_furniture(); init_furniture();
extern void init_worn(); init_worn();
}
void item_add_type(const char *type,
void *new, void *delete,
void *copyTo, void *copy,
void *store, void *read) {
ITEM_FUNC_DATA *funcs = NULL;
// first, make sure no item type by this name already
// exists. If one does, delete it so it can be replaced
if((funcs = hashRemove(type_table, type)) != NULL)
deleteItemFuncData(funcs);
funcs = newItemFuncData(new, delete, copyTo, copy, store, read);
hashPut(type_table, type, funcs);
}
LIST *itemTypeList(void) {
LIST *list = newList();
HASH_ITERATOR *hash_i = newHashIterator(type_table);
const char *key = NULL;
void *val = NULL;
ITERATE_HASH(key, val, hash_i)
listPutWith(list, strdup(key), strcasecmp);
deleteHashIterator(hash_i);
return list;
}
void *objGetTypeData(OBJ_DATA *obj, const char *type) {
ITEM_DATA *data = objGetAuxiliaryData(obj, "type_data");
return hashGet(data->item_table, type);
}
void objSetType(OBJ_DATA *obj, const char *type) {
ITEM_FUNC_DATA *funcs = hashGet(type_table, type);
ITEM_DATA *data = objGetAuxiliaryData(obj, "type_data");
void *old_item_data = hashGet(data->item_table, type);
// if the type exists and we're not already of the type, set it on us
if(funcs != NULL && old_item_data == NULL)
hashPut(data->item_table, type, funcs->new());
}
void objDeleteType(OBJ_DATA *obj, const char *type) {
ITEM_FUNC_DATA *funcs = hashGet(type_table, type);
ITEM_DATA *data = objGetAuxiliaryData(obj, "type_data");
void *old_item_data = hashRemove(data->item_table, type);
if(old_item_data) funcs->delete(old_item_data);
}
bool objIsType(OBJ_DATA *obj, const char *type) {
ITEM_DATA *data = objGetAuxiliaryData(obj, "type_data");
return hashIn(data->item_table, type);
}
const char *objGetTypes(OBJ_DATA *obj) {
static char buf[MAX_BUFFER];
ITEM_DATA *data = objGetAuxiliaryData(obj, "type_data");
if(hashSize(data->item_table) == 0)
sprintf(buf, "none");
else {
*buf = '\0';
HASH_ITERATOR *hash_i = newHashIterator(data->item_table);
const char *key = NULL;
void *val = NULL;
int count = 0;
ITERATE_HASH(key, val, hash_i) {
sprintf(buf, "%s%s%s", buf, (count > 0 ? ", " : ""), key);
count++;
}
deleteHashIterator(hash_i);
}
return buf;
}