From e7bffb75331100faababf120e50948835c0bca38 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 19 Jun 2015 07:53:11 +0200 Subject: [PATCH 1/2] implement post-combat forced leave from ship/building --- src/battle.c | 3 +++ src/laws.c | 7 ++++++- src/laws.h | 6 +++++- src/laws.test.c | 16 ++++++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/battle.c b/src/battle.c index 9fb58751d..18e506192 100644 --- a/src/battle.c +++ b/src/battle.c @@ -4307,6 +4307,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/laws.c b/src/laws.c index fcb7b10ca..b93482716 100755 --- a/src/laws.c +++ b/src/laws.c @@ -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); @@ -4438,7 +4443,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"); 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); From 9b7a4e813ba91b2e5e12e9f2aa0fed014286fed9 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 19 Jun 2015 13:17:01 +0200 Subject: [PATCH 2/2] functional test for forced leave configuration. functional test for forced leave after combat. functional test for MAKE TEMP. error handling for Lua function building.create(). reduce some errors to warnings. initialize race.battle_flags correctly (when not created through XML). re-initialize processor in case config has changed. handle missing translation of combat status, with error message. --- scripts/tests/config.lua | 1 - scripts/tests/init.lua | 1 + scripts/tests/laws.lua | 114 +++++++++++++++++++++++++++++++++++++++ src/battle.c | 1 - src/bind_building.c | 9 +++- src/kernel/config.c | 2 +- src/kernel/race.c | 1 + src/kernel/xmlreader.c | 2 +- src/laws.c | 16 +++--- src/reports.c | 12 ++++- src/util/bsdstring.c | 1 + 11 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 scripts/tests/laws.lua 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 18e506192..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; 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 b93482716..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; @@ -4378,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"); @@ -4528,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/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 {