diff --git a/res/core/spells.xml b/res/core/spells.xml index cb7fcf911..59d06a522 100644 --- a/res/core/spells.xml +++ b/res/core/spells.xml @@ -10,14 +10,12 @@ - - @@ -25,12 +23,10 @@ - - @@ -38,19 +34,16 @@ - - - @@ -58,18 +51,15 @@ - - - @@ -77,12 +67,10 @@ - - @@ -90,25 +78,21 @@ - - - - @@ -116,7 +100,6 @@ - @@ -124,20 +107,17 @@ - - - diff --git a/res/e3a/spells.xml b/res/e3a/spells.xml index 74eb89146..80d9e6260 100644 --- a/res/e3a/spells.xml +++ b/res/e3a/spells.xml @@ -10,14 +10,12 @@ - - @@ -39,7 +37,6 @@ - @@ -106,7 +103,6 @@ - @@ -119,7 +115,6 @@ - @@ -189,7 +184,6 @@ - @@ -205,7 +199,6 @@ - @@ -269,7 +262,6 @@ - @@ -304,12 +296,11 @@ - + - @@ -394,21 +385,18 @@ - - - @@ -416,7 +404,6 @@ - @@ -426,7 +413,6 @@ - @@ -435,7 +421,6 @@ - @@ -444,7 +429,6 @@ - @@ -454,7 +438,6 @@ - @@ -472,39 +455,33 @@ - - - - - - @@ -518,7 +495,7 @@ - + diff --git a/res/e3a/strings.xml b/res/e3a/strings.xml index 054cabfaa..eb9f48cf3 100644 --- a/res/e3a/strings.xml +++ b/res/e3a/strings.xml @@ -210,7 +210,7 @@ Dieser Zauber wird die gesamte Ausrüstung der Zieleinheit für einige Zeit vor den Blicken anderer verschleiern. Der Zauber schützt nicht vor Dieben und Spionen. This spell will hide the whole equipment of a target unit from the looks of others. It will not protect against thieves or spies. - + Durch dieses uralte Tanzritual ruft der Zauberkundige die Kräfte des Lebens und der Fruchtbarkeit an. Die darauf folgenden Regenfälle begünstigen das Wachstum und erhöhen die Ernteerträge einiger Bauern der Region bis der Regen wieder nachlässt. This ancient rite calls upon the forces of life and fertility. For the next few weeks, the peasants' harvest will be extraordinary good. diff --git a/res/eressea/spells.xml b/res/eressea/spells.xml index 1d762f4bd..6b2e43a15 100644 --- a/res/eressea/spells.xml +++ b/res/eressea/spells.xml @@ -10,14 +10,12 @@ - - @@ -494,12 +492,10 @@ - - @@ -507,7 +503,6 @@ - @@ -520,12 +515,10 @@ - - @@ -533,18 +526,15 @@ - - - @@ -558,12 +548,10 @@ - - @@ -583,25 +571,21 @@ - - - - @@ -609,7 +593,6 @@ - @@ -617,20 +600,17 @@ - - - diff --git a/scripts/eressea/e3/init.lua b/scripts/eressea/e3/init.lua index e376eaadc..f7402268c 100644 --- a/scripts/eressea/e3/init.lua +++ b/scripts/eressea/e3/init.lua @@ -1,4 +1,3 @@ -require 'eressea.e3.rules' require 'eressea.spells' eressea.log.debug("rules for game E3") diff --git a/scripts/eressea/e3/rules.lua b/scripts/eressea/e3/rules.lua deleted file mode 100644 index e49e03438..000000000 --- a/scripts/eressea/e3/rules.lua +++ /dev/null @@ -1,35 +0,0 @@ --- the "raindance" spell -function raindance(r, mage, level, force) - if (create_curse(mage, r, "blessedharvest", force, 1+force*2, 100 * force)) then - -- slightly crooked way of reporting an action to everyone in the region - local msg = message.create("raindance_effect") - msg:set_unit("mage", mage) - if (msg:report_action(r, mage, 3)) then - local msg2 = message.create("raindance_effect") - msg2:set_unit("mage", nil) - msg2:report_action(r, mage, 4) - end - end - return level -end - --- the "blessed harvest" spell -function blessedharvest(r, mage, level, force) - if create_curse(mage, r, "blessedharvest", force, 1+force*2, 50 * force) then - -- slightly crooked way of reporting an action to everyone in the region - local msg = message.create("harvest_effect") - msg:set_unit("mage", mage) - if (msg:report_action(r, mage, 3)) then - local msg2 = message.create("harvest_effect") - msg2:set_unit("mage", nil) - msg2:report_action(r, mage, 4) - end - for idx, rn in ipairs(r.adj) do - -- nur landregionen haben moral>=0 - if r.morale>=0 then - create_curse(mage, r, "blessedharvest", force, force*2, 50 * force) - end - end - end - return level -end diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua index 46afc966a..4b4fe7dd4 100644 --- a/scripts/tests/e2/init.lua +++ b/scripts/tests/e2/init.lua @@ -20,3 +20,4 @@ require 'tests.magicbag' require 'tests.process' require 'tests.xmas' require 'tests.production' +require 'tests.spells' diff --git a/scripts/tests/e3/init.lua b/scripts/tests/e3/init.lua index 06e03d9b4..fc0586f89 100644 --- a/scripts/tests/e3/init.lua +++ b/scripts/tests/e3/init.lua @@ -5,11 +5,12 @@ require 'tests.e3.rules' require 'tests.e3.parser' require 'tests.e3.morale' require 'tests.e3.items' +require 'tests.e3.production' +require 'tests.spells' require 'tests.economy' require 'tests.orders' require 'tests.common' require 'tests.items' require 'tests.magicbag' require 'tests.process' -require 'tests.e3.production' require 'tests.production' diff --git a/scripts/tests/e3/spells.lua b/scripts/tests/e3/spells.lua index 5cd8ef431..24f97c221 100644 --- a/scripts/tests/e3/spells.lua +++ b/scripts/tests/e3/spells.lua @@ -32,10 +32,9 @@ function test_raindance() u:add_order("ARBEITEN") process_orders() process_orders() + assert_equal(500, r:get_resource("money")) process_orders() - assert_equal(800, r:get_resource("money")) - process_orders() - assert_equal(900, r:get_resource("money")) + assert_equal(600, r:get_resource("money")) end function test_magic() diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua new file mode 100644 index 000000000..e3c0a3021 --- /dev/null +++ b/scripts/tests/spells.lua @@ -0,0 +1,83 @@ +require 'lunit' +module("tests.spells", package.seeall, lunit.testcase) + +function setup() + eressea.free_game() + eressea.settings.set("nmr.removenewbie", "0") + eressea.settings.set("nmr.timeout", "0") + eressea.settings.set("NewbieImmunity", "0") + eressea.settings.set("rules.food.flags", "4") + eressea.settings.set("rules.encounters", "0") + eressea.settings.set("magic.regeneration.enable", "0") +end + +function test_create_bogus() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u.magic = 'gwyrrd' + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe Katastrophe'") + process_orders() + assert_equal(f.messages[3], 'error173') -- HACKity HACK +end + +function test_create_roi() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u.magic = 'gwyrrd' + u.aura = 100 + u:add_item("money", 3000) + u:add_spell("create_roi") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe einen Ring der Unsichtbarkeit'") + local amax = u.aura_max + process_orders() + assert_equal(1, u:get_item("roi")) + assert_equal(50, u.aura) + assert_equal(amax - 1, u.aura_max) +end + +function test_create_aots() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u.magic = 'gwyrrd' + u.aura = 100 + u:add_item("money", 3000) + u:add_spell("create_aots") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe ein Amulett des wahren Sehens'") + local amax = u.aura_max + process_orders() + assert_equal(1, u:get_item("aots")) + assert_equal(50, u.aura) + assert_equal(amax - 1, u.aura_max) +end + +function test_create_dreameye() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u = unit.create(f, r, 1) + u.race = "elf" + u:set_skill("magic", 10) + u.magic = 'gwyrrd' + u.aura = 100 + u:add_item("dragonhead", 1) + u:add_spell("create_dreameye") + u:clear_orders() + u:add_order("ZAUBERE 'Erschaffe ein Traumauge'") + local amax = u.aura_max + process_orders() + assert_equal(1, u:get_item("dreameye")) + assert_equal(100, u.aura) + assert_equal(amax - 5, u.aura_max) +end + diff --git a/src/bind_faction.c b/src/bind_faction.c index d16f15936..f9321f6b5 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -268,6 +268,23 @@ static int tolua_faction_setkey(lua_State * L) return 0; } +static int tolua_faction_get_messages(lua_State * L) +{ + faction *self = (faction *)tolua_tousertype(L, 1, 0); + int i = 1; + mlist *ml; + if (!self->msgs) { + return 0; + } + lua_newtable(L); + for (ml = self->msgs->begin; ml; ml = ml->next, ++i) { + lua_pushnumber(L, i); + lua_pushstring(L, ml->msg->type->name); + lua_rawset(L, -3); + } + return 1; +} + static int tolua_faction_count_msg_type(lua_State *L) { faction *self = (faction *)tolua_tousertype(L, 1, 0); const char *str = tolua_tostring(L, 2, 0); @@ -637,6 +654,7 @@ void tolua_faction_open(lua_State * L) /* tech debt hack, siehe https://paper.dropbox.com/doc/Weihnachten-2015-5tOx5r1xsgGDBpb0gILrv#:h=Probleme-mit-Tests-(Nachtrag-0 */ tolua_function(L, TOLUA_CAST "count_msg_type", tolua_faction_count_msg_type); + tolua_variable(L, TOLUA_CAST "messages", tolua_faction_get_messages, NULL); tolua_function(L, TOLUA_CAST "get_key", tolua_faction_getkey); tolua_function(L, TOLUA_CAST "set_key", tolua_faction_setkey); diff --git a/src/bind_unit.c b/src/bind_unit.c index 34b647418..1d6579b0e 100644 --- a/src/bind_unit.c +++ b/src/bind_unit.c @@ -193,6 +193,13 @@ static int tolua_unit_set_id(lua_State * L) return 0; } +static int tolua_unit_get_auramax(lua_State * L) +{ + unit *self = (unit *)tolua_tousertype(L, 1, 0); + lua_pushinteger(L, max_spellpoints(self->region, self)); + return 1; +} + static int tolua_unit_get_hpmax(lua_State * L) { unit *self = (unit *)tolua_tousertype(L, 1, 0); @@ -1033,6 +1040,7 @@ void tolua_unit_open(lua_State * L) tolua_variable(L, TOLUA_CAST "race", &tolua_unit_get_race, tolua_unit_set_race); tolua_variable(L, TOLUA_CAST "hp_max", &tolua_unit_get_hpmax, 0); + tolua_variable(L, TOLUA_CAST "aura_max", &tolua_unit_get_auramax, 0); tolua_function(L, TOLUA_CAST "show", &tolua_bufunit); } diff --git a/src/bindings.c b/src/bindings.c index 1d6270b35..9ea548465 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -92,6 +92,20 @@ TOLUA_PKG(locale); TOLUA_PKG(log); TOLUA_PKG(game); +int tolua_toid(lua_State * L, int idx, int def) +{ + int no = 0; + int type = lua_type(L, idx); + if (type == LUA_TNUMBER) { + no = (int)tolua_tonumber(L, idx, def); + } + else { + const char *str = tolua_tostring(L, idx, NULL); + no = str ? atoi36(str) : def; + } + return no; +} + int log_lua_error(lua_State * L) { const char *error = lua_tostring(L, -1); diff --git a/src/bindings.h b/src/bindings.h index 354bb199a..5cb64a038 100755 --- a/src/bindings.h +++ b/src/bindings.h @@ -18,6 +18,7 @@ extern "C" { struct _dictionary_; struct selist; + int tolua_toid(struct lua_State *L, int idx, int def); int tolua_sqlite_open(struct lua_State *L); int tolua_bindings_open(struct lua_State *L, const struct _dictionary_ *d); int tolua_itemlist_next(struct lua_State *L); diff --git a/src/economy.c b/src/economy.c index 1a4cc5b18..48653d0aa 100644 --- a/src/economy.c +++ b/src/economy.c @@ -2658,8 +2658,7 @@ expandwork(region * r, request * work_begin, request * work_end, int maxwork) const curse_type *blessedharvest_ct = ct_find("blessedharvest"); if (blessedharvest_ct) { int happy = - (int)curse_geteffect(get_curse(r->attribs, blessedharvest_ct)); - happy = MIN(happy, jobs); + (int)(jobs * curse_geteffect(get_curse(r->attribs, blessedharvest_ct))); earnings += happy; } } diff --git a/src/helpers.c b/src/helpers.c index e30daf278..ab59ea60c 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -24,7 +24,9 @@ without prior permission by the authors of Eressea. #include #include +#include #include +#include #include #include #include @@ -157,23 +159,12 @@ static void push_param(lua_State * L, char c, spllprm * param) } /** callback to use lua for spell functions */ -static int lua_callspell(castorder * co) +static int lua_callspell(castorder * co, const char *fname) { lua_State *L = (lua_State *)global.vm_state; - const char *fname = co->sp->sname; unit *caster = co_get_caster(co); region * r = co_get_region(co); int result = -1; - const char *hashpos = strchr(fname, '#'); - char fbuf[64]; - - if (hashpos != NULL) { - ptrdiff_t len = hashpos - fname; - assert(len < (ptrdiff_t) sizeof(fbuf)); - memcpy(fbuf, fname, len); - fbuf[len] = '\0'; - fname = fbuf; - } lua_getglobal(L, fname); if (lua_isfunction(L, -1)) { @@ -456,8 +447,9 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord) return result; } + /* compat code for old data files */ -static int caldera_read(trigger * t, struct gamedata *data) +static int caldera_read(trigger *t, struct gamedata *data) { UNUSED_ARG(t); read_building_reference(data); @@ -470,43 +462,24 @@ struct trigger_type tt_caldera = { caldera_read }; - -int tolua_toid(lua_State * L, int idx, int def) -{ - int no = 0; - int type = lua_type(L, idx); - if (type == LUA_TNUMBER) { - no = (int)tolua_tonumber(L, idx, def); - } - else { - const char *str = tolua_tostring(L, idx, NULL); - no = str ? atoi36(str) : def; - } - return no; -} - void register_tolua_helpers(void) { tt_register(&tt_caldera); at_register(&at_direction); at_register(&at_building_action); - register_function((pf_generic)lua_callspell, TOLUA_CAST "lua_castspell"); - register_function((pf_generic)lua_initfamiliar, - TOLUA_CAST "lua_initfamiliar"); - register_function((pf_generic)lua_getresource, - TOLUA_CAST "lua_getresource"); - register_function((pf_generic)lua_changeresource, - TOLUA_CAST "lua_changeresource"); - register_function((pf_generic)lua_equipmentcallback, - TOLUA_CAST "lua_equip"); + callbacks.cast_spell = lua_callspell; - register_function((pf_generic)lua_wage, TOLUA_CAST "lua_wage"); - register_function((pf_generic)lua_maintenance, - TOLUA_CAST "lua_maintenance"); + register_function((pf_generic)lua_initfamiliar, "lua_initfamiliar"); + register_function((pf_generic)lua_getresource, "lua_getresource"); + register_function((pf_generic)lua_changeresource, "lua_changeresource"); + register_function((pf_generic)lua_equipmentcallback, "lua_equip"); + + register_function((pf_generic)lua_wage, "lua_wage"); + register_function((pf_generic)lua_maintenance, "lua_maintenance"); item_use_fun = use_item_lua; res_produce_fun = produce_resource_lua; res_limit_fun = limit_resource_lua; - register_item_give(lua_giveitem, TOLUA_CAST "lua_giveitem"); + register_item_give(lua_giveitem, "lua_giveitem"); } diff --git a/src/helpers.h b/src/helpers.h index d77765187..d0bbcc58b 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -14,9 +14,9 @@ without prior permission by the authors of Eressea. extern "C" { #endif - struct lua_State; - void register_tolua_helpers(void); - int tolua_toid(struct lua_State *L, int idx, int def); + struct lua_State; + + void register_tolua_helpers(void); #ifdef __cplusplus } diff --git a/src/kernel/CMakeLists.txt b/src/kernel/CMakeLists.txt index b8423ae03..e572d0763 100644 --- a/src/kernel/CMakeLists.txt +++ b/src/kernel/CMakeLists.txt @@ -6,6 +6,7 @@ alliance.test.c ally.test.c build.test.c building.test.c +# callbacks.test.c command.test.c config.test.c # connection.test.c @@ -38,6 +39,7 @@ alliance.c ally.c build.c building.c +callbacks.c command.c config.c connection.c diff --git a/src/kernel/callbacks.c b/src/kernel/callbacks.c new file mode 100644 index 000000000..d8070bd04 --- /dev/null +++ b/src/kernel/callbacks.c @@ -0,0 +1,4 @@ +#include +#include "callbacks.h" + +struct callbacks callbacks; diff --git a/src/kernel/callbacks.h b/src/kernel/callbacks.h new file mode 100644 index 000000000..71f3900c4 --- /dev/null +++ b/src/kernel/callbacks.h @@ -0,0 +1,35 @@ +/* +Copyright (c) 1998-2015, Enno Rehling +Katja Zedel + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +**/ + +#ifndef H_KRNL_CALLBACKS_H +#define H_KRNL_CALLBACKS_H + +#ifdef __cplusplus +extern "C" { +#endif + + struct castorder; + + extern struct callbacks { + int (*cast_spell)(struct castorder *co, const char *fname); + } callbacks; + +#ifdef __cplusplus +} +#endif +#endif /* H_KRNL_CALLBACKS_H */ diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index 9da82c88d..9f96ea9d7 100644 --- a/src/kernel/jsonconf.c +++ b/src/kernel/jsonconf.c @@ -594,9 +594,6 @@ static void json_spells(cJSON *json) { if (strcmp(item->string, "index") == 0) { continue; } - else if (strcmp(item->string, "cast") == 0) { - sp->cast_fun = (spell_f)get_function(item->valuestring); - } else if (strcmp(item->string, "syntax") == 0) { sp->syntax = strdup(item->valuestring); } diff --git a/src/kernel/spell.c b/src/kernel/spell.c index 0db20fe48..0abb487f7 100644 --- a/src/kernel/spell.c +++ b/src/kernel/spell.c @@ -33,7 +33,30 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include -static critbit_tree cb_fumbles; + +static critbit_tree cb_spell_fun; +void add_spellcast(const char *sname, spell_f fun) +{ + size_t len; + char data[64]; + + len = cb_new_kv(sname, strlen(sname), &fun, sizeof(fun), data); + assert(len <= sizeof(data)); + cb_insert(&cb_spell_fun, data, len); +} + +spell_f get_spellcast(const char *sname) +{ + void * match; + spell_f result = NULL; + + if (cb_find_prefix(&cb_spell_fun, sname, strlen(sname) + 1, &match, 1, 0)) { + cb_get_kv(match, &result, sizeof(result)); + } + return result; +} + +static critbit_tree cb_fumble_fun; void add_fumble(const char *sname, fumble_f fun) { size_t len; @@ -41,7 +64,7 @@ void add_fumble(const char *sname, fumble_f fun) len = cb_new_kv(sname, strlen(sname), &fun, sizeof(fun), data); assert(len <= sizeof(data)); - cb_insert(&cb_fumbles, data, len); + cb_insert(&cb_fumble_fun, data, len); } fumble_f get_fumble(const char *sname) @@ -49,7 +72,7 @@ fumble_f get_fumble(const char *sname) void * match; fumble_f result = NULL; - if (cb_find_prefix(&cb_fumbles, sname, strlen(sname) + 1, &match, 1, 0)) { + if (cb_find_prefix(&cb_fumble_fun, sname, strlen(sname) + 1, &match, 1, 0)) { cb_get_kv(match, &result, sizeof(result)); } return result; @@ -71,7 +94,8 @@ static void free_spell_cb(void *cbdata) { } void free_spells(void) { - cb_clear(&cb_fumbles); + cb_clear(&cb_fumble_fun); + cb_clear(&cb_spell_fun); cb_clear(&cb_spells); selist_foreach(spells, free_spell_cb); selist_free(spells); diff --git a/src/kernel/spell.h b/src/kernel/spell.h index 47d9644cf..17a565fa6 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -40,7 +40,6 @@ extern "C" { int sptyp; int rank; /* Reihenfolge der Zauber */ struct spell_component *components; - spell_f cast_fun; } spell; typedef struct spellref { @@ -51,6 +50,9 @@ extern "C" { void add_fumble(const char *sname, fumble_f fun); fumble_f get_fumble(const char *sname); + void add_spellcast(const char *sname, spell_f fun); + spell_f get_spellcast(const char *sname); + struct spellref *spellref_create(struct spell *sp, const char *name); void spellref_free(struct spellref *spref); struct spell *spellref_get(struct spellref *spref); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 418a1ba6e..9f671d44c 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -279,11 +279,8 @@ parse_function(xmlNodePtr node, pf_generic * funPtr, xmlChar ** namePtr) xmlChar *propValue = xmlGetProp(node, BAD_CAST "value"); assert(propValue != NULL); fun = get_function((const char *)propValue); - if (fun != NULL) { - xmlFree(propValue); - - propValue = xmlGetProp(node, BAD_CAST "name"); - } + xmlFree(propValue); + propValue = xmlGetProp(node, BAD_CAST "name"); *namePtr = propValue; *funPtr = fun; return 0; @@ -1311,7 +1308,6 @@ static int parse_spellbooks(xmlDocPtr doc) static int parse_spells(xmlDocPtr doc) { - pf_generic cast = 0; xmlXPathContextPtr xpath = xmlXPathNewContext(doc); xmlXPathObjectPtr spells; @@ -1386,44 +1382,9 @@ static int parse_spells(xmlDocPtr doc) sp->sptyp |= REGIONSPELL; k = xml_ivalue(node, "combat", 0); - if (k >= 0 && k <= 3) + if (k >= 0 && k <= 3) { sp->sptyp |= modes[k]; - - /* reading eressea/spells/spell/function */ - - xpath->node = node; - result = xmlXPathEvalExpression(BAD_CAST "function", xpath); - - if (result->nodesetval->nodeNr == 0) { - cast = get_function(sp->sname); - if (!cast) { - log_error("no spell cast function registered for '%s'\n", sp->sname); - } } - else { - for (k = 0; k != result->nodesetval->nodeNr; ++k) { - xmlNodePtr node = result->nodesetval->nodeTab[k]; - pf_generic fun; - - parse_function(node, &fun, &propValue); - assert(propValue != NULL); - if (strcmp((const char *)propValue, "cast") == 0) { - if (fun) { - cast = fun; - } - else { - log_error("unknown function name '%s' for spell '%s'\n", (const char *)propValue, sp->sname); - } - } - else { - log_error("unknown function type '%s' for spell '%s'\n", (const char *)propValue, sp->sname); - } - xmlFree(propValue); - } - } - sp->cast_fun = (spell_f)cast; - xmlXPathFreeObject(result); - /* reading eressea/spells/spell/resource */ xpath->node = node; result = xmlXPathEvalExpression(BAD_CAST "resource", xpath); diff --git a/src/magic.c b/src/magic.c index 4e74d2cb4..a20fbc477 100644 --- a/src/magic.c +++ b/src/magic.c @@ -23,10 +23,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" #include "study.h" +#include "helpers.h" #include "laws.h" #include #include +#include #include #include #include @@ -2996,8 +2998,26 @@ spell *unit_getspell(struct unit *u, const char *name, const struct locale * lan int cast_spell(struct castorder *co) { + const char *fname = co->sp->sname; + const char *hashpos = strchr(fname, '#'); + char fbuf[64]; + spell_f fun; + const spell *sp = co->sp; - return sp->cast_fun(co); + if (hashpos != NULL) { + ptrdiff_t len = hashpos - fname; + assert(len < (ptrdiff_t) sizeof(fbuf)); + memcpy(fbuf, fname, len); + fbuf[len] = '\0'; + fname = fbuf; + } + + fun = get_spellcast(sp->sname); + if (!fun) { + log_warning("no spell function for %s, try callback", sp->sname); + return callbacks.cast_spell(co, fname); + } + return fun(co); } static critbit_tree cb_spellbooks; diff --git a/src/magic.test.c b/src/magic.test.c index 624dd0129..380001035 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -380,8 +380,8 @@ void test_multi_cast(CuTest *tc) { struct locale * lang; test_setup(); + add_spellcast("fireball", cast_fireball); sp = create_spell("fireball"); - sp->cast_fun = cast_fireball; CuAssertPtrEquals(tc, sp, find_spell("fireball")); lang = test_create_locale(); diff --git a/src/spells.c b/src/spells.c index 142a96a7b..c515c0144 100644 --- a/src/spells.c +++ b/src/spells.c @@ -1104,8 +1104,9 @@ static int sp_blessedharvest(castorder * co) if (create_curse(mage, &r->attribs, ct_find("blessedharvest"), co->force, duration, 1.0, 0)) { - message *seen = msg_message("harvest_effect", "mage", mage); - message *unseen = msg_message("harvest_effect", "mage", NULL); + const char * effect = co->sp->sname[0]=='b' ? "harvest_effect" : "raindance_effect"; + message *seen = msg_message(effect, "mage", mage); + message *unseen = msg_message(effect, "mage", NULL); report_effect(r, mage, seen, unseen); msg_release(seen); msg_release(unseen); @@ -2930,10 +2931,6 @@ static int dc_read_compat(struct attrib *a, void *target, gamedata *data) } return AT_READ_FAIL; /* we don't care for the attribute. */ } - -attrib_type at_deathcloud_compat = { - "zauber_todeswolke", NULL, NULL, NULL, NULL, dc_read_compat -}; #endif /* ------------------------------------------------------------- */ @@ -6499,6 +6496,99 @@ int sp_becomewyrm(castorder * co) return 0; } +/* ------------------------------------------------------------- */ +/* Name: Plappermaul +* Stufe: 4 +* Gebiet: Cerddor +* Kategorie: Einheit +* +* Wirkung: +* Einheit ausspionieren. Gibt auch Zauber und Kampfstatus aus. Wirkt +* gegen Magieresistenz. Ist diese zu hoch, so wird der Zauber entdeckt +* (Meldung) und der Zauberer erhaelt nur die Talente, nicht die Werte +* der Einheit und auch keine Zauber. +* +* Flag: +* (UNITSPELL | TESTCANSEE) +*/ +static int sp_babbler(castorder * co) +{ + unit *target; + region *r = co_get_region(co); + unit *mage = co->magician.u; + int cast_level = co->level; + spellparameter *pa = co->par; + message *msg; + + /* wenn kein Ziel gefunden, Zauber abbrechen */ + if (pa->param[0]->flag == TARGET_NOTFOUND) + return 0; + + target = pa->param[0]->data.u; + + if (target->faction == mage->faction) { + /* Die Einheit ist eine der unsrigen */ + cmistake(mage, co->order, 45, MSG_MAGIC); + } + + /* Magieresistenz Unit */ + if (target_resists_magic(mage, target, TYP_UNIT, 0)) { + spy_message(5, mage, target); + msg = msg_message("babbler_resist", "unit mage", target, mage); + } + else { + spy_message(100, mage, target); + msg = msg_message("babbler_effect", "unit", target); + } + r_addmessage(r, target->faction, msg); + msg_release(msg); + return cast_level; +} + +/* ------------------------------------------------------------- */ +/* Name: Traumdeuten +* Stufe: 7 +* Kategorie: Einheit +* +* Wirkung: +* Wirkt gegen Magieresistenz. Spioniert die Einheit aus. Gibt alle +* Gegenstaende, Talente mit Stufe, Zauber und Kampfstatus an. +* +* Magieresistenz hier pruefen, wegen Fehlermeldung +* +* Flag: +* (UNITSPELL) +*/ +static int sp_readmind(castorder * co) +{ + unit *target; + unit *mage = co->magician.u; + int cast_level = co->level; + spellparameter *pa = co->par; + + /* wenn kein Ziel gefunden, Zauber abbrechen */ + if (pa->param[0]->flag == TARGET_NOTFOUND) + return 0; + + target = pa->param[0]->data.u; + + if (target->faction == mage->faction) { + /* Die Einheit ist eine der unsrigen */ + cmistake(mage, co->order, 45, MSG_MAGIC); + } + + /* Magieresistenz Unit */ + if (target_resists_magic(mage, target, TYP_UNIT, 0)) { + cmistake(mage, co->order, 180, MSG_MAGIC); + /* "Fuehlt sich beobachtet" */ + ADDMSG(&target->faction->msgs, msg_message("stealdetect", "unit", target)); + return 0; + } + spy_message(2, mage, target); + + return cast_level; +} + typedef struct spelldata { const char *sname; spell_f cast; @@ -6618,7 +6708,7 @@ static spelldata spell_functions[] = { { "concealing_aura", sp_itemcloak, 0 }, { "tybiedfumbleshield", sp_fumbleshield, 0 }, #ifdef SHOWASTRAL_NOT_BORKED - { "show_astral", sp_showastral, 0}, + { "show_astral", sp_showastral, 0 }, #endif { "resist_magic", sp_resist_magic_bonus, 0 }, { "keeploot", sp_keeploot, 0 }, @@ -6656,18 +6746,24 @@ static spelldata spell_functions[] = { { "firestorm", sp_immolation, 0 }, { "coldfront", sp_immolation, 0 }, { "acidrain", sp_immolation, 0 }, + { "blabbermouth", sp_babbler, NULL }, + { "summon_familiar", sp_summon_familiar, NULL }, + { "meteor_rain", sp_kampfzauber, NULL }, + { "fireball", sp_kampfzauber, NULL }, + { "hail", sp_kampfzauber, NULL }, + { "readmind", sp_readmind, NULL }, + { "blessedharvest", sp_blessedharvest, NULL }, + { "raindance", sp_blessedharvest, NULL }, { 0, 0, 0 } }; static void register_spelldata(void) { int i; - char zText[32]; - strcpy(zText, "fumble_"); for (i = 0; spell_functions[i].sname; ++i) { spelldata *data = spell_functions + i; if (data->cast) { - register_function((pf_generic)data->cast, data->sname); + add_spellcast(data->sname, data->cast); } if (data->fumble) { add_fumble(data->sname, data->fumble); @@ -6675,117 +6771,18 @@ static void register_spelldata(void) } } -/* ------------------------------------------------------------- */ -/* Name: Plappermaul -* Stufe: 4 -* Gebiet: Cerddor -* Kategorie: Einheit -* -* Wirkung: -* Einheit ausspionieren. Gibt auch Zauber und Kampfstatus aus. Wirkt -* gegen Magieresistenz. Ist diese zu hoch, so wird der Zauber entdeckt -* (Meldung) und der Zauberer erhaelt nur die Talente, nicht die Werte -* der Einheit und auch keine Zauber. -* -* Flag: -* (UNITSPELL | TESTCANSEE) -*/ -static int sp_babbler(castorder * co) -{ - unit *target; - region *r = co_get_region(co); - unit *mage = co->magician.u; - int cast_level = co->level; - spellparameter *pa = co->par; - message *msg; - - /* wenn kein Ziel gefunden, Zauber abbrechen */ - if (pa->param[0]->flag == TARGET_NOTFOUND) - return 0; - - target = pa->param[0]->data.u; - - if (target->faction == mage->faction) { - /* Die Einheit ist eine der unsrigen */ - cmistake(mage, co->order, 45, MSG_MAGIC); - } - - /* Magieresistenz Unit */ - if (target_resists_magic(mage, target, TYP_UNIT, 0)) { - spy_message(5, mage, target); - msg = msg_message("babbler_resist", "unit mage", target, mage); - } - else { - spy_message(100, mage, target); - msg = msg_message("babbler_effect", "unit", target); - } - r_addmessage(r, target->faction, msg); - msg_release(msg); - return cast_level; -} - -/* ------------------------------------------------------------- */ -/* Name: Traumdeuten -* Stufe: 7 -* Kategorie: Einheit -* -* Wirkung: -* Wirkt gegen Magieresistenz. Spioniert die Einheit aus. Gibt alle -* Gegenstaende, Talente mit Stufe, Zauber und Kampfstatus an. -* -* Magieresistenz hier pruefen, wegen Fehlermeldung -* -* Flag: -* (UNITSPELL) -*/ -static int sp_readmind(castorder * co) -{ - unit *target; - unit *mage = co->magician.u; - int cast_level = co->level; - spellparameter *pa = co->par; - - /* wenn kein Ziel gefunden, Zauber abbrechen */ - if (pa->param[0]->flag == TARGET_NOTFOUND) - return 0; - - target = pa->param[0]->data.u; - - if (target->faction == mage->faction) { - /* Die Einheit ist eine der unsrigen */ - cmistake(mage, co->order, 45, MSG_MAGIC); - } - - /* Magieresistenz Unit */ - if (target_resists_magic(mage, target, TYP_UNIT, 0)) { - cmistake(mage, co->order, 180, MSG_MAGIC); - /* "Fuehlt sich beobachtet" */ - ADDMSG(&target->faction->msgs, msg_message("stealdetect", "unit", target)); - return 0; - } - spy_message(2, mage, target); - - return cast_level; -} - -void register_magicresistance(void); - void register_spells(void) { register_borders(); - at_register(&at_deathcloud_compat); +#ifdef COMPAT_DEATHCLOUD + at_deprecate("zauber_todeswolke", dc_read_compat); +#endif /* init_firewall(); */ ct_register(&ct_firewall); ct_register(&ct_deathcloud); - register_function((pf_generic)sp_blessedharvest, "cast_blessedharvest"); - register_function((pf_generic)sp_summon_familiar, "cast_familiar"); - register_function((pf_generic)sp_babbler, "cast_babbler"); - register_function((pf_generic)sp_readmind, "cast_readmind"); - register_function((pf_generic)sp_kampfzauber, "combat_spell"); - register_spelldata(); register_unitcurse(); diff --git a/src/spells.h b/src/spells.h index 65270a164..275f41f7a 100644 --- a/src/spells.h +++ b/src/spells.h @@ -27,6 +27,7 @@ extern "C" { struct unit; struct message; + void register_magicresistance(void); void register_spells(void); void set_spelldata(struct spell *sp);