From edd3b36a9fd6785ddc3507bc14077c2f13a03172 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 Apr 2017 18:18:47 +0200 Subject: [PATCH 1/9] add a callbacks module. make last-chance spell function in lua for spells with none. --- src/bindings.c | 14 ++++++++++++++ src/bindings.h | 1 + src/helpers.c | 14 -------------- src/helpers.h | 5 ++--- src/kernel/CMakeLists.txt | 2 ++ src/kernel/callbacks.c | 4 ++++ src/kernel/callbacks.h | 35 +++++++++++++++++++++++++++++++++++ src/magic.c | 6 +++++- 8 files changed, 63 insertions(+), 18 deletions(-) create mode 100644 src/kernel/callbacks.c create mode 100644 src/kernel/callbacks.h 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..2275236cb 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/helpers.c b/src/helpers.c index 59695e9b4..924082bcd 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -455,20 +455,6 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord) return result; } -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) { at_register(&at_direction); diff --git a/src/helpers.h b/src/helpers.h index d77765187..5187f7bcf 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -14,9 +14,8 @@ 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..99db5e390 --- /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); + } callbacks; + +#ifdef __cplusplus +} +#endif +#endif /* H_KRNL_CALLBACKS_H */ diff --git a/src/magic.c b/src/magic.c index 602207c02..8db533923 100644 --- a/src/magic.c +++ b/src/magic.c @@ -27,6 +27,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +#include #include #include #include @@ -3006,7 +3007,10 @@ spell *unit_getspell(struct unit *u, const char *name, const struct locale * lan int cast_spell(struct castorder *co) { const spell *sp = co->sp; - return sp->cast_fun(co); + if (sp->cast_fun) { + return sp->cast_fun(co); + } + return callbacks.cast_spell(co); } static critbit_tree cb_spellbooks; From bd9968c2667f4a3f0bd209f00ee4bd1f74e8eb01 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 Apr 2017 18:23:42 +0200 Subject: [PATCH 2/9] set the callback, remove lua_callspell from XML. WIP: some spells cannot find their lua callback. --- res/core/spells.xml | 20 -------------------- res/e3a/spells.xml | 25 ------------------------- res/eressea/spells.xml | 20 -------------------- src/helpers.c | 4 +++- 4 files changed, 3 insertions(+), 66 deletions(-) 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..89a977275 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,10 @@ - - @@ -394,21 +384,18 @@ - - - @@ -416,7 +403,6 @@ - @@ -426,7 +412,6 @@ - @@ -435,7 +420,6 @@ - @@ -444,7 +428,6 @@ - @@ -454,7 +437,6 @@ - @@ -472,39 +454,33 @@ - - - - - - @@ -518,7 +494,6 @@ - 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/src/helpers.c b/src/helpers.c index 924082bcd..429c5d190 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -24,6 +24,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include #include @@ -460,7 +461,8 @@ void register_tolua_helpers(void) at_register(&at_direction); at_register(&at_building_action); - register_function((pf_generic)lua_callspell, TOLUA_CAST "lua_castspell"); + callbacks.cast_spell = lua_callspell; + register_function((pf_generic)lua_initfamiliar, TOLUA_CAST "lua_initfamiliar"); register_function((pf_generic)lua_getresource, From 724a41ac8537a3bfd78fc97cd8905f9a6129a8e7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 Apr 2017 18:41:30 +0200 Subject: [PATCH 3/9] refactor: pass function name to callback, calculate it in call_spell instead. --- src/helpers.c | 13 +------------ src/kernel/callbacks.h | 2 +- src/kernel/xmlreader.c | 2 +- src/magic.c | 15 ++++++++++++++- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/helpers.c b/src/helpers.c index 429c5d190..4e020cefe 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -157,23 +157,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)) { diff --git a/src/kernel/callbacks.h b/src/kernel/callbacks.h index 99db5e390..71f3900c4 100644 --- a/src/kernel/callbacks.h +++ b/src/kernel/callbacks.h @@ -26,7 +26,7 @@ extern "C" { struct castorder; extern struct callbacks { - int (*cast_spell)(struct castorder *co); + int (*cast_spell)(struct castorder *co, const char *fname); } callbacks; #ifdef __cplusplus diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 60c80dade..c0595b4f5 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1399,7 +1399,7 @@ static int parse_spells(xmlDocPtr doc) if (result->nodesetval->nodeNr == 0) { cast = get_function(sp->sname); if (!cast) { - log_error("no spell cast function registered for '%s'\n", sp->sname); + log_info("no spell cast function registered for '%s'\n", sp->sname); } } else { diff --git a/src/magic.c b/src/magic.c index 8db533923..d7bc63ca2 100644 --- a/src/magic.c +++ b/src/magic.c @@ -3006,11 +3006,24 @@ 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]; + const spell *sp = co->sp; if (sp->cast_fun) { return sp->cast_fun(co); } - return callbacks.cast_spell(co); + + if (hashpos != NULL) { + ptrdiff_t len = hashpos - fname; + assert(len < (ptrdiff_t) sizeof(fbuf)); + memcpy(fbuf, fname, len); + fbuf[len] = '\0'; + fname = fbuf; + } + + return callbacks.cast_spell(co, fname); } static critbit_tree cb_spellbooks; From 976b23be724385db3deb7376961ae2ffb2499b1e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 Apr 2017 20:54:53 +0200 Subject: [PATCH 4/9] refactor E3 to use the same raindance/harvest spells as E2. only indirect effects are different. --- res/e3a/spells.xml | 2 ++ scripts/eressea/e3/init.lua | 1 - scripts/eressea/e3/rules.lua | 35 ----------------------------------- scripts/tests/e3/spells.lua | 5 ++--- src/economy.c | 3 +-- src/spells.c | 5 +++-- 6 files changed, 8 insertions(+), 43 deletions(-) delete mode 100644 scripts/eressea/e3/rules.lua diff --git a/res/e3a/spells.xml b/res/e3a/spells.xml index 89a977275..80d9e6260 100644 --- a/res/e3a/spells.xml +++ b/res/e3a/spells.xml @@ -296,6 +296,7 @@ + @@ -494,6 +495,7 @@ + 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/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/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/spells.c b/src/spells.c index 8bf30de88..5341a8e11 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); From 80d696d02ab8eec9557af571ca025e75ce114b02 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 Apr 2017 22:15:18 +0200 Subject: [PATCH 5/9] remove the funcpointer from struct spell. --- res/e3a/strings.xml | 2 +- src/bindings.h | 2 +- src/helpers.c | 20 ++++++++----------- src/helpers.h | 1 + src/kernel/jsonconf.c | 3 --- src/kernel/spell.c | 32 ++++++++++++++++++++++++++---- src/kernel/spell.h | 4 +++- src/kernel/xmlreader.c | 45 +++--------------------------------------- src/magic.c | 13 +++++++----- src/magic.test.c | 2 +- src/spells.c | 17 ++++++++-------- 11 files changed, 63 insertions(+), 78 deletions(-) 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/src/bindings.h b/src/bindings.h index 2275236cb..5cb64a038 100755 --- a/src/bindings.h +++ b/src/bindings.h @@ -18,7 +18,7 @@ extern "C" { struct _dictionary_; struct selist; - int tolua_toid(struct lua_State * L, int idx, int def); + 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/helpers.c b/src/helpers.c index 4e020cefe..700850018 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -23,6 +23,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include #include @@ -452,21 +453,16 @@ void register_tolua_helpers(void) callbacks.cast_spell = lua_callspell; - 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"); + 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, TOLUA_CAST "lua_wage"); - register_function((pf_generic)lua_maintenance, - TOLUA_CAST "lua_maintenance"); + 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 5187f7bcf..d0bbcc58b 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -15,6 +15,7 @@ extern "C" { #endif struct lua_State; + void register_tolua_helpers(void); #ifdef __cplusplus diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c index 6dd3909b5..32ab06e08 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 900f98ff0..393bbecb9 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 da077347a..41feaa17d 100644 --- a/src/kernel/spell.h +++ b/src/kernel/spell.h @@ -41,7 +41,6 @@ extern "C" { int sptyp; int rank; /* Reihenfolge der Zauber */ struct spell_component *components; - spell_f cast_fun; } spell; typedef struct spellref { @@ -52,6 +51,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 c0595b4f5..7367a2023 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; @@ -1388,44 +1384,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_info("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 d7bc63ca2..63c443296 100644 --- a/src/magic.c +++ b/src/magic.c @@ -23,6 +23,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" #include "study.h" +#include "helpers.h" #include "laws.h" #include @@ -3009,12 +3010,9 @@ 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; - if (sp->cast_fun) { - return sp->cast_fun(co); - } - if (hashpos != NULL) { ptrdiff_t len = hashpos - fname; assert(len < (ptrdiff_t) sizeof(fbuf)); @@ -3023,7 +3021,12 @@ int cast_spell(struct castorder *co) fname = fbuf; } - return callbacks.cast_spell(co, fname); + 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 3f279315c..746905029 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -377,8 +377,8 @@ void test_multi_cast(CuTest *tc) { struct locale * lang; test_setup(); + add_spellcast("fireball", cast_fireball); sp = create_spell("fireball", 0); - 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 5341a8e11..468441cdd 100644 --- a/src/spells.c +++ b/src/spells.c @@ -6615,12 +6615,10 @@ static spelldata spell_functions[] = { 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); @@ -6733,11 +6731,14 @@ void register_spells(void) 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"); + add_spellcast("blabbermouth", sp_babbler); + add_spellcast("summon_familiar", sp_summon_familiar); + add_spellcast("meteor_rain", sp_kampfzauber); + add_spellcast("fireball", sp_kampfzauber); + add_spellcast("hail", sp_kampfzauber); + add_spellcast("readmind", sp_readmind); + add_spellcast("blessedharvest", sp_blessedharvest); + add_spellcast("raindance", sp_blessedharvest); register_spelldata(); From 51a991413fa31d56e97ef82091c9f6c1e85bf4e4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 Apr 2017 22:46:35 +0200 Subject: [PATCH 6/9] use at_deprecate, as is intended. --- src/spells.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/spells.c b/src/spells.c index 468441cdd..332647fae 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2931,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 /* ------------------------------------------------------------- */ @@ -6725,7 +6721,9 @@ 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); From 773e8c79d0facc308da398ae363af9a76e6b3c64 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 30 Apr 2017 22:49:26 +0200 Subject: [PATCH 7/9] some code normalization. --- src/spells.c | 207 +++++++++++++++++++++++++-------------------------- src/spells.h | 1 + 2 files changed, 103 insertions(+), 105 deletions(-) diff --git a/src/spells.c b/src/spells.c index 332647fae..8f74eaf36 100644 --- a/src/spells.c +++ b/src/spells.c @@ -6448,6 +6448,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; @@ -6567,7 +6660,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 }, @@ -6605,6 +6698,14 @@ 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 } }; @@ -6622,101 +6723,6 @@ 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(); @@ -6729,15 +6735,6 @@ void register_spells(void) ct_register(&ct_firewall); ct_register(&ct_deathcloud); - add_spellcast("blabbermouth", sp_babbler); - add_spellcast("summon_familiar", sp_summon_familiar); - add_spellcast("meteor_rain", sp_kampfzauber); - add_spellcast("fireball", sp_kampfzauber); - add_spellcast("hail", sp_kampfzauber); - add_spellcast("readmind", sp_readmind); - add_spellcast("blessedharvest", sp_blessedharvest); - add_spellcast("raindance", sp_blessedharvest); - 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); From c281a1e5c9ac9f02524da9e18790c8a6233bf09d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 1 May 2017 13:26:17 +0200 Subject: [PATCH 8/9] compatibility code for old data that contains a caldera. --- src/helpers.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/helpers.c b/src/helpers.c index 700850018..8ba6f8942 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -18,6 +18,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -446,8 +447,23 @@ 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) +{ + UNUSED_ARG(t); + read_building_reference(data); + return AT_READ_FAIL; +} + +struct trigger_type tt_caldera = { + "caldera", + NULL, NULL, NULL, NULL, + caldera_read +}; + void register_tolua_helpers(void) { + tt_register(&tt_caldera); at_register(&at_direction); at_register(&at_building_action); From 8e9866f0ce4b0e6f7ee636a7901ffe9b8a9a0812 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 1 May 2017 19:09:00 +0200 Subject: [PATCH 9/9] additional tests for spells. also some support functionality for lua tests. --- scripts/tests/e2/init.lua | 1 + scripts/tests/e3/init.lua | 3 +- scripts/tests/spells.lua | 83 +++++++++++++++++++++++++++++++++++++++ src/bind_faction.c | 18 +++++++++ src/bind_unit.c | 8 ++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 scripts/tests/spells.lua 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/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); }