spellbooks fully operational (and could be loaded from XML definitions if I had them)

fixed the cleanup between tests to properly free locales
This commit is contained in:
Enno Rehling 2012-05-23 20:22:12 -07:00
parent f45a494277
commit 92e96689bb
12 changed files with 217 additions and 21 deletions

View File

@ -38,6 +38,7 @@ without prior permission by the authors of Eressea.
#include <kernel/teleport.h>
#include <kernel/faction.h>
#include <kernel/save.h>
#include <kernel/spell.h>
#include <gamecode/creport.h>
#include <gamecode/economy.h>
@ -684,6 +685,7 @@ static int tolua_set_alliance_name(lua_State * L)
return 0;
}
#ifdef WRITE_SPELLS
#include <libxml/tree.h>
#include <util/functions.h>
#include <util/xml.h>
@ -755,6 +757,7 @@ static int tolua_write_spells(lua_State * L)
xmlFreeDoc(doc);
return 0;
}
#endif
static int config_get_ships(lua_State * L)
{
@ -975,6 +978,7 @@ static int tolua_get_spell_text(lua_State * L)
return 1;
}
#ifdef TODO
static int tolua_get_spell_school(lua_State * L)
{
spell *self = (spell *) tolua_tousertype(L, 1, 0);
@ -988,6 +992,7 @@ static int tolua_get_spell_level(lua_State * L)
lua_pushnumber(L, self->level);
return 1;
}
#endif
static int tolua_get_spell_name(lua_State * L)
{
@ -1177,8 +1182,10 @@ int tolua_eressea_open(lua_State * L)
{
tolua_function(L, TOLUA_CAST "__tostring", tolua_get_spell_name);
tolua_variable(L, TOLUA_CAST "name", tolua_get_spell_name, 0);
#ifdef TODO
tolua_variable(L, TOLUA_CAST "school", tolua_get_spell_school, 0);
tolua_variable(L, TOLUA_CAST "level", tolua_get_spell_level, 0);
#endif
tolua_variable(L, TOLUA_CAST "text", tolua_get_spell_text, 0);
} tolua_endmodule(L);
tolua_module(L, TOLUA_CAST "eventbus", 1);
@ -1263,7 +1270,9 @@ int tolua_eressea_open(lua_State * L)
tolua_function(L, TOLUA_CAST "translate", &tolua_translate);
tolua_function(L, TOLUA_CAST "rng_int", tolua_rng_int);
tolua_function(L, TOLUA_CAST "spells", tolua_get_spells);
#ifdef WRITE_SPELLS
tolua_function(L, TOLUA_CAST "write_spells", tolua_write_spells);
#endif
tolua_function(L, TOLUA_CAST "read_xml", tolua_read_xml);
} tolua_endmodule(L);
return 1;

View File

@ -34,6 +34,7 @@
#include <kernel/ship.c>
#include <kernel/skill.c>
#include <kernel/spell.c>
#include <kernel/spellbook.c>
#include <kernel/teleport.c>
#include <kernel/terrain.c>
#include <kernel/textstore.c>

View File

@ -18,6 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <platform.h>
#include <kernel/config.h>
#include <kernel/types.h>
#include "magic.h"
#include "building.h"
@ -35,6 +36,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "ship.h"
#include "skill.h"
#include "spell.h"
#include "spellbook.h"
#include "teleport.h"
#include "terrain.h"
#include "unit.h"
@ -49,6 +51,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* util includes */
#include <util/attrib.h>
#include <util/critbit.h>
#include <util/language.h>
#include <util/lists.h>
#include <util/log.h>
@ -2924,3 +2927,28 @@ struct quicklist **get_spelllist(struct sc_mage *mage, struct faction *f)
}
return NULL;
}
static critbit_tree cb_spellbooks;
spellbook * get_spellbook(const char * name)
{
char buffer[64];
spellbook * result;
const void * match;
if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0)) {
cb_get_kv(match, &result, sizeof(result));
} else {
size_t len = strlen(name);
result = create_spellbook(name);
assert(strlen(name)+sizeof(result)<sizeof(buffer));
len = cb_new_kv(name, len, &result, sizeof(result), buffer);
cb_insert(&cb_spellbooks, buffer, len);
}
return result;
}
void free_spellbooks(void)
{
cb_clear(&cb_spellbooks);
}

View File

@ -25,7 +25,7 @@ extern "C" {
#include "curse.h"
struct fighter;
struct building;
struct quicklist;
struct spellbook;
/* ------------------------------------------------------------- */
@ -385,6 +385,8 @@ typedef struct sc_mage {
struct storage *store);
extern double MagicPower(void);
extern struct spellbook * get_spellbook(const char * name);
extern void free_spellbooks(void);
#ifdef __cplusplus
}
#endif

View File

@ -21,14 +21,48 @@ void test_updatespells(CuTest * tc)
f = test_create_faction(0);
sp = create_spell("testspell", 0);
CuAssertPtrNotNull(tc, sp);
spellbook_add(&book, sp, 1);
book = create_spellbook("spells");
CuAssertPtrNotNull(tc, book);
spellbook_add(book, sp, 1);
update_spellbook(f, 1);
}
void test_spellbooks(CuTest * tc)
{
spell *sp;
spellbook *herp, *derp;
spellbook_entry *entry;
const char * sname = "herpderp";
test_cleanup();
herp = get_spellbook("herp");
derp = get_spellbook("derp");
CuAssertPtrNotNull(tc, herp);
CuAssertPtrNotNull(tc, derp);
CuAssertTrue(tc, derp!=herp);
CuAssertStrEquals(tc, "herp", herp->name);
CuAssertStrEquals(tc, "derp", derp->name);
sp = create_spell(sname, 0);
spellbook_add(herp, sp, 1);
CuAssertPtrNotNull(tc, sp);
entry = spellbook_get(herp, sname);
CuAssertPtrNotNull(tc, entry);
CuAssertPtrEquals(tc, sp, entry->sp);
CuAssertPtrEquals(tc, 0, spellbook_get(derp, sname));
test_cleanup();
herp = get_spellbook("herp");
CuAssertPtrNotNull(tc, herp);
CuAssertPtrEquals(tc, 0, spellbook_get(herp, sname));
}
CuSuite *get_magic_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_updatespells);
SUITE_ADD_TEST(suite, test_spellbooks);
return suite;
}

View File

@ -1,15 +1,27 @@
#include <platform.h>
#include <kernel/config.h>
#include <kernel/spell.h>
#include <kernel/magic.h>
#include <util/quicklist.h>
#include "spellbook.h"
void spellbook_add(spellbook **sbp, struct spell * sp, int level)
spellbook * create_spellbook(const char * name)
{
spellbook *result = (spellbook *)malloc(sizeof(spellbook));
result->name = strdup(name);
result->spells = 0;
return result;
}
void spellbook_add(spellbook *sb, struct spell * sp, int level)
{
spellbook_entry * sbe = (spellbook_entry *)malloc(sizeof(spellbook_entry));
assert(sb);
sbe->sp = sp;
sbe->level = level;
ql_push(sbp, sbe);
ql_push(&sb->spells, sbe);
}
void spellbook_free(spellbook *sb)
@ -17,11 +29,12 @@ void spellbook_free(spellbook *sb)
quicklist *ql;
int qi;
for (qi = 0, ql = sb; ql; ql_advance(&ql, &qi, 1)) {
assert(sb);
for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) {
spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi);
free(sbe);
}
ql_free(sb);
ql_free(sb->spells);
}
int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data)
@ -29,7 +42,7 @@ int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *),
quicklist *ql;
int qi;
for (qi = 0, ql = sb; ql; ql_advance(&ql, &qi, 1)) {
for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) {
spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi);
int result = callback(sbe, data);
if (result) {
@ -38,3 +51,18 @@ int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *),
}
return 0;
}
spellbook_entry * spellbook_get(spellbook *sb, const char * name)
{
quicklist *ql;
int qi;
for (qi = 0, ql = sb->spells; ql; ql_advance(&ql, &qi, 1)) {
spellbook_entry *sbe = (spellbook_entry *) ql_get(ql, qi);
if (strcmp(name, sbe->sp->sname)==0) {
return sbe;
}
}
return 0;
}

View File

@ -24,19 +24,25 @@ extern "C" {
#endif
struct spell;
struct quicklist;
typedef struct spellbook_entry {
struct spell * sp;
int level;
} spellbook_entry;
typedef struct quicklist spellbook;
typedef struct spellbook
{
char * name;
struct quicklist * spells;
} spellbook;
spellbook * school_books[MAXMAGIETYP];
spellbook * create_spellbook(const char * name);
void spellbook_add(spellbook **sbp, struct spell * sp, int level);
void spellbook_add(spellbook *sbp, struct spell * sp, int level);
int spellbook_foreach(spellbook *sb, int (*callback)(spellbook_entry *, void *), void * data);
void spellbook_free(spellbook *sb);
spellbook_entry * spellbook_get(spellbook *sb, const char * name);
#ifdef __cplusplus
}

View File

@ -18,23 +18,35 @@ int count_spell_cb(spellbook_entry * sbe, void * ptr)
return 0;
}
void test_spellbook(CuTest * tc)
void test_named_spellbooks(CuTest * tc)
{
spell * sp;
spellbook * sb = 0;
spellbook * sb;
int counter = 0;
sp = create_spell("testspell", 0);
spellbook_add(&sb, sp, 1);
sb = create_spellbook("spells");
CuAssertPtrNotNull(tc, sb);
CuAssertStrEquals(tc, "spells", sb->name);
sp = create_spell("testspell", 0);
spellbook_add(sb, sp, 1);
CuAssertPtrNotNull(tc, sb->spells);
spellbook_foreach(sb, count_spell_cb, &counter);
CuAssertIntEquals(tc, 1, counter);
#ifdef TODO
/* try adding the same spell twice. that should fail */
spellbook_add(sb, sp, 1);
spellbook_foreach(sb, count_spell_cb, &counter);
CuAssertIntEquals(tc, 1, counter);
#endif
spellbook_free(sb);
}
CuSuite *get_spellbook_suite(void)
{
CuSuite *suite = CuSuiteNew();
SUITE_ADD_TEST(suite, test_spellbook);
SUITE_ADD_TEST(suite, test_named_spellbooks);
return suite;
}

View File

@ -26,6 +26,7 @@ without prior permission by the authors of Eressea.
#include "terrain.h"
#include "skill.h"
#include "spell.h"
#include "spellbook.h"
#include "calendar.h"
/* util includes */
@ -1461,6 +1462,58 @@ static int parse_equipment(xmlDocPtr doc)
return 0;
}
static int parse_spellbooks(xmlDocPtr doc)
{
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
xmlXPathObjectPtr spellbooks;
/* reading eressea/spells/spell */
spellbooks = xmlXPathEvalExpression(BAD_CAST "/eressea/spells/spellbook", xpath);
if (spellbooks->nodesetval != NULL) {
xmlNodeSetPtr nodes = spellbooks->nodesetval;
int i, k;
for (i = 0; i != nodes->nodeNr; ++i) {
xmlXPathObjectPtr result;
xmlNodePtr node = nodes->nodeTab[i];
xmlChar *propValue;
spellbook * sb;
propValue = xmlGetProp(node, BAD_CAST "name");
assert(propValue != NULL);
sb = get_spellbook((const char *)propValue);
xmlFree(propValue);
xpath->node = node;
result = xmlXPathEvalExpression(BAD_CAST "entry", xpath);
if (result->nodesetval->nodeNr > 0) {
for (k = 0; k != result->nodesetval->nodeNr; ++k) {
xmlNodePtr node = result->nodesetval->nodeTab[k];
spell * sp = 0;
int level = xml_ivalue(node, "level", -1);
propValue = xmlGetProp(node, BAD_CAST "name");
if (propValue) {
sp = find_spell((const char *)propValue);
xmlFree(propValue);
}
if (sp && level>0) {
spellbook_add(sb, sp, level);
} else {
log_error("invalid entry at index '%d' in spellbook '%s'\n", k, sb->name);
}
}
}
xmlXPathFreeObject(result);
}
}
xmlXPathFreeObject(spellbooks);
xmlXPathFreeContext(xpath);
return 0;
}
static int parse_spells(xmlDocPtr doc)
{
xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
@ -1505,7 +1558,7 @@ static int parse_spells(xmlDocPtr doc)
sp->syntax = strdup((const char *)propValue);
xmlFree(propValue);
}
#ifdef TODO /* no longer need it, spellbooks! */
/* magic type */
propValue = xmlGetProp(node, BAD_CAST "type");
assert(propValue != NULL);
@ -1515,7 +1568,7 @@ static int parse_spells(xmlDocPtr doc)
}
assert(sp->magietyp != MAXMAGIETYP);
xmlFree(propValue);
#endif
/* level, rank and flags */
sp->level = xml_ivalue(node, "level", -1);
sp->rank = (char)xml_ivalue(node, "rank", -1);
@ -2332,6 +2385,7 @@ void register_xmlreader(void)
xml_register_callback(parse_buildings); /* requires resources */
xml_register_callback(parse_ships); /* requires terrains */
xml_register_callback(parse_spells); /* requires resources */
xml_register_callback(parse_spellbooks); /* requires spells */
xml_register_callback(parse_equipment); /* requires spells */
xml_register_callback(parse_races); /* requires spells */
xml_register_callback(parse_calendar);

View File

@ -112,8 +112,9 @@ void test_cleanup(void)
global.functions.maintenance = NULL;
global.functions.wage = NULL;
default_locale = 0;
locales = 0; /* TODO: this is evil and leaky */
free_spells(); /* TODO: this is just as bad! */
free_locales(); /* TODO: this is evil and leaky */
free_spells();
free_spellbooks();
free_gamedata();
}

View File

@ -234,3 +234,23 @@ void ** get_translations(const struct locale *lang, int index)
}
return lstrs[0].tokens + index;
}
void free_locales(void)
{
while (locales) {
int i;
locale * next = locales->next;
for (i=0; i!=SMAXHASH; ++i) {
while (locales->strings[i]) {
struct locale_str * strings = locales->strings[i];
free(strings->key);
free(strings->str);
locales->strings[i] = strings->nexthash;
free(strings);
}
}
free(locales);
locales = next;
}
}

View File

@ -29,6 +29,7 @@ extern "C" {
/** managing multiple locales: **/
extern struct locale *find_locale(const char *name);
extern struct locale *make_locale(const char *key);
extern void free_locales(void);
/** operations on locales: **/
extern void locale_setstring(struct locale *lang, const char *key,