diff --git a/src/bindings/bindings.c b/src/bindings/bindings.c index 964b2f588..34cefe183 100644 --- a/src/bindings/bindings.c +++ b/src/bindings/bindings.c @@ -38,6 +38,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include @@ -684,6 +685,7 @@ static int tolua_set_alliance_name(lua_State * L) return 0; } +#ifdef WRITE_SPELLS #include #include #include @@ -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; diff --git a/src/build/kernel.c b/src/build/kernel.c index 9ac333f94..22e8992b8 100644 --- a/src/build/kernel.c +++ b/src/build/kernel.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 1da2e01b8..78eabe9b3 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -18,6 +18,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #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 +#include #include #include #include @@ -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)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; } diff --git a/src/kernel/spellbook.c b/src/kernel/spellbook.c index 00dd6de7a..3f32b12bb 100644 --- a/src/kernel/spellbook.c +++ b/src/kernel/spellbook.c @@ -1,15 +1,27 @@ #include #include +#include +#include #include #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; +} + diff --git a/src/kernel/spellbook.h b/src/kernel/spellbook.h index 71eb427d2..f4724ec5b 100644 --- a/src/kernel/spellbook.h +++ b/src/kernel/spellbook.h @@ -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 } diff --git a/src/kernel/spellbook_test.c b/src/kernel/spellbook_test.c index c4adad24d..62d8fa5ea 100644 --- a/src/kernel/spellbook_test.c +++ b/src/kernel/spellbook_test.c @@ -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; } diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 84fbe5b19..d8fdfd1e7 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -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); diff --git a/src/tests.c b/src/tests.c index c73b2bb18..a78268590 100644 --- a/src/tests.c +++ b/src/tests.c @@ -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(); } diff --git a/src/util/language.c b/src/util/language.c index 917a51626..d50c55d6d 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -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; + } +} \ No newline at end of file diff --git a/src/util/language.h b/src/util/language.h index e851865a0..eb7c81986 100644 --- a/src/util/language.h +++ b/src/util/language.h @@ -29,8 +29,9 @@ 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: **/ + /** operations on locales: **/ extern void locale_setstring(struct locale *lang, const char *key, const char *value); extern const char *locale_getstring(const struct locale *lang,