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;