From 6d15767a1896bc2f03f4b9c4b6b1dd1a2fc7cb61 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 28 Jan 2017 19:42:20 +0100 Subject: [PATCH] create a spellref structure. use this when referring to spells that may not (yet) exist. use it for race::precombatspell (rare use case). --- clibs | 2 +- src/kernel/race.c | 2 ++ src/kernel/race.h | 3 ++- src/kernel/spell.c | 29 +++++++++++++++++++++++++++++ src/kernel/spell.h | 9 +++++++++ src/kernel/spell.test.c | 17 +++++++++++++++++ src/kernel/xmlreader.c | 15 +++++++++++++-- src/magic.c | 7 +++++-- 8 files changed, 78 insertions(+), 6 deletions(-) diff --git a/clibs b/clibs index 27c8b3202..f91ef37f0 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit 27c8b3202b52766465743c3324fc0b52c5ba4b11 +Subproject commit f91ef37f08c5244bf616f1836c0aa9caaf36805c diff --git a/src/kernel/race.c b/src/kernel/race.c index a78a9e340..c18761dcd 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -32,6 +32,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "region.h" #include "ship.h" #include "skill.h" +#include "spell.h" #include "terrain.h" #include "unit.h" @@ -182,6 +183,7 @@ void racelist_insert(struct race_list **rl, const struct race *r) void free_races(void) { while (races) { race * rc = races->next; + spellref_free(races->precombatspell); free_params(&races->parameters); free(xrefs); xrefs = 0; diff --git a/src/kernel/race.h b/src/kernel/race.h index 6673676bd..496dfa763 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -45,6 +45,7 @@ extern "C" { struct param; struct spell; + struct spellref; struct locale; extern int num_races; @@ -137,7 +138,7 @@ extern "C" { int at_bonus; /* Ver�ndert den Angriffsskill (default: 0) */ int df_bonus; /* Ver�ndert den Verteidigungskill (default: 0) */ struct param *parameters; // additional properties, for an example see natural_armor - const struct spell *precombatspell; + struct spellref *precombatspell; signed char *study_speed; /* study-speed-bonus in points/turn (0=30 Tage) */ int flags; int battle_flags; diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 5415c4a0e..5e4a57e86 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -145,3 +145,32 @@ spell *find_spellbyid(unsigned int id) log_warning("cannot find spell by id: %u\n", id); return NULL; } + +struct spellref *spellref_create(const char *name) +{ + spellref *spref = malloc(sizeof(spellref)); + + spref->name = strdup(name); + spref->sp = NULL; + return spref; +} + +void spellref_free(spellref *spref) +{ + if (spref) { + free(spref->name); + free(spref); + } +} + +struct spell *spellref_get(struct spellref *spref) +{ + if (!spref->sp) { + spref->sp = find_spell(spref->name); + if (spref->sp) { + free(spref->name); + spref->name = NULL; + } + } + return spref->sp; +} diff --git a/src/kernel/spell.h b/src/kernel/spell.h index f74fda6e2..b5b227b50 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -45,6 +45,15 @@ extern "C" { fumble_f fumble; } spell; + typedef struct spellref { + char * name; + struct spell *sp; + } spellref; + + struct spellref *spellref_create(const char *name); + void spellref_free(struct spellref *spref); + struct spell *spellref_get(struct spellref *spref); + int sp_antimagiczone(struct castorder *co); struct spell * create_spell(const char * name, unsigned int id); diff --git a/src/kernel/spell.test.c b/src/kernel/spell.test.c index 6bb2ac449..4a8cd617a 100644 --- a/src/kernel/spell.test.c +++ b/src/kernel/spell.test.c @@ -69,9 +69,26 @@ static void test_create_spell_with_id(CuTest * tc) test_cleanup(); } +static void test_spellref(CuTest *tc) +{ + spellref *ref; + spell *sp; + test_setup(); + ref = spellref_create("hodor"); + CuAssertPtrNotNull(tc, ref); + CuAssertPtrEquals(tc, NULL, spellref_get(ref)); + sp = create_spell("hodor", 0); + CuAssertPtrNotNull(tc, sp); + CuAssertPtrEquals(tc, sp, spellref_get(ref)); + CuAssertPtrEquals(tc, NULL, ref->name); + spellref_free(ref); + test_cleanup(); +} + CuSuite *get_spell_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_spellref); SUITE_ADD_TEST(suite, test_create_a_spell); SUITE_ADD_TEST(suite, test_create_duplicate_spell); SUITE_ADD_TEST(suite, test_create_spell_with_id); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index cba01bc7b..238b04227 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -87,6 +87,17 @@ static const spell *xml_spell(xmlNode * node, const char *name) return sp; } +static spellref *xml_spellref(xmlNode * node, const char *name) +{ + xmlChar *propValue = xmlGetProp(node, BAD_CAST name); + if (propValue != NULL) { + spellref *ref = spellref_create((const char *)propValue); + xmlFree(propValue); + return ref; + } + return NULL; +} + static xmlChar *xml_cleanup_string(xmlChar * str) { xmlChar *read = str; @@ -1853,7 +1864,7 @@ static int parse_races(xmlDocPtr doc) || !"precombatspell is already initialized"); for (k = 0; k != result->nodesetval->nodeNr; ++k) { xmlNodePtr node = result->nodesetval->nodeTab[k]; - rc->precombatspell = xml_spell(node, "spell"); + rc->precombatspell = xml_spellref(node, "spell"); } xmlXPathFreeObject(result); @@ -2076,10 +2087,10 @@ void register_xmlreader(void) xml_register_callback(parse_buildings); /* requires resources */ xml_register_callback(parse_ships); /* requires terrains */ + xml_register_callback(parse_races); /* requires spells */ 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); } #endif diff --git a/src/magic.c b/src/magic.c index f2992538c..7969253e0 100644 --- a/src/magic.c +++ b/src/magic.c @@ -560,8 +560,11 @@ const spell *get_combatspell(const unit * u, int nr) if (m) { return m->combatspells[nr].sp; } - else if (u_race(u)->precombatspell != NULL) { - return u_race(u)->precombatspell; + else { + const race * rc = u_race(u); + if (rc->precombatspell) { + return spellref_get(rc->precombatspell); + } } return NULL;