diff --git a/res/equipment.xml b/res/equipment.xml index a38004797..1a38ab808 100644 --- a/res/equipment.xml +++ b/res/equipment.xml @@ -32,9 +32,9 @@ - - - + + + @@ -48,10 +48,10 @@ - - - - + + + + @@ -59,12 +59,12 @@ - - - - - - + + + + + + @@ -75,9 +75,9 @@ - - - + + + @@ -87,9 +87,9 @@ - - - + + + @@ -99,16 +99,16 @@ - - + + - - - + + + diff --git a/src/bindings/bind_unit.c b/src/bindings/bind_unit.c index 49c65d786..c0aec9d92 100644 --- a/src/bindings/bind_unit.c +++ b/src/bindings/bind_unit.c @@ -493,7 +493,7 @@ static int tolua_unit_castspell(lua_State * L) static int unit_addspell(unit * u, const char *name) { sc_mage *m = get_mage(u); - spell *spadd = find_spell(m->magietyp, name); + spell *spadd = find_spell(name); if (!spadd) { log_error(("spell %s could not be found\n", name)); @@ -501,6 +501,7 @@ static int unit_addspell(unit * u, const char *name) } else { quicklist **starget = get_spelllist(m, u->faction); add_spell(starget, spadd); + add_spellname(m, spadd); } return 0; } diff --git a/src/gamecode/items.c b/src/gamecode/items.c index 3c2767278..4849ce144 100644 --- a/src/gamecode/items.c +++ b/src/gamecode/items.c @@ -118,7 +118,7 @@ use_antimagiccrystal(unit * u, const struct item_type *itype, int amount, for (i = 0; i != amount; ++i) { int effect, duration = 2; double force; - spell *sp = find_spell(M_NONE, "antimagiczone"); + spell *sp = find_spell("antimagiczone"); attrib **ap = &r->attribs; unused(ord); assert(sp); diff --git a/src/kernel.vcxproj b/src/kernel.vcxproj index 81ea82887..f71b97588 100644 --- a/src/kernel.vcxproj +++ b/src/kernel.vcxproj @@ -121,6 +121,7 @@ + diff --git a/src/kernel.vcxproj.filters b/src/kernel.vcxproj.filters index caadb2064..e5f59818f 100644 --- a/src/kernel.vcxproj.filters +++ b/src/kernel.vcxproj.filters @@ -298,6 +298,9 @@ kernel + + kernel + diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index bf3c354b2..740bf7703 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -149,6 +149,7 @@ void equip_unit_mask(struct unit *u, const struct equipment *eq, int mask) for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); add_spell(&m->spells, sp); + add_spellname(m, sp); } } } diff --git a/src/kernel/magic.c b/src/kernel/magic.c index 50c9d579b..cb8dfae07 100644 --- a/src/kernel/magic.c +++ b/src/kernel/magic.c @@ -58,6 +58,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include #include @@ -213,14 +214,17 @@ void read_spells(struct quicklist **slistp, magic_t mtype, int i = store->r_int(store); if (i < 0) break; - sp = find_spellbyid(M_NONE, (spellid_t) i); + sp = find_spellbyid((unsigned int) i); } else { store->r_tok_buf(store, spname, sizeof(spname)); if (strcmp(spname, "end") == 0) break; - sp = find_spell(mtype, spname); + sp = find_spell(spname); + if (!sp) { + log_error(("read_spells: could not find spell '%s' in school '%s'\n", spname, magic_school[mtype])); + } } - if (sp != NULL) { + if (sp) { add_spell(slistp, sp); } } @@ -244,14 +248,17 @@ static int read_mage(attrib * a, void *owner, struct storage *store) spid = store->r_int(store); level = store->r_int(store); if (spid >= 0) { - sp = find_spellbyid(mage->magietyp, (spellid_t) spid); + sp = find_spellbyid((unsigned int) spid); } } else { store->r_tok_buf(store, spname, sizeof(spname)); level = store->r_int(store); if (strcmp("none", spname) != 0) { - sp = find_spell(mage->magietyp, spname); + sp = find_spell(spname); + if (!sp) { + log_error(("read_mage: could not find combat spell '%s' in school '%s'\n", spname, magic_school[mage->magietyp])); + } } } if (sp && level >= 0) { @@ -343,14 +350,16 @@ static int read_seenspell(attrib * a, void *owner, struct storage *store) store->r_tok_buf(store, token, sizeof(token)); i = atoi(token); if (i != 0) { - sp = find_spellbyid(M_NONE, (spellid_t) i); + sp = find_spellbyid((unsigned int) i); } else { int mtype; mtype = store->r_int(store); - sp = find_spell((magic_t) mtype, token); + sp = find_spell(token); + if (!sp) { + log_error(("read_seenspell: could not find spell '%s' in school '%s'\n", token, magic_school[mtype])); + } } - if (sp == NULL) { - /* log_error(("could not find seenspell '%s'\n", buf)); */ + if (!sp) { return AT_READ_FAIL; } a->data.v = sp; @@ -488,8 +497,10 @@ void updatespelllist(unit * u) || know_school(u->faction, sp->magietyp)) { faction *f = u->faction; - if (!know) + if (!know) { add_spell(dst, sp); + add_spellname(mage, sp); + } if (!ismonster && !already_seen(u->faction, sp)) { a_add(&f->attribs, a_new(&at_reportspell))->data.v = sp; a_add(&f->attribs, a_new(&at_seenspell))->data.v = sp; @@ -521,6 +532,18 @@ sc_mage *create_mage(unit * u, magic_t mtyp) /* ------------------------------------------------------------- */ /* Funktionen für die Bearbeitung der List-of-known-spells */ +void add_spellname(sc_mage * mage, const spell * sp) +{ + spell_names * names = mage->spellnames; + while (names) { + variant token; + const char *n = spell_name(sp, names->lang); + token.v = (void *)sp; + addtoken(names->tokens, n, token); + names = names->next; + } +} + void add_spell(struct quicklist **slistp, spell * sp) { if (ql_set_insert(slistp, sp) != 0) { @@ -2568,14 +2591,14 @@ static castorder *cast_cmd(unit * u, order * ord) /* Vertraute können auch Zauber sprechen, die sie selbst nicht * können. get_spellfromtoken findet aber nur jene Sprüche, die * die Einheit beherrscht. */ - if (sp == NULL && is_familiar(u)) { + if (!sp && is_familiar(u)) { familiar = u; mage = get_familiar_mage(u); if (mage != NULL) sp = get_spellfromtoken(mage, s, mage->faction->locale); } - if (sp == NULL) { + if (!sp) { /* Fehler 'Spell not found' */ cmistake(u, ord, 173, MSG_MAGIC); return 0; diff --git a/src/kernel/magic.h b/src/kernel/magic.h index 311024d54..3e88bba47 100644 --- a/src/kernel/magic.h +++ b/src/kernel/magic.h @@ -86,19 +86,6 @@ extern "C" { /* ------------------------------------------------------------- */ /* Magierichtungen */ -/* typedef unsigned char magic_t; */ - enum { - M_GRAY = 0, /* Gray */ - M_ILLAUN = 1, /* Illaun */ - M_TYBIED = 2, /* Tybied */ - M_CERDDOR = 3, /* Cerddor */ - M_GWYRRD = 4, /* Gwyrrd */ - M_DRAIG = 5, /* Draig */ - M_COMMON = 6, /* common spells */ - MAXMAGIETYP, - /* this enum is stored in the datafile, so do not change the numbers around */ - M_NONE = (magic_t) - 1 - }; extern const char *magic_school[MAXMAGIETYP]; /* ------------------------------------------------------------- */ @@ -113,19 +100,26 @@ extern "C" { * - Spruchliste */ - typedef struct combatspell { - int level; - const struct spell *sp; - } combatspell; +typedef struct combatspell { + int level; + const struct spell *sp; +} combatspell; - typedef struct sc_mage { - magic_t magietyp; - int spellpoints; - int spchange; - int spellcount; - combatspell combatspells[MAXCOMBATSPELLS]; - struct quicklist *spells; - } sc_mage; +typedef struct spell_names { + struct spell_names *next; + const struct locale *lang; + struct tnode * tokens; +} spell_names; + +typedef struct sc_mage { + magic_t magietyp; + int spellpoints; + int spchange; + int spellcount; + combatspell combatspells[MAXCOMBATSPELLS]; + struct quicklist *spells; + struct spell_names * spellnames; +} sc_mage; /* ------------------------------------------------------------- */ /* Zauberliste */ @@ -164,7 +158,7 @@ extern "C" { } spell_component; typedef struct spell { - spellid_t id; + unsigned int id; char *sname; char *syntax; char *parameter; @@ -278,6 +272,7 @@ extern "C" { void unset_combatspell(struct unit *u, spell * sp); /* löscht Kampfzauber */ void add_spell(struct quicklist **slistp, spell * sp); + void add_spellname(sc_mage * mage, const spell * sp); /* fügt den Spruch mit der Id spellid der Spruchliste der Einheit hinzu. */ boolean u_hasspell(const struct unit *u, const struct spell *sp); /* prüft, ob der Spruch in der Spruchliste der Einheit steht. */ diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 5f9e6e8f8..cb5df21ca 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -35,12 +35,15 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include - /* Bitte die Sprüche nach Gebieten und Stufe ordnen, denn in derselben - * Reihenfolge wie in Spelldaten tauchen sie auch im Report auf - */ - quicklist *spells = NULL; +spell * create_spell(const char * name) +{ + spell * sp = (spell *) calloc(1, sizeof(spell)); + sp->sname = strdup(name); + return sp; +} + void register_spell(spell * sp) { if (sp->id == 0) { @@ -49,120 +52,56 @@ void register_spell(spell * sp) add_spell(&spells, sp); } -/** versucht einen Spruch über gebiet + name zu identifizieren. - * gibt ansonsten NULL zurück */ -spell *find_spell(magic_t mtype, const char *name) +spell *find_spell(const char *name) { quicklist *ql = spells; int qi; - spell *spx = NULL; for (qi = 0; ql; ql_advance(&ql, &qi, 1)) { spell *sp = (spell *) ql_get(ql, qi); if (strcmp(name, sp->sname) == 0) { - if (mtype == M_NONE || sp->magietyp == mtype) - return sp; - spx = sp; + return sp; } } - if (spx == NULL) { - log_error(("cannot find spell by name: %s\n", name)); - } - return spx; + log_warning(("find_spell: could not find spell '%s'\n", name)); + return 0; } /* ------------------------------------------------------------- */ /* Spruch identifizieren */ -typedef struct spell_names { - struct spell_names *next; - const struct locale *lang; - magic_t mtype; - struct tnode names; -} spell_names; - -static spell_names *spellnames; - -static spell_names *init_spellnames(const struct locale *lang, magic_t mtype) -{ - quicklist *ql; - int qi; - spell_names *sn = (spell_names *) calloc(sizeof(spell_names), 1); - sn->next = spellnames; - sn->lang = lang; - sn->mtype = mtype; - for (qi = 0, ql = spells; ql; ql_advance(&ql, &qi, 1)) { - spell *sp = (spell *) ql_get(ql, qi); - if (sp->magietyp == mtype) { - const char *n = spell_name(sp, lang); - variant token; - token.v = sp; - addtoken(&sn->names, n, token); - } - } - return spellnames = sn; -} - -static spell_names *get_spellnames(const struct locale *lang, magic_t mtype) -{ - spell_names *sn = spellnames; - while (sn) { - if (sn->mtype == mtype && sn->lang == lang) - break; - sn = sn->next; - } - if (!sn) - return init_spellnames(lang, mtype); - return sn; -} - -static spell *get_spellfromtoken_i(const char *name, const struct locale *lang, - magic_t mtype) -{ - variant token = { 0 }; - spell_names *sn; - - sn = get_spellnames(lang, mtype); - if (findtoken(&sn->names, name, &token) == E_TOK_NOMATCH) { - magic_t mt; - /* if we could not find it in the main magic type, we look through all the others */ - for (mt = 0; mt != MAXMAGIETYP; ++mt) { - if (mt != mtype) { - sn = get_spellnames(lang, mt); - if (findtoken(&sn->names, name, &token) != E_TOK_NOMATCH) - break; - } - } - } - - if (token.v != NULL) - return (spell *) token.v; - if (lang == default_locale) - return NULL; - return get_spellfromtoken_i(name, default_locale, mtype); -} - spell *get_spellfromtoken(unit * u, const char *name, const struct locale * lang) { + variant token; sc_mage *m = get_mage(u); - spell *sp; - - if (m == NULL) - return NULL; - sp = get_spellfromtoken_i(name, lang, m->magietyp); - if (sp != NULL) { + struct spell_names * names = m->spellnames; + for (;names;names=names->next) { + if (names->lang==lang) break; + } + if (!names) { quicklist *ql = m->spells; int qi; - - if (ql_set_find(&ql, &qi, sp)) { - return sp; + names = (spell_names *)calloc(1, sizeof(spell_names)); + names->next = m->spellnames; + names->lang = lang; + names->tokens = (tnode *)calloc(1, sizeof(tnode)); + for (qi = 0, ql = m->spells; ql; ql_advance(&ql, &qi, 1)) { + spell *sp = (spell *) ql_get(ql, qi); + const char *n = spell_name(sp, lang); + token.v = sp; + addtoken(names->tokens, n, token); } + m->spellnames = names; } - return NULL; + + if (findtoken(names->tokens, name, &token) != E_TOK_NOMATCH) { + return (spell *) token.v; + } + return 0; } -spell *find_spellbyid(magic_t mtype, spellid_t id) +spell *find_spellbyid(unsigned int id) { quicklist *ql; int qi; @@ -180,9 +119,7 @@ spell *find_spellbyid(magic_t mtype, spellid_t id) spell *sp = (spell *) ql_get(ql, qi); unsigned int hashid = hashstring(sp->sname); if (hashid == id) { - if (sp->magietyp == mtype || mtype == M_NONE) { - return sp; - } + return sp; } } diff --git a/src/kernel/spell.h b/src/kernel/spell.h index e2c591128..c43aa8cc7 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -29,6 +29,8 @@ extern "C" { struct curse_type; struct castorder; struct curse; + struct region; + struct unit; /* Prototypen */ @@ -43,9 +45,11 @@ extern "C" { extern struct attrib_type at_wdwpyramid; extern struct quicklist *spells; + + extern struct spell * create_spell(const char * name); extern void register_spell(struct spell *sp); - extern struct spell *find_spell(magic_t mtype, const char *name); - extern struct spell *find_spellbyid(magic_t mtype, spellid_t i); + extern struct spell *find_spell(const char *name); + extern struct spell *find_spellbyid(unsigned int i); extern struct spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale *lang); diff --git a/src/kernel/spell_test.c b/src/kernel/spell_test.c new file mode 100644 index 000000000..ebcb74dfe --- /dev/null +++ b/src/kernel/spell_test.c @@ -0,0 +1,29 @@ +#include +#include +#include + +#include +#include + +#include + +static void test_register_spell(CuTest * tc) +{ + spell * sp; + + CuAssertPtrEquals(tc, 0, find_spell("testspell")); + + CuAssertPtrEquals(tc, spells, 0); + sp = create_spell("testspell"); + sp->magietyp = 5; + register_spell(sp); + CuAssertIntEquals(tc, 1, ql_length(spells)); + CuAssertPtrEquals(tc, sp, find_spell("testspell")); +} + +CuSuite *get_spell_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_register_spell); + return suite; +} diff --git a/src/kernel/types.h b/src/kernel/types.h index 866a72cc2..2b2772564 100644 --- a/src/kernel/types.h +++ b/src/kernel/types.h @@ -31,10 +31,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include typedef short terrain_t; -typedef short magic_t; typedef short typ_t; typedef short item_t; -typedef unsigned int spellid_t; struct attrib; struct attrib_type; @@ -375,6 +373,19 @@ typedef enum { NODIRECTION = -1 } direction_t; +typedef enum { + M_GRAY = 0, /* Gray */ + M_ILLAUN = 1, /* Illaun */ + M_TYBIED = 2, /* Tybied */ + M_CERDDOR = 3, /* Cerddor */ + M_GWYRRD = 4, /* Gwyrrd */ + M_DRAIG = 5, /* Draig */ + M_COMMON = 6, /* common spells */ + MAXMAGIETYP, + /* this enum is stored in the datafile, so do not change the numbers around */ + M_NONE = -1 +} magic_t; + #define DONT_HELP 0 #define HELP_MONEY 1 /* Mitversorgen von Einheiten */ #define HELP_FIGHT 2 /* Bei Verteidigung mithelfen */ diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 51b7084cb..d2799feac 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -90,7 +90,7 @@ static const spell *xml_spell(xmlNode * node, const char *name) const spell *sp = NULL; xmlChar *propValue = xmlGetProp(node, BAD_CAST name); if (propValue != NULL) { - sp = find_spell(M_NONE, (const char *)propValue); + sp = find_spell((const char *)propValue); assert(sp); xmlFree(propValue); } @@ -1322,12 +1322,14 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); - sp = find_spell(mtype, (const char *)propValue); - assert(sp); - xmlFree(propValue); - if (sp != NULL) { + sp = find_spell((const char *)propValue); + if (!sp) { + log_error(("no spell '%s' in school '%s' for equipment-set '%s'\n", + (const char *)propValue, magic_school[mtype], eq->name)); + } else { equipment_addspell(eq, sp); } + xmlFree(propValue); } } } @@ -1492,13 +1494,13 @@ static int parse_spells(xmlDocPtr doc) xmlChar *propValue; int k; spell_component *component; - spell *sp = (spell *) calloc(1, sizeof(spell)); + spell *sp; static int modes[] = { 0, PRECOMBATSPELL, COMBATSPELL, POSTCOMBATSPELL }; /* spellname */ propValue = xmlGetProp(node, BAD_CAST "name"); assert(propValue != NULL); - sp->sname = strdup((const char *)propValue); + sp = create_spell((const char *)propValue); xmlFree(propValue); propValue = xmlGetProp(node, BAD_CAST "parameters"); diff --git a/src/tests.c b/src/tests.c index 118910c05..39d9cd0c9 100644 --- a/src/tests.c +++ b/src/tests.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ int RunAllTests(void) CuSuiteAddSuite(suite, get_curse_suite()); CuSuiteAddSuite(suite, get_market_suite()); CuSuiteAddSuite(suite, get_move_suite()); + CuSuiteAddSuite(suite, get_spell_suite()); CuSuiteAddSuite(suite, get_laws_suite()); CuSuiteAddSuite(suite, get_battle_suite()); diff --git a/src/util/umlaut.c b/src/util/umlaut.c index cb3f22ea4..6904e91b5 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -61,6 +61,7 @@ void addtoken(tnode * root, const char *str, variant id) 0, ""} }; + assert(root); if (!*str) { root->id = id; root->flags |= LEAF; @@ -135,8 +136,18 @@ void addtoken(tnode * root, const char *str, variant id) } } +void freetokens(struct tnode *root) +{ + int i; + for (i=0;root && i!=NODEHASHSIZE;++i) { + freetokens(root->next[i]->node); + free(root->next[i]); + } +} + int findtoken(const tnode * tk, const char *str, variant * result) { + assert(tk); if (!str || *str == 0) return E_TOK_NOMATCH; diff --git a/src/util/umlaut.h b/src/util/umlaut.h index aeabccc39..d19f35b2d 100644 --- a/src/util/umlaut.h +++ b/src/util/umlaut.h @@ -38,6 +38,7 @@ extern "C" { int findtoken(const struct tnode *tk, const char *str, variant * result); void addtoken(struct tnode *root, const char *str, variant id); + void freetokens(struct tnode *root); typedef struct local_names { struct local_names *next;