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