//***************************************************************************** // // stats.c // // defines a couple datastructures for storing, setting, and modifying the // combat stats of characters. Traditionally, stats can range between 0 and // some maximum value that depends on the character. Values that can start at 0 // and increase indefinitely on a character. // //***************************************************************************** #include <sys/time.h> #include "../mud.h" #include "../character.h" #include "../utils.h" #include "../storage.h" #include "../auxiliary.h" #include "stats.h" //***************************************************************************** // mandatory modules //***************************************************************************** #include "../scripts/scripts.h" #include "../scripts/pychar.h" #include "../scripts/pymudsys.h" //***************************************************************************** // local datastructures and variables //***************************************************************************** // the default value for base stats int stat_default_val = 0; // a list of all the valid statistic names LIST *stat_names = NULL; typedef struct { int curr; // the current value of the character's stat int base; // the base (unmodified) max for the character int mod; // how much is our max modified by the offset of our base? long last_used; // the last time we used this statistic } STAT_DATA; typedef struct { MAP *stat_map; // a mapping from name:STAT_DATA } STAT_AUX_DATA; STAT_DATA *newStatData() { STAT_DATA *data = calloc(1, sizeof(STAT_DATA)); // just temporary data->curr = data->base = stat_default_val; data->mod = 0; data->last_used = time(0); return data; } void deleteStatData(STAT_DATA *data) { free(data); } void statDataCopyTo(STAT_DATA *from, STAT_DATA *to) { *to = *from; } STAT_DATA *statDataCopy(STAT_DATA *data) { STAT_DATA *newstat = newStatData(); statDataCopyTo(data, newstat); return newstat; } STORAGE_SET *statDataStore(STAT_DATA *data) { STORAGE_SET *set = new_storage_set(); store_int(set, "curr", data->curr); store_int(set, "base", data->base); store_int(set, "mod", data->mod); store_long(set, "last_used", data->last_used); return set; } STAT_DATA *statDataRead(STORAGE_SET *set) { STAT_DATA *data = newStatData(); data->curr = read_int (set, "curr"); data->base = read_int (set, "base"); data->mod = read_int (set, "mod"); data->last_used = read_long(set, "last_used"); return data; } //***************************************************************************** // functions for creating, saving, and loading auxiliary data //***************************************************************************** STAT_AUX_DATA * newStatAuxData() { STAT_AUX_DATA *data = malloc(sizeof(STAT_AUX_DATA)); data->stat_map = newMap(string_hash, strcasecmp); // fill us up with entries for all the stat names LIST_ITERATOR *name_i = newListIterator(stat_names); char *name = NULL; ITERATE_LIST(name, name_i) mapPut(data->stat_map, name, newStatData()); deleteListIterator(name_i); return data; } void deleteStatAuxData(STAT_AUX_DATA *data) { // iterate across our list of stat names, and // delete the entry in the stat table for each name MAP_ITERATOR *map_i = newMapIterator(data->stat_map); STAT_DATA *stat = NULL; const char *name = NULL; ITERATE_MAP(name, stat, map_i) deleteStatData(stat); deleteMapIterator(map_i); deleteMap(data->stat_map); free(data); } void statAuxDataCopyTo(STAT_AUX_DATA *from, STAT_AUX_DATA *to) { // first, delete all of our old data if it's needed if(mapSize(to->stat_map) > 0) { MAP_ITERATOR *map_i = newMapIterator(to->stat_map); STAT_DATA *stat = NULL; const char *name = NULL; ITERATE_MAP(name, stat, map_i) deleteStatData(mapRemove(to->stat_map, name)); deleteMapIterator(map_i); } // now, copy everything MAP_ITERATOR *map_i = newMapIterator(from->stat_map); STAT_DATA *stats = NULL; const char *name = NULL; ITERATE_MAP(name, stats, map_i) mapPut(to->stat_map, name, statDataCopy(stats)); deleteMapIterator(map_i); } STAT_AUX_DATA * statAuxDataCopy(STAT_AUX_DATA *data) { STAT_AUX_DATA *newdata = malloc(sizeof(STAT_AUX_DATA)); newdata->stat_map = newMap(string_hash, strcasecmp); statAuxDataCopyTo(data, newdata); return newdata; } STORAGE_SET *statAuxDataStore(STAT_AUX_DATA *data) { STORAGE_SET *set = new_storage_set(); STORAGE_SET_LIST *stats = new_storage_list(); store_list(set, "stats", stats); // iterate across all of our stats, and each one to // the stat list that we will be storing in the storage set MAP_ITERATOR *map_i = newMapIterator(data->stat_map); STAT_DATA *stat = NULL; const char *name = NULL; ITERATE_MAP(name, stat, map_i) { STORAGE_SET *one_stat = new_storage_set(); store_string(one_stat, "key", name); store_set (one_stat, "val", statDataStore(stat)); storage_list_put(stats, one_stat); } deleteMapIterator(map_i); return set; } STAT_AUX_DATA *statAuxDataRead(STORAGE_SET *set) { STAT_AUX_DATA *data = newStatAuxData(); STORAGE_SET_LIST *stats = read_list(set, "stats"); STORAGE_SET *one_stat = NULL; // parse each stat, and its corresponding values while( (one_stat = storage_list_next(stats)) != NULL) { STAT_DATA *stat = statDataRead(read_set(one_stat, "val")); STAT_DATA *old = mapGet(data->stat_map, read_string(one_stat, "key")); if(old) statDataCopyTo(stat, old); deleteStatData(stat); } return data; } //***************************************************************************** // python extensions //***************************************************************************** PyObject *PyChar_GetStat(PyObject *self, PyObject *args) { char *stat = NULL; if(!PyArg_ParseTuple(args, "s", &stat)) { PyErr_Format(PyExc_TypeError, "Stat name must be supplied."); return NULL; } CHAR_DATA *ch = PyChar_AsChar(self); if(ch == NULL) { PyErr_Format(PyExc_StandardError, "Character does not exist."); return NULL; } return Py_BuildValue("i", charGetStat(ch, stat)); } PyObject *PyChar_GetBaseStat(PyObject *self, PyObject *args) { char *stat = NULL; if(!PyArg_ParseTuple(args, "s", &stat)) { PyErr_Format(PyExc_TypeError, "Stat name must be supplied."); return NULL; } CHAR_DATA *ch = PyChar_AsChar(self); if(ch == NULL) { PyErr_Format(PyExc_StandardError, "Character does not exist."); return NULL; } return Py_BuildValue("i", charGetBaseStat(ch, stat)); } PyObject *PyChar_GetMaxStat(PyObject *self, PyObject *args) { char *stat = NULL; if(!PyArg_ParseTuple(args, "s", &stat)) { PyErr_Format(PyExc_TypeError, "Stat name must be supplied."); return NULL; } CHAR_DATA *ch = PyChar_AsChar(self); if(ch == NULL) { PyErr_Format(PyExc_StandardError, "Character does not exist."); return NULL; } return Py_BuildValue("i", charGetMaxStat(ch, stat)); } PyObject *PyChar_SetStat(PyObject *self, PyObject *args) { char *stat = NULL; int amnt = 0; if(!PyArg_ParseTuple(args, "si", &stat, &amnt)) { PyErr_Format(PyExc_TypeError, "Stat name and amount must be supplied."); return NULL; } CHAR_DATA *ch = PyChar_AsChar(self); if(ch == NULL) { PyErr_Format(PyExc_StandardError, "Character does not exist."); return NULL; } // increase our stat charSetStat(ch, stat, amnt); return Py_BuildValue("i", 1); } PyObject *PyChar_SetBaseStat(PyObject *self, PyObject *args) { char *stat = NULL; int amnt = 0; if(!PyArg_ParseTuple(args, "si", &stat, &amnt)) { PyErr_Format(PyExc_TypeError, "Stat name and amount must be supplied."); return NULL; } CHAR_DATA *ch = PyChar_AsChar(self); if(ch == NULL) { PyErr_Format(PyExc_StandardError, "Character does not exist."); return NULL; } // increase our stat charSetBaseStat(ch, stat, amnt); return Py_BuildValue("i", 1); } // // adds a new type of statistic to the game, with a base value PyObject *PyMudSys_add_stat(PyObject *self, PyObject *args) { char *stat = NULL; if(!PyArg_ParseTuple(args, "s", &stat)) { PyErr_Format(PyExc_TypeError, "A stat name must be supplied."); return NULL; } stat_add(stat); return Py_BuildValue("i", 1); } // // Returns whether or not a stat with the given name exists PyObject *PyMudSys_stat_exists(PyObject *self, PyObject *args) { char *stat = NULL; if(!PyArg_ParseTuple(args, "s", &stat)) { PyErr_Format(PyExc_TypeError, "A stat name must be supplied."); return NULL; } return Py_BuildValue("i", stat_exists(stat)); } //***************************************************************************** // implementation of stats.h //***************************************************************************** void init_stats(void) { stat_names = newList(); auxiliariesInstall("stat_aux_data", newAuxiliaryFuncs(AUXILIARY_TYPE_CHAR, newStatAuxData, deleteStatAuxData, statAuxDataCopyTo, statAuxDataCopy, statAuxDataStore, statAuxDataRead)); // get our python extensions set up PyChar_addMethod("get_stat", PyChar_GetStat, METH_VARARGS, NULL); PyChar_addMethod("get_base_stat",PyChar_GetBaseStat, METH_VARARGS, NULL); PyChar_addMethod("set_stat", PyChar_SetStat, METH_VARARGS, NULL); PyChar_addMethod("set_base_stat",PyChar_SetBaseStat, METH_VARARGS, NULL); PyChar_addMethod("get_max_stat", PyChar_GetMaxStat, METH_VARARGS, NULL); PyMudSys_addMethod("add_stat", PyMudSys_add_stat, METH_VARARGS, NULL); PyMudSys_addMethod("stat_exists",PyMudSys_stat_exists, METH_VARARGS, NULL); } void stat_add(const char *name) { if(!stat_exists(name)) listPutWith(stat_names, strdup(name), strcasecmp); } LIST *get_stats(void) { return listCopyWith(stat_names, strdup); } void stat_set_default(int val) { stat_default_val = val; } bool stat_exists(const char *name) { return (listGetWith(stat_names, name, strcasecmp) != NULL); } int charGetStat(CHAR_DATA *ch, const char *stat) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); return (stats ? stats->curr : 0); } void charSetStat(CHAR_DATA *ch, const char *stat, int val) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); if(stats != NULL) stats->curr = val; } int charGetMaxStat(CHAR_DATA *ch, const char *stat) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); if(stats == NULL) return 0; else { int max = stats->base + stats->mod; return (max <= 0 ? 0 : max); } } void charModifyMaxStat(CHAR_DATA *ch, const char *stat, int amount) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); if(stats != NULL) stats->mod += amount; } int charGetBaseStat(CHAR_DATA *ch, const char *stat) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); return (stats ? stats->base : 0); } void charSetBaseStat(CHAR_DATA *ch, const char *stat, int val) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); if(stats != NULL) stats->base = val; } void charResetStat(CHAR_DATA *ch, const char *stat) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); if(stats != NULL) stats->curr = charGetMaxStat(ch, stat); } void charResetMaxStat(CHAR_DATA *ch, const char *stat) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); if(stats != NULL) stats->mod = 0; } void charUseStat(CHAR_DATA *ch, const char *stat) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); if(stats != NULL) stats->last_used = time(0); } long charGetStatUsed(CHAR_DATA *ch, const char *stat) { STAT_AUX_DATA *stat_aux = charGetAuxiliaryData(ch, "stat_aux_data"); STAT_DATA *stats = mapGet(stat_aux->stat_map, stat); return (stats ? stats->last_used : 0); }