diff --git a/scripts/tests/e2/astral.lua b/scripts/tests/e2/astral.lua new file mode 100644 index 000000000..efed6345f --- /dev/null +++ b/scripts/tests/e2/astral.lua @@ -0,0 +1,89 @@ +require "lunit" + +module("tests.e2.astral", 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.peasants.growth.factor", "0") + eressea.settings.set("magic.fumble.enable", "0") + eressea.settings.set("magic.regeneration.enable", "0") +end + +local function dump_messages(f) + for k, v in ipairs(f.messages) do + print(v) + end +end + +function test_fetch_astral() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1.magic = "gray" + u1:set_skill("magic", 6) + u1.aura = 0 + u1:add_spell("fetch_astral") + + u1:clear_orders() + u1:add_order("ZAUBERE Ruf~der~Realitaet " .. itoa36(u2.id)) + process_orders() + assert_equal(1, f:count_msg_type('missing_components_list'), 'no components') + + u1.aura = 12 -- 2 Aura pro Stufe + process_orders() + assert_equal(12, u1.aura) + assert_equal(1, f:count_msg_type('spellfail_astralonly'), 'astral space') + + u2.region = u2.region:get_astral('fog') + process_orders() + assert_equal(0, u1.aura) + assert_equal(u1.region, u2.region) +end + +function test_pull_astral() + local r = region.create(0, 0, "plain") + local f = faction.create("human") + local u1 = unit.create(f, r, 1) + local u2 = unit.create(f, r, 1) + u1.magic = "gray" + u1:set_skill("magic", 6) + u1.aura = 0 + u1:add_spell("pull_astral") + + u1:clear_orders() + u1:add_order("ZAUBERE Astraler~Ruf " .. itoa36(u2.id)) + process_orders() + assert_equal(1, f:count_msg_type('error209'), 'syntax error') + u1:clear_orders() + + u1:clear_orders() + u1:add_order("ZAUBERE Astraler~Ruf 1 0 " .. itoa36(u2.id)) + process_orders() + assert_equal(0, f:count_msg_type('error209'), 'syntax error') + assert_equal(1, f:count_msg_type('error194'), 'target region') + + u1:clear_orders() + u1:add_order("ZAUBERE Astraler~Ruf 0 0 " .. itoa36(u2.id)) + u1.aura = 0 -- missing components + process_orders() + assert_equal(0, f:count_msg_type('error194'), 'target region') + assert_equal(1, f:count_msg_type('missing_components_list'), 'no components') + + u1.aura = 12 -- 2 Aura pro Stufe + process_orders() + assert_equal(1, f:count_msg_type('spellfail_astralonly'), 'astral space') + + u1.region = u1.region:get_astral('fog') + assert_equal('fog', u1.region.terrain) + process_orders() + assert_equal(0, f:count_msg_type('spellfail_astralonly'), 'astral space') + assert_equal(1, f:count_msg_type('send_astral'), 'astral space') + + assert_equal(u1.region, u2.region) +end + diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua index 9dd507671..22195a1f4 100644 --- a/scripts/tests/e2/init.lua +++ b/scripts/tests/e2/init.lua @@ -1,6 +1,7 @@ +require 'tests.e2.astral' +require 'tests.e2.spells' require 'tests.e2.e2features' require 'tests.e2.insects' -require 'tests.e2.spells' require 'tests.e2.buildings' require 'tests.e2.production' require 'tests.e2.adamantium' diff --git a/scripts/tests/e2/items.lua b/scripts/tests/e2/items.lua index 11bcdaed5..d19b3246f 100644 --- a/scripts/tests/e2/items.lua +++ b/scripts/tests/e2/items.lua @@ -9,6 +9,7 @@ function setup() eressea.settings.set("rules.ship.storms", "0") eressea.settings.set("rules.encounters", "0") eressea.settings.set("magic.regeneration.enable", "0") + eressea.settings.set("rules.grow.formula", "0") eressea.settings.set("study.random_progress", "0") end diff --git a/scripts/tests/spells.lua b/scripts/tests/spells.lua index de56472c3..27a5424f7 100644 --- a/scripts/tests/spells.lua +++ b/scripts/tests/spells.lua @@ -8,6 +8,7 @@ function setup() eressea.settings.set("NewbieImmunity", "0") eressea.settings.set("rules.food.flags", "4") eressea.settings.set("rules.encounters", "0") + eressea.settings.set("magic.fumble.enable", "0") eressea.settings.set("magic.regeneration.enable", "0") end @@ -21,7 +22,7 @@ function test_create_bogus() u:clear_orders() u:add_order("ZAUBERE 'Erschaffe Katastrophe'") process_orders() - assert_equal(f.messages[3], 'error173') -- HACKity HACK + assert_equal(1, f:count_msg_type('error173'), 'spell not found') end function test_create_roi() diff --git a/src/bind_faction.c b/src/bind_faction.c index c0875aae2..ac797093d 100644 --- a/src/bind_faction.c +++ b/src/bind_faction.c @@ -39,6 +39,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include typedef struct helpmode { diff --git a/src/bind_region.c b/src/bind_region.c index a87b6f856..e041fba77 100644 --- a/src/bind_region.c +++ b/src/bind_region.c @@ -8,6 +8,7 @@ #include "bind_building.h" #include "chaos.h" +#include "teleport.h" #include #include @@ -561,6 +562,24 @@ static int tolua_region_getkey(lua_State * L) return 1; } +static int tolua_region_getastral(lua_State * L) +{ + region *r = (region *)tolua_tousertype(L, 1, 0); + region *rt = r_standard_to_astral(r); + + if (!rt) { + const char *tname = tolua_tostring(L, 2, 0); + plane *pl = get_astralplane(); + rt = new_region(real2tp(r->x), real2tp(r->y), pl, 0); + if (tname) { + const terrain_type *terrain = get_terrain(tname); + terraform_region(rt, terrain); + } + } + tolua_pushusertype(L, rt, TOLUA_CAST "region"); + return 1; +} + static int tolua_region_setkey(lua_State * L) { region *self = (region *)tolua_tousertype(L, 1, 0); @@ -772,6 +791,8 @@ void tolua_region_open(lua_State * L) tolua_variable(L, TOLUA_CAST "owner", &tolua_region_get_owner, &tolua_region_set_owner); + tolua_function(L, TOLUA_CAST "get_astral", tolua_region_getastral); + tolua_function(L, TOLUA_CAST "get_key", tolua_region_getkey); tolua_function(L, TOLUA_CAST "set_key", tolua_region_setkey); } diff --git a/src/bindings.c b/src/bindings.c index f9f51ded3..3fda9b844 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -476,22 +476,17 @@ static int tolua_write_reports(lua_State * L) return 1; } -static int tolua_process_orders(lua_State * L) -{ - UNUSED_ARG(L); -#if 0 - order * ord = parse_order("@GIB xmis ALLES Gurgelkraut", default_locale); - assert(ord); - free_order(ord); - return 0; -#endif - processorders(); - return 0; -} - static int tolua_turn_begin(lua_State * L) { + faction *f; UNUSED_ARG(L); + for (f = factions; f; f = f->next) { + if (f->msgs) { + free_messagelist(f->msgs->begin); + free(f->msgs); + f->msgs = NULL; + } + } turn_begin(); return 0; } @@ -510,6 +505,14 @@ static int tolua_turn_end(lua_State * L) return 0; } +static int tolua_process_orders(lua_State * L) +{ + UNUSED_ARG(L); + tolua_turn_begin(L); + tolua_turn_process(L); + return tolua_turn_end(L); +} + static int tolua_write_passwords(lua_State * L) { int result = writepasswd(); diff --git a/src/kernel/calendar.c b/src/kernel/calendar.c index df9f6c204..93722b5bc 100644 --- a/src/kernel/calendar.c +++ b/src/kernel/calendar.c @@ -4,7 +4,8 @@ #include "calendar.h" #include "move.h" /* storms */ -#include +#include "kernel/config.h" +#include "util/log.h" #include #include @@ -45,6 +46,10 @@ const gamedate *get_gamedate(int turn_now, gamedate * gd) int t = turn_now - first_turn(); assert(gd); + if (t<0) { + log_fatal("current turn %d is before first %d", + turn_now, first_turn()); + } assert(t>=0); gd->turn = turn_now; diff --git a/src/laws.c b/src/laws.c index ff9c9e880..ea3fdf3c2 100644 --- a/src/laws.c +++ b/src/laws.c @@ -4140,13 +4140,6 @@ void turn_end(void) update_spells(); } -void processorders(void) -{ - turn_begin(); - turn_process(); - turn_end(); -} - void update_subscriptions(void) { FILE *F; diff --git a/src/laws.h b/src/laws.h index 56ed9623b..ae2c712ca 100755 --- a/src/laws.h +++ b/src/laws.h @@ -53,7 +53,6 @@ extern "C" { int enter_building(struct unit *u, struct order *ord, int id, bool report); int enter_ship(struct unit *u, struct order *ord, int id, bool report); - void processorders(void); void turn_begin(void); void turn_process(void); void turn_end(void); diff --git a/src/magic.c b/src/magic.c index 78e818f53..8fd0271e5 100644 --- a/src/magic.c +++ b/src/magic.c @@ -1819,12 +1819,12 @@ static int addparam_building(const char *const param[], spllprm ** spobjp) static int addparam_region(const char *const param[], spllprm ** spobjp, const unit * u, - order * ord) + order * ord, message **err) { assert(param[0]); - if (param[1] == 0) { + if (param[1] == NULL) { /* Fehler: Zielregion vergessen */ - cmistake(u, ord, 194, MSG_MAGIC); + *err = msg_error(u, ord, 194); return -1; } else { @@ -1846,7 +1846,7 @@ addparam_region(const char *const param[], spllprm ** spobjp, const unit * u, } else { /* Fehler: Zielregion vergessen */ - cmistake(u, ord, 194, MSG_MAGIC); + *err = msg_error(u, ord, 194); return -1; } return 2; @@ -1855,7 +1855,7 @@ addparam_region(const char *const param[], spllprm ** spobjp, const unit * u, static int addparam_unit(const char *const param[], spllprm ** spobjp, const unit * u, - order * ord) + order * ord, message **err) { spllprm *spobj; int i = 0; @@ -1865,7 +1865,7 @@ addparam_unit(const char *const param[], spllprm ** spobjp, const unit * u, if (isparam(param[0], u->faction->locale, P_TEMP)) { if (param[1] == NULL) { /* Fehler: Ziel vergessen */ - cmistake(u, ord, 203, MSG_MAGIC); + *err = msg_error(u, ord, 203); return -1; } ++i; @@ -1883,7 +1883,7 @@ addparam_unit(const char *const param[], spllprm ** spobjp, const unit * u, static spellparameter *add_spellparameter(region * target_r, unit * u, const char *syntax, const char *const param[], int size, struct order *ord) { - bool fail = false; + struct message *err = NULL; int i = 0; int p = 0; const char *c; @@ -1919,7 +1919,7 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, } par->param = malloc(size * sizeof(spllprm *)); - while (!fail && *c && i < size && param[i] != NULL) { + while (!err && *c && i < size && param[i] != NULL) { spllprm *spobj = NULL; int j = -1; switch (*c) { @@ -1938,12 +1938,14 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, break; case 'u': /* Parameter ist eine Einheit, evtl. TEMP */ - j = addparam_unit(param + i, &spobj, u, ord); + j = addparam_unit(param + i, &spobj, u, ord, &err); ++c; break; case 'r': /* Parameter sind zwei Regionskoordinaten innerhalb der "normalen" Plane */ - j = addparam_region(param + i, &spobj, u, ord); + if (i + 1 < size) { + j = addparam_region(param + i, &spobj, u, ord, &err); + } ++c; break; case 'b': @@ -1977,7 +1979,7 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, break; case P_UNIT: if (i < size) { - j = addparam_unit(param + i, &spobj, u, ord); + j = addparam_unit(param + i, &spobj, u, ord, &err); ++c; } break; @@ -2003,8 +2005,10 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, j = -1; break; } - if (j < 0) - fail = true; + if (j < 0 && !err) { + /* syntax error */ + err = msg_error(u, ord, 209); + } else { if (spobj != NULL) par->param[p++] = spobj; @@ -2012,14 +2016,18 @@ static spellparameter *add_spellparameter(region * target_r, unit * u, } } - /* im Endeffekt waren es evtl. nur p parameter (wegen TEMP) */ + /* im Endeffekt waren es evtl. nur p parameter (weniger weil TEMP nicht gilt) */ par->length = p; - if (fail || par->length < minlen) { - cmistake(u, ord, 209, MSG_MAGIC); - free_spellparameter(par); - return NULL; - } + if (!err && p < minlen) { + /* syntax error */ + err = msg_error(u, ord, 209); + } + if (err) { + ADDMSG(&u->faction->msgs, err); + free_spellparameter(par); + par = NULL; + } return par; } @@ -2390,8 +2398,9 @@ unit *get_clone(const unit * u) attrib *a = a_find(u->attribs, &at_clone); if (a != NULL) { unit *uc = (unit *)a->data.v; - if (uc->number > 0) + if (uc->number > 0) { return uc; + } } return NULL; } @@ -2400,7 +2409,7 @@ static bool is_moving_ship(ship * sh) { const unit *u = ship_owner(sh); - if (u) + if (u) { switch (getkeyword(u->thisorder)) { case K_ROUTE: case K_MOVE: @@ -2409,9 +2418,11 @@ static bool is_moving_ship(ship * sh) default: return false; } + } return false; } +#define MAX_PARAMETERS 32 static castorder *cast_cmd(unit * u, order * ord) { char token[128]; @@ -2612,33 +2623,25 @@ static castorder *cast_cmd(unit * u, order * ord) } /* Weitere Argumente zusammenbasteln */ if (sp->parameter) { - char **params = (char**)malloc(2 * sizeof(char *)); - int p = 0, size = 2; - for (;;) { + char *params[MAX_PARAMETERS]; + int i, p; + for (p = 0; p != MAX_PARAMETERS; ++p) { s = gettoken(token, sizeof(token)); - if (!s || *s == 0) + if (!s || *s == 0) { break; - if (p + 1 >= size) { - char ** tmp; - tmp = (char**)realloc(params, sizeof(char *) * size * 2); - if (tmp) { - size *= 2; - params = tmp; - } - else { - log_error("error allocationg %d bytes: %s", size * 2, strerror(errno)); - break; - } } - params[p++] = str_strdup(s); + params[p] = str_strdup(s); + } + if (p == MAX_PARAMETERS) { + log_error("%s: MAX_PARAMETERS (%d) too small to CAST %s, parsing stopped early.", + unitname(u), MAX_PARAMETERS, sp->sname); } - params[p] = 0; args = add_spellparameter(target_r, caster, sp->parameter, (const char *const *)params, p, ord); - for (p = 0; params[p]; ++p) - free(params[p]); - free(params); + for (i = 0; i != p; ++i) { + free(params[i]); + } if (args == NULL) { /* Syntax war falsch */ return 0; diff --git a/src/spells.c b/src/spells.c index 57807ae83..bd2c8ea1a 100644 --- a/src/spells.c +++ b/src/spells.c @@ -5311,7 +5311,7 @@ int sp_fetchastral(castorder * co) { int n; unit *mage = co->magician.u; - int cast_level = co->level; + int cast_level = 0; spellparameter *pa = co->par; double power = co->force; int remaining_cap = (int)((power - 3) * 1500); @@ -5343,6 +5343,7 @@ int sp_fetchastral(castorder * co) "spellfail_astralonly", "")); continue; } + if (rtl != NULL) free_regionlist(rtl); rtl = astralregions(u->region, NULL); @@ -5359,6 +5360,7 @@ int sp_fetchastral(castorder * co) ro = u->region; } + cast_level = co->level; /* at least one unit could have been teleported */ if (is_cursed(ro->attribs, &ct_astralblock)) { ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, "spellfail_astralblock", ""));