diff --git a/scripts/tests/config.lua b/scripts/tests/config.lua index b24da72bc..d21ecda1e 100644 --- a/scripts/tests/config.lua +++ b/scripts/tests/config.lua @@ -36,4 +36,3 @@ function test_read_ship() s = ship.create(nil, "boat") assert_not_nil(s) end - diff --git a/scripts/tests/init.lua b/scripts/tests/init.lua index 57477be1d..d54236e2d 100644 --- a/scripts/tests/init.lua +++ b/scripts/tests/init.lua @@ -7,3 +7,4 @@ require 'tests.pool' require 'tests.regions' require 'tests.settings' require 'tests.study' +require 'tests.laws' diff --git a/scripts/tests/laws.lua b/scripts/tests/laws.lua new file mode 100644 index 000000000..f0fef15a9 --- /dev/null +++ b/scripts/tests/laws.lua @@ -0,0 +1,114 @@ +require "lunit" + +module("tests.laws", package.seeall, lunit.testcase) + +function setup() + eressea.free_game() + conf = [[{ + "races": { + "human" : {} + }, + "terrains" : { + "plain": { "flags" : [ "land", "walk", "sail" ] } + }, + "keywords" : { + "de": { + "attack" : "ATTACKIERE", + "maketemp" : "MACHETEMP", + "end" : "ENDE", + "recruit" : "REKRUTIERE" + } + }, + "buildings" : { + "castle" : {} + } + }]] + + eressea.config.reset() + eressea.config.parse(conf) +end + +function test_force_leave_on() + local r = region.create(0, 0, "plain") + local f1 = faction.create("owner@eressea.de") + local f2 = faction.create("guest@eressea.de") + local u1 = unit.create(f1, r, 1) + local u2 = unit.create(f2, r, 1) + local b1 = building.create(r, "castle") + u1.building = b1 + u2.building = b1 + eressea.settings.set("rules.owners.force_leave", "2") + process_orders() + assert_equal(b1, u1.building) + assert_equal(nil, u2.building) +end + +function test_force_leave_off() + local r = region.create(0, 0, "plain") + local f1 = faction.create("owner@eressea.de") + local f2 = faction.create("guest@eressea.de") + local u1 = unit.create(f1, r, 1) + local u2 = unit.create(f2, r, 1) + local b1 = building.create(r, "castle") + u1.building = b1 + u2.building = b1 + eressea.settings.set("rules.owners.force_leave", "0") + process_orders() + assert_equal(b1, u1.building) + assert_equal(b1, u2.building) +end + +function test_make_temp() + local r = region.create(0, 0, "plain") + local f1 = faction.create("owner@eressea.de", "human", "de") + local u1 = unit.create(f1, r, 10) + local u, u2 + + u1.building = building.create(r, "castle") + u1.status = 1 + u1:clear_orders() + u1:add_order("MACHETEMP 1 Hodor") + u1:add_order("REKRUTIERE 1") + u1:add_order("ENDE") + process_orders() + for u in r.units do + if u~=u1 then + u2 = u + break + end + end + assert_not_equal(nil, u2) + assert_not_equal(nil, u2.building) + assert_equal(1, u2.number) + assert_equal(1, u2.status) + assert_equal("Hodor", u2.name) +end + +function test_force_leave_postcombat() + local r = region.create(0, 0, "plain") + local f1 = faction.create("owner@eressea.de", "human", "de") + local f2 = faction.create("guest@eressea.de", "human", "de") + local u1 = unit.create(f1, r, 10) + local u2 = unit.create(f2, r, 10) + local u, u3 + local b1 = building.create(r, "castle") + u1.building = b1 + u2.building = b1 + eressea.settings.set("rules.owners.force_leave", "1") + u1:clear_orders() + u1:add_order("ATTACKIERE " .. itoa36(u2.id)) + u2:clear_orders() + u2:add_order("MACHETEMP 2 Hodor") + u2:add_order("REKRUTIERE 1") + u2:add_order("ENDE") + process_orders() + for u in r.units do + if u~=u1 and u~=u2 then + u3 = u + break + end + end + assert_not_equal(nil, u3) + assert_equal(nil, u3.building) + assert_equal(1, u3.number) +end diff --git a/src/battle.c b/src/battle.c index 9fb58751d..e06d45979 100644 --- a/src/battle.c +++ b/src/battle.c @@ -3946,7 +3946,6 @@ static bool start_battle(region * r, battle ** bp) unit *u; bool fighting = false; - /* list_foreach geht nicht, wegen flucht */ for (u = r->units; u != NULL; u = u->next) { if (fval(u, UFL_LONGACTION)) continue; @@ -4307,6 +4306,9 @@ void do_battle(region * r) /* Auswirkungen berechnen: */ aftermath(b); + if (rule_force_leave(FORCE_LEAVE_POSTCOMBAT)) { + force_leave(b->region); + } /* Hier ist das Gefecht beendet, und wir können die * Hilfsstrukturen * wieder löschen: */ diff --git a/src/bind_building.c b/src/bind_building.c index f52789700..aa9ba8e79 100644 --- a/src/bind_building.c +++ b/src/bind_building.c @@ -20,6 +20,7 @@ without prior permission by the authors of Eressea. #include #include +#include #include #include @@ -190,7 +191,13 @@ static int tolua_building_create(lua_State * L) { region *r = (region *)tolua_tousertype(L, 1, 0); const char *bname = tolua_tostring(L, 2, 0); - if (bname) { + if (!r) { + log_error("building.create expects a region as argument 1"); + } + if (!bname) { + log_error("building.create expects a name as argument 2"); + } + if (bname) { const building_type *btype = bt_find(bname); if (btype) { building *b = new_building(btype, r, default_locale); diff --git a/src/kernel/config.c b/src/kernel/config.c index 6a5815499..d298f77d7 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -991,7 +991,7 @@ void init_locale(struct locale *lang) addtoken(tokens, name, var); } else { - log_error("no translation for magic school %s in locale %s", tok, locale_name(lang)); + log_warning("no translation for magic school %s in locale %s", tok, locale_name(lang)); } tok = strtok(NULL, " "); } diff --git a/src/kernel/race.c b/src/kernel/race.c index 81af9d9a1..2c86c5e51 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -183,6 +183,7 @@ race *rc_get_or_create(const char *zName) rc->recruit_multi = 1.0F; rc->regaura = 1.0F; rc->speed = 1.0F; + rc->battle_flags = BF_CANATTACK; if (strchr(zName, ' ') != NULL) { log_error("race '%s' has an invalid name. remove spaces\n", zName); assert(strchr(zName, ' ') == NULL); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index b4b1da708..1343b3908 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1726,7 +1726,7 @@ static int parse_races(xmlDocPtr doc) if (xml_bvalue(node, "resistpierce", false)) rc->battle_flags |= BF_RES_PIERCE; if (xml_bvalue(node, "canattack", true)) - rc->battle_flags |= BF_CANATTACK; + rc->battle_flags |= BF_CANATTACK; // TODO: invert this flag, so rc_get_or_create gets simpler for (child = node->children; child; child = child->next) { if (strcmp((const char *)child->name, "ai") == 0) { diff --git a/src/laws.c b/src/laws.c index fcb7b10ca..46c471cd5 100755 --- a/src/laws.c +++ b/src/laws.c @@ -3346,7 +3346,7 @@ void new_units(void) } u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); if (name != NULL) - free(name); + free(name); // TODO: use a buffer on the stack instead? fset(u2, UFL_ISNEW); a_add(&u2->attribs, a_new(&at_alias))->data.i = alias; @@ -4337,6 +4337,11 @@ void force_leave(region *r) { } } +bool rule_force_leave(int flags) { + int rules = get_param_int(global.parameters, "rules.owners.force_leave", 0); + return (rules&flags) == flags; +} + static void maintain_buildings_1(region * r) { maintain_buildings(r, false); @@ -4373,6 +4378,12 @@ void init_processor(void) { int p; + while (processors) { + processor * next = processors->next; + free(processors); + processors = next; + } + p = 10; add_proc_global(p, new_units, "Neue Einheiten erschaffen"); @@ -4438,7 +4449,7 @@ void init_processor(void) add_proc_unit(p, follow_unit, "Folge auf Einheiten setzen"); p += 10; /* rest rng again before economics */ - if (get_param_int(global.parameters, "rules.owners.force_leave", 0)) { + if (rule_force_leave(FORCE_LEAVE_ALL)) { add_proc_region(p, force_leave, "kick non-allies out of buildings/ships"); } add_proc_region(p, economics, "Zerstoeren, Geben, Rekrutieren, Vergessen"); @@ -4523,13 +4534,9 @@ void init_processor(void) void processorders(void) { - static int init = 0; + init_processor(); - if (!init) { - init_processor(); - init = 1; - } - update_spells(); + update_spells(); process(); /*************************************************/ diff --git a/src/laws.h b/src/laws.h index 4f4188448..6da5ed5de 100755 --- a/src/laws.h +++ b/src/laws.h @@ -105,9 +105,13 @@ extern "C" { bool seefaction(const struct faction *f, const struct region *r, const struct unit *u, int modifier); int armedmen(const struct unit *u, bool siege_weapons); - void force_leave(struct region *r); int peasant_luck_effect(int peasants, int luck, int maxp, double variance); + #define FORCE_LEAVE_POSTCOMBAT 1 + #define FORCE_LEAVE_ALL 2 + bool rule_force_leave(int flag); + void force_leave(struct region *r); + #ifdef __cplusplus } #endif diff --git a/src/laws.test.c b/src/laws.test.c index 609b93d03..4c9f43ba5 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -230,6 +230,21 @@ static void test_display_cmd(CuTest *tc) { test_cleanup(); } +static void test_rule_force_leave(CuTest *tc) { + set_param(&global.parameters, "rules.owners.force_leave", "0"); + CuAssertIntEquals(tc, false, rule_force_leave(FORCE_LEAVE_ALL)); + CuAssertIntEquals(tc, false, rule_force_leave(FORCE_LEAVE_POSTCOMBAT)); + set_param(&global.parameters, "rules.owners.force_leave", "1"); + CuAssertIntEquals(tc, false, rule_force_leave(FORCE_LEAVE_ALL)); + CuAssertIntEquals(tc, true, rule_force_leave(FORCE_LEAVE_POSTCOMBAT)); + set_param(&global.parameters, "rules.owners.force_leave", "2"); + CuAssertIntEquals(tc, true, rule_force_leave(FORCE_LEAVE_ALL)); + CuAssertIntEquals(tc, false, rule_force_leave(FORCE_LEAVE_POSTCOMBAT)); + set_param(&global.parameters, "rules.owners.force_leave", "3"); + CuAssertIntEquals(tc, true, rule_force_leave(FORCE_LEAVE_ALL)); + CuAssertIntEquals(tc, true, rule_force_leave(FORCE_LEAVE_POSTCOMBAT)); +} + static void test_force_leave_buildings(CuTest *tc) { ally *al; region *r; @@ -779,6 +794,7 @@ CuSuite *get_laws_suite(void) SUITE_ADD_TEST(suite, test_enter_building); SUITE_ADD_TEST(suite, test_enter_ship); SUITE_ADD_TEST(suite, test_display_cmd); + SUITE_ADD_TEST(suite, test_rule_force_leave); SUITE_ADD_TEST(suite, test_force_leave_buildings); SUITE_ADD_TEST(suite, test_force_leave_ships); SUITE_ADD_TEST(suite, test_force_leave_ships_on_ocean); diff --git a/src/reports.c b/src/reports.c index 4d71d29b0..be2114f97 100644 --- a/src/reports.c +++ b/src/reports.c @@ -114,8 +114,18 @@ const char *combatstatus[] = { const char *report_kampfstatus(const unit * u, const struct locale *lang) { static char fsbuf[64]; // FIXME: static return value + const char * status = LOC(lang, combatstatus[u->status]); - strlcpy(fsbuf, LOC(lang, combatstatus[u->status]), sizeof(fsbuf)); + if (!status) { + const char *lname = locale_name(lang); + struct locale *wloc = get_or_create_locale(lname); + log_error("no translation for combat status %s in %s", combatstatus[u->status], lname); + locale_setstring(wloc, combatstatus[u->status], combatstatus[u->status]); + strlcpy(fsbuf, combatstatus[u->status], sizeof(fsbuf)); + } + else { + strlcpy(fsbuf, status, sizeof(fsbuf)); + } if (fval(u, UFL_NOAID)) { strcat(fsbuf, ", "); strcat(fsbuf, LOC(lang, "status_noaid")); diff --git a/src/util/bsdstring.c b/src/util/bsdstring.c index 4205b9480..865e0198e 100644 --- a/src/util/bsdstring.c +++ b/src/util/bsdstring.c @@ -31,6 +31,7 @@ size_t strlcpy(char *dst, const char *src, size_t siz) register const char *s = src; register size_t n = siz; + assert(src && dst); /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do {