//*****************************************************************************
//
// dyn_vars.c
//
// This module allows key/value pairs to be dynamically created on characters,
// objects, and rooms. Values can be strings, integers, or doubles. If a value
// is called for in the wrong type (e.g. you're trying to get a string as an
// integer) the module will automagically handle the conversion. Variable types
// default to ints.
//
//*****************************************************************************
#include "../mud.h"
#include "../utils.h"
#include "../character.h"
#include "../room.h"
#include "../object.h"
#include "../storage.h"
#include "../auxiliary.h"
#include "dyn_vars.h"
//*****************************************************************************
//
// local functions and datastructurs
//
//*****************************************************************************
// used in storage_sets to keep track of what kind of data we're saving
const char *dyn_var_types[] = {
"string",
"int",
"long",
"double"
};
typedef struct dyn_var {
char *str_val;
int type;
} DYN_VAR;
DYN_VAR *newDynVarString(const char *str) {
DYN_VAR *data = malloc(sizeof(DYN_VAR));
data->str_val = strdupsafe(str);
data->type = DYN_VAR_STRING;
return data;
}
DYN_VAR *newDynVarInt(int val) {
DYN_VAR *data = malloc(sizeof(DYN_VAR));
char str_val[20]; sprintf(str_val, "%d", val);
data->str_val = strdup(str_val);
data->type = DYN_VAR_INT;
return data;
}
DYN_VAR *newDynVarLong(long val) {
DYN_VAR *data = malloc(sizeof(DYN_VAR));
char str_val[20]; sprintf(str_val, "%ld", val);
data->str_val = strdup(str_val);
data->type = DYN_VAR_LONG;
return data;
}
DYN_VAR *newDynVarDouble(double val) {
DYN_VAR *data = malloc(sizeof(DYN_VAR));
char str_val[20]; sprintf(str_val, "%lf", val);
data->str_val = strdup(str_val);
data->type = DYN_VAR_DOUBLE;
return data;
}
void deleteDynVar(DYN_VAR *data) {
if(data->str_val) free(data->str_val);
free(data);
}
DYN_VAR *dynVarCopy(DYN_VAR *data) {
DYN_VAR *new_data = malloc(sizeof(DYN_VAR));
new_data->str_val = strdup(data->str_val);
new_data->type = data->type;
return new_data;
}
//
// delete a hashtable of vars
//
void deleteDynVarTable(HASHTABLE *table) {
HASH_ITERATOR *hash_i = newHashIterator(table);
const char *key = NULL;
DYN_VAR *val = NULL;
ITERATE_HASH(key, val, hash_i) {
deleteDynVar(val);
} deleteHashIterator(hash_i);
deleteHashtable(table);
}
//*****************************************************************************
//
// dyn_var auxiliary data
//
//*****************************************************************************
typedef struct dyn_var_aux_data {
HASHTABLE *dyn_vars;
} DYN_VAR_AUX_DATA;
DYN_VAR_AUX_DATA *
newDynVarAuxData() {
DYN_VAR_AUX_DATA *data = malloc(sizeof(DYN_VAR_AUX_DATA));
// Hashtables can take up lots of storage space. Because of this, let's
// not create any tables until it's actually needed. This will cut down
// on lots of memory usage w.r.t. NPCs who do not use character variables
// data->dyn_vars = newHashtable();
data->dyn_vars = NULL;
return data;
}
void
deleteDynVarAuxData(DYN_VAR_AUX_DATA *data) {
if(data->dyn_vars)
deleteDynVarTable(data->dyn_vars);
free(data);
}
void
dynVarAuxDataCopyTo(DYN_VAR_AUX_DATA *from, DYN_VAR_AUX_DATA *to) {
int from_size = (from->dyn_vars ? hashSize(from->dyn_vars) : 0);
int to_size = (to->dyn_vars ? hashSize(to->dyn_vars) : 0);
// clear out our current data
if(to_size > 0) {
deleteDynVarTable(to->dyn_vars);
to->dyn_vars = NULL;
}
// check to see if the "from" table exists
if(from_size > 0) {
// make sure the "to" table exists
if(to->dyn_vars == NULL)
to->dyn_vars = newHashtable();
// copy everything over
HASH_ITERATOR *from_i = newHashIterator(from->dyn_vars);
const char *key = NULL;
DYN_VAR *val = NULL;
ITERATE_HASH(key, val, from_i)
hashPut(to->dyn_vars, key, dynVarCopy(val));
deleteHashIterator(from_i);
}
}
DYN_VAR_AUX_DATA *
dynVarAuxDataCopy(DYN_VAR_AUX_DATA *data) {
DYN_VAR_AUX_DATA *new_data = newDynVarAuxData();
dynVarAuxDataCopyTo(data, new_data);
return new_data;
}
STORAGE_SET *dynVarAuxDataStore(DYN_VAR_AUX_DATA *data) {
// first, check if the table even exists
if(data->dyn_vars == NULL || hashSize(data->dyn_vars) == 0)
return new_storage_set();
STORAGE_SET *set = new_storage_set();
HASH_ITERATOR *hash_i = newHashIterator(data->dyn_vars);
STORAGE_SET_LIST *list = new_storage_list();
const char *key = NULL;
DYN_VAR *val = NULL;
store_list(set, "variables", list);
// iterate across all the entries and add them
ITERATE_HASH(key, val, hash_i) {
STORAGE_SET *var_set = new_storage_set();
store_string(var_set, "key", key);
store_string(var_set, "val", val->str_val);
store_string(var_set, "type", dyn_var_types[val->type]);
storage_list_put(list, var_set);
}
deleteHashIterator(hash_i);
return set;
}
HASHTABLE *variableRead(STORAGE_SET *set) {
HASHTABLE *table = newHashtable();
STORAGE_SET_LIST *list = read_list(set, "list");
STORAGE_SET *var = NULL;
while( (var = storage_list_next(list)) != NULL)
hashPut(table, read_string(var, "key"), (void *)read_int(var, "val"));
return table;
}
DYN_VAR_AUX_DATA *dynVarAuxDataRead(STORAGE_SET *set) {
// if the set doesn't contain any entries, don't bother trying to parse
if(!storage_contains(set, "variables"))
return newDynVarAuxData();
DYN_VAR_AUX_DATA *data = newDynVarAuxData();
STORAGE_SET_LIST *list = read_list(set, "variables");
STORAGE_SET *var_set = NULL;
data->dyn_vars = newHashtable();
while( (var_set = storage_list_next(list)) != NULL) {
const char *var_type = read_string(var_set, "type");
if(!strcasecmp(var_type, "int"))
hashPut(data->dyn_vars, read_string(var_set, "key"),
newDynVarInt(read_int(var_set, "val")));
else if(!strcasecmp(var_type, "long"))
hashPut(data->dyn_vars, read_string(var_set, "key"),
newDynVarLong(read_long(var_set, "val")));
else if(!strcasecmp(var_type, "double"))
hashPut(data->dyn_vars, read_string(var_set, "key"),
newDynVarDouble(read_double(var_set, "val")));
else if(!strcasecmp(var_type, "string"))
hashPut(data->dyn_vars, read_string(var_set, "key"),
newDynVarString(read_string(var_set, "val")));
else
log_string("ERROR: Tried to read unknown dyn_var type, %s.", var_type);
}
return data;
}
void init_dyn_vars() {
// install dyn vars on the character datastructure
auxiliariesInstall("dyn_var_aux_data",
newAuxiliaryFuncs(AUXILIARY_TYPE_CHAR |
AUXILIARY_TYPE_ROOM |
AUXILIARY_TYPE_OBJ,
newDynVarAuxData, deleteDynVarAuxData,
dynVarAuxDataCopyTo, dynVarAuxDataCopy,
dynVarAuxDataStore,dynVarAuxDataRead));
}
//*****************************************************************************
//
// functions for interacting with dyn_vars
//
//*****************************************************************************
int dynGetVarType(DYN_VAR_AUX_DATA *data, const char *key) {
DYN_VAR *var = (data->dyn_vars ? hashGet(data->dyn_vars, key) : NULL);
return (var ? var->type : DYN_VAR_INT);
}
int dynGetInt(DYN_VAR_AUX_DATA *data, const char *key) {
DYN_VAR *var = (data->dyn_vars ? hashGet(data->dyn_vars, key) : NULL);
return (var ? atoi(var->str_val) : 0);
}
long dynGetLong(DYN_VAR_AUX_DATA *data, const char *key) {
DYN_VAR *var = (data->dyn_vars ? hashGet(data->dyn_vars, key) : NULL);
return (var ? atol(var->str_val) : 0);
}
double dynGetDouble(DYN_VAR_AUX_DATA *data, const char *key) {
DYN_VAR *var = (data->dyn_vars ? hashGet(data->dyn_vars, key) : NULL);
return (var ? atof(var->str_val) : 0);
}
const char *dynGetString(DYN_VAR_AUX_DATA *data, const char *key) {
DYN_VAR *var = (data->dyn_vars ? hashGet(data->dyn_vars, key) : NULL);
return (var ? var->str_val : "");
}
void dynSetInt(DYN_VAR_AUX_DATA *data, const char *key, int val) {
DYN_VAR *old = (data->dyn_vars ? hashRemove(data->dyn_vars, key) : NULL);
if(data->dyn_vars == NULL && val != 0)
data->dyn_vars = newHashtable();
if(old != NULL)
deleteDynVar(old);
if(val != 0)
hashPut(data->dyn_vars, key, newDynVarInt(val));
}
void dynSetLong(DYN_VAR_AUX_DATA *data, const char *key, long val) {
DYN_VAR *old = (data->dyn_vars ? hashRemove(data->dyn_vars, key) : NULL);
if(data->dyn_vars == NULL && val != 0)
data->dyn_vars = newHashtable();
if(old != NULL)
deleteDynVar(old);
if(val != 0)
hashPut(data->dyn_vars, key, newDynVarLong(val));
}
void dynSetDouble(DYN_VAR_AUX_DATA *data, const char *key, double val) {
DYN_VAR *old = (data->dyn_vars ? hashRemove(data->dyn_vars, key) : NULL);
if(data->dyn_vars == NULL && val != 0)
data->dyn_vars = newHashtable();
if(old != NULL)
deleteDynVar(old);
if(val != 0)
hashPut(data->dyn_vars, key, newDynVarDouble(val));
}
void dynSetString(DYN_VAR_AUX_DATA *data, const char *key, const char *val) {
DYN_VAR *old = (data->dyn_vars ? hashRemove(data->dyn_vars, key) : NULL);
if(data->dyn_vars == NULL && *val != '\0')
data->dyn_vars = newHashtable();
if(old != NULL)
deleteDynVar(old);
if(*val != '\0')
hashPut(data->dyn_vars, key, newDynVarString(val));
}
bool dynHasVar(DYN_VAR_AUX_DATA *data, const char *key) {
return (data->dyn_vars ? hashIn(data->dyn_vars, key) : FALSE);
}
void dynDeleteVar(DYN_VAR_AUX_DATA *data, const char *key) {
DYN_VAR *var = (data->dyn_vars ? hashRemove(data->dyn_vars, key) : NULL);
if(var != NULL) deleteDynVar(var);
}
int charGetVarType(CHAR_DATA *ch, const char *key) {
return dynGetVarType(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key);
}
int charGetInt(CHAR_DATA *ch, const char *key) {
return dynGetInt(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key);
}
long charGetLong(CHAR_DATA *ch, const char *key) {
return dynGetLong(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key);
}
double charGetDouble(CHAR_DATA *ch, const char *key) {
return dynGetDouble(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key);
}
const char *charGetString(CHAR_DATA *ch, const char *key) {
return dynGetString(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key);
}
void charSetInt(CHAR_DATA *ch, const char *key, int val) {
dynSetInt(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key, val);
}
void charSetLong(CHAR_DATA *ch, const char *key, long val) {
dynSetLong(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key, val);
}
void charSetDouble(CHAR_DATA *ch, const char *key, double val) {
dynSetDouble(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key, val);
}
void charSetString(CHAR_DATA *ch, const char *key, const char *val) {
dynSetString(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key, val);
}
bool charHasVar(CHAR_DATA *ch, const char *key) {
return dynHasVar(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key);
}
void charDeleteVar(CHAR_DATA *ch, const char *key) {
dynDeleteVar(charGetAuxiliaryData(ch, "dyn_var_aux_data"), key);
}
int roomGetVarType(ROOM_DATA *rm, const char *key) {
return dynGetVarType(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key);
}
int roomGetInt(ROOM_DATA *rm, const char *key) {
return dynGetInt(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key);
}
long roomGetLong(ROOM_DATA *rm, const char *key) {
return dynGetLong(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key);
}
double roomGetDouble(ROOM_DATA *rm, const char *key) {
return dynGetDouble(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key);
}
const char *roomGetString(ROOM_DATA *rm, const char *key) {
return dynGetString(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key);
}
void roomSetInt(ROOM_DATA *rm, const char *key, int val) {
dynSetInt(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key, val);
}
void roomSetLong(ROOM_DATA *rm, const char *key, long val) {
dynSetLong(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key, val);
}
void roomSetDouble(ROOM_DATA *rm, const char *key, double val) {
dynSetDouble(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key, val);
}
void roomSetString(ROOM_DATA *rm, const char *key, const char *val) {
dynSetString(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key, val);
}
bool roomHasVar(ROOM_DATA *rm, const char *key) {
return dynHasVar(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key);
}
void roomDeleteVar(ROOM_DATA *rm, const char *key) {
dynDeleteVar(roomGetAuxiliaryData(rm, "dyn_var_aux_data"), key);
}
int objGetVarType(OBJ_DATA *ob, const char *key) {
return dynGetVarType(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key);
}
int objGetInt(OBJ_DATA *ob, const char *key) {
return dynGetInt(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key);
}
long objGetLong(OBJ_DATA *ob, const char *key) {
return dynGetLong(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key);
}
double objGetDouble(OBJ_DATA *ob, const char *key) {
return dynGetDouble(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key);
}
const char *objGetString(OBJ_DATA *ob, const char *key) {
return dynGetString(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key);
}
void objSetInt(OBJ_DATA *ob, const char *key, int val) {
dynSetInt(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key, val);
}
void objSetLong(OBJ_DATA *ob, const char *key, long val) {
dynSetLong(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key, val);
}
void objSetDouble(OBJ_DATA *ob, const char *key, double val) {
dynSetDouble(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key, val);
}
void objSetString(OBJ_DATA *ob, const char *key, const char *val) {
dynSetString(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key, val);
}
bool objHasVar(OBJ_DATA *ob, const char *key) {
return dynHasVar(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key);
}
void objDeleteVar(OBJ_DATA *ob, const char *key) {
dynDeleteVar(objGetAuxiliaryData(ob, "dyn_var_aux_data"), key);
}