From 17d410345ff6b68e5e6c4ef15fa1d45205174957 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Tue, 28 Feb 2017 21:50:49 +0100
Subject: [PATCH 01/48] failing test for bug 2288

---
 scripts/tests/e3/rules.lua | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/scripts/tests/e3/rules.lua b/scripts/tests/e3/rules.lua
index 2cba83f21..3a5cdadfa 100644
--- a/scripts/tests/e3/rules.lua
+++ b/scripts/tests/e3/rules.lua
@@ -37,6 +37,10 @@ function teardown()
     set_rule("rules.ship.storms")
 end
 
+function test_calendar()
+    assert_equal(get_season(396), "calendar::winter")
+end
+
 function disable_test_bug_1738_build_castle_e3()
     local r = region.create(0, 0, "plain")    
     local f = faction.create("bug_1738@eressea.de", "human", "de")
@@ -990,4 +994,4 @@ function test_bug2187()
 --  write_report(f)
       
   set_rule("rules.food.flags", "4")
-end
\ No newline at end of file
+end

From e2e602e7ba96adb2b89c35415c649b20789fd875 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Wed, 1 Mar 2017 08:28:15 +0100
Subject: [PATCH 02/48] fix off-by-one calendar, bug 2288

---
 res/core/calendar.xml           | 2 +-
 scripts/tests/e2/e2features.lua | 5 +++++
 src/calendar.c                  | 2 +-
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/res/core/calendar.xml b/res/core/calendar.xml
index 42f83d58b..d96037698 100644
--- a/res/core/calendar.xml
+++ b/res/core/calendar.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<calendar name="secondage" newyear="month_1" start="0">
+<calendar name="secondage" newyear="month_1">
   <season name="winter">
     <month name="month_4" storm="50" />
     <month name="month_5" storm="30" />
diff --git a/scripts/tests/e2/e2features.lua b/scripts/tests/e2/e2features.lua
index de94ea34f..cba363d83 100644
--- a/scripts/tests/e2/e2features.lua
+++ b/scripts/tests/e2/e2features.lua
@@ -10,6 +10,11 @@ function setup()
     eressea.settings.set("rules.encounters", "0")
 end
 
+function test_calendar()
+    assert_equal(get_season(1011), "calendar::winter")
+    assert_equal(get_season(1012), "calendar::spring")
+end
+
 function test_herbalism()
 -- OBS: herbalism is currently an E2-only skill
     local r = region.create(0, 0, "plain")
diff --git a/src/calendar.c b/src/calendar.c
index 2099b6631..d2a70c974 100644
--- a/src/calendar.c
+++ b/src/calendar.c
@@ -18,7 +18,7 @@ int seasons = 0;
 
 int first_turn(void)
 {
-    return config_get_int("game.start", 1);
+    return config_get_int("game.start", 0);
 }
 
 const gamedate *get_gamedate(int turn, gamedate * gd)

From fc8e6dc6de1da81b7681697bb2886ae3c9246831 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Wed, 1 Mar 2017 14:59:20 +0100
Subject: [PATCH 03/48] TARNE PARTEI creport test

---
 src/creport.test.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++
 src/spy.c          | 22 +++++++++++---------
 src/spy.h          | 11 ++++++----
 src/spy.test.c     |  8 --------
 4 files changed, 70 insertions(+), 22 deletions(-)

diff --git a/src/creport.test.c b/src/creport.test.c
index 21a6c09b7..079220738 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -1,6 +1,7 @@
 #include <platform.h>
 #include "creport.h"
 #include "move.h"
+#include "spy.h"
 #include "travelthru.h"
 #include "keyword.h"
 
@@ -48,9 +49,59 @@ static void test_cr_unit(CuTest *tc) {
     test_cleanup();
 }
 
+static int cr_get_int(stream *strm, const char *match, int def)
+{
+    char line[1024];
+
+    strm->api->rewind(strm->handle);
+    while (strm->api->readln(strm->handle, line, sizeof(line))==0) {
+        if (strstr(line, match)) {
+            return atoi(line);
+        }
+    }
+    return def;
+}
+
+static void test_cr_factionstealth(CuTest *tc) {
+    stream strm;
+    faction *f1, *f2, *fr;
+    region *r;
+    unit *u;
+
+    test_setup();
+    mstream_init(&strm);
+    f1 = test_create_faction(0);
+    f2 = test_create_faction(0);
+    fr = test_create_faction(0);
+    r = test_create_region(0, 0, 0);
+    u = test_create_unit(f1, r);
+
+    cr_output_unit(&strm, u->region, f1, u, seen_unit);
+    CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+
+    set_factionstealth(u, f2);
+    CuAssertPtrNotNull(tc, u->attribs);
+
+    cr_output_unit(&strm, u->region, f1, u, seen_unit);
+    CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+
+    cr_output_unit(&strm, u->region, f2, u, seen_unit);
+    CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1));
+
+    mstream_done(&strm);
+    test_cleanup();
+}
+
 CuSuite *get_creport_suite(void)
 {
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_cr_unit);
+    SUITE_ADD_TEST(suite, test_cr_factionstealth);
     return suite;
 }
diff --git a/src/spy.c b/src/spy.c
index d4082cad7..c9667f7ee 100644
--- a/src/spy.c
+++ b/src/spy.c
@@ -178,7 +178,7 @@ int spy_cmd(unit * u, struct order *ord)
     return 0;
 }
 
-void set_factionstealth(unit * u, faction * f)
+static bool can_set_factionstealth(const unit * u, const faction * f)
 {
     region *lastr = NULL;
     /* for all units mu of our faction, check all the units in the region
@@ -194,7 +194,7 @@ void set_factionstealth(unit * u, faction * f)
                     faction *fv = visible_faction(f, ru);
                     if (fv == f) {
                         if (cansee(f, lastr, ru, 0))
-                            break;
+                            return true;
                     }
                 }
                 ru = ru->next;
@@ -204,13 +204,15 @@ void set_factionstealth(unit * u, faction * f)
         }
         mu = mu->nextF;
     }
-    if (mu != NULL) {
-        attrib *a = a_find(u->attribs, &at_otherfaction);
-        if (!a)
-            a = a_add(&u->attribs, make_otherfaction(f));
-        else
-            a->data.v = f;
-    }
+    return true;
+}
+
+void set_factionstealth(unit *u, faction *f) {
+    attrib *a = a_find(u->attribs, &at_otherfaction);
+    if (!a)
+        a = a_add(&u->attribs, make_otherfaction(f));
+    else
+        a->data.v = f;
 }
 
 int setstealth_cmd(unit * u, struct order *ord)
@@ -315,7 +317,7 @@ int setstealth_cmd(unit * u, struct order *ord)
                 }
                 else {
                     struct faction *f = findfaction(nr);
-                    if (f == NULL) {
+                    if (f == NULL || !can_set_factionstealth(u, f)) {
                         cmistake(u, ord, 66, MSG_EVENT);
                         break;
                     }
diff --git a/src/spy.h b/src/spy.h
index d3ee0c728..665595ef4 100644
--- a/src/spy.h
+++ b/src/spy.h
@@ -26,12 +26,15 @@ extern "C" {
     struct region;
     struct strlist;
     struct order;
+    struct faction;
 
-    extern int setstealth_cmd(struct unit *u, struct order *ord);
-    extern int spy_cmd(struct unit *u, struct order *ord);
-    extern int sabotage_cmd(struct unit *u, struct order *ord);
-    extern void spy_message(int spy, const struct unit *u,
+    int setstealth_cmd(struct unit *u, struct order *ord);
+    int spy_cmd(struct unit *u, struct order *ord);
+    int sabotage_cmd(struct unit *u, struct order *ord);
+    void spy_message(int spy, const struct unit *u,
         const struct unit *target);
+    void set_factionstealth(struct unit * u, struct faction * f);
+    
 
 #define OCEAN_SWIMMER_CHANCE 0.1
 #define CANAL_SWIMMER_CHANCE 0.9
diff --git a/src/spy.test.c b/src/spy.test.c
index ae1550689..0dfaada7a 100644
--- a/src/spy.test.c
+++ b/src/spy.test.c
@@ -50,14 +50,6 @@ static void test_simple_spy_message(CuTest *tc) {
     test_cleanup();
 }
 
-static void set_factionstealth(unit *u, faction *f) {
-    attrib *a = a_find(u->attribs, &at_otherfaction);
-    if (!a)
-        a = a_add(&u->attribs, make_otherfaction(f));
-    else
-        a->data.v = f;
-}
-
 static void test_all_spy_message(CuTest *tc) {
     spy_fixture fix;
     item_type *itype;

From 6d9387f6c23ae9aef9fa301da0a4eea1f2f2d939 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 1 Mar 2017 18:16:07 +0100
Subject: [PATCH 04/48] warn about unused variables, back on

---
 src/CMakeLists.txt | 2 +-
 src/creport.test.c | 3 +--
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 43f109fed..f9c92ff2c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -21,7 +21,7 @@ COMPILE_DEFINITIONS ERESSEA_BUILDNO="${ERESSEA_BUILDNO}")
 ENDIF()
 
 IF (CMAKE_COMPILER_IS_GNUCC)
-    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=unused-but-set-variable")
+#    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=unused-but-set-variable")
 ENDIF()
 IF (CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
 #    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wno-sign-conversion")
diff --git a/src/creport.test.c b/src/creport.test.c
index 079220738..11701b62e 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -64,7 +64,7 @@ static int cr_get_int(stream *strm, const char *match, int def)
 
 static void test_cr_factionstealth(CuTest *tc) {
     stream strm;
-    faction *f1, *f2, *fr;
+    faction *f1, *f2;
     region *r;
     unit *u;
 
@@ -72,7 +72,6 @@ static void test_cr_factionstealth(CuTest *tc) {
     mstream_init(&strm);
     f1 = test_create_faction(0);
     f2 = test_create_faction(0);
-    fr = test_create_faction(0);
     r = test_create_region(0, 0, 0);
     u = test_create_unit(f1, r);
 

From 295614643a3eccf7c689c0151836a701b5eba580 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 1 Mar 2017 19:18:00 +0100
Subject: [PATCH 05/48] more factionstealth testing.

---
 src/creport.c      | 24 +++++++++---------------
 src/creport.test.c | 10 ++++++++++
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index c2d10d1c0..d2f50e816 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -763,12 +763,9 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
         stream_printf(out, "\"%s\";Beschr\n", str);
     }
     /* print faction information */
-    sf = visible_faction(f, u);
+    sf = visible_faction(NULL, u);
     prefix = raceprefix(u);
     if (u->faction == f || omniscient(f)) {
-        const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction);
-        const faction *otherfaction =
-            a_otherfaction ? get_otherfaction(a_otherfaction) : NULL;
         /* my own faction, full info */
         const attrib *a = NULL;
         unit *mage;
@@ -780,12 +777,12 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
             stream_printf(out, "%d;gruppe\n", g->gid);
         }
         stream_printf(out, "%d;Partei\n", u->faction->no);
-        if (sf != u->faction)
+        if (sf && sf != u->faction) {
             stream_printf(out, "%d;Verkleidung\n", sf->no);
-        if (fval(u, UFL_ANON_FACTION))
-            stream_printf(out, "%d;Parteitarnung\n", (u->flags & UFL_ANON_FACTION)!=0);
-        if (otherfaction && otherfaction != u->faction) {
-            stream_printf(out, "%d;Anderepartei\n", otherfaction->no);
+            stream_printf(out, "%d;Anderepartei\n", sf->no);
+        }
+        if (fval(u, UFL_ANON_FACTION)) {
+            stream_printf(out, "%d;Parteitarnung\n", (u->flags & UFL_ANON_FACTION) != 0);
         }
         mage = get_familiar_mage(u);
         if (mage) {
@@ -798,17 +795,14 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
             stream_printf(out, "%d;Parteitarnung\n", (u->flags & UFL_ANON_FACTION) != 0);
         }
         else {
-            const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction);
-            const faction *otherfaction =
-                a_otherfaction ? get_otherfaction(a_otherfaction) : NULL;
             /* other unit. show visible faction, not u->faction */
-            stream_printf(out, "%d;Partei\n", sf->no);
+            stream_printf(out, "%d;Partei\n", sf ? sf->no : f->no);
             if (sf == f) {
                 stream_printf(out, "1;Verraeter\n");
             }
-            if (otherfaction && otherfaction != u->faction) {
+            if (sf && sf != u->faction) {
                 if (alliedunit(u, f, HELP_FSTEALTH)) {
-                    stream_printf(out, "%d;Anderepartei\n", otherfaction->no);
+                    stream_printf(out, "%d;Anderepartei\n", sf->no);
                 }
             }
         }
diff --git a/src/creport.test.c b/src/creport.test.c
index 11701b62e..14f40268c 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -5,6 +5,7 @@
 #include "travelthru.h"
 #include "keyword.h"
 
+#include <kernel/ally.h>
 #include <kernel/building.h>
 #include <kernel/faction.h>
 #include <kernel/item.h>
@@ -67,6 +68,7 @@ static void test_cr_factionstealth(CuTest *tc) {
     faction *f1, *f2;
     region *r;
     unit *u;
+    ally *al;
 
     test_setup();
     mstream_init(&strm);
@@ -93,6 +95,14 @@ static void test_cr_factionstealth(CuTest *tc) {
     CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1));
 
+    al = ally_add(&f1->allies, f2);
+    al->status = HELP_FSTEALTH;
+
+    cr_output_unit(&strm, u->region, f2, u, seen_unit);
+    CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1));
+
     mstream_done(&strm);
     test_cleanup();
 }

From e0085eac0c797add6302bb53e24b3e472684cc58 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 1 Mar 2017 19:52:23 +0100
Subject: [PATCH 06/48] write a test for get_addresses before modifying it.

---
 src/creport.c      |  2 +-
 src/reports.c      |  2 +-
 src/reports.h      |  1 +
 src/reports.test.c | 27 +++++++++++++++++++++++++++
 4 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index d2f50e816..99a9ede97 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -764,7 +764,6 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
     }
     /* print faction information */
     sf = visible_faction(NULL, u);
-    prefix = raceprefix(u);
     if (u->faction == f || omniscient(f)) {
         /* my own faction, full info */
         const attrib *a = NULL;
@@ -807,6 +806,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
             }
         }
     }
+    prefix = raceprefix(u);
     if (prefix) {
         prefix = mkname("prefix", prefix);
         stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale,
diff --git a/src/reports.c b/src/reports.c
index a70219b0b..acbc36f69 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -1024,7 +1024,7 @@ static void add_travelthru_addresses(region *r, faction *f, selist **flist, int
     travelthru_map(r, cb_add_address, &cbdata);
 }
 
-static void get_addresses(report_context * ctx)
+void get_addresses(report_context * ctx)
 {
     /* "TODO: travelthru" */
     region *r;
diff --git a/src/reports.h b/src/reports.h
index 4fab104ef..855234376 100644
--- a/src/reports.h
+++ b/src/reports.h
@@ -81,6 +81,7 @@ extern "C" {
 
     void prepare_report(report_context *ctx, struct faction *f);
     void finish_reports(report_context *ctx);
+    void get_addresses(report_context * ctx);
 
     typedef int(*report_fun) (const char *filename, report_context * ctx,
         const char *charset);
diff --git a/src/reports.test.c b/src/reports.test.c
index e3ca5c89b..534cb2187 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -279,6 +279,32 @@ static void test_prepare_travelthru(CuTest *tc) {
     test_cleanup();
 }
 
+static void test_get_addresses(CuTest *tc) {
+    report_context ctx;
+    faction *f, *f2, *f1;
+    region *r;
+    int i;
+
+    test_setup();
+    f = test_create_faction(0);
+    f1 = test_create_faction(0);
+    f2 = test_create_faction(0);
+    r = test_create_region(0, 0, 0);
+    test_create_unit(f, r);
+    test_create_unit(f1, r);
+    test_create_unit(f2, r);
+    prepare_report(&ctx, f);
+    CuAssertPtrEquals(tc, r, ctx.first);
+    CuAssertPtrEquals(tc, NULL, ctx.last);
+    get_addresses(&ctx);
+    CuAssertPtrNotNull(tc, ctx.addresses);
+    CuAssertIntEquals(tc, 3, selist_length(ctx.addresses));
+    CuAssertIntEquals(tc, 1, (i=0, selist_find(&ctx.addresses, &i, f1, NULL)));
+    CuAssertIntEquals(tc, 1, (i=0, selist_find(&ctx.addresses, &i, f2, NULL)));
+    CuAssertIntEquals(tc, 1, (i=0, selist_find(&ctx.addresses, &i, f, NULL)));
+    test_cleanup();
+}
+
 void test_prepare_lighthouse_capacity(CuTest *tc) {
     building *b;
     building_type *btype;
@@ -490,6 +516,7 @@ CuSuite *get_reports_suite(void)
     SUITE_ADD_TEST(suite, test_prepare_lighthouse_owners);
     SUITE_ADD_TEST(suite, test_prepare_lighthouse_capacity);
     SUITE_ADD_TEST(suite, test_prepare_travelthru);
+    SUITE_ADD_TEST(suite, test_get_addresses);
     SUITE_ADD_TEST(suite, test_reorder_units);
     SUITE_ADD_TEST(suite, test_seen_faction);
     SUITE_ADD_TEST(suite, test_regionid);

From 83a862d557c4989d99c7daf3cbc9f5b2c6aa7cbc Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 1 Mar 2017 19:54:52 +0100
Subject: [PATCH 07/48] add a failing test for bug 2286

---
 src/reports.test.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/src/reports.test.c b/src/reports.test.c
index 534cb2187..a6f53d43a 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -2,6 +2,7 @@
 #include "reports.h"
 
 #include "move.h"
+#include "spy.h"
 #include "lighthouse.h"
 #include "travelthru.h"
 #include "keyword.h"
@@ -298,10 +299,39 @@ static void test_get_addresses(CuTest *tc) {
     CuAssertPtrEquals(tc, NULL, ctx.last);
     get_addresses(&ctx);
     CuAssertPtrNotNull(tc, ctx.addresses);
+    CuAssertIntEquals(tc, 1, (i = 0, selist_find(&ctx.addresses, &i, f, NULL)));
+    CuAssertIntEquals(tc, 1, (i = 0, selist_find(&ctx.addresses, &i, f1, NULL)));
+    CuAssertIntEquals(tc, 1, (i = 0, selist_find(&ctx.addresses, &i, f2, NULL)));
     CuAssertIntEquals(tc, 3, selist_length(ctx.addresses));
+    test_cleanup();
+}
+
+static void test_get_addresses_fstealth(CuTest *tc) {
+    report_context ctx;
+    faction *f, *f2, *f1;
+    region *r;
+    unit *u;
+    int i;
+
+    test_setup();
+    f = test_create_faction(0);
+    f1 = test_create_faction(0);
+    f2 = test_create_faction(0);
+    r = test_create_region(0, 0, 0);
+    test_create_unit(f, r);
+    test_create_unit(f1, r);
+    u = test_create_unit(f2, r);
+    set_factionstealth(u, f1);
+
+    prepare_report(&ctx, f);
+    CuAssertPtrEquals(tc, r, ctx.first);
+    CuAssertPtrEquals(tc, NULL, ctx.last);
+    get_addresses(&ctx);
+    CuAssertPtrNotNull(tc, ctx.addresses);
+    CuAssertIntEquals(tc, 1, (i = 0, selist_find(&ctx.addresses, &i, f, NULL)));
     CuAssertIntEquals(tc, 1, (i=0, selist_find(&ctx.addresses, &i, f1, NULL)));
     CuAssertIntEquals(tc, 1, (i=0, selist_find(&ctx.addresses, &i, f2, NULL)));
-    CuAssertIntEquals(tc, 1, (i=0, selist_find(&ctx.addresses, &i, f, NULL)));
+    CuAssertIntEquals(tc, 3, selist_length(ctx.addresses));
     test_cleanup();
 }
 
@@ -517,6 +547,7 @@ CuSuite *get_reports_suite(void)
     SUITE_ADD_TEST(suite, test_prepare_lighthouse_capacity);
     SUITE_ADD_TEST(suite, test_prepare_travelthru);
     SUITE_ADD_TEST(suite, test_get_addresses);
+    SUITE_ADD_TEST(suite, test_get_addresses_fstealth);
     SUITE_ADD_TEST(suite, test_reorder_units);
     SUITE_ADD_TEST(suite, test_seen_faction);
     SUITE_ADD_TEST(suite, test_regionid);

From 98447668caef8a0c09406e89fb82f5ac15867570 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 1 Mar 2017 20:37:49 +0100
Subject: [PATCH 08/48] fix bad tests, upgrade clibs.

---
 clibs              |  2 +-
 src/reports.test.c | 16 +++++++---------
 2 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/clibs b/clibs
index 27c8b3202..d286006a2 160000
--- a/clibs
+++ b/clibs
@@ -1 +1 @@
-Subproject commit 27c8b3202b52766465743c3324fc0b52c5ba4b11
+Subproject commit d286006a28c8aa7cd70ed7fd4cd172b50ade9727
diff --git a/src/reports.test.c b/src/reports.test.c
index a6f53d43a..e0cabb6d8 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -284,7 +284,6 @@ static void test_get_addresses(CuTest *tc) {
     report_context ctx;
     faction *f, *f2, *f1;
     region *r;
-    int i;
 
     test_setup();
     f = test_create_faction(0);
@@ -299,9 +298,9 @@ static void test_get_addresses(CuTest *tc) {
     CuAssertPtrEquals(tc, NULL, ctx.last);
     get_addresses(&ctx);
     CuAssertPtrNotNull(tc, ctx.addresses);
-    CuAssertIntEquals(tc, 1, (i = 0, selist_find(&ctx.addresses, &i, f, NULL)));
-    CuAssertIntEquals(tc, 1, (i = 0, selist_find(&ctx.addresses, &i, f1, NULL)));
-    CuAssertIntEquals(tc, 1, (i = 0, selist_find(&ctx.addresses, &i, f2, NULL)));
+    CuAssertTrue(tc, selist_contains(ctx.addresses, f, NULL));
+    CuAssertTrue(tc, selist_contains(ctx.addresses, f1, NULL));
+    CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL));
     CuAssertIntEquals(tc, 3, selist_length(ctx.addresses));
     test_cleanup();
 }
@@ -311,7 +310,6 @@ static void test_get_addresses_fstealth(CuTest *tc) {
     faction *f, *f2, *f1;
     region *r;
     unit *u;
-    int i;
 
     test_setup();
     f = test_create_faction(0);
@@ -328,10 +326,10 @@ static void test_get_addresses_fstealth(CuTest *tc) {
     CuAssertPtrEquals(tc, NULL, ctx.last);
     get_addresses(&ctx);
     CuAssertPtrNotNull(tc, ctx.addresses);
-    CuAssertIntEquals(tc, 1, (i = 0, selist_find(&ctx.addresses, &i, f, NULL)));
-    CuAssertIntEquals(tc, 1, (i=0, selist_find(&ctx.addresses, &i, f1, NULL)));
-    CuAssertIntEquals(tc, 1, (i=0, selist_find(&ctx.addresses, &i, f2, NULL)));
-    CuAssertIntEquals(tc, 3, selist_length(ctx.addresses));
+    CuAssertTrue(tc, selist_contains(ctx.addresses, f, NULL));
+    CuAssertTrue(tc, selist_contains(ctx.addresses, f1, NULL));
+    CuAssertTrue(tc, ! selist_contains(ctx.addresses, f2, NULL));
+    CuAssertIntEquals(tc, 2, selist_length(ctx.addresses));
     test_cleanup();
 }
 

From 7f03417c37132b3ae05b7a1e7f1cebfa12018517 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 1 Mar 2017 21:10:50 +0100
Subject: [PATCH 09/48] bug 2286: fix missing addresses. was using cansee_unit
 wrong, mixed up traveler (ut) and target (u).

---
 src/reports.c      |  2 +-
 src/reports.test.c | 40 +++++++++++++++++++++++++++++++++++-----
 2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/src/reports.c b/src/reports.c
index acbc36f69..ea504d46b 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -1006,7 +1006,7 @@ static void cb_add_address(region *r, unit *ut, void *cbdata) {
         for (u = r->units; u; u = u->next) {
             faction *sf = visible_faction(f, u);
             assert(u->faction != f);   /* if this is see_travel only, then I shouldn't be here. */
-            if (data->lastf != sf && cansee_unit(u, ut, data->stealthmod)) {
+            if (data->lastf != sf && cansee_unit(ut, u, data->stealthmod)) {
                 add_seen_faction_i(data->flist, sf);
                 data->lastf = sf;
                 break;
diff --git a/src/reports.test.c b/src/reports.test.c
index e0cabb6d8..c026041a9 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -317,9 +317,8 @@ static void test_get_addresses_fstealth(CuTest *tc) {
     f2 = test_create_faction(0);
     r = test_create_region(0, 0, 0);
     test_create_unit(f, r);
-    test_create_unit(f1, r);
-    u = test_create_unit(f2, r);
-    set_factionstealth(u, f1);
+    u = test_create_unit(f1, r);
+    set_factionstealth(u, f2);
 
     prepare_report(&ctx, f);
     CuAssertPtrEquals(tc, r, ctx.first);
@@ -327,8 +326,38 @@ static void test_get_addresses_fstealth(CuTest *tc) {
     get_addresses(&ctx);
     CuAssertPtrNotNull(tc, ctx.addresses);
     CuAssertTrue(tc, selist_contains(ctx.addresses, f, NULL));
-    CuAssertTrue(tc, selist_contains(ctx.addresses, f1, NULL));
-    CuAssertTrue(tc, ! selist_contains(ctx.addresses, f2, NULL));
+    CuAssertTrue(tc, !selist_contains(ctx.addresses, f1, NULL));
+    CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL));
+    CuAssertIntEquals(tc, 2, selist_length(ctx.addresses));
+    test_cleanup();
+}
+
+static void test_get_addresses_travelthru(CuTest *tc) {
+    report_context ctx;
+    faction *f, *f2, *f1;
+    region *r1, *r2;
+    unit *u;
+
+    test_setup();
+    f = test_create_faction(0);
+    f1 = test_create_faction(0);
+    f2 = test_create_faction(0);
+    r1 = test_create_region(0, 0, 0);
+    r2 = test_create_region(1, 0, 0);
+    u = test_create_unit(f, r2);
+    travelthru_add(r1, u);
+    u = test_create_unit(f1, r1);
+    set_factionstealth(u, f2);
+    u->building = test_create_building(u->region, test_create_buildingtype("tower"));
+
+    prepare_report(&ctx, f);
+    CuAssertPtrEquals(tc, r1, ctx.first);
+    CuAssertPtrEquals(tc, NULL, ctx.last);
+    get_addresses(&ctx);
+    CuAssertPtrNotNull(tc, ctx.addresses);
+    CuAssertTrue(tc, selist_contains(ctx.addresses, f, NULL));
+    CuAssertTrue(tc, !selist_contains(ctx.addresses, f1, NULL));
+    CuAssertTrue(tc, selist_contains(ctx.addresses, f2, NULL));
     CuAssertIntEquals(tc, 2, selist_length(ctx.addresses));
     test_cleanup();
 }
@@ -546,6 +575,7 @@ CuSuite *get_reports_suite(void)
     SUITE_ADD_TEST(suite, test_prepare_travelthru);
     SUITE_ADD_TEST(suite, test_get_addresses);
     SUITE_ADD_TEST(suite, test_get_addresses_fstealth);
+    SUITE_ADD_TEST(suite, test_get_addresses_travelthru);
     SUITE_ADD_TEST(suite, test_reorder_units);
     SUITE_ADD_TEST(suite, test_seen_faction);
     SUITE_ADD_TEST(suite, test_regionid);

From 912a8b5412d7fd213ab29e226c060ddbcb8c7b17 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 1 Mar 2017 21:17:37 +0100
Subject: [PATCH 10/48] bug 2291: json settings must not override eressea.ini.
 https://bugs.eressea.de/view.php?id=2291

---
 src/kernel/jsonconf.c      | 20 ++++++++++----------
 src/kernel/jsonconf.test.c |  3 +++
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/src/kernel/jsonconf.c b/src/kernel/jsonconf.c
index 287aa61db..0f5642c42 100644
--- a/src/kernel/jsonconf.c
+++ b/src/kernel/jsonconf.c
@@ -797,18 +797,18 @@ static void json_settings(cJSON *json) {
         return;
     }
     for (child = json->child; child; child = child->next) {
-        if (child->valuestring) {
-            config_set(child->string, child->valuestring);
-        }
-        else {
-            char value[32];
-            if (child->type == cJSON_Number && child->valuedouble && child->valueint<child->valuedouble) {
-                sprintf(value, "%f", child->valuedouble);
+        if (config_get(child->string) == NULL) {
+            if (child->valuestring) {
+                config_set(child->string, child->valuestring);
             }
             else {
-                sprintf(value, "%d", child->valueint);
-            }
-            if (config_get(child->string) == NULL) {
+                char value[32];
+                if (child->type == cJSON_Number && child->valuedouble && child->valueint < child->valuedouble) {
+                    sprintf(value, "%f", child->valuedouble);
+                }
+                else {
+                    sprintf(value, "%d", child->valueint);
+                }
                 config_set(child->string, value);
             }
         }
diff --git a/src/kernel/jsonconf.test.c b/src/kernel/jsonconf.test.c
index 8b8ac8c14..456a27d22 100644
--- a/src/kernel/jsonconf.test.c
+++ b/src/kernel/jsonconf.test.c
@@ -70,14 +70,17 @@ static void test_settings(CuTest * tc)
         "\"integer\" : 14,"
         "\"true\": true,"
         "\"game.id\": 4,"
+        "\"game.name\": \"E3\","
         "\"false\": false,"
         "\"float\" : 1.5 }}";
     cJSON *json = cJSON_Parse(data);
 
     test_cleanup();
     config_set("game.id", "42"); /* should not be replaced */
+    config_set("game.name", "Eressea"); /* should not be replaced */
     json_config(json);
     CuAssertStrEquals(tc, "42", config_get("game.id"));
+    CuAssertStrEquals(tc, "Eressea", config_get("game.name"));
     CuAssertStrEquals(tc, "1", config_get("true"));
     CuAssertStrEquals(tc, "0", config_get("false"));
     CuAssertStrEquals(tc, "1d4", config_get("string"));

From 3cb24299fa4231df4929559c20b2fd9bbad61edf Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 2 Mar 2017 12:39:21 +0100
Subject: [PATCH 11/48] bug 2292: only land regions can be guarded.
 https://bugs.eressea.de/view.php?id=2292 Also adding tests for every other
 failure reason.

---
 src/guard.c      |   3 ++
 src/guard.h      |   2 +-
 src/guard.test.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++
 src/laws.c       |  45 ++++++++++----------
 4 files changed, 133 insertions(+), 22 deletions(-)

diff --git a/src/guard.c b/src/guard.c
index 07640452c..1f2ee7f3f 100644
--- a/src/guard.c
+++ b/src/guard.c
@@ -34,6 +34,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 guard_t can_start_guarding(const unit * u)
 {
+    if (!u->region->land) {
+        return E_GUARD_TERRAIN;
+    }
     if (u->status >= ST_FLEE || fval(u, UFL_FLEEING))
         return E_GUARD_FLEEING;
     /* Monster der Monsterpartei duerfen immer bewachen */
diff --git a/src/guard.h b/src/guard.h
index 101369f40..5a717d92d 100644
--- a/src/guard.h
+++ b/src/guard.h
@@ -12,7 +12,7 @@ extern "C" {
     struct unit;
     struct region;
     
-    typedef enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING } guard_t;
+    typedef enum { E_GUARD_OK, E_GUARD_UNARMED, E_GUARD_NEWBIE, E_GUARD_FLEEING, E_GUARD_TERRAIN } guard_t;
 
     guard_t can_start_guarding(const struct unit * u);
     void update_guards(void);
diff --git a/src/guard.test.c b/src/guard.test.c
index 17aa2891c..1ffd1b4da 100644
--- a/src/guard.test.c
+++ b/src/guard.test.c
@@ -7,7 +7,9 @@
 #include <kernel/config.h>
 #include <kernel/faction.h>
 #include <kernel/unit.h>
+#include <kernel/order.h>
 #include <kernel/race.h>
+#include <kernel/terrain.h>
 #include <kernel/item.h>
 #include <kernel/region.h>
 
@@ -128,14 +130,117 @@ static void test_guard_monsters(CuTest * tc)
     test_cleanup();
 }
 
+static void test_update_guard(CuTest * tc)
+/* https://bugs.eressea.de/view.php?id=2292 */
+{
+    unit *ug;
+    region *r;
+    item_type *itype;
+    const struct terrain_type *t_ocean, *t_plain;
+
+    test_setup();
+    t_ocean = test_create_terrain("ocean", SEA_REGION);
+    t_plain = test_create_terrain("plain", LAND_REGION);
+    itype = it_get_or_create(rt_get_or_create("sword"));
+    new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
+    r = test_create_region(0, 0, t_ocean);
+    ug = test_create_unit(test_create_faction(0), r);
+    i_change(&ug->items, itype, 1);
+    set_level(ug, SK_MELEE, 2);
+    setguard(ug, true);
+    CuAssertIntEquals(tc, 1, armedmen(ug, false));
+    CuAssertTrue(tc, is_guard(ug));
+
+    terraform_region(r, t_ocean);
+    update_guards();
+    CuAssertTrue(tc, ! is_guard(ug));
+
+    test_cleanup();
+}
+
+static void test_guard_on(CuTest * tc)
+{
+    unit *ug;
+    region *r;
+    item_type *itype;
+    terrain_type *t_ocean, *t_plain;
+
+    test_setup();
+    t_ocean = test_create_terrain("ocean", SEA_REGION);
+    t_plain = test_create_terrain("plain", LAND_REGION);
+    itype = it_get_or_create(rt_get_or_create("sword"));
+    new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
+    r = test_create_region(0, 0, t_plain);
+    ug = test_create_unit(test_create_faction(0), r);
+    i_change(&ug->items, itype, 1);
+    set_level(ug, SK_MELEE, 2);
+    ug->thisorder = create_order(K_GUARD, ug->faction->locale, NULL);
+
+    setguard(ug, false);
+    CuAssertIntEquals(tc, E_GUARD_OK, can_start_guarding(ug));
+    guard_on_cmd(ug, ug->thisorder);
+    CuAssertTrue(tc, is_guard(ug));
+
+    terraform_region(r, t_ocean);
+
+    setguard(ug, false);
+    CuAssertIntEquals(tc, E_GUARD_TERRAIN, can_start_guarding(ug));
+    guard_on_cmd(ug, ug->thisorder);
+    CuAssertTrue(tc, !is_guard(ug));
+    CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error2"));
+
+    setguard(ug, false);
+    t_ocean->flags &= ~ SEA_REGION;
+    CuAssertIntEquals(tc, E_GUARD_TERRAIN, can_start_guarding(ug));
+    guard_on_cmd(ug, ug->thisorder);
+    CuAssertTrue(tc, !is_guard(ug));
+    CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error_onlandonly"));
+
+    terraform_region(r, t_plain);
+
+    i_change(&ug->items, itype, -1);
+    CuAssertIntEquals(tc, E_GUARD_UNARMED, can_start_guarding(ug));
+    guard_on_cmd(ug, ug->thisorder);
+    CuAssertTrue(tc, !is_guard(ug));
+    CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "unit_unarmed"));
+    i_change(&ug->items, itype, 1);
+
+    test_clear_messages(ug->faction);
+    set_level(ug, SK_MELEE, 0);
+    CuAssertIntEquals(tc, E_GUARD_UNARMED, can_start_guarding(ug));
+    guard_on_cmd(ug, ug->thisorder);
+    CuAssertTrue(tc, !is_guard(ug));
+    CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "unit_unarmed"));
+    set_level(ug, SK_MELEE, 2);
+
+    ug->status = ST_FLEE;
+    CuAssertIntEquals(tc, E_GUARD_FLEEING, can_start_guarding(ug));
+    guard_on_cmd(ug, ug->thisorder);
+    CuAssertTrue(tc, !is_guard(ug));
+    CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error320"));
+    ug->status = ST_FIGHT;
+
+    config_set("NewbieImmunity", "5");
+    CuAssertIntEquals(tc, E_GUARD_NEWBIE, can_start_guarding(ug));
+    guard_on_cmd(ug, ug->thisorder);
+    CuAssertTrue(tc, !is_guard(ug));
+    CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error304"));
+    config_set("NewbieImmunity", NULL);
+
+    test_clear_messages(ug->faction);
+    test_cleanup();
+}
+
 CuSuite *get_guard_suite(void)
 {
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_is_guarded);
     SUITE_ADD_TEST(suite, test_is_guard);
     SUITE_ADD_TEST(suite, test_guard_unskilled);
+    SUITE_ADD_TEST(suite, test_guard_on);
     SUITE_ADD_TEST(suite, test_guard_armed);
     SUITE_ADD_TEST(suite, test_guard_unarmed);
     SUITE_ADD_TEST(suite, test_guard_monsters);
+    SUITE_ADD_TEST(suite, test_update_guard);
     return suite;
 }
diff --git a/src/laws.c b/src/laws.c
index 253b45b89..dfbd163cb 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -2686,31 +2686,34 @@ int guard_on_cmd(unit * u, struct order *ord)
         return 0;
     }
 
-    if (fval(u->region->terrain, SEA_REGION)) {
-        cmistake(u, ord, 2, MSG_EVENT);
+    if (fval(u, UFL_MOVED)) {
+        cmistake(u, ord, 187, MSG_EVENT);
+    }
+    else if (fval(u_race(u), RCF_ILLUSIONARY)
+        || u_race(u) == get_race(RC_SPELL)) {
+        cmistake(u, ord, 95, MSG_EVENT);
     }
     else {
-        if (fval(u, UFL_MOVED)) {
-            cmistake(u, ord, 187, MSG_EVENT);
+        int err = can_start_guarding(u);
+        if (err == E_GUARD_OK) {
+            setguard(u, true);
         }
-        else if (fval(u_race(u), RCF_ILLUSIONARY)
-            || u_race(u) == get_race(RC_SPELL)) {
-            cmistake(u, ord, 95, MSG_EVENT);
+        else if (err == E_GUARD_TERRAIN) {
+            if (fval(u->region->terrain, SEA_REGION)) {
+                cmistake(u, ord, 2, MSG_EVENT);
+            }
+            else {
+                ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", ""));
+            }
         }
-        else {
-            int err = can_start_guarding(u);
-            if (err == E_GUARD_OK) {
-                setguard(u, true);
-            }
-            else if (err == E_GUARD_UNARMED) {
-                ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", ""));
-            }
-            else if (err == E_GUARD_FLEEING) {
-                cmistake(u, ord, 320, MSG_EVENT);
-            }
-            else if (err == E_GUARD_NEWBIE) {
-                cmistake(u, ord, 304, MSG_EVENT);
-            }
+        else if (err == E_GUARD_UNARMED) {
+            ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", ""));
+        }
+        else if (err == E_GUARD_FLEEING) {
+            cmistake(u, ord, 320, MSG_EVENT);
+        }
+        else if (err == E_GUARD_NEWBIE) {
+            cmistake(u, ord, 304, MSG_EVENT);
         }
     }
     return 0;

From 326f543ece2aaf13966c76b598e4e76801f7a0e0 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 2 Mar 2017 13:01:27 +0100
Subject: [PATCH 12/48] gcc reports unused variable. and for once, that points
 to a bug!

---
 src/guard.c      | 1 +
 src/guard.test.c | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/guard.c b/src/guard.c
index 1f2ee7f3f..a7fa1a97a 100644
--- a/src/guard.c
+++ b/src/guard.c
@@ -72,6 +72,7 @@ void setguard(unit * u, bool enabled)
     } else {
         assert(!fval(u, UFL_MOVED));
         assert(u->status < ST_FLEE);
+        assert(u->region->land);
         fset(u, UFL_GUARD);
         fset(u->region, RF_GUARDED);
     }
diff --git a/src/guard.test.c b/src/guard.test.c
index 1ffd1b4da..cc59af4d8 100644
--- a/src/guard.test.c
+++ b/src/guard.test.c
@@ -143,7 +143,7 @@ static void test_update_guard(CuTest * tc)
     t_plain = test_create_terrain("plain", LAND_REGION);
     itype = it_get_or_create(rt_get_or_create("sword"));
     new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
-    r = test_create_region(0, 0, t_ocean);
+    r = test_create_region(0, 0, t_plain);
     ug = test_create_unit(test_create_faction(0), r);
     i_change(&ug->items, itype, 1);
     set_level(ug, SK_MELEE, 2);

From 45854851ae4b26a19d3584689ca5479ea96b982c Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 2 Mar 2017 18:08:58 +0100
Subject: [PATCH 13/48] bug 2292: allow packice to be guarded again.
 https://bugs.eressea.de/view.php?id=2292

---
 src/guard.c      |  8 ++++----
 src/guard.test.c | 16 ++++++++--------
 src/laws.c       |  7 +------
 3 files changed, 13 insertions(+), 18 deletions(-)

diff --git a/src/guard.c b/src/guard.c
index a7fa1a97a..55f189b6c 100644
--- a/src/guard.c
+++ b/src/guard.c
@@ -24,17 +24,18 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "monsters.h"
 
 #include <kernel/ally.h>
-#include <kernel/unit.h>
+#include <kernel/building.h>
 #include <kernel/faction.h>
 #include <kernel/race.h>
 #include <kernel/region.h>
-#include <kernel/building.h>
+#include <kernel/terrain.h>
+#include <kernel/unit.h>
 
 #include <assert.h>
 
 guard_t can_start_guarding(const unit * u)
 {
-    if (!u->region->land) {
+    if (u->region->terrain->flags & SEA_REGION) {
         return E_GUARD_TERRAIN;
     }
     if (u->status >= ST_FLEE || fval(u, UFL_FLEEING))
@@ -72,7 +73,6 @@ void setguard(unit * u, bool enabled)
     } else {
         assert(!fval(u, UFL_MOVED));
         assert(u->status < ST_FLEE);
-        assert(u->region->land);
         fset(u, UFL_GUARD);
         fset(u->region, RF_GUARDED);
     }
diff --git a/src/guard.test.c b/src/guard.test.c
index cc59af4d8..8302bcc9a 100644
--- a/src/guard.test.c
+++ b/src/guard.test.c
@@ -140,7 +140,7 @@ static void test_update_guard(CuTest * tc)
 
     test_setup();
     t_ocean = test_create_terrain("ocean", SEA_REGION);
-    t_plain = test_create_terrain("plain", LAND_REGION);
+    t_plain = test_create_terrain("packice", ARCTIC_REGION);
     itype = it_get_or_create(rt_get_or_create("sword"));
     new_weapontype(itype, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 2);
     r = test_create_region(0, 0, t_plain);
@@ -181,6 +181,13 @@ static void test_guard_on(CuTest * tc)
     guard_on_cmd(ug, ug->thisorder);
     CuAssertTrue(tc, is_guard(ug));
 
+    terraform_region(r, test_create_terrain("packice", ARCTIC_REGION));
+
+    setguard(ug, false);
+    CuAssertIntEquals(tc, E_GUARD_OK, can_start_guarding(ug));
+    guard_on_cmd(ug, ug->thisorder);
+    CuAssertTrue(tc, is_guard(ug));
+
     terraform_region(r, t_ocean);
 
     setguard(ug, false);
@@ -189,13 +196,6 @@ static void test_guard_on(CuTest * tc)
     CuAssertTrue(tc, !is_guard(ug));
     CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error2"));
 
-    setguard(ug, false);
-    t_ocean->flags &= ~ SEA_REGION;
-    CuAssertIntEquals(tc, E_GUARD_TERRAIN, can_start_guarding(ug));
-    guard_on_cmd(ug, ug->thisorder);
-    CuAssertTrue(tc, !is_guard(ug));
-    CuAssertPtrNotNull(tc, test_find_messagetype(ug->faction->msgs, "error_onlandonly"));
-
     terraform_region(r, t_plain);
 
     i_change(&ug->items, itype, -1);
diff --git a/src/laws.c b/src/laws.c
index dfbd163cb..3d996971b 100644
--- a/src/laws.c
+++ b/src/laws.c
@@ -2699,12 +2699,7 @@ int guard_on_cmd(unit * u, struct order *ord)
             setguard(u, true);
         }
         else if (err == E_GUARD_TERRAIN) {
-            if (fval(u->region->terrain, SEA_REGION)) {
-                cmistake(u, ord, 2, MSG_EVENT);
-            }
-            else {
-                ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", ""));
-            }
+            cmistake(u, ord, 2, MSG_EVENT);
         }
         else if (err == E_GUARD_UNARMED) {
             ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unit_unarmed", ""));

From 4502141c5b6c851c0f7091bd8d83ccd7de174e6b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 2 Mar 2017 18:28:00 +0100
Subject: [PATCH 14/48] bug 2292: set mailcmd from eressea.ini this fixes
 https://bugs.eressea.de/view.php?id=2292

---
 src/kernel/config.c      | 22 +++++++++++++---------
 src/kernel/config.h      |  2 +-
 src/kernel/config.test.c | 14 +++++++++++++-
 src/reports.c            |  2 +-
 4 files changed, 28 insertions(+), 12 deletions(-)

diff --git a/src/kernel/config.c b/src/kernel/config.c
index 3f04b03b3..b605fddd4 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -833,17 +833,21 @@ const char * game_name(void)
     return param ? param : global.gamename;
 }
 
-const char * game_name_upper(void)
+const char * game_mailcmd(void)
 {
-    static char result[32]; /* FIXME: static result */
-    char *r = result;
-    const char *param = game_name();
-    const char *c = param;
-    while (*c && (result+sizeof(result))>r) {
-        *r++ = (char)toupper(*c++);
+    const char *param = config_get("game.mailcmd");
+    if (!param) {
+        static char result[32]; /* FIXME: static result */
+        char *r = result;
+        const char *c;
+        param = game_name();
+        for (c = param; *c && (result + sizeof(result)) > r; ++c) {
+            *r++ = (char)toupper(*c);
+        }
+        *r = '\0';
+        return result;
     }
-    *r = '\0';
-    return result;
+    return param;
 }
 
 int game_id(void) {
diff --git a/src/kernel/config.h b/src/kernel/config.h
index e38d1dd56..3b307bbdd 100644
--- a/src/kernel/config.h
+++ b/src/kernel/config.h
@@ -51,7 +51,7 @@ extern "C" {
     param_t getparam(const struct locale *lang);
 
     const char * game_name(void);
-    const char * game_name_upper(void);
+    const char * game_mailcmd(void);
     int game_id(void);
     /* returns a value between [0..xpct_2], generated with two dice */
 
diff --git a/src/kernel/config.test.c b/src/kernel/config.test.c
index 9a10a4c56..7acf8e948 100644
--- a/src/kernel/config.test.c
+++ b/src/kernel/config.test.c
@@ -245,7 +245,6 @@ static void test_config_inifile(CuTest *tc) {
     config_set_from(ini);
     CuAssertStrEquals(tc, "Eressea", config_get("game.name"));
     CuAssertStrEquals(tc, "Eressea", game_name());
-    CuAssertStrEquals(tc, "ERESSEA", game_name_upper());
     CuAssertIntEquals(tc, 42, game_id());
     iniparser_freedict(ini);
     test_cleanup();
@@ -274,6 +273,18 @@ static void test_findparam(CuTest *tc) {
     test_cleanup();
 }
 
+static void test_game_mailcmd(CuTest *tc) {
+    test_setup();
+    CuAssertStrEquals(tc, "Eressea", game_name());
+    CuAssertStrEquals(tc, "ERESSEA", game_mailcmd());
+    config_set("game.name", "Hodor");
+    CuAssertStrEquals(tc, "Hodor", game_name());
+    CuAssertStrEquals(tc, "HODOR", game_mailcmd());
+    config_set("game.mailcmd", "ERESSEA");
+    CuAssertStrEquals(tc, "ERESSEA", game_mailcmd());
+    test_cleanup();
+}
+
 CuSuite *get_config_suite(void)
 {
     CuSuite *suite = CuSuiteNew();
@@ -287,6 +298,7 @@ CuSuite *get_config_suite(void)
     SUITE_ADD_TEST(suite, test_getunit);
     SUITE_ADD_TEST(suite, test_read_unitid);
     SUITE_ADD_TEST(suite, test_default_order);
+    SUITE_ADD_TEST(suite, test_game_mailcmd);
     SUITE_ADD_TEST(suite, test_rules);
     return suite;
 }
diff --git a/src/reports.c b/src/reports.c
index ea504d46b..a07b60f4b 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -1945,7 +1945,7 @@ static void eval_regions(struct opstack **stack, const void *userdata)
 const char *get_mailcmd(const struct locale *loc)
 {
     static char result[64]; /* FIXME: static return buffer */
-    snprintf(result, sizeof(result), "%s %d %s", game_name_upper(), game_id(), LOC(loc, "mailcmd"));
+    snprintf(result, sizeof(result), "%s %d %s", game_mailcmd(), game_id(), LOC(loc, "mailcmd"));
     return result;
 }
 

From b0baba4405890cbb5678fa099b74aaabd18d5a35 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 2 Mar 2017 19:21:11 +0100
Subject: [PATCH 15/48] bug 2290: sawmill bonus was broken. not pleased with
 the test, which is in lua only. https://bugs.eressea.de/view.php?id=2290

---
 scripts/tests/e2/init.lua |  3 +--
 scripts/tests/e3/init.lua |  1 +
 scripts/tests/economy.lua | 14 ++++++++++++++
 src/economy.c             |  4 ++--
 src/economy.test.c        |  6 ++++++
 5 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/scripts/tests/e2/init.lua b/scripts/tests/e2/init.lua
index afaac7209..25e21f3e5 100644
--- a/scripts/tests/e2/init.lua
+++ b/scripts/tests/e2/init.lua
@@ -1,5 +1,3 @@
-require 'tests.economy'
-
 require 'tests.e2.undead'
 require 'tests.e2.shiplanding'
 require 'tests.e2.e2features'
@@ -8,6 +6,7 @@ require 'tests.e2.destroy'
 require 'tests.e2.guard'
 require 'tests.e2.spells'
 require 'tests.e2.stealth'
+require 'tests.economy'
 require 'tests.orders'
 require 'tests.common'
 require 'tests.report'
diff --git a/scripts/tests/e3/init.lua b/scripts/tests/e3/init.lua
index 4655fdcef..4501e35eb 100644
--- a/scripts/tests/e3/init.lua
+++ b/scripts/tests/e3/init.lua
@@ -4,6 +4,7 @@ require 'tests.e3.spells'
 require 'tests.e3.rules'
 require 'tests.e3.parser'
 require 'tests.e3.morale'
+require 'tests.economy'
 require 'tests.orders'
 require 'tests.common'
 -- require 'tests.report'
diff --git a/scripts/tests/economy.lua b/scripts/tests/economy.lua
index b628dd47b..fe1574887 100644
--- a/scripts/tests/economy.lua
+++ b/scripts/tests/economy.lua
@@ -127,6 +127,20 @@ function test_ironkeeper_guards_iron()
     assert_equal(level, u:get_item("iron"))
 end
 
+function test_sawmill()
+    local r = region.create(0, 0, "plain")
+    r:set_resource("tree", 100)
+    local u = unit.create(faction.create("human"), r)
+    u:add_item("money", 250) -- sawmill maintenance
+    u:set_skill("forestry", 6)
+    u.building = building.create(r, "sawmill")
+    u.building.size = 1
+    u:add_order("MACHE 6 HOLZ")
+    process_orders()
+    assert_equal(6, u:get_item("log"))
+    assert_equal(97, r:get_resource("tree"))
+end
+
 function test_ent_guards_trees()
     local r = region.create(0, 0, "plain")
     r:set_resource("tree", 100)
diff --git a/src/economy.c b/src/economy.c
index f9ded29de..a3b300788 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -1123,7 +1123,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
     allocation *al;
     int nreq = 0;
     resource_limit *rdata = get_resourcelimit(rtype);
-    int avail = 0;
+    int avail = INT_MAX;
 
     for (al = alist; al; al = al->next) {
         nreq += required(al->want, al->save);
@@ -1145,7 +1145,7 @@ attrib_allocation(const resource_type * rtype, region * r, allocation * alist)
             if (rx>0 && rng_int() % nreq < rx) ++x;
             avail -= x;
             nreq -= want;
-            al->get = x * al->save.sa[0] / al->save.sa[1];
+            al->get = x * al->save.sa[1] / al->save.sa[0];
             al->get = MIN(al->want, al->get);
             if (rdata->produce) {
                 int use = required(al->get, al->save);
diff --git a/src/economy.test.c b/src/economy.test.c
index 6d9c84542..e14b473b4 100644
--- a/src/economy.test.c
+++ b/src/economy.test.c
@@ -407,6 +407,12 @@ static void test_make_item(CuTest *tc) {
     CuAssertIntEquals(tc, 22, get_item(u, itype));
     CuAssertIntEquals(tc, 283, u->region->resources->amount); /* no free lunches */
 
+    rdata->modifiers[0].value = frac_make(1, 2);
+    make_item(u, itype, 6);
+    split_allocations(u->region);
+    CuAssertIntEquals(tc, 28, get_item(u, itype));
+    CuAssertIntEquals(tc, 280, u->region->resources->amount); /* 50% saving = 3 stones make 6 stones */
+
     rdata->modifiers[0].flags = RMF_REQUIREDBUILDING;
     rdata->modifiers[0].race = NULL;
     rdata->modifiers[0].btype = bt_get_or_create("mine");

From bec7a338ab013827460615b17db92d32f560412e Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@kn-bremen.de>
Date: Thu, 2 Mar 2017 08:08:35 +0100
Subject: [PATCH 16/48] fix mail processing scripts

---
 process/orders-accept  | 4 ++++
 process/orders-process | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/process/orders-accept b/process/orders-accept
index 78af0a056..2f8f0bd29 100755
--- a/process/orders-accept
+++ b/process/orders-accept
@@ -360,6 +360,10 @@ def accept(game, locale, stream, extend=None):
     return 0
 
 # the main body of the script:
+try:
+    os.mkdir(os.path.join(rootdir, 'log'))
+except:
+    pass # already exists?
 LOG_FILENAME=os.path.join(rootdir, 'log/orders.log')
 logging.basicConfig(level=logging.DEBUG, filename=LOG_FILENAME)
 logger = logging
diff --git a/process/orders-process b/process/orders-process
index b33cc05bf..79c7b3378 100755
--- a/process/orders-process
+++ b/process/orders-process
@@ -2,6 +2,7 @@
 # -*- coding: iso-8859-1 -*-
 
 from os import unlink, symlink, rename, popen, tmpfile
+import sys
 import os
 import os.path
 import ConfigParser
@@ -82,7 +83,7 @@ frommail = 'eressea-server@kn-bremen.de'
 gamename = 'Eressea'
 sender = '%s Server <%s>' % (gamename, frommail)
 
-inifile = os.path.join(gamedir, 'eressea.ini')
+inifile = os.path.join(game_dir, 'eressea.ini')
 if not os.path.exists(inifile):
     print "no such file: " . inifile
 else:
@@ -202,7 +203,7 @@ for line in lines:
     results = check_pwd(infile, email, pw_data)
     logfile = open(os.path.join(game_dir, "zug.log"), "a")
     dirname, filename = split_filename(infile)
-    msg = messages["validate-"+locale] + " " + infilename + "\n\n"
+    msg = messages["validate-"+locale] + " " + infile + "\n\n"
     for faction, game_email, success, pwd in results:
         msg = msg + messages["faction-"+locale] + " " + faction + "\n"
         if success: failed = False

From caa8159428ef17f0b2d0b668a0d00ada291b6c32 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 09:52:17 +0100
Subject: [PATCH 17/48] eliminate duplicate string definition

---
 res/core/de/strings.xml | 9 ---------
 src/report.c            | 4 ++--
 2 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml
index 26e8cc862..5dc649aa1 100644
--- a/res/core/de/strings.xml
+++ b/res/core/de/strings.xml
@@ -6570,15 +6570,6 @@
     </string>
   </namespace>
 
-  <string name="nr_tree">
-    <text locale="de">Baum</text>
-    <text locale="en">tree</text>
-  </string>
-  <string name="nr_tree_p">
-    <text locale="de">Bäume</text>
-    <text locale="en">trees</text>
-  </string>
-
   <string name="nr_mallorntree">
     <text locale="de">Mallornbaum</text>
     <text locale="en">mallorn tree</text>
diff --git a/src/report.c b/src/report.c
index cf00abbc3..6af46ba07 100644
--- a/src/report.c
+++ b/src/report.c
@@ -987,10 +987,10 @@ static void describe(struct stream *out, const region * r, faction * f)
                 }
             }
             else if (trees == 1) {
-                bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree"), size);
+                bytes = (int)strlcpy(bufp, LOC(f->locale, "tree"), size);
             }
             else {
-                bytes = (int)strlcpy(bufp, LOC(f->locale, "nr_tree_p"), size);
+                bytes = (int)strlcpy(bufp, LOC(f->locale, "tree_p"), size);
             }
             if (wrptr(&bufp, &size, bytes) != 0)
                 WARN_STATIC_BUFFER();

From 614978a3433bf9250212b705784ca3996977ee58 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 10:26:39 +0100
Subject: [PATCH 18/48] add a breaking test for the CR. trees and peasants are
 not reported correctly.

---
 tests/write-reports.sh | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/tests/write-reports.sh b/tests/write-reports.sh
index 2183b17dd..6581066f0 100755
--- a/tests/write-reports.sh
+++ b/tests/write-reports.sh
@@ -16,10 +16,10 @@ while [ ! -d $ROOT/.git ]; do
   ROOT=`dirname $ROOT`
 done
 
-set -e
+#set -e
 cd $ROOT/tests
 setup
-cleanup
+#cleanup
 VALGRIND=`which valgrind`
 TESTS=../Debug/eressea/test_eressea
 SERVER=../Debug/eressea/eressea
@@ -34,10 +34,14 @@ $VALGRIND $SERVER -t 184 ../scripts/reports.lua
 [ -d reports ] || quit 4 "no reports directory created"
 CRFILE=184-zvto.cr
 grep -q PARTEI reports/$CRFILE || quit 1 "CR did not contain any factions"
+grep -q -E '"B.ume";type"' reports/$CRFILE || \
+	quit 1 "CR did not contain trees"
+grep -q '"Bauern";type"' reports/$CRFILE || \
+	quit 1 "CR did not contain peasants"
 grep -q REGION reports/$CRFILE || quit 2 "CR did not contain any regions"
 grep -q SCHIFF reports/$CRFILE || quit 3 "CR did not contain any ships"
 grep -q BURG reports/$CRFILE || quit 4 "CR did not contain any buildings"
 grep -q EINHEIT reports/$CRFILE || quit 5 "CR did not contain any units"
 grep -q GEGENSTAENDE reports/$CRFILE || quit 6 "CR did not contain any items"
 echo "integration tests: PASS"
-cleanup
+#cleanup

From 5675ef6091ffc7bb08a1cfff25e9c0f07595d9ed Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 11:10:59 +0100
Subject: [PATCH 19/48] clean and extend the enum of resources.

---
 src/economy.c       |  6 +++---
 src/kernel/item.c   | 22 +++++++++++++---------
 src/kernel/item.h   | 27 +++++++++++++++++++--------
 src/modules/arena.c |  2 +-
 4 files changed, 36 insertions(+), 21 deletions(-)

diff --git a/src/economy.c b/src/economy.c
index a3b300788..248344e47 100644
--- a/src/economy.c
+++ b/src/economy.c
@@ -2130,7 +2130,7 @@ static void planttrees(unit * u, int raw)
     }
 
     /* Mallornb�ume kann man nur in Mallornregionen z�chten */
-    rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED);
+    rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORN_SEED : R_SEED);
 
     /* Skill pr�fen */
     skill = effskill(u, SK_HERBALISM, 0);
@@ -2195,7 +2195,7 @@ static void breedtrees(unit * u, int raw)
     }
 
     /* Mallornb�ume kann man nur in Mallornregionen z�chten */
-    rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORNSEED : R_SEED);
+    rtype = get_resourcetype(fval(r, RF_MALLORN) ? R_MALLORN_SEED : R_SEED);
 
     /* Skill pr�fen */
     skill = effskill(u, SK_HERBALISM, 0);
@@ -2313,7 +2313,7 @@ static void breed_cmd(unit * u, struct order *ord)
     default:
         if (p != P_ANY) {
             rtype = findresourcetype(s, u->faction->locale);
-            if (rtype == get_resourcetype(R_SEED) || rtype == get_resourcetype(R_MALLORNSEED)) {
+            if (rtype == get_resourcetype(R_SEED) || rtype == get_resourcetype(R_MALLORN_SEED)) {
                 breedtrees(u, m);
                 break;
             }
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 6e64c147f..58e3326a2 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -614,25 +614,24 @@ struct order *ord)
 #define R_MINHERB R_PLAIN_1
 #define R_MINPOTION R_FAST
 #define R_MINITEM R_IRON
-#define MAXITEMS MAX_ITEMS
-#define MAXRESOURCES MAX_RESOURCES
-#define MAXHERBS MAX_HERBS
-#define MAXPOTIONS MAX_POTIONS
 #define MAXHERBSPERPOTION 6
 
-const potion_type *oldpotiontype[MAXPOTIONS + 1];
+const potion_type *oldpotiontype[MAX_POTIONS + 1];
 
 /*** alte items ***/
 
 static const char *resourcenames[MAX_RESOURCES] = {
+    "money", "aura", "permaura",
+    "hp", "peasant", "person",
+    "sapling", "mallornsapling", 
+    "tree", "mallorntree",
+    "seed", "mallornseed",
     "iron", "stone", "horse", "ao_healing",
     "aots", "roi", "rop", "ao_chastity",
     "laen", "fairyboot", "aoc", "pegasus",
     "elvenhorse", "charger", "dolphin", "roqf", "trollbelt",
     "aurafocus", "sphereofinv", "magicbag",
-    "magicherbbag", "dreameye", "p2", "seed", "mallornseed",
-    "money", "aura", "permaura",
-    "hp", "peasant", "person"
+    "magicherbbag", "dreameye", "p2"
 };
 
 const resource_type *get_resourcetype(resource_t type) {
@@ -966,7 +965,7 @@ static void init_oldpotions(void)
     };
     int p;
 
-    for (p = 0; p != MAXPOTIONS; ++p) {
+    for (p = 0; p != MAX_POTIONS; ++p) {
         item_type *itype = it_find(potionnames[p]);
         if (itype != NULL) {
             oldpotiontype[p] = itype->rtype->ptype;
@@ -978,6 +977,11 @@ void init_resources(void)
 {
     resource_type *rtype;
 
+    /* there are resources that are special and must be hard-coded.
+     * these are not items, but things like trees or hitpoints
+     * which can be used in a construction recipe or as a spell ingredient.
+     */
+
     rt_get_or_create(resourcenames[R_PERSON]); /* lousy hack */
 
     rtype = rt_get_or_create(resourcenames[R_PEASANT]);
diff --git a/src/kernel/item.h b/src/kernel/item.h
index c1ac38517..c08c676be 100644
--- a/src/kernel/item.h
+++ b/src/kernel/item.h
@@ -252,8 +252,27 @@ extern "C" {
         variant magres, int prot, unsigned int flags);
     potion_type *new_potiontype(item_type * itype, int level);
 
+
+    /* these constants are used with get_resourcetype.
+     * The order of the enum is not important for stored data.
+     * The resourcenames array must be updated to match.
+     */
+
     typedef enum {
+        /* SPECIAL */
+        R_SILVER,
+        R_AURA,                     /* Aura */
+        R_PERMAURA,                 /* Permanente Aura */
+        R_LIFE,
+        R_PEASANT,
+        R_PERSON,
+        R_SAPLING,
+        R_MALLORN_SAPLING,
+        R_TREE,
+        R_MALLORN_TREE,
         /* ITEMS: */
+        R_SEED,
+        R_MALLORN_SEED,
         R_IRON,
         R_STONE,
         R_HORSE,
@@ -277,15 +296,7 @@ extern "C" {
         R_SACK_OF_CONSERVATION,
         R_TACTICCRYSTAL,
         R_WATER_OF_LIFE,
-        R_SEED,
-        R_MALLORNSEED,
         /* SONSTIGE */
-        R_SILVER,
-        R_AURA,                     /* Aura */
-        R_PERMAURA,                 /* Permanente Aura */
-        R_LIFE,
-        R_PEASANT,
-        R_PERSON,
 
         MAX_RESOURCES,              /* do not use outside item.c ! */
         NORESOURCE = -1
diff --git a/src/modules/arena.c b/src/modules/arena.c
index fbc3f0673..aada12234 100644
--- a/src/modules/arena.c
+++ b/src/modules/arena.c
@@ -149,7 +149,7 @@ enter_arena(unit * u, const item_type * itype, int amount, order * ord)
 
     assert(!"not implemented");
     /*
-            for (res=0;res!=MAXRESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) {
+            for (res=0;res!=MAX_RESOURCES;++res) if (res!=R_SILVER && res!=R_ARENA_GATE && (is_item(res) || is_herb(res) || is_potion(res))) {
             int x = get_resource(u, res);
             if (x) {
             if (u2) {

From aa662e65d20bc80d819aff09dd3b01007473723d Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 11:25:17 +0100
Subject: [PATCH 20/48] eliminate R_PERSON hack.

---
 res/core/messages.xml  | 12 ++++++++++++
 src/give.c             | 24 +++++++++++++++++++++++-
 src/give.test.c        |  2 ++
 src/kernel/item.c      |  4 +---
 src/kernel/item.h      |  1 -
 src/kernel/item.test.c |  2 --
 6 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/res/core/messages.xml b/res/core/messages.xml
index e312fcc7c..32d8e35a6 100644
--- a/res/core/messages.xml
+++ b/res/core/messages.xml
@@ -6882,6 +6882,7 @@
     <text locale="de">"$string"</text>
     <text locale="en">"$string"</text>
   </message>
+
   <message name="give_person" section="economy">
     <type>
       <arg name="unit" type="unit"/>
@@ -6892,6 +6893,16 @@
     <text locale="en">"$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to $unit($target)."</text>
   </message>
 
+  <message name="receive_person" section="economy">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="amount" type="int"/>
+      <arg name="target" type="unit"/>
+    </type>
+    <text locale="de">"$unit($target) erhält $int($amount) Person$if($eq($amount,1),"","en") von $unit($unit)."</text>
+    <text locale="en">"$unit($target) receives $int($amount) person$if($eq($amount,1),"","s") from $unit($unit)."</text>
+  </message>
+
   <message name="give" section="economy">
     <type>
       <arg name="unit" type="unit"/>
@@ -6913,6 +6924,7 @@
     <text locale="de">"$unit($target) erhält $int($amount) $resource($resource,$amount) von $unit($unit)."</text>
     <text locale="en">"$unit($target) receives $int($amount) $resource($resource,$amount) from $unit($unit)."</text>
   </message>
+
   <message name="give_person_ocean" section="economy">
     <type>
       <arg name="unit" type="unit"/>
diff --git a/src/give.c b/src/give.c
index 5abb950a6..eeb641665 100644
--- a/src/give.c
+++ b/src/give.c
@@ -121,6 +121,28 @@ const resource_type * rtype, struct order *ord, int error)
     }
 }
 
+static void add_give_person(unit * u, unit * u2, int given,
+    struct order *ord, int error)
+{
+    assert(u2);
+    if (error) {
+        cmistake(u, ord, error, MSG_COMMERCE);
+    }
+    else if (u2->faction != u->faction) {
+        message *msg;
+
+        msg = msg_message("give_person", "unit target resource amount",
+            u, u2, given);
+        add_message(&u->faction->msgs, msg);
+        msg_release(msg);
+
+        msg = msg_message("receive_person", "unit target resource amount",
+            u, u2, given);
+        add_message(&u2->faction->msgs, msg);
+        msg_release(msg);
+    }
+}
+
 static bool limited_give(const item_type * type)
 {
     /* trade only money 2:1, if at all */
@@ -531,7 +553,7 @@ void give_unit(unit * u, unit * u2, order * ord)
         cmistake(u, ord, 156, MSG_COMMERCE);
         return;
     }
-    add_give(u, u2, u->number, u->number, get_resourcetype(R_PERSON), ord, 0);
+    add_give_person(u, u2, u->number, ord, 0);
     u_setfaction(u, u2->faction);
     u2->faction->newbies += u->number;
 }
diff --git a/src/give.test.c b/src/give.test.c
index fbb71cf3c..33f70fb90 100644
--- a/src/give.test.c
+++ b/src/give.test.c
@@ -83,6 +83,8 @@ static void test_give_unit(CuTest * tc) {
     CuAssertPtrEquals(tc, env.f2, env.src->faction);
     CuAssertIntEquals(tc, 1, env.f2->newbies);
     CuAssertPtrEquals(tc, 0, env.f1->units);
+    CuAssertPtrNotNull(tc, test_find_messagetype(env.f1->msgs, "give_person"));
+    CuAssertPtrNotNull(tc, test_find_messagetype(env.f2->msgs, "receive_person"));
     test_cleanup();
 }
 
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 58e3326a2..6c96cb0b0 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -622,7 +622,7 @@ const potion_type *oldpotiontype[MAX_POTIONS + 1];
 
 static const char *resourcenames[MAX_RESOURCES] = {
     "money", "aura", "permaura",
-    "hp", "peasant", "person",
+    "hp", "peasant",
     "sapling", "mallornsapling", 
     "tree", "mallorntree",
     "seed", "mallornseed",
@@ -982,8 +982,6 @@ void init_resources(void)
      * which can be used in a construction recipe or as a spell ingredient.
      */
 
-    rt_get_or_create(resourcenames[R_PERSON]); /* lousy hack */
-
     rtype = rt_get_or_create(resourcenames[R_PEASANT]);
     rtype->uchange = res_changepeasants;
 
diff --git a/src/kernel/item.h b/src/kernel/item.h
index c08c676be..bb114c8ac 100644
--- a/src/kernel/item.h
+++ b/src/kernel/item.h
@@ -265,7 +265,6 @@ extern "C" {
         R_PERMAURA,                 /* Permanente Aura */
         R_LIFE,
         R_PEASANT,
-        R_PERSON,
         R_SAPLING,
         R_MALLORN_SAPLING,
         R_TREE,
diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c
index 52e7d9917..c824d082a 100644
--- a/src/kernel/item.test.c
+++ b/src/kernel/item.test.c
@@ -165,8 +165,6 @@ static void test_core_resources(CuTest *tc) {
     CuAssertPtrNotNull(tc, rtype->itype->give);
     CuAssertPtrNotNull(tc, rtype = rt_find("peasant"));
     CuAssertPtrEquals(tc, 0, rtype->itype);
-    CuAssertPtrNotNull(tc, rtype = rt_find("person"));
-    CuAssertPtrEquals(tc, 0, rtype->itype);
     CuAssertPtrNotNull(tc, rtype = rt_find("permaura"));
     CuAssertPtrEquals(tc, 0, rtype->itype);
     CuAssertPtrNotNull(tc, rtype = rt_find("hp"));

From 6a8762540970158af26dee391df74a1b13328cdd Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 15:26:04 +0100
Subject: [PATCH 21/48] refactor cr_output_resources for easy testing. Write a
 (failing) test that checks first resource is silver.

---
 src/creport.c      | 38 +++++++++++++++++++++++++-------------
 src/creport.h      |  3 ++-
 src/creport.test.c | 27 +++++++++++++++++++++++++++
 src/kernel/item.c  | 10 +++++-----
 src/reports.c      |  3 ++-
 5 files changed, 61 insertions(+), 20 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index 99a9ede97..aa4fd2f98 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -1157,11 +1157,9 @@ cr_borders(const region * r, const faction * f, seen_mode mode, FILE * F)
     }
 }
 
-static void
-cr_output_resources(FILE * F, report_context * ctx, region *r, bool see_unit)
+void cr_output_resources(stream *out, const faction * f, const region *r, bool see_unit)
 {
     char cbuf[BUFFERSIZE], *pos = cbuf;
-    faction *f = ctx->f;
     resource_report result[MAX_RAWMATERIALS];
     int n, size = report_resources(r, result, MAX_RAWMATERIALS, f, see_unit);
 
@@ -1169,15 +1167,18 @@ cr_output_resources(FILE * F, report_context * ctx, region *r, bool see_unit)
     int trees = rtrees(r, 2);
     int saplings = rtrees(r, 1);
 
-    if (trees > 0)
-        fprintf(F, "%d;Baeume\n", trees);
-    if (saplings > 0)
-        fprintf(F, "%d;Schoesslinge\n", saplings);
-    if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0))
-        fprintf(F, "1;Mallorn\n");
+    if (trees > 0) {
+        stream_printf(out, "%d;Baeume\n", trees);
+    }
+    if (saplings > 0) {
+        stream_printf(out, "%d;Schoesslinge\n", trees);
+    }
+    if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) {
+        sputs("1;Mallorn\n", out);
+    }
     for (n = 0; n < size; ++n) {
         if (result[n].level >= 0 && result[n].number >= 0) {
-            fprintf(F, "%d;%s\n", result[n].number, crtag(result[n].name));
+            stream_printf(out, "%d;%s\n", result[n].number, crtag(result[n].name));
         }
     }
 #endif
@@ -1189,10 +1190,21 @@ cr_output_resources(FILE * F, report_context * ctx, region *r, bool see_unit)
                 result[n].level);
         }
     }
-    if (pos != cbuf)
-        fputs(cbuf, F);
+    if (pos != cbuf) {
+        sputs(cbuf, out);
+    }
 }
 
+static void cr_output_resources_compat(FILE *F, report_context * ctx,
+    region *r, bool see_unit)
+{
+    /* TODO: eliminate this function */
+    stream strm;
+    fstream_init(&strm, F);
+    cr_output_resources(&strm, ctx->f, r, see_unit);
+}
+
+
 static void
 cr_region_header(FILE * F, int plid, int nx, int ny, int uid)
 {
@@ -1357,7 +1369,7 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r)
 
             /* this writes both some tags (RESOURCECOMPAT) and a block.
              * must not write any blocks before it */
-            cr_output_resources(F, ctx, r, r->seen.mode >= seen_unit);
+            cr_output_resources_compat(F, ctx, r, r->seen.mode >= seen_unit);
 
             if (r->seen.mode >= seen_unit) {
                 /* trade */
diff --git a/src/creport.h b/src/creport.h
index fc2517859..435bb637f 100644
--- a/src/creport.h
+++ b/src/creport.h
@@ -29,7 +29,8 @@ extern "C" {
     int crwritemap(const char *filename);
     void cr_output_unit(struct stream *out, const struct region * r,
         const struct faction * f, const struct unit * u, seen_mode mode);
-
+    void cr_output_resources(struct stream *out, const struct faction * f,
+        const struct region *r, bool see_unit);
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/creport.test.c b/src/creport.test.c
index 14f40268c..254a73cbb 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -50,6 +50,32 @@ static void test_cr_unit(CuTest *tc) {
     test_cleanup();
 }
 
+static void test_cr_resources(CuTest *tc) {
+    stream strm;
+    char line[1024];
+    faction *f;
+    region *r;
+
+    test_cleanup();
+    f = test_create_faction(0);
+    r = test_create_region(0, 0, 0);
+    r->land->horses = 100;
+    r->land->peasants = 200;
+    r->land->money = 300;
+
+    mstream_init(&strm);
+    cr_output_resources(&strm, f, r, false);
+    strm.api->rewind(strm.handle);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "\"Silber\";type", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "300;number", line);
+    mstream_done(&strm);
+    test_cleanup();
+}
+
 static int cr_get_int(stream *strm, const char *match, int def)
 {
     char line[1024];
@@ -111,6 +137,7 @@ CuSuite *get_creport_suite(void)
 {
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_cr_unit);
+    SUITE_ADD_TEST(suite, test_cr_resources);
     SUITE_ADD_TEST(suite, test_cr_factionstealth);
     return suite;
 }
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 6c96cb0b0..476387075 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -982,23 +982,23 @@ void init_resources(void)
      * which can be used in a construction recipe or as a spell ingredient.
      */
 
-    rtype = rt_get_or_create(resourcenames[R_PEASANT]);
-    rtype->uchange = res_changepeasants;
-
     rtype = rt_get_or_create(resourcenames[R_SILVER]);
     rtype->flags |= RTF_ITEM | RTF_POOLED;
     rtype->uchange = res_changeitem;
     rtype->itype = it_get_or_create(rtype);
     rtype->itype->give = give_money;
 
+    rtype = rt_get_or_create(resourcenames[R_AURA]);
+    rtype->uchange = res_changeaura;
+
     rtype = rt_get_or_create(resourcenames[R_PERMAURA]);
     rtype->uchange = res_changepermaura;
 
     rtype = rt_get_or_create(resourcenames[R_LIFE]);
     rtype->uchange = res_changehp;
 
-    rtype = rt_get_or_create(resourcenames[R_AURA]);
-    rtype->uchange = res_changeaura;
+    rtype = rt_get_or_create(resourcenames[R_PEASANT]);
+    rtype->uchange = res_changepeasants;
 
     /* alte typen registrieren: */
     init_oldpotions();
diff --git a/src/reports.c b/src/reports.c
index a07b60f4b..74b800a90 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -2049,7 +2049,8 @@ static void log_orders(const struct message *msg)
     }
 }
 
-int stream_printf(struct stream * out, const char *format, ...) {
+int stream_printf(struct stream * out, const char *format, ...)
+{
     va_list args;
     int result;
     char buffer[4096];

From 83f170541b23ab2826280a31fd422f1f0725397a Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 15:51:04 +0100
Subject: [PATCH 22/48] short unit-test for resources in the CR. now complains
 because Bauern!=Bauer. TODO: crtag is shit.

---
 src/creport.c      | 12 ++++++-----
 src/creport.test.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 58 insertions(+), 6 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index aa4fd2f98..c766ae872 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -91,10 +91,11 @@ bool opt_cr_absolute_coords = false;
 #ifdef TAG_LOCALE
 static const char *crtag(const char *key)
 {
-    static const struct locale *lang = NULL;
-    if (!lang)
-        lang = get_locale(TAG_LOCALE);
-    return LOC(lang, key);
+    /* TODO: those locale lookups are shit, but static kills testing */
+    const char *result;
+    const struct locale *lang = get_locale(TAG_LOCALE);
+    result = LOC(lang, key);
+    return result;
 }
 #else
 #define crtag(x) (x)
@@ -1096,6 +1097,7 @@ static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale
 static char *cr_output_resource(char *buf, const char *name,
     const struct locale *loc, int amount, int level)
 {
+    assert(name);
     buf += sprintf(buf, "RESOURCE %u\n", hashstring(name));
     buf += sprintf(buf, "\"%s\";type\n", translate(name, LOC(loc, name)));
     if (amount >= 0) {
@@ -1171,7 +1173,7 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s
         stream_printf(out, "%d;Baeume\n", trees);
     }
     if (saplings > 0) {
-        stream_printf(out, "%d;Schoesslinge\n", trees);
+        stream_printf(out, "%d;Schoesslinge\n", saplings);
     }
     if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) {
         sputs("1;Mallorn\n", out);
diff --git a/src/creport.test.c b/src/creport.test.c
index 254a73cbb..8819aab9b 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -55,23 +55,73 @@ static void test_cr_resources(CuTest *tc) {
     char line[1024];
     faction *f;
     region *r;
+    struct locale *lang;
+
+    test_setup();
+    lang = get_or_create_locale("de"); /* CR tags are translated from this */
+    locale_setstring(lang, "money", "Silber");
+    locale_setstring(lang, "money_p", "Silber");
+    locale_setstring(lang, "horse", "Pferd");
+    locale_setstring(lang, "horse_p", "Pferde");
+    locale_setstring(lang, "peasant", "Bauer");
+    locale_setstring(lang, "peasant_p", "Bauern");
+    locale_setstring(lang, "tree", "Baum");
+    locale_setstring(lang, "tree_p", "B?ume");
+    locale_setstring(lang, "sapling", "Schoessling");
+    locale_setstring(lang, "sapling_p", "Schoesslinge");
 
-    test_cleanup();
     f = test_create_faction(0);
     r = test_create_region(0, 0, 0);
     r->land->horses = 100;
     r->land->peasants = 200;
     r->land->money = 300;
+    rsettrees(r, 0, 1);
+    rsettrees(r, 1, 2);
+    rsettrees(r, 2, 3);
 
     mstream_init(&strm);
     cr_output_resources(&strm, f, r, false);
     strm.api->rewind(strm.handle);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "3;Baeume", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "2;Schoesslinge", line);
+
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertStrEquals(tc, "\"Silber\";type", line);
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertStrEquals(tc, "300;number", line);
+
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "\"Bauern\";type", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "200;number", line);
+
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "\"Pferde\";type", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "300;number", line);
+
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "\"Schoesslinge\";type", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "2;number", line);
+
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "\"B?ume\";type", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "3;number", line);
+
     mstream_done(&strm);
     test_cleanup();
 }

From 45862a06d04dbc2990c484e8951c9bdc457fb075 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 16:55:11 +0100
Subject: [PATCH 23/48] Add a good test for the NR. TODO: make it fail.

---
 src/creport.test.c     |  6 ++---
 src/kernel/item.c      | 16 +++++-------
 src/kernel/item.test.c |  8 +++---
 src/report.c           | 20 ++++++++-------
 src/report.h           |  3 ++-
 src/report.test.c      | 58 +++++++++++++++++++++++++++++++++++++-----
 6 files changed, 79 insertions(+), 32 deletions(-)

diff --git a/src/creport.test.c b/src/creport.test.c
index 8819aab9b..b329e2d22 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -65,8 +65,8 @@ static void test_cr_resources(CuTest *tc) {
     locale_setstring(lang, "horse_p", "Pferde");
     locale_setstring(lang, "peasant", "Bauer");
     locale_setstring(lang, "peasant_p", "Bauern");
-    locale_setstring(lang, "tree", "Baum");
-    locale_setstring(lang, "tree_p", "B?ume");
+    locale_setstring(lang, "tree", "Blume");
+    locale_setstring(lang, "tree_p", "Blumen");
     locale_setstring(lang, "sapling", "Schoessling");
     locale_setstring(lang, "sapling_p", "Schoesslinge");
 
@@ -118,7 +118,7 @@ static void test_cr_resources(CuTest *tc) {
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
-    CuAssertStrEquals(tc, "\"B?ume\";type", line);
+    CuAssertStrEquals(tc, "\"Blumen\";type", line);
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertStrEquals(tc, "3;number", line);
 
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 476387075..1fb90d456 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -610,12 +610,6 @@ struct order *ord)
     return -1;                    /* use the mechanism */
 }
 
-#define R_MINOTHER R_SILVER
-#define R_MINHERB R_PLAIN_1
-#define R_MINPOTION R_FAST
-#define R_MINITEM R_IRON
-#define MAXHERBSPERPOTION 6
-
 const potion_type *oldpotiontype[MAX_POTIONS + 1];
 
 /*** alte items ***/
@@ -982,21 +976,25 @@ void init_resources(void)
      * which can be used in a construction recipe or as a spell ingredient.
      */
 
+    /* special resources needed in report_region */
     rtype = rt_get_or_create(resourcenames[R_SILVER]);
     rtype->flags |= RTF_ITEM | RTF_POOLED;
     rtype->uchange = res_changeitem;
     rtype->itype = it_get_or_create(rtype);
     rtype->itype->give = give_money;
 
+    rtype = rt_get_or_create(resourcenames[R_HORSE]);
+    rtype->flags |= RTF_ITEM | RTF_LIMITED;
+    rtype->itype = it_get_or_create(rtype);
+    rtype->itype->flags |= ITF_ANIMAL | ITF_BIG;
+
+    /* "special" spell components */
     rtype = rt_get_or_create(resourcenames[R_AURA]);
     rtype->uchange = res_changeaura;
-
     rtype = rt_get_or_create(resourcenames[R_PERMAURA]);
     rtype->uchange = res_changepermaura;
-
     rtype = rt_get_or_create(resourcenames[R_LIFE]);
     rtype->uchange = res_changehp;
-
     rtype = rt_get_or_create(resourcenames[R_PEASANT]);
     rtype->uchange = res_changepeasants;
 
diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c
index c824d082a..6e3615797 100644
--- a/src/kernel/item.test.c
+++ b/src/kernel/item.test.c
@@ -117,14 +117,14 @@ void test_findresourcetype(CuTest * tc)
     test_setup();
 
     lang = get_or_create_locale("de");
-    locale_setstring(lang, "horse", "Pferd");
+    locale_setstring(lang, "log", "Holz");
     locale_setstring(lang, "peasant", "Bauer");
     init_resources();
     CuAssertPtrNotNull(tc, rt_find("peasant"));
-    CuAssertPtrEquals(tc, 0, rt_find("horse"));
-    itype = test_create_itemtype("horse");
+    CuAssertPtrEquals(tc, 0, rt_find("log"));
+    itype = test_create_itemtype("log");
 
-    CuAssertPtrEquals(tc, (void*)itype->rtype, (void*)findresourcetype("Pferd", lang));
+    CuAssertPtrEquals(tc, (void*)itype->rtype, (void*)findresourcetype("Holz", lang));
     CuAssertPtrEquals(tc, (void *)rt_find("peasant"), (void *)findresourcetype("Bauer", lang));
     test_cleanup();
 }
diff --git a/src/report.c b/src/report.c
index 6af46ba07..6e8d811bc 100644
--- a/src/report.c
+++ b/src/report.c
@@ -878,7 +878,7 @@ bool see_border(const connection * b, const faction * f, const region * r)
     return cs;
 }
 
-static void describe(struct stream *out, const region * r, faction * f)
+void report_region(struct stream *out, const region * r, faction * f)
 {
     int n;
     bool dh;
@@ -1181,7 +1181,6 @@ static void describe(struct stream *out, const region * r, faction * f)
             dh = 1;
         }
     }
-    newline(out);
     *bufp = 0;
     paragraph(out, buf, 0, 0, 0);
 
@@ -1999,7 +1998,7 @@ static void cb_write_travelthru(region *r, unit *u, void *cbdata) {
     }
 }
 
-void write_travelthru(struct stream *out, region *r, const faction *f)
+void report_travelthru(struct stream *out, region *r, const faction *f)
 {
     int maxtravel;
     char buf[8192];
@@ -2281,7 +2280,8 @@ report_plaintext(const char *filename, report_context * ctx,
 
         if (r->seen.mode == seen_unit) {
             anyunits = 1;
-            describe(out, r, f);
+            newline(out);
+            report_region(out, r, f);
             if (markets_module() && r->land) {
                 const item_type *lux = r_luxury(r);
                 const item_type *herb = r->land->herbtype;
@@ -2308,20 +2308,22 @@ report_plaintext(const char *filename, report_context * ctx,
             }
             guards(out, r, f);
             newline(out);
-            write_travelthru(out, r, f);
+            report_travelthru(out, r, f);
         }
         else {
             if (r->seen.mode == seen_far) {
-                describe(out, r, f);
+                newline(out);
+                report_region(out, r, f);
                 newline(out);
                 guards(out, r, f);
                 newline(out);
-                write_travelthru(out, r, f);
+                report_travelthru(out, r, f);
             }
             else {
-                describe(out, r, f);
                 newline(out);
-                write_travelthru(out, r, f);
+                report_region(out, r, f);
+                newline(out);
+                report_travelthru(out, r, f);
             }
         }
         /* Statistik */
diff --git a/src/report.h b/src/report.h
index 84a6c66d4..45c620562 100644
--- a/src/report.h
+++ b/src/report.h
@@ -27,7 +27,8 @@ extern "C" {
     void register_nr(void);
     void report_cleanup(void);
     void write_spaces(struct stream *out, size_t num);
-    void write_travelthru(struct stream *out, struct region * r, const struct faction * f);
+    void report_travelthru(struct stream *out, struct region * r, const struct faction * f);
+    void report_region(struct stream *out, const struct region * r, struct faction * f);
 
     void nr_spell_syntax(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang);
     void nr_spell(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang);
diff --git a/src/report.test.c b/src/report.test.c
index aa3c52695..5b1a8c058 100644
--- a/src/report.test.c
+++ b/src/report.test.c
@@ -56,7 +56,52 @@ static void test_write_many_spaces(CuTest *tc) {
     mstream_done(&out);
 }
 
-static void test_write_travelthru(CuTest *tc) {
+static void test_report_region(CuTest *tc) {
+    char buf[1024];
+    region *r;
+    faction *f;
+    stream out = { 0 };
+    size_t len;
+    struct locale *lang;
+
+    test_setup();
+    init_resources();
+    lang = get_or_create_locale("de"); /* CR tags are translated from this */
+    locale_setstring(lang, "money", "Silber");
+    locale_setstring(lang, "money_p", "Silber");
+    locale_setstring(lang, "horse", "Pferd");
+    locale_setstring(lang, "horse_p", "Pferde");
+    locale_setstring(lang, "peasant", "Bauer");
+    locale_setstring(lang, "peasant_p", "Bauern");
+    locale_setstring(lang, "tree", "Blume");
+    locale_setstring(lang, "tree_p", "Blumen");
+    locale_setstring(lang, "stone", "Stein");
+    locale_setstring(lang, "stone_p", "Steine");
+    locale_setstring(lang, "sapling", "Schoessling");
+    locale_setstring(lang, "sapling_p", "Schoesslinge");
+    locale_setstring(lang, "plain", "Ebene");
+
+    mstream_init(&out);
+    r = test_create_region(0, 0, 0);
+    r->land->peasants = 100;
+    r->land->horses = 200;
+    rsettrees(r, 0, 1);
+    rsettrees(r, 1, 2);
+    rsettrees(r, 2, 3);
+    region_setname(r, "Hodor");
+    f = test_create_faction(0);
+    f->locale = lang;
+
+    report_region(&out, r, f);
+    out.api->rewind(out.handle);
+    len = out.api->read(out.handle, buf, sizeof(buf));
+    buf[len] = '\0';
+    CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 3/2 Blumen, 100 Bauern, 200 Pferde.\n", buf);
+    mstream_done(&out);
+    test_cleanup();
+}
+
+static void test_report_travelthru(CuTest *tc) {
     stream out = { 0 };
     char buf[1024];
     size_t len;
@@ -65,7 +110,7 @@ static void test_write_travelthru(CuTest *tc) {
     unit *u;
     struct locale *lang;
 
-    test_cleanup();
+    test_setup();
     lang = get_or_create_locale("de");
     locale_setstring(lang, "travelthru_header", "Durchreise: ");
     mstream_init(&out);
@@ -77,7 +122,7 @@ static void test_write_travelthru(CuTest *tc) {
     unit_setname(u, "Hodor");
     unit_setid(u, 1);
 
-    write_travelthru(&out, r, f);
+    report_travelthru(&out, r, f);
     out.api->rewind(out.handle);
     len = out.api->read(out.handle, buf, sizeof(buf));
     CuAssertIntEquals_Msg(tc, "no travelers, no report", 0, (int)len);
@@ -85,7 +130,7 @@ static void test_write_travelthru(CuTest *tc) {
 
     mstream_init(&out);
     travelthru_add(r, u);
-    write_travelthru(&out, r, f);
+    report_travelthru(&out, r, f);
     out.api->rewind(out.handle);
     len = out.api->read(out.handle, buf, sizeof(buf));
     buf[len] = '\0';
@@ -94,7 +139,7 @@ static void test_write_travelthru(CuTest *tc) {
 
     mstream_init(&out);
     move_unit(u, r, 0);
-    write_travelthru(&out, r, f);
+    report_travelthru(&out, r, f);
     out.api->rewind(out.handle);
     len = out.api->read(out.handle, buf, sizeof(buf));
     CuAssertIntEquals_Msg(tc, "do not list units that stopped in the region", 0, (int)len);
@@ -234,7 +279,8 @@ CuSuite *get_report_suite(void)
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_write_spaces);
     SUITE_ADD_TEST(suite, test_write_many_spaces);
-    SUITE_ADD_TEST(suite, test_write_travelthru);
+    SUITE_ADD_TEST(suite, test_report_travelthru);
+    SUITE_ADD_TEST(suite, test_report_region);
     SUITE_ADD_TEST(suite, test_write_spell_syntax);
     return suite;
 }

From 52dd11a28f0dda31f80c2c07197dae631b313ca6 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 17:18:17 +0100
Subject: [PATCH 24/48] create a failing test for stones in the NR.

---
 src/kernel/resources.c |  1 +
 src/report.test.c      | 34 +++++++++++++++++++++++++++++++---
 src/reports.c          |  8 +++++---
 3 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/src/kernel/resources.c b/src/kernel/resources.c
index ae93d542a..a3f86aac6 100644
--- a/src/kernel/resources.c
+++ b/src/kernel/resources.c
@@ -203,6 +203,7 @@ struct rawmaterial_type *rmt_create(struct resource_type *rtype)
     rawmaterial_type *rmtype;
 
     assert(!rtype->raw);
+    assert(!rtype->itype || rtype->itype->construction);
     rmtype = rtype->raw = malloc(sizeof(rawmaterial_type));
     rmtype->rtype = rtype;
     rmtype->terraform = terraform_default;
diff --git a/src/report.test.c b/src/report.test.c
index 5b1a8c058..92bfe3d9e 100644
--- a/src/report.test.c
+++ b/src/report.test.c
@@ -9,6 +9,7 @@
 #include <kernel/item.h>
 #include <kernel/race.h>
 #include <kernel/region.h>
+#include <kernel/resources.h>
 #include <kernel/ship.h>
 #include <kernel/unit.h>
 #include <kernel/spell.h>
@@ -60,12 +61,22 @@ static void test_report_region(CuTest *tc) {
     char buf[1024];
     region *r;
     faction *f;
+    unit *u;
     stream out = { 0 };
     size_t len;
     struct locale *lang;
+    struct resource_type *rt_stone;
+    construction *cons;
 
     test_setup();
     init_resources();
+    rt_stone = rt_get_or_create("stone");
+    rt_stone->itype = it_get_or_create(rt_stone);
+    cons = rt_stone->itype->construction = calloc(1, sizeof(construction));
+    cons->minskill = 1;
+    cons->skill = SK_QUARRYING;
+    rmt_create(rt_stone);
+
     lang = get_or_create_locale("de"); /* CR tags are translated from this */
     locale_setstring(lang, "money", "Silber");
     locale_setstring(lang, "money_p", "Silber");
@@ -80,23 +91,40 @@ static void test_report_region(CuTest *tc) {
     locale_setstring(lang, "sapling", "Schoessling");
     locale_setstring(lang, "sapling_p", "Schoesslinge");
     locale_setstring(lang, "plain", "Ebene");
+    locale_setstring(lang, "see_travel", "durchgereist");
 
     mstream_init(&out);
     r = test_create_region(0, 0, 0);
-    r->land->peasants = 100;
-    r->land->horses = 200;
+    add_resource(r, 1, 100, 10, rt_stone);
+    CuAssertIntEquals(tc, 135, r->resources->amount);
+    CuAssertIntEquals(tc, 1, r->resources->level);
+    r->land->peasants = 5;
+    r->land->horses = 7;
+    r->land->money = 2;
     rsettrees(r, 0, 1);
     rsettrees(r, 1, 2);
     rsettrees(r, 2, 3);
     region_setname(r, "Hodor");
     f = test_create_faction(0);
     f->locale = lang;
+    u = test_create_unit(f, r);
+    set_level(u, SK_QUARRYING, 1);
 
+    r->seen.mode = seen_travel;
     report_region(&out, r, f);
     out.api->rewind(out.handle);
     len = out.api->read(out.handle, buf, sizeof(buf));
     buf[len] = '\0';
-    CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 3/2 Blumen, 100 Bauern, 200 Pferde.\n", buf);
+    CuAssertStrEquals(tc, "Hodor (0,0) (durchgereist), Ebene, 3/2 Blumen, 5 Bauern, 2 Silber, 7 Pferde.\n", buf);
+
+    r->seen.mode = seen_unit;
+    out.api->rewind(out.handle);
+    report_region(&out, r, f);
+    out.api->rewind(out.handle);
+    len = out.api->read(out.handle, buf, sizeof(buf));
+    buf[len] = '\0';
+    CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 3/2 Blumen, 135 Steine/1, 5 Bauern, 2 Silber, 7 Pferde.\n", buf);
+
     mstream_done(&out);
     test_cleanup();
 }
diff --git a/src/reports.c b/src/reports.c
index 74b800a90..737e4fc48 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -448,17 +448,19 @@ const faction * viewer, bool see_unit)
         while (res) {
             int maxskill = 0;
             const item_type *itype = resource2item(res->type->rtype);
-            int level = res->level + itype->construction->minskill - 1;
+            int minskill = itype->construction->minskill;
+            skill_t skill = itype->construction->skill;
+            int level = res->level + minskill - 1;
             int visible = -1;
             if (res->type->visible == NULL) {
                 visible = res->amount;
-                level = res->level + itype->construction->minskill - 1;
+                level = res->level + minskill - 1;
             }
             else {
                 const unit *u;
                 for (u = r->units; visible != res->amount && u != NULL; u = u->next) {
                     if (u->faction == viewer) {
-                        int s = effskill(u, itype->construction->skill, 0);
+                        int s = effskill(u, skill, 0);
                         if (s > maxskill) {
                             maxskill = s;
                             visible = res->type->visible(res, maxskill);

From d6ce1d9cfeeda100e10c9ac3cb429ac874a7786e Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 17:26:00 +0100
Subject: [PATCH 25/48] Add a test for singular resources.

---
 src/report.test.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/report.test.c b/src/report.test.c
index 92bfe3d9e..0bfea3c69 100644
--- a/src/report.test.c
+++ b/src/report.test.c
@@ -125,6 +125,19 @@ static void test_report_region(CuTest *tc) {
     buf[len] = '\0';
     CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 3/2 Blumen, 135 Steine/1, 5 Bauern, 2 Silber, 7 Pferde.\n", buf);
 
+    r->resources->amount = 1;
+    r->land->peasants = 1;
+    r->land->horses = 1;
+    r->land->money = 1;
+
+    r->seen.mode = seen_unit;
+    out.api->rewind(out.handle);
+    report_region(&out, r, f);
+    out.api->rewind(out.handle);
+    len = out.api->read(out.handle, buf, sizeof(buf));
+    buf[len] = '\0';
+    CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 3/2 Blumen, 1 Stein/1, 1 Bauer, 1 Silber, 1 Pferd.\n", buf);
+
     mstream_done(&out);
     test_cleanup();
 }

From 0379a17350b778040b318657282408f996657494 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 17:42:57 +0100
Subject: [PATCH 26/48] make report_resource return an rtype, not a name.

---
 src/creport.c      | 12 ++++++------
 src/creport.test.c |  1 +
 src/kernel/item.c  |  5 +++++
 src/report.c       |  2 +-
 src/reports.c      | 25 +++++++++++++------------
 src/reports.h      |  2 +-
 6 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index c766ae872..ee7abcc87 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -1094,12 +1094,12 @@ static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale
     }
 }
 
-static char *cr_output_resource(char *buf, const char *name,
+static char *cr_output_resource(char *buf, const resource_type *rtype,
     const struct locale *loc, int amount, int level)
 {
-    assert(name);
-    buf += sprintf(buf, "RESOURCE %u\n", hashstring(name));
-    buf += sprintf(buf, "\"%s\";type\n", translate(name, LOC(loc, name)));
+    assert(rtype);
+    buf += sprintf(buf, "RESOURCE %u\n", hashstring(rtype->_name));
+    buf += sprintf(buf, "\"%s\";type\n", translate(rtype->_name, LOC(loc, rtype->_name)));
     if (amount >= 0) {
         if (level >= 0)
             buf += sprintf(buf, "%d;skill\n", level);
@@ -1180,7 +1180,7 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s
     }
     for (n = 0; n < size; ++n) {
         if (result[n].level >= 0 && result[n].number >= 0) {
-            stream_printf(out, "%d;%s\n", result[n].number, crtag(result[n].name));
+/*            stream_printf(out, "%d;%s\n", result[n].number, crtag(result[n].name)); */
         }
     }
 #endif
@@ -1188,7 +1188,7 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s
     for (n = 0; n < size; ++n) {
         if (result[n].number >= 0) {
             pos =
-                cr_output_resource(pos, result[n].name, f->locale, result[n].number,
+                cr_output_resource(pos, result[n].rtype, f->locale, result[n].number,
                 result[n].level);
         }
     }
diff --git a/src/creport.test.c b/src/creport.test.c
index b329e2d22..aff170b01 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -58,6 +58,7 @@ static void test_cr_resources(CuTest *tc) {
     struct locale *lang;
 
     test_setup();
+    init_resources();
     lang = get_or_create_locale("de"); /* CR tags are translated from this */
     locale_setstring(lang, "money", "Silber");
     locale_setstring(lang, "money_p", "Silber");
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 1fb90d456..48ea7a690 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -988,6 +988,11 @@ void init_resources(void)
     rtype->itype = it_get_or_create(rtype);
     rtype->itype->flags |= ITF_ANIMAL | ITF_BIG;
 
+    rtype = rt_get_or_create(resourcenames[R_SAPLING]);
+    rtype = rt_get_or_create(resourcenames[R_TREE]);
+    rtype = rt_get_or_create(resourcenames[R_MALLORN_SAPLING]);
+    rtype = rt_get_or_create(resourcenames[R_MALLORN_TREE]);
+
     /* "special" spell components */
     rtype = rt_get_or_create(resourcenames[R_AURA]);
     rtype->uchange = res_changeaura;
diff --git a/src/report.c b/src/report.c
index 6e8d811bc..43a7ab514 100644
--- a/src/report.c
+++ b/src/report.c
@@ -1005,7 +1005,7 @@ void report_region(struct stream *out, const region * r, faction * f)
         for (n = 0; n < numresults; ++n) {
             if (result[n].number >= 0 && result[n].level >= 0) {
                 bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number,
-                    LOC(f->locale, result[n].name), result[n].level);
+                    LOC(f->locale, result[n].rtype->_name), result[n].level);
                 if (wrptr(&bufp, &size, bytes) != 0)
                     WARN_STATIC_BUFFER();
             }
diff --git a/src/reports.c b/src/reports.c
index 737e4fc48..63e274265 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -346,11 +346,11 @@ report_items(const unit *u, item * result, int size, const unit * owner,
     return n;
 }
 
-static void
-report_resource(resource_report * result, const char *name, int number,
-int level)
+static void report_resource(resource_report * result, const resource_type *rtype, 
+    int number, int level)
 {
-    result->name = name;
+    assert(rtype);
+    result->rtype = rtype;
     result->number = number;
     result->level = level;
 }
@@ -408,37 +408,38 @@ const faction * viewer, bool see_unit)
         int trees = rtrees(r, 2);
         int saplings = rtrees(r, 1);
         bool mallorn = fval(r, RF_MALLORN) != 0;
+        const resource_type *rtype;
 
         if (money) {
             if (n >= size)
                 return -1;
-            report_resource(result + n, "money", money, -1);
+            report_resource(result + n, get_resourcetype(R_SILVER), money, -1);
             ++n;
         }
         if (peasants) {
             if (n >= size)
                 return -1;
-            report_resource(result + n, "peasant", peasants, -1);
+            report_resource(result + n, get_resourcetype(R_PEASANT), peasants, -1);
             ++n;
         }
         if (horses) {
             if (n >= size)
                 return -1;
-            report_resource(result + n, "horse", horses, -1);
+            report_resource(result + n, get_resourcetype(R_HORSE), horses, -1);
             ++n;
         }
         if (saplings) {
             if (n >= size)
                 return -1;
-            report_resource(result + n, mallorn ? "mallornsapling" : "sapling",
-                saplings, -1);
+            rtype = get_resourcetype(mallorn ? R_MALLORN_SAPLING : R_SAPLING);
+            report_resource(result + n, rtype, saplings, -1);
             ++n;
         }
         if (trees) {
             if (n >= size)
                 return -1;
-            report_resource(result + n, mallorn ? "mallorn" : "tree", trees,
-                -1);
+            rtype = get_resourcetype(mallorn ? R_MALLORN_TREE : R_TREE);
+            report_resource(result + n, rtype, trees, -1);
             ++n;
         }
     }
@@ -471,7 +472,7 @@ const faction * viewer, bool see_unit)
             if (level >= 0 && visible >= 0) {
                 if (n >= size)
                     return -1;
-                report_resource(result + n, res->type->rtype->_name, visible, level);
+                report_resource(result + n, res->type->rtype, visible, level);
                 n++;
             }
             res = res->next;
diff --git a/src/reports.h b/src/reports.h
index 855234376..6ce14e775 100644
--- a/src/reports.h
+++ b/src/reports.h
@@ -107,7 +107,7 @@ extern "C" {
     } arg_regions;
 
     typedef struct resource_report {
-        const char *name;
+        const struct resource_type *rtype;
         int number;
         int level;
     } resource_report;

From 8d7f9663912b83134b391f97a909ec742da45699 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 18:23:24 +0100
Subject: [PATCH 27/48] BUG 2298: fix CR output. always use the plural form.

---
 src/creport.c      | 7 +++++--
 src/creport.test.c | 4 ++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index ee7abcc87..b9088f020 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -1097,9 +1097,11 @@ static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale
 static char *cr_output_resource(char *buf, const resource_type *rtype,
     const struct locale *loc, int amount, int level)
 {
+    const char * name;
     assert(rtype);
+    name = resourcename(rtype, 1);
     buf += sprintf(buf, "RESOURCE %u\n", hashstring(rtype->_name));
-    buf += sprintf(buf, "\"%s\";type\n", translate(rtype->_name, LOC(loc, rtype->_name)));
+    buf += sprintf(buf, "\"%s\";type\n", translate(name, LOC(loc, rtype->_name)));
     if (amount >= 0) {
         if (level >= 0)
             buf += sprintf(buf, "%d;skill\n", level);
@@ -1180,7 +1182,8 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s
     }
     for (n = 0; n < size; ++n) {
         if (result[n].level >= 0 && result[n].number >= 0) {
-/*            stream_printf(out, "%d;%s\n", result[n].number, crtag(result[n].name)); */
+            const char * name = resourcename(result[n].rtype, result[n].number != 1);
+            stream_printf(out, "%d;%s\n", result[n].number, crtag(name));
         }
     }
 #endif
diff --git a/src/creport.test.c b/src/creport.test.c
index aff170b01..d0ce1532d 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -73,7 +73,7 @@ static void test_cr_resources(CuTest *tc) {
 
     f = test_create_faction(0);
     r = test_create_region(0, 0, 0);
-    r->land->horses = 100;
+    r->land->horses = 1;
     r->land->peasants = 200;
     r->land->money = 300;
     rsettrees(r, 0, 1);
@@ -107,7 +107,7 @@ static void test_cr_resources(CuTest *tc) {
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertStrEquals(tc, "\"Pferde\";type", line);
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
-    CuAssertStrEquals(tc, "300;number", line);
+    CuAssertStrEquals(tc, "1;number", line);
 
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));

From f699c32f0e76ddb46f5a237920153f6445be1dab Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 18:25:15 +0100
Subject: [PATCH 28/48] BUG 2298: fix NR display. always use correct singular
 or plural form.

---
 src/report.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/report.c b/src/report.c
index 43a7ab514..612df1dad 100644
--- a/src/report.c
+++ b/src/report.c
@@ -1004,8 +1004,9 @@ void report_region(struct stream *out, const region * r, faction * f)
 
         for (n = 0; n < numresults; ++n) {
             if (result[n].number >= 0 && result[n].level >= 0) {
+                const char * name = resourcename(result[n].rtype, result[n].number!=1);
                 bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number,
-                    LOC(f->locale, result[n].rtype->_name), result[n].level);
+                    LOC(f->locale, name), result[n].level);
                 if (wrptr(&bufp, &size, bytes) != 0)
                     WARN_STATIC_BUFFER();
             }

From dbe5980577bf92554877ed4da1860561621f6b8e Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 18:47:49 +0100
Subject: [PATCH 29/48] CR is missing saplings?

---
 src/creport.c          |  4 ++++
 tests/run-turn.sh      |  5 ++++-
 tests/write-reports.sh | 14 +++++++++-----
 3 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index b9088f020..706f622de 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -417,6 +417,7 @@ static int cr_resources(variant var, char *buffer, const void *userdata)
     char *wp = buffer;
     if (rlist != NULL) {
         const char *name = resourcename(rlist->type, rlist->number != 1);
+        assert(name);
         wp +=
             sprintf(wp, "\"%d %s", rlist->number, translate(name, LOC(f->locale,
             name)));
@@ -425,6 +426,7 @@ static int cr_resources(variant var, char *buffer, const void *userdata)
             if (rlist == NULL)
                 break;
             name = resourcename(rlist->type, rlist->number != 1);
+            assert(name);
             wp +=
                 sprintf(wp, ", %d %s", rlist->number, translate(name,
                 LOC(f->locale, name)));
@@ -1100,6 +1102,7 @@ static char *cr_output_resource(char *buf, const resource_type *rtype,
     const char * name;
     assert(rtype);
     name = resourcename(rtype, 1);
+    assert(name);
     buf += sprintf(buf, "RESOURCE %u\n", hashstring(rtype->_name));
     buf += sprintf(buf, "\"%s\";type\n", translate(name, LOC(loc, rtype->_name)));
     if (amount >= 0) {
@@ -1183,6 +1186,7 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s
     for (n = 0; n < size; ++n) {
         if (result[n].level >= 0 && result[n].number >= 0) {
             const char * name = resourcename(result[n].rtype, result[n].number != 1);
+            assert(name);
             stream_printf(out, "%d;%s\n", result[n].number, crtag(name));
         }
     }
diff --git a/tests/run-turn.sh b/tests/run-turn.sh
index 519ed8bd8..9297278c3 100755
--- a/tests/run-turn.sh
+++ b/tests/run-turn.sh
@@ -53,10 +53,13 @@ assert_grep_count reports/$CRFILE '^BURG' 1
 assert_grep_count reports/$CRFILE '^EINHEIT' 2
 assert_grep_count reports/$CRFILE '^GEGENSTAENDE' 2
 
+assert_grep_count reports/185-heg.cr ';Baeume' 4
+assert_grep_count reports/185-heg.cr '"B.ume";type' 4
+assert_grep_count reports/185-heg.cr '"Pferde";type' 6
 assert_grep_count reports/185-heg.nr 'erblickt' 6
 assert_grep_count reports/185-heg.cr '"lighthouse";visibility' 6
 assert_grep_count reports/185-heg.cr '"neighbour";visibility' 11
 assert_grep_count reports/185-6rLo.cr '^EINHEIT' 2
 assert_grep_count reports/185-6rLo.cr '^REGION' 13
 echo "integration tests: PASS"
-cleanup
+#cleanup
diff --git a/tests/write-reports.sh b/tests/write-reports.sh
index 6581066f0..5621e84a9 100755
--- a/tests/write-reports.sh
+++ b/tests/write-reports.sh
@@ -34,14 +34,18 @@ $VALGRIND $SERVER -t 184 ../scripts/reports.lua
 [ -d reports ] || quit 4 "no reports directory created"
 CRFILE=184-zvto.cr
 grep -q PARTEI reports/$CRFILE || quit 1 "CR did not contain any factions"
-grep -q -E '"B.ume";type"' reports/$CRFILE || \
-	quit 1 "CR did not contain trees"
-grep -q '"Bauern";type"' reports/$CRFILE || \
-	quit 1 "CR did not contain peasants"
+grep -q -E '"B.ume";type' reports/$CRFILE || \
+	quit 1 "regions did not contain trees"
+grep -q -E '"Silber";type' reports/$CRFILE || \
+	quit 1 "regions did not contain silver"
+grep -q '"Bauern";type' reports/$CRFILE || \
+	quit 1 "regions did not contain peasants"
+grep -q '"Sch..linge";type' reports/$CRFILE || \
+	quit 1 "regions did not contain saplings"
 grep -q REGION reports/$CRFILE || quit 2 "CR did not contain any regions"
 grep -q SCHIFF reports/$CRFILE || quit 3 "CR did not contain any ships"
 grep -q BURG reports/$CRFILE || quit 4 "CR did not contain any buildings"
 grep -q EINHEIT reports/$CRFILE || quit 5 "CR did not contain any units"
 grep -q GEGENSTAENDE reports/$CRFILE || quit 6 "CR did not contain any items"
 echo "integration tests: PASS"
-#cleanup
+cleanup

From cdb65dfd36dce5365a2ad45a02f3f0fec82b0d6b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 18:57:28 +0100
Subject: [PATCH 30/48] Turns out: We did not have a singular form of sapling.

---
 res/core/de/strings.xml | 10 ++++++++++
 src/creport.c           |  4 ++--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml
index 5dc649aa1..d69c0919f 100644
--- a/res/core/de/strings.xml
+++ b/res/core/de/strings.xml
@@ -6604,11 +6604,21 @@
   </string>
 
   <string name="sapling">
+    <text locale="de">Schößling</text>
+    <text locale="en">sapling</text>
+  </string>
+
+  <string name="sapling_p">
     <text locale="de">Schößlinge</text>
     <text locale="en">saplings</text>
   </string>
 
   <string name="mallornsapling">
+    <text locale="de">Mallornschößling</text>
+    <text locale="en">mallorn sapling</text>
+  </string>
+
+  <string name="mallornsapling_p">
     <text locale="de">Mallornschößlinge</text>
     <text locale="en">mallorn saplings</text>
   </string>
diff --git a/src/creport.c b/src/creport.c
index b9088f020..bb2d68d1d 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -1178,7 +1178,7 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s
         stream_printf(out, "%d;Schoesslinge\n", saplings);
     }
     if (fval(r, RF_MALLORN) && (trees > 0 || saplings > 0)) {
-        sputs("1;Mallorn\n", out);
+        sputs("1;Mallorn", out);
     }
     for (n = 0; n < size; ++n) {
         if (result[n].level >= 0 && result[n].number >= 0) {
@@ -1196,7 +1196,7 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s
         }
     }
     if (pos != cbuf) {
-        sputs(cbuf, out);
+        swrite(cbuf, 1, pos - cbuf, out);
     }
 }
 

From e233ed434447d1a076756c3bdee68eb093fffe60 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 19:23:47 +0100
Subject: [PATCH 31/48] eliminate source of randomness from test

---
 src/report.test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/report.test.c b/src/report.test.c
index 0bfea3c69..3c6a09ae1 100644
--- a/src/report.test.c
+++ b/src/report.test.c
@@ -96,7 +96,7 @@ static void test_report_region(CuTest *tc) {
     mstream_init(&out);
     r = test_create_region(0, 0, 0);
     add_resource(r, 1, 100, 10, rt_stone);
-    CuAssertIntEquals(tc, 135, r->resources->amount);
+    r->resources->amount = 135;
     CuAssertIntEquals(tc, 1, r->resources->level);
     r->land->peasants = 5;
     r->land->horses = 7;

From 33b98b59ec3b3c9d515a09809d8e1c4f44209c49 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sun, 5 Mar 2017 22:28:08 +0100
Subject: [PATCH 32/48] when make_frac cannot find a gcd, cheat.

---
 src/util/variant.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/util/variant.c b/src/util/variant.c
index c1d42808d..af5d690f4 100644
--- a/src/util/variant.c
+++ b/src/util/variant.c
@@ -2,6 +2,7 @@
 #include "variant.h"
 
 #include <assert.h>
+#include <stdlib.h>
 #include <limits.h>
 
 const variant frac_zero = { .sa = { 0, 1 } };
@@ -41,8 +42,13 @@ variant frac_make(int num, int den)
     int g = gcd(num, den);
     num /= g;
     den /= g;
-    assert(num >= SHRT_MIN && num <= SHRT_MAX);
-    assert(den >= SHRT_MIN && den <= SHRT_MAX);
+    if (num < SHRT_MIN || num > SHRT_MAX || den < SHRT_MIN || den > SHRT_MAX) {
+        int a = abs(num/SHRT_MIN) + 1;
+        int b = abs(den/SHRT_MIN) + 1;
+        if (b>a) a = b;
+        num /= a;
+        den /= a;
+    }
     v.sa[0] = (short)num;
     v.sa[1] = (short)den;
     return v;

From 1c72b0f29739eeb61902f3ccb1eff965a5d6c1c0 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 6 Mar 2017 07:42:12 +0100
Subject: [PATCH 33/48] warn about missing game.mailcmd setting

---
 src/kernel/config.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/kernel/config.c b/src/kernel/config.c
index b605fddd4..a18fc6494 100644
--- a/src/kernel/config.c
+++ b/src/kernel/config.c
@@ -845,6 +845,7 @@ const char * game_mailcmd(void)
             *r++ = (char)toupper(*c);
         }
         *r = '\0';
+        log_warning("game.mailcmd configuration is not set, using %s from game.name", result);
         return result;
     }
     return param;

From 4b246863c0588fdec7560268ed8a0c6b7668a342 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 6 Mar 2017 20:37:17 +0100
Subject: [PATCH 34/48] bug 2303: correct the test. we cannot reuse the
 memstream. need to recreate it for each test. need to rewrite the code in
 creport.c, it is crazy.

---
 src/creport.c      | 10 +++++-----
 src/creport.test.c | 17 +++++++++++------
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index 99a9ede97..e023e28a5 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -796,14 +796,14 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
         else {
             /* other unit. show visible faction, not u->faction */
             stream_printf(out, "%d;Partei\n", sf ? sf->no : f->no);
-            if (sf == f) {
-                stream_printf(out, "1;Verraeter\n");
-            }
-            if (sf && sf != u->faction) {
-                if (alliedunit(u, f, HELP_FSTEALTH)) {
+            if (alliedunit(u, f, HELP_FSTEALTH)) {
+                if (sf && sf != u->faction) {
                     stream_printf(out, "%d;Anderepartei\n", sf->no);
                 }
             }
+            else if (sf == f) {
+                stream_printf(out, "1;Verraeter\n");
+            }
         }
     }
     prefix = raceprefix(u);
diff --git a/src/creport.test.c b/src/creport.test.c
index 14f40268c..441c4dc87 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -71,39 +71,44 @@ static void test_cr_factionstealth(CuTest *tc) {
     ally *al;
 
     test_setup();
-    mstream_init(&strm);
     f1 = test_create_faction(0);
     f2 = test_create_faction(0);
     r = test_create_region(0, 0, 0);
     u = test_create_unit(f1, r);
 
+    mstream_init(&strm);
     cr_output_unit(&strm, u->region, f1, u, seen_unit);
     CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    mstream_done(&strm);
 
     set_factionstealth(u, f2);
     CuAssertPtrNotNull(tc, u->attribs);
 
+    mstream_init(&strm);
     cr_output_unit(&strm, u->region, f1, u, seen_unit);
     CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
     CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    mstream_done(&strm);
 
+    mstream_init(&strm);
     cr_output_unit(&strm, u->region, f2, u, seen_unit);
-    CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
-    CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1));
+    mstream_done(&strm);
 
     al = ally_add(&f1->allies, f2);
     al->status = HELP_FSTEALTH;
-
+    mstream_init(&strm);
     cr_output_unit(&strm, u->region, f2, u, seen_unit);
     CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
     CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
-    CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1));
-
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
     mstream_done(&strm);
+
     test_cleanup();
 }
 

From 05bb109a093ddb823c44a20f11e95abfa27927cd Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 6 Mar 2017 21:35:48 +0100
Subject: [PATCH 35/48] BUG 2303: allied units are not traitors. had to rewrite
 the creport code for this, it is probably less efficient now than ever, but
 at least it works.

---
 src/attributes/otherfaction.c | 19 +++++++------
 src/attributes/otherfaction.h |  2 +-
 src/battle.c                  |  3 +-
 src/creport.c                 | 52 +++++++++++++++--------------------
 src/kernel/faction.c          |  4 +--
 src/kernel/unit.c             |  8 ++++--
 src/report.c                  |  7 ++---
 src/reports.c                 | 25 +++++++++--------
 8 files changed, 56 insertions(+), 64 deletions(-)

diff --git a/src/attributes/otherfaction.c b/src/attributes/otherfaction.c
index 83c56e767..c9e56fe27 100644
--- a/src/attributes/otherfaction.c
+++ b/src/attributes/otherfaction.c
@@ -57,10 +57,16 @@ attrib_type at_otherfaction = {
     "otherfaction", NULL, NULL, NULL, write_of, read_of, NULL, ATF_UNIQUE
 };
 
-struct faction *get_otherfaction(const struct attrib *a)
+faction *get_otherfaction(const unit * u)
 {
-    faction * f = (faction *)(a->data.v);
-    return (f && f->_alive) ? f : NULL;
+    attrib *a = a_find(u->attribs, &at_otherfaction);
+    if (a) {
+        faction * f = (faction *)(a->data.v);
+        if (f && f->_alive) {
+            return f;
+        }
+    }
+    return NULL;
 }
 
 struct attrib *make_otherfaction(struct faction *f)
@@ -73,11 +79,8 @@ struct attrib *make_otherfaction(struct faction *f)
 faction *visible_faction(const faction * f, const unit * u)
 {
     if (f == NULL || !alliedunit(u, f, HELP_FSTEALTH)) {
-        attrib *a = a_find(u->attribs, &at_otherfaction);
-        if (a) {
-            faction *fv = get_otherfaction(a);
-            if (fv) return fv;
-        }
+        faction *fv = get_otherfaction(u);
+        if (fv) return fv;
     }
     return u->faction;
 }
diff --git a/src/attributes/otherfaction.h b/src/attributes/otherfaction.h
index 726d86b0e..8a6471658 100644
--- a/src/attributes/otherfaction.h
+++ b/src/attributes/otherfaction.h
@@ -25,7 +25,7 @@ extern "C" {
     struct attrib;
     extern struct attrib_type at_otherfaction;
 
-    extern struct faction *get_otherfaction(const struct attrib *a);
+    extern struct faction *get_otherfaction(const struct unit *u);
     extern struct attrib *make_otherfaction(struct faction *f);
     extern struct faction *visible_faction(const struct faction *f,
         const struct unit *u);
diff --git a/src/battle.c b/src/battle.c
index 9864adc41..018133516 100644
--- a/src/battle.c
+++ b/src/battle.c
@@ -3126,8 +3126,7 @@ fighter *make_fighter(battle * b, unit * u, side * s1, bool attack)
     int speeded = 0, speed = 1;
     int rest;
     const group *g = NULL;
-    const attrib *a = a_find(u->attribs, &at_otherfaction);
-    const faction *stealthfaction = a ? get_otherfaction(a) : NULL;
+    const faction *stealthfaction = get_otherfaction(u);
     unsigned int flags = 0;
 
     assert(u->number);
diff --git a/src/creport.c b/src/creport.c
index e023e28a5..df616a105 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -748,8 +748,9 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
     const char *pzTmp;
     skill *sv;
     item result[MAX_INVENTORY];
-    const faction *sf;
+    const faction *fother, *fseen;
     const char *prefix;
+    bool allied;
 
     assert(u && u->number);
     assert(u->region == r); /* TODO: if this holds true, then why did we pass in r? */
@@ -762,10 +763,8 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
     if (str) {
         stream_printf(out, "\"%s\";Beschr\n", str);
     }
-    /* print faction information */
-    sf = visible_faction(NULL, u);
-    if (u->faction == f || omniscient(f)) {
-        /* my own faction, full info */
+
+    if (u->faction == f) {
         const attrib *a = NULL;
         unit *mage;
 
@@ -775,36 +774,29 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
             const group *g = (const group *)a->data.v;
             stream_printf(out, "%d;gruppe\n", g->gid);
         }
-        stream_printf(out, "%d;Partei\n", u->faction->no);
-        if (sf && sf != u->faction) {
-            stream_printf(out, "%d;Verkleidung\n", sf->no);
-            stream_printf(out, "%d;Anderepartei\n", sf->no);
-        }
-        if (fval(u, UFL_ANON_FACTION)) {
-            stream_printf(out, "%d;Parteitarnung\n", (u->flags & UFL_ANON_FACTION) != 0);
-        }
         mage = get_familiar_mage(u);
         if (mage) {
             stream_printf(out, "%u;familiarmage\n", mage->no);
         }
     }
-    else {
-        if (fval(u, UFL_ANON_FACTION)) {
-            /* faction info is hidden */
-            stream_printf(out, "%d;Parteitarnung\n", (u->flags & UFL_ANON_FACTION) != 0);
-        }
-        else {
-            /* other unit. show visible faction, not u->faction */
-            stream_printf(out, "%d;Partei\n", sf ? sf->no : f->no);
-            if (alliedunit(u, f, HELP_FSTEALTH)) {
-                if (sf && sf != u->faction) {
-                    stream_printf(out, "%d;Anderepartei\n", sf->no);
-                }
-            }
-            else if (sf == f) {
-                stream_printf(out, "1;Verraeter\n");
-            }
-        }
+
+    fseen = u->faction;
+    fother = get_otherfaction(u);
+    allied = u->faction == f || alliedunit(u, f, HELP_FSTEALTH);
+    if (fother && f != u->faction && !allied) {
+        /* getarnt, keine eigene, und kein HELFE fuer uns: wir sehen den fake */
+        fseen = fother;
+    }
+    stream_printf(out, "%d;Partei\n", fseen->no);
+    if (fother && fother!=fseen) {
+        stream_printf(out, "%d;Anderepartei\n", fother->no);
+    }
+    if (fseen==f && fval(u, UFL_ANON_FACTION)) {
+        sputs("1;Parteitarnung", out);
+    }
+    if (!allied && fother == f) {
+        /* sieht aus wie unsere, ist es aber nicht. */
+        stream_printf(out, "1;Verraeter\n");
     }
     prefix = raceprefix(u);
     if (prefix) {
diff --git a/src/kernel/faction.c b/src/kernel/faction.c
index 57cd5d3af..139474048 100755
--- a/src/kernel/faction.c
+++ b/src/kernel/faction.c
@@ -449,12 +449,10 @@ void destroyfaction(faction ** fp)
     /* units of other factions that were disguised as this faction
      * have their disguise replaced by ordinary faction hiding. */
     if (rule_stealth_other()) {
-        /* TODO: f.alive should be tested for in get_otherfaction */
         region *rc;
         for (rc = regions; rc; rc = rc->next) {
             for (u = rc->units; u; u = u->next) {
-                attrib *a = a_find(u->attribs, &at_otherfaction);
-                if (a && get_otherfaction(a) == f) {
+                if (u->attribs && get_otherfaction(u) == f) {
                     a_removeall(&u->attribs, &at_otherfaction);
                     if (rule_stealth_anon()) {
                         fset(u, UFL_ANON_FACTION);
diff --git a/src/kernel/unit.c b/src/kernel/unit.c
index 4592d0bc7..595accba2 100644
--- a/src/kernel/unit.c
+++ b/src/kernel/unit.c
@@ -1565,9 +1565,11 @@ unit *create_unit(region * r, faction * f, int number, const struct race *urace,
                 set_group(u, g);
             }
         }
-        a = a_find(creator->attribs, &at_otherfaction);
-        if (a) {
-            a_add(&u->attribs, make_otherfaction(get_otherfaction(a)));
+        if (creator->attribs) {
+            faction *otherf = get_otherfaction(creator);
+            if (otherf) {
+                a_add(&u->attribs, make_otherfaction(otherf));
+            }
         }
 
         a = a_add(&u->attribs, a_new(&at_creator));
diff --git a/src/report.c b/src/report.c
index cf00abbc3..81d5ad016 100644
--- a/src/report.c
+++ b/src/report.c
@@ -680,7 +680,6 @@ static void rps_nowrap(struct stream *out, const char *s)
 static void
 nr_unit(struct stream *out, const faction * f, const unit * u, int indent, seen_mode mode)
 {
-    attrib *a_otherfaction;
     char marker;
     int dh;
     bool isbattle = (bool)(mode == seen_battle);
@@ -692,16 +691,14 @@ nr_unit(struct stream *out, const faction * f, const unit * u, int indent, seen_
     newline(out);
     dh = bufunit(f, u, indent, mode, buf, sizeof(buf));
 
-    a_otherfaction = a_find(u->attribs, &at_otherfaction);
-
     if (u->faction == f) {
         marker = '*';
     }
     else if (is_allied(u->faction, f)) {
         marker = 'o';
     }
-    else if (a_otherfaction && f != u->faction
-        && get_otherfaction(a_otherfaction) == f && !fval(u, UFL_ANON_FACTION)) {
+    else if (u->attribs && f != u->faction
+        && !fval(u, UFL_ANON_FACTION) && get_otherfaction(u) == f) {
         marker = '!';
     }
     else {
diff --git a/src/reports.c b/src/reports.c
index a07b60f4b..8f59f47a2 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -497,7 +497,6 @@ size_t size)
     bufp = STRLCPY(bufp, unitname(u), size);
     fv = visible_faction(f, u);
     if (!isbattle) {
-        attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction);
         if (u->faction == f) {
             if (fval(u, UFL_GROUP)) {
                 attrib *a = a_find(u->attribs, &at_group);
@@ -511,11 +510,11 @@ size_t size)
                 bufp = STRLCPY(bufp, ", ", size);
                 bufp = STRLCPY(bufp, LOC(f->locale, "anonymous"), size);
             }
-            else if (a_otherfaction) {
-                faction *otherfaction = get_otherfaction(a_otherfaction);
-                if (otherfaction) {
+            else if (u->attribs) {
+                faction *otherf = get_otherfaction(u);
+                if (otherf) {
                     bufp = STRLCPY(bufp, ", ", size);
-                    bufp = STRLCPY(bufp, factionname(otherfaction), size);
+                    bufp = STRLCPY(bufp, factionname(otherf), size);
                 }
             }
         }
@@ -525,13 +524,15 @@ size_t size)
                 bufp = STRLCPY(bufp, LOC(f->locale, "anonymous"), size);
             }
             else {
-                if (a_otherfaction && alliedunit(u, f, HELP_FSTEALTH)) {
-                    faction *f = get_otherfaction(a_otherfaction);
-                    int result =
-                        snprintf(bufp, size, ", %s (%s)", factionname(f),
-                        factionname(u->faction));
-                    if (wrptr(&bufp, &size, result) != 0)
-                        WARN_STATIC_BUFFER();
+                if (u->attribs && alliedunit(u, f, HELP_FSTEALTH)) {
+                    faction *otherf = get_otherfaction(u);
+                    if (otherf) {
+                        int result =
+                            snprintf(bufp, size, ", %s (%s)", factionname(otherf),
+                                factionname(u->faction));
+                        if (wrptr(&bufp, &size, result) != 0)
+                            WARN_STATIC_BUFFER();
+                    }
                 }
                 else {
                     bufp = STRLCPY(bufp, ", ", size);

From e3a969ce9b6d078fe0731f2982e04faac005190d Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 6 Mar 2017 21:43:31 +0100
Subject: [PATCH 36/48] add a test to see that frac_make can handle large
 integers.

---
 src/util/variant.test.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/util/variant.test.c b/src/util/variant.test.c
index 12299720b..37aa3f77e 100644
--- a/src/util/variant.test.c
+++ b/src/util/variant.test.c
@@ -30,6 +30,16 @@ static void test_fractions(CuTest *tc) {
     CuAssertIntEquals(tc, -1, frac_sign(frac_make(-1, 1)));
     CuAssertIntEquals(tc, -1, frac_sign(frac_make(1, -1)));
     CuAssertIntEquals(tc, 0, frac_sign(frac_make(0, 1)));
+
+    /* we reduce large integers by calculating the gcd */
+    a = frac_make(480000, 3000);
+    CuAssertIntEquals(tc, 160, a.sa[0]);
+    CuAssertIntEquals(tc, 1, a.sa[1]);
+
+    /* if num is too big for a short, and the gcd is 1, we cheat: */
+    a = frac_make(480001, 3000);
+    CuAssertIntEquals(tc, 32000, a.sa[0]);
+    CuAssertIntEquals(tc, 200, a.sa[1]);
 }
 
 CuSuite *get_variant_suite(void)

From ce9e2ce314211a84349e8eed78ade5e88d88b29a Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Mon, 6 Mar 2017 22:24:15 +0100
Subject: [PATCH 37/48] fix invalid arguments for give/receive messages.

---
 src/give.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/give.c b/src/give.c
index eeb641665..b52168647 100644
--- a/src/give.c
+++ b/src/give.c
@@ -131,12 +131,12 @@ static void add_give_person(unit * u, unit * u2, int given,
     else if (u2->faction != u->faction) {
         message *msg;
 
-        msg = msg_message("give_person", "unit target resource amount",
+        msg = msg_message("give_person", "unit target amount",
             u, u2, given);
         add_message(&u->faction->msgs, msg);
         msg_release(msg);
 
-        msg = msg_message("receive_person", "unit target resource amount",
+        msg = msg_message("receive_person", "unit target amount",
             u, u2, given);
         add_message(&u2->faction->msgs, msg);
         msg_release(msg);

From 29a8342b4e961f1ca40af1c5dfddb263f2ca466d Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Tue, 7 Mar 2017 19:30:52 +0100
Subject: [PATCH 38/48] BUG 2305: show the correct Parteitarnung in the CR. We
 didn't have the required tests, so of course I broke it.

---
 src/creport.c      | 31 +++++++++++++------------
 src/creport.test.c | 57 ++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 72 insertions(+), 16 deletions(-)

diff --git a/src/creport.c b/src/creport.c
index f5d0f27fd..f22096f19 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -751,7 +751,7 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
     const char *pzTmp;
     skill *sv;
     item result[MAX_INVENTORY];
-    const faction *fother, *fseen;
+    const faction *fother;
     const char *prefix;
     bool allied;
 
@@ -783,24 +783,27 @@ void cr_output_unit(stream *out, const region * r, const faction * f,
         }
     }
 
-    fseen = u->faction;
     fother = get_otherfaction(u);
     allied = u->faction == f || alliedunit(u, f, HELP_FSTEALTH);
-    if (fother && f != u->faction && !allied) {
-        /* getarnt, keine eigene, und kein HELFE fuer uns: wir sehen den fake */
-        fseen = fother;
+    if (allied) {
+        /* allies can tell that the unit is anonymous */
+        /* the true faction is visible to allies */
+        stream_printf(out, "%d;Partei\n", u->faction->no);
+        if (fother) {
+            stream_printf(out, "%d;Anderepartei\n", fother->no);
+        }
+    } else if (!fval(u, UFL_ANON_FACTION)) {
+        /* OBS: anonymity overrides everything */
+        /* we have no alliance, so we get duped */
+        stream_printf(out, "%d;Partei\n", (fother ? fother : u->faction)->no);
+        if (fother==f) {
+            /* sieht aus wie unsere, ist es aber nicht. */
+            stream_printf(out, "1;Verraeter\n");
+        }
     }
-    stream_printf(out, "%d;Partei\n", fseen->no);
-    if (fother && fother!=fseen) {
-        stream_printf(out, "%d;Anderepartei\n", fother->no);
-    }
-    if (fseen==f && fval(u, UFL_ANON_FACTION)) {
+    if (fval(u, UFL_ANON_FACTION)) {
         sputs("1;Parteitarnung", out);
     }
-    if (!allied && fother == f) {
-        /* sieht aus wie unsere, ist es aber nicht. */
-        stream_printf(out, "1;Verraeter\n");
-    }
     prefix = raceprefix(u);
     if (prefix) {
         prefix = mkname("prefix", prefix);
diff --git a/src/creport.test.c b/src/creport.test.c
index a56d1d589..62ad7fb10 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -130,10 +130,12 @@ static void test_cr_resources(CuTest *tc) {
 static int cr_get_int(stream *strm, const char *match, int def)
 {
     char line[1024];
+    size_t len = strlen(match);
 
     strm->api->rewind(strm->handle);
     while (strm->api->readln(strm->handle, line, sizeof(line))==0) {
-        if (strstr(line, match)) {
+        const char * pos = strstr(line, match);
+        if (pos && pos[len]=='\0') {
             return atoi(line);
         }
     }
@@ -153,30 +155,69 @@ static void test_cr_factionstealth(CuTest *tc) {
     r = test_create_region(0, 0, 0);
     u = test_create_unit(f1, r);
 
+    /* report to ourselves */
     mstream_init(&strm);
     cr_output_unit(&strm, u->region, f1, u, seen_unit);
     CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Parteitarnung", -1));
     mstream_done(&strm);
 
+    /* ... also when we are anonymous */
+    u->flags |= UFL_ANON_FACTION;
+    mstream_init(&strm);
+    cr_output_unit(&strm, u->region, f1, u, seen_unit);
+    CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Parteitarnung", -1));
+    u->flags &= ~UFL_ANON_FACTION;
+    mstream_done(&strm);
+
+    /* we see that our unit is cloaked */
     set_factionstealth(u, f2);
     CuAssertPtrNotNull(tc, u->attribs);
-
     mstream_init(&strm);
     cr_output_unit(&strm, u->region, f1, u, seen_unit);
     CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
     CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Parteitarnung", -1));
     mstream_done(&strm);
 
+    /* ... also when we are anonymous */
+    u->flags |= UFL_ANON_FACTION;
+    mstream_init(&strm);
+    cr_output_unit(&strm, u->region, f1, u, seen_unit);
+    CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Parteitarnung", -1));
+    u->flags &= ~UFL_ANON_FACTION;
+    mstream_done(&strm);
+
+    /* we can tell that someone is presenting as us */
     mstream_init(&strm);
     cr_output_unit(&strm, u->region, f2, u, seen_unit);
     CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Partei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Verraeter", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Parteitarnung", -1));
     mstream_done(&strm);
 
+    /* ... but not if they are anonymous */
+    u->flags |= UFL_ANON_FACTION;
+    mstream_init(&strm);
+    cr_output_unit(&strm, u->region, f2, u, seen_unit);
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Parteitarnung", -1));
+    u->flags &= ~UFL_ANON_FACTION;
+    mstream_done(&strm);
+
+    /* we see the same thing as them when we are an ally */
     al = ally_add(&f1->allies, f2);
     al->status = HELP_FSTEALTH;
     mstream_init(&strm);
@@ -184,6 +225,18 @@ static void test_cr_factionstealth(CuTest *tc) {
     CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
     CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Parteitarnung", -1));
+    mstream_done(&strm);
+
+    /* ... also when they are anonymous */
+    u->flags |= UFL_ANON_FACTION;
+    mstream_init(&strm);
+    cr_output_unit(&strm, u->region, f1, u, seen_unit);
+    CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
+    CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
+    CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));
+    CuAssertIntEquals(tc, 1, cr_get_int(&strm, ";Parteitarnung", -1));
+    u->flags &= ~UFL_ANON_FACTION;
     mstream_done(&strm);
 
     test_cleanup();

From 517da2dff10bd73e275b5e85c895339a51cacae7 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 8 Mar 2017 18:15:31 +0100
Subject: [PATCH 39/48] breaking test for bug 2309

---
 src/reports.test.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/src/reports.test.c b/src/reports.test.c
index c026041a9..9dab0c0a7 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -7,6 +7,7 @@
 #include "travelthru.h"
 #include "keyword.h"
 
+#include <kernel/ally.h>
 #include <kernel/config.h>
 #include <kernel/building.h>
 #include <kernel/faction.h>
@@ -20,10 +21,13 @@
 #include <kernel/spellbook.h>
 #include <kernel/terrain.h>
 
+#include <util/attrib.h>
 #include <util/language.h>
 #include <util/lists.h>
 #include <util/message.h>
 
+#include <attributes/key.h>
+
 #include <selist.h>
 #include <stream.h>
 #include <memstream.h>
@@ -153,6 +157,42 @@ static void test_sparagraph(CuTest *tc) {
     freestrlist(sp);
 }
 
+static void test_bufunit_bug_2305(CuTest *tc) {
+    unit *u;
+    faction *f1, *f2;
+    region *r;
+    ally *al;
+    char buf[1024];
+
+    test_setup();
+    r = test_create_region(0, 0, 0);
+    f1 = test_create_faction(0);
+    f2 = test_create_faction(0);
+    u = test_create_unit(f1, r);
+    faction_setname(u->faction, "UFO");
+    renumber_faction(u->faction, 1);
+    unit_setname(u, "Hodor");
+    unit_setid(u, 1);
+    key_set(&u->attribs, 42, 42);
+
+    /* report to self */
+    bufunit(f1, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressive.", buf);
+
+    /* report to another faction */
+    bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buf);
+
+    al = ally_add(&f1->allies, f2);
+    al->status = HELP_FSTEALTH;
+
+    /* report to an allied faction (bug 2305) */
+    bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buf);
+
+    test_cleanup();
+}
+
 static void test_write_unit(CuTest *tc) {
     unit *u;
     faction *f;
@@ -160,7 +200,7 @@ static void test_write_unit(CuTest *tc) {
     struct locale *lang;
     char buffer[1024];
 
-    test_cleanup();
+    test_setup();
     rc = rc_get_or_create("human");
     rc->bonus[SK_ALCHEMY] = 1;
     lang = get_or_create_locale("de");
@@ -581,6 +621,7 @@ CuSuite *get_reports_suite(void)
     SUITE_ADD_TEST(suite, test_regionid);
     SUITE_ADD_TEST(suite, test_sparagraph);
     SUITE_ADD_TEST(suite, test_write_unit);
+    SUITE_ADD_TEST(suite, test_bufunit_bug_2305);
     SUITE_ADD_TEST(suite, test_arg_resources);
     return suite;
 }

From 4bda1a34e026bde2a08a77cc098c86c1fbc353d7 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 8 Mar 2017 18:29:04 +0100
Subject: [PATCH 40/48] made a mistake in this test. creport was reporting to
 wrong faction (that sees the same output, so it didn't fail).

---
 src/creport.test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/creport.test.c b/src/creport.test.c
index 62ad7fb10..acd6201f9 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -231,7 +231,7 @@ static void test_cr_factionstealth(CuTest *tc) {
     /* ... also when they are anonymous */
     u->flags |= UFL_ANON_FACTION;
     mstream_init(&strm);
-    cr_output_unit(&strm, u->region, f1, u, seen_unit);
+    cr_output_unit(&strm, u->region, f2, u, seen_unit);
     CuAssertIntEquals(tc, f1->no, cr_get_int(&strm, ";Partei", -1));
     CuAssertIntEquals(tc, f2->no, cr_get_int(&strm, ";Anderepartei", -1));
     CuAssertIntEquals(tc, -1, cr_get_int(&strm, ";Verraeter", -1));

From 77abd703bdb6b586b3dde608f6a78b1d462dce18 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 8 Mar 2017 20:15:41 +0100
Subject: [PATCH 41/48] backfill test that demonstrates bug 2305.

---
 src/attributes/otherfaction.h |  6 +--
 src/reports.test.c            | 83 ++++++++++++++++++++++++++++-------
 tests/runtests.bat            |  1 +
 vs2017-build.bat              | 13 ++++++
 4 files changed, 83 insertions(+), 20 deletions(-)
 create mode 100644 vs2017-build.bat

diff --git a/src/attributes/otherfaction.h b/src/attributes/otherfaction.h
index 8a6471658..a274bcd49 100644
--- a/src/attributes/otherfaction.h
+++ b/src/attributes/otherfaction.h
@@ -25,9 +25,9 @@ extern "C" {
     struct attrib;
     extern struct attrib_type at_otherfaction;
 
-    extern struct faction *get_otherfaction(const struct unit *u);
-    extern struct attrib *make_otherfaction(struct faction *f);
-    extern struct faction *visible_faction(const struct faction *f,
+    struct faction *get_otherfaction(const struct unit *u);
+    struct attrib *make_otherfaction(struct faction *f);
+    struct faction *visible_faction(const struct faction *f,
         const struct unit *u);
 
 #ifdef __cplusplus
diff --git a/src/reports.test.c b/src/reports.test.c
index 9dab0c0a7..65d50c93e 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -27,6 +27,7 @@
 #include <util/message.h>
 
 #include <attributes/key.h>
+#include <attributes/otherfaction.h>
 
 #include <selist.h>
 #include <stream.h>
@@ -157,48 +158,95 @@ static void test_sparagraph(CuTest *tc) {
     freestrlist(sp);
 }
 
-static void test_bufunit_bug_2305(CuTest *tc) {
-    unit *u;
+static void test_bufunit_fstealth(CuTest *tc) {
     faction *f1, *f2;
     region *r;
+    unit *u;
     ally *al;
-    char buf[1024];
+    char buf[256];
+    struct locale *lang;
 
     test_setup();
-    r = test_create_region(0, 0, 0);
+    lang = get_or_create_locale("de");
+    locale_setstring(lang, "status_aggressive", "aggressive");
+    locale_setstring(lang, "anonymous", "anonymous");
     f1 = test_create_faction(0);
+    f1->locale = lang;
     f2 = test_create_faction(0);
+    f2->locale = lang;
+    r = test_create_region(0, 0, 0);
     u = test_create_unit(f1, r);
-    faction_setname(u->faction, "UFO");
-    renumber_faction(u->faction, 1);
+    faction_setname(f1, "UFO");
+    renumber_faction(f1, 1);
+    faction_setname(f2, "TWW");
+    renumber_faction(f2, 2);
     unit_setname(u, "Hodor");
     unit_setid(u, 1);
     key_set(&u->attribs, 42, 42);
 
-    /* report to self */
+    /* report to ourselves */
     bufunit(f1, u, 0, seen_unit, buf, sizeof(buf));
     CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressive.", buf);
 
-    /* report to another faction */
-    bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
-    CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buf);
+    /* ... also when we are anonymous */
+    u->flags |= UFL_ANON_FACTION;
+    bufunit(f1, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human, aggressive.", buf);
+    u->flags &= ~UFL_ANON_FACTION;
 
+    /* we see that our unit is cloaked */
+    set_factionstealth(u, f2);
+    CuAssertPtrNotNull(tc, u->attribs);
+    bufunit(f1, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), TWW (2), 1 human, aggressive.", buf);
+
+    /* ... also when we are anonymous */
+    u->flags |= UFL_ANON_FACTION;
+    bufunit(f1, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human, aggressive.", buf);
+    u->flags &= ~UFL_ANON_FACTION;
+
+    /* we can see that someone is presenting as us */
+    bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), TWW (2), 1 human.", buf);
+
+    /* ... but not if they are anonymous */
+    u->flags |= UFL_ANON_FACTION;
+    bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human.", buf);
+    u->flags &= ~UFL_ANON_FACTION;
+
+    /* we see the same thing as them when we are an ally */
     al = ally_add(&f1->allies, f2);
     al->status = HELP_FSTEALTH;
-
-    /* report to an allied faction (bug 2305) */
     bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
-    CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buf);
+    CuAssertStrEquals(tc, "Hodor (1), TWW (2) (UFO (1)), 1 human.", buf);
+
+    /* ... also when they are anonymous */
+    u->flags |= UFL_ANON_FACTION;
+    bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human.", buf);
+    u->flags &= ~UFL_ANON_FACTION;
+
+    /* fstealth has no influence when we are allies, same results again */
+    set_factionstealth(u, NULL);
+    bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), UFO(1), 1 human.", buf);
+
+    u->flags |= UFL_ANON_FACTION;
+    bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
+    CuAssertStrEquals(tc, "Hodor (1), anonymous, 1 human.", buf);
+    u->flags &= ~UFL_ANON_FACTION;
 
     test_cleanup();
 }
 
-static void test_write_unit(CuTest *tc) {
+static void test_bufunit(CuTest *tc) {
     unit *u;
     faction *f;
     race *rc;
     struct locale *lang;
-    char buffer[1024];
+    char buffer[256];
 
     test_setup();
     rc = rc_get_or_create("human");
@@ -231,6 +279,7 @@ static void test_write_unit(CuTest *tc) {
     f->locale = get_or_create_locale("de");
     bufunit(f, u, 0, 0, buffer, sizeof(buffer));
     CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buffer);
+
     test_cleanup();
 }
 
@@ -620,8 +669,8 @@ CuSuite *get_reports_suite(void)
     SUITE_ADD_TEST(suite, test_seen_faction);
     SUITE_ADD_TEST(suite, test_regionid);
     SUITE_ADD_TEST(suite, test_sparagraph);
-    SUITE_ADD_TEST(suite, test_write_unit);
-    SUITE_ADD_TEST(suite, test_bufunit_bug_2305);
+    SUITE_ADD_TEST(suite, test_bufunit);
+    SUITE_ADD_TEST(suite, test_bufunit_fstealth);
     SUITE_ADD_TEST(suite, test_arg_resources);
     return suite;
 }
diff --git a/tests/runtests.bat b/tests/runtests.bat
index 41b5f8056..7a58e5762 100644
--- a/tests/runtests.bat
+++ b/tests/runtests.bat
@@ -3,6 +3,7 @@ IF EXIST ..\build-vs10 SET BUILD=..\build-vs10\eressea\Debug
 IF EXIST ..\build-vs11 SET BUILD=..\build-vs11\eressea\Debug
 IF EXIST ..\build-vs12 SET BUILD=..\build-vs12\eressea\Debug
 IF EXIST ..\build-vs14 SET BUILD=..\build-vs14\eressea\Debug
+IF EXIST ..\build-vs15 SET BUILD=..\build-vs15\eressea\Debug
 SET SERVER=%BUILD%\eressea.exe
 %BUILD%\test_eressea.exe
 %SERVER% ..\scripts\run-tests.lua
diff --git a/vs2017-build.bat b/vs2017-build.bat
new file mode 100644
index 000000000..7503153fe
--- /dev/null
+++ b/vs2017-build.bat
@@ -0,0 +1,13 @@
+@ECHO OFF
+SET VSVERSION=15
+SET SRCDIR=%CD%
+CD ..
+SET ERESSEA=%CD%
+
+CD %SRCDIR%
+IF exist build-vs%VSVERSION% goto HAVEDIR
+mkdir build-vs%VSVERSION%
+:HAVEDIR
+cd build-vs%VSVERSION%
+"%ProgramFiles%\CMake\bin\cmake.exe" -G "Visual Studio %VSVERSION%" -DCMAKE_PREFIX_PATH="%ProgramFiles(x86)%/Lua/5.1;%ERESSEA%/dependencies-win32" -DCMAKE_MODULE_PATH="%SRCDIR%/cmake/Modules" -DCMAKE_SUPPRESS_REGENERATION=TRUE ..
+PAUSE

From f54165d4f14df2b95a26046527c74fc0d516312f Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Wed, 8 Mar 2017 20:30:32 +0100
Subject: [PATCH 42/48] BUG 2309: show true faction to allies.
 https://bugs.eressea.de/view.php?id=2309

---
 src/reports.c      | 4 ++++
 src/reports.test.c | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/reports.c b/src/reports.c
index aae3d3031..85ab34209 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -536,6 +536,10 @@ size_t size)
                         if (wrptr(&bufp, &size, result) != 0)
                             WARN_STATIC_BUFFER();
                     }
+                    else {
+                        bufp = STRLCPY(bufp, ", ", size);
+                        bufp = STRLCPY(bufp, factionname(fv), size);
+                    }
                 }
                 else {
                     bufp = STRLCPY(bufp, ", ", size);
diff --git a/src/reports.test.c b/src/reports.test.c
index 65d50c93e..976e9dfe1 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -231,7 +231,7 @@ static void test_bufunit_fstealth(CuTest *tc) {
     /* fstealth has no influence when we are allies, same results again */
     set_factionstealth(u, NULL);
     bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));
-    CuAssertStrEquals(tc, "Hodor (1), UFO(1), 1 human.", buf);
+    CuAssertStrEquals(tc, "Hodor (1), UFO (1), 1 human.", buf);
 
     u->flags |= UFL_ANON_FACTION;
     bufunit(f2, u, 0, seen_unit, buf, sizeof(buf));

From be0b54494ee2cf9532175655c09c6636aca2659a Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Fri, 10 Mar 2017 21:29:37 +0100
Subject: [PATCH 43/48] clean up some tests. the test locale gets some extra
 strings. test_create_world is bad, stop using it. unfinished.

---
 src/kernel/alliance.test.c |   3 +-
 src/kernel/building.test.c | 165 ++++++++++---------------------------
 src/kernel/item.c          |   1 +
 src/kernel/unit.test.c     |   8 +-
 src/laws.test.c            | 107 +++++++++++-------------
 src/magic.test.c           |  35 ++++----
 src/market.test.c          |   4 +-
 src/move.test.c            |  24 +++---
 src/piracy.test.c          |   2 +-
 src/spy.test.c             |  17 +---
 src/study.test.c           |  11 +--
 src/tests.c                |  46 +++++++++--
 src/tests.h                |   5 +-
 src/tests.test.c           |  37 ---------
 src/upkeep.test.c          |  21 +++--
 src/vortex.test.c          |   2 +-
 16 files changed, 186 insertions(+), 302 deletions(-)

diff --git a/src/kernel/alliance.test.c b/src/kernel/alliance.test.c
index c0ec03fbc..f63767672 100644
--- a/src/kernel/alliance.test.c
+++ b/src/kernel/alliance.test.c
@@ -17,7 +17,7 @@ typedef struct alliance_fixture {
 } alliance_fixture;
 
 static void setup_alliance(alliance_fixture *fix) {
-    test_create_world();
+    test_setup();
     fix->rc = test_create_race("human");
     fix->f1 = test_create_faction(fix->rc);
     fix->f2 = test_create_faction(fix->rc);
@@ -49,7 +49,6 @@ static void test_alliance_join(CuTest *tc) {
     alliance_fixture fix;
     alliance * al;
 
-    test_setup();
     setup_alliance(&fix);
     CuAssertPtrEquals(tc, 0, fix.f1->alliance);
     CuAssertPtrEquals(tc, 0, fix.f2->alliance);
diff --git a/src/kernel/building.test.c b/src/kernel/building.test.c
index 2819d4a16..3f415a913 100644
--- a/src/kernel/building.test.c
+++ b/src/kernel/building.test.c
@@ -40,18 +40,13 @@ static void test_building_set_owner(CuTest * tc)
     struct building *bld;
     struct unit *u1, *u2;
     struct faction *f;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    human = rc_find("human");
-    btype = bt_find("castle");
-    f = test_create_faction(human);
-    r = findregion(0, 0);
+    f = test_create_faction(NULL);
+    r = test_create_region(0, 0, NULL);
 
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     u1 = test_create_unit(f, r);
     u_set_building(u1, bld);
     CuAssertPtrEquals(tc, u1, building_owner(bld));
@@ -70,22 +65,13 @@ static void test_buildingowner_goes_to_next_when_empty(CuTest * tc)
     struct building *bld;
     struct unit *u, *u2;
     struct faction *f;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    human = rc_find("human");
-    CuAssertPtrNotNull(tc, human);
+    f = test_create_faction(NULL);
+    r = test_create_plain(0, 0);
 
-    btype = bt_find("castle");
-    CuAssertPtrNotNull(tc, btype);
-
-    f = test_create_faction(human);
-    r = findregion(0, 0);
-
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     CuAssertPtrNotNull(tc, bld);
 
     u = test_create_unit(f, r);
@@ -105,22 +91,13 @@ static void test_buildingowner_goes_to_other_when_empty(CuTest * tc)
     struct building *bld;
     struct unit *u, *u2;
     struct faction *f;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    human = rc_find("human");
-    CuAssertPtrNotNull(tc, human);
+    f = test_create_faction(NULL);
+    r = test_create_plain(0, 0);
 
-    btype = bt_find("castle");
-    CuAssertPtrNotNull(tc, btype);
-
-    f = test_create_faction(human);
-    r = findregion(0, 0);
-
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     CuAssertPtrNotNull(tc, bld);
 
     u2 = test_create_unit(f, r);
@@ -141,23 +118,14 @@ static void test_buildingowner_goes_to_same_faction_when_empty(CuTest * tc)
     struct building *bld;
     struct unit *u, *u2, *u3;
     struct faction *f1, *f2;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    human = rc_find("human");
-    CuAssertPtrNotNull(tc, human);
+    f1 = test_create_faction(NULL);
+    f2 = test_create_faction(NULL);
+    r = test_create_plain(0, 0);
 
-    btype = bt_find("castle");
-    CuAssertPtrNotNull(tc, btype);
-
-    f1 = test_create_faction(human);
-    f2 = test_create_faction(human);
-    r = findregion(0, 0);
-
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     CuAssertPtrNotNull(tc, bld);
 
     u2 = test_create_unit(f2, r);
@@ -181,22 +149,12 @@ static void test_buildingowner_goes_to_next_after_leave(CuTest * tc)
     struct building *bld;
     struct unit *u, *u2;
     struct faction *f;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
+    f = test_create_faction(NULL);
+    r = test_create_plain(0, 0);
 
-    human = rc_find("human");
-    CuAssertPtrNotNull(tc, human);
-
-    btype = bt_find("castle");
-    CuAssertPtrNotNull(tc, btype);
-
-    f = test_create_faction(human);
-    r = findregion(0, 0);
-
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     CuAssertPtrNotNull(tc, bld);
 
     u = test_create_unit(f, r);
@@ -216,22 +174,13 @@ static void test_buildingowner_goes_to_other_after_leave(CuTest * tc)
     struct building *bld;
     struct unit *u, *u2;
     struct faction *f;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    human = rc_find("human");
-    CuAssertPtrNotNull(tc, human);
+    f = test_create_faction(NULL);
+    r = test_create_plain(0, 0);
 
-    btype = bt_find("castle");
-    CuAssertPtrNotNull(tc, btype);
-
-    f = test_create_faction(human);
-    r = findregion(0, 0);
-
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     CuAssertPtrNotNull(tc, bld);
 
     u2 = test_create_unit(f, r);
@@ -251,23 +200,14 @@ static void test_buildingowner_goes_to_same_faction_after_leave(CuTest * tc)
     struct building *bld;
     struct unit *u, *u2, *u3;
     struct faction *f1, *f2;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    human = rc_find("human");
-    CuAssertPtrNotNull(tc, human);
+    f1 = test_create_faction(NULL);
+    f2 = test_create_faction(NULL);
+    r = test_create_plain(0, 0);
 
-    btype = bt_find("castle");
-    CuAssertPtrNotNull(tc, btype);
-
-    f1 = test_create_faction(human);
-    f2 = test_create_faction(human);
-    r = findregion(0, 0);
-
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     CuAssertPtrNotNull(tc, bld);
 
     u2 = test_create_unit(f2, r);
@@ -293,22 +233,13 @@ static void test_buildingowner_resets_when_empty(CuTest * tc)
     struct building *bld;
     struct unit *u;
     struct faction *f;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    human = rc_find("human");
-    CuAssertPtrNotNull(tc, human);
+    f = test_create_faction(NULL);
+    r = test_create_plain(0, 0);
 
-    btype = bt_find("castle");
-    CuAssertPtrNotNull(tc, btype);
-
-    f = test_create_faction(human);
-    r = findregion(0, 0);
-
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     CuAssertPtrNotNull(tc, bld);
 
     u = test_create_unit(f, r);
@@ -328,22 +259,13 @@ void test_buildingowner_goes_to_empty_unit_after_leave(CuTest * tc)
     struct building *bld;
     struct unit *u1, *u2, *u3;
     struct faction *f1;
-    const struct building_type *btype;
-    const struct race *human;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    human = rc_find("human");
-    CuAssertPtrNotNull(tc, human);
+    f1 = test_create_faction(NULL);
+    r = test_create_plain(0, 0);
 
-    btype = bt_find("castle");
-    CuAssertPtrNotNull(tc, btype);
-
-    f1 = test_create_faction(human);
-    r = findregion(0, 0);
-
-    bld = test_create_building(r, btype);
+    bld = test_create_building(r, NULL);
     CuAssertPtrNotNull(tc, bld);
 
     u1 = test_create_unit(f1, r);
@@ -394,16 +316,15 @@ static void test_buildingtype_exists(CuTest * tc)
     building *b;
     building_type *btype, *btype2;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    btype2 = bt_get_or_create("castle");
+    btype2 = test_create_buildingtype("castle");
     assert(btype2);
-    btype = test_create_buildingtype("Hodor");
+    btype = test_create_buildingtype("lighhouse");
     btype->maxsize = 10;
 
-    r = findregion(-1, 0);
-    b = new_building(btype, r, default_locale);
+    r = test_create_plain(0, 0);
+    b = test_create_building(r, btype);
     CuAssertPtrNotNull(tc, b);
     b->size = 10;
 
diff --git a/src/kernel/item.c b/src/kernel/item.c
index 48ea7a690..605511005 100644
--- a/src/kernel/item.c
+++ b/src/kernel/item.c
@@ -981,6 +981,7 @@ void init_resources(void)
     rtype->flags |= RTF_ITEM | RTF_POOLED;
     rtype->uchange = res_changeitem;
     rtype->itype = it_get_or_create(rtype);
+    rtype->itype->weight = 1;
     rtype->itype->give = give_money;
 
     rtype = rt_get_or_create(resourcenames[R_HORSE]);
diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c
index 7c7bb087b..e1654b821 100644
--- a/src/kernel/unit.test.c
+++ b/src/kernel/unit.test.c
@@ -225,12 +225,12 @@ static void test_default_name(CuTest *tc) {
     struct locale* lang;
     char buf[32], compare[32];
 
-    test_cleanup();
-    test_create_world();
-    lang = get_or_create_locale("de");
+    test_setup();
+
+    lang = test_create_locale();
     locale_setstring(lang, "unitdefault", "Zweiheit");
 
-    u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0));
+    u = test_create_unit(test_create_faction(NULL), test_create_plain(0, 0));
 
     default_name(u, buf, sizeof(buf));
 
diff --git a/src/laws.test.c b/src/laws.test.c
index c27651d83..672105e08 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -34,15 +34,12 @@ static void test_new_building_can_be_renamed(CuTest * tc)
 {
     region *r;
     building *b;
-    building_type *btype;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
+    test_create_locale();
+    r = test_create_region(0, 0, 0);
 
-    btype = bt_get_or_create("castle");
-    r = findregion(-1, 0);
-
-    b = new_building(btype, r, default_locale);
+    b = test_create_building(r, NULL);
     CuAssertTrue(tc, !renamed_building(b));
 }
 
@@ -54,12 +51,10 @@ static void test_rename_building(CuTest * tc)
     faction *f;
     building_type *btype;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    btype = bt_get_or_create("castle");
-
-    r = findregion(-1, 0);
+    btype = test_create_buildingtype("castle");
+    r = test_create_region(0, 0, 0);
     b = new_building(btype, r, default_locale);
     f = test_create_faction(NULL);
     u = test_create_unit(f, r);
@@ -78,12 +73,10 @@ static void test_rename_building_twice(CuTest * tc)
     building *b;
     building_type *btype;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    btype = bt_get_or_create("castle");
-
-    r = findregion(-1, 0);
+    btype = test_create_buildingtype("castle");
+    r = test_create_region(0, 0, 0);
     b = new_building(btype, r, default_locale);
     f = test_create_faction(NULL);
     u = test_create_unit(f, r);
@@ -104,11 +97,10 @@ static void test_contact(CuTest * tc)
     building_type *btype;
     ally *al;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    btype = bt_get_or_create("castle");
-    r = findregion(0, 0);
+    btype = test_create_buildingtype("castle");
+    r = test_create_region(0, 0, 0);
     b = new_building(btype, r, default_locale);
     u1 = test_create_unit(test_create_faction(0), r);
     u2 = test_create_unit(test_create_faction(0), r);
@@ -134,13 +126,12 @@ static void test_enter_building(CuTest * tc)
     building *b;
     race * rc;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, 0);
     rc = rc_get_or_create("human");
     u = test_create_unit(test_create_faction(rc), r);
-    b = test_create_building(r, bt_get_or_create("castle"));
+    b = test_create_building(r, test_create_buildingtype("castle"));
 
     rc->flags = RCF_WALK;
     u->building = 0;
@@ -489,7 +480,7 @@ static void setup_pay_cmd(struct pay_fixture *fix) {
     f = test_create_faction(NULL);
     r = findregion(0, 0);
     assert(r && f);
-    btcastle = bt_get_or_create("castle");
+    btcastle = test_create_buildingtype("castle");
     btcastle->taxes = level_taxes;
     b = test_create_building(r, btcastle);
     assert(b);
@@ -530,7 +521,8 @@ static void test_pay_cmd_other_building(CuTest *tc) {
     test_setup();
     setup_pay_cmd(&fix);
     f = fix.u1->faction;
-    b = test_create_building(fix.u1->region, bt_get_or_create("lighthouse"));
+    /* lighthouse is not in the test locale, so we're using castle */
+    b = test_create_building(fix.u1->region, test_create_buildingtype("lighthouse"));
     config_set("rules.region_owners", "1");
     config_set("rules.region_owner_pay_building", "lighthouse");
     update_owners(b->region);
@@ -569,14 +561,13 @@ static void test_new_units(CuTest *tc) {
     region *r;
     const struct locale *loc;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
     f = test_create_faction(NULL);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     assert(r && f);
     u = test_create_unit(f, r);
     assert(u && !u->next);
-    loc = get_locale("de");
+    loc = test_create_locale();
     assert(loc);
     u->orders = create_order(K_MAKETEMP, loc, "hurr");
     new_units();
@@ -598,11 +589,10 @@ void setup_guard(guard_fixture *fix, bool armed) {
     faction *f;
     unit * u;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
     f = test_create_faction(NULL);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     assert(r && f);
     u = test_create_unit(f, r);
     fset(u, UFL_GUARD);
@@ -707,18 +697,18 @@ static void test_reserve_self(CuTest *tc) {
     const resource_type *rtype;
     const struct locale *loc;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
+    init_resources();
 
     rtype = get_resourcetype(R_SILVER);
     assert(rtype && rtype->itype);
     f = test_create_faction(NULL);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, 0);
     assert(r && f);
     u1 = test_create_unit(f, r);
     u2 = test_create_unit(f, r);
     assert(u1 && u2);
-    loc = get_locale("de");
+    loc = test_create_locale();
     assert(loc);
     ord = create_order(K_RESERVE, loc, "200 SILBER");
     assert(ord);
@@ -741,7 +731,7 @@ static void statistic_test(CuTest *tc, int peasants, int luck, int maxp,
 }
 
 static void test_peasant_luck_effect(CuTest *tc) {
-    test_cleanup();
+    test_setup();
 
     config_set("rules.peasants.peasantluck.factor", "10");
     config_set("rules.peasants.growth.factor", "0.001");
@@ -891,7 +881,7 @@ static void test_long_order_normal(CuTest *tc) {
     unit *u;
     order *ord;
 
-    test_cleanup();
+    test_setup();
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     fset(u, UFL_MOVED);
     fset(u, UFL_LONGACTION);
@@ -909,7 +899,7 @@ static void test_long_order_normal(CuTest *tc) {
 static void test_long_order_none(CuTest *tc) {
     /* TODO: write more tests */
     unit *u;
-    test_cleanup();
+    test_setup();
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     update_long_order(u);
     CuAssertPtrEquals(tc, 0, u->thisorder);
@@ -921,7 +911,7 @@ static void test_long_order_none(CuTest *tc) {
 static void test_long_order_cast(CuTest *tc) {
     /* TODO: write more tests */
     unit *u;
-    test_cleanup();
+    test_setup();
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
     unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
@@ -935,7 +925,7 @@ static void test_long_order_cast(CuTest *tc) {
 static void test_long_order_buy_sell(CuTest *tc) {
     /* TODO: write more tests */
     unit *u;
-    test_cleanup();
+    test_setup();
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
     unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
@@ -950,7 +940,7 @@ static void test_long_order_buy_sell(CuTest *tc) {
 static void test_long_order_multi_long(CuTest *tc) {
     /* TODO: write more tests */
     unit *u;
-    test_cleanup();
+    test_setup();
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     unit_addorder(u, create_order(K_MOVE, u->faction->locale, 0));
     unit_addorder(u, create_order(K_DESTROY, u->faction->locale, 0));
@@ -964,7 +954,7 @@ static void test_long_order_multi_long(CuTest *tc) {
 static void test_long_order_multi_buy(CuTest *tc) {
     /* TODO: write more tests */
     unit *u;
-    test_cleanup();
+    test_setup();
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
     unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
@@ -978,7 +968,7 @@ static void test_long_order_multi_buy(CuTest *tc) {
 static void test_long_order_multi_sell(CuTest *tc) {
     /* TODO: write more tests */
     unit *u;
-    test_cleanup();
+    test_setup();
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     unit_addorder(u, create_order(K_SELL, u->faction->locale, 0));
     unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
@@ -993,7 +983,7 @@ static void test_long_order_multi_sell(CuTest *tc) {
 static void test_long_order_buy_cast(CuTest *tc) {
     /* TODO: write more tests */
     unit *u;
-    test_cleanup();
+    test_setup();
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     unit_addorder(u, create_order(K_BUY, u->faction->locale, 0));
     unit_addorder(u, create_order(K_CAST, u->faction->locale, 0));
@@ -1006,7 +996,7 @@ static void test_long_order_buy_cast(CuTest *tc) {
 
 static void test_long_order_hungry(CuTest *tc) {
     unit *u;
-    test_cleanup();
+    test_setup();
     config_set("hunger.long", "1");
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     fset(u, UFL_HUNGER);
@@ -1145,7 +1135,7 @@ static void test_ally_cmd(CuTest *tc) {
 
 static void test_nmr_warnings(CuTest *tc) {
     faction *f1, *f2;
-    test_cleanup();
+    test_setup();
     config_set("nmr.timeout", "3");
     f1 = test_create_faction(0);
     f2 = test_create_faction(0);
@@ -1166,7 +1156,7 @@ static void test_nmr_warnings(CuTest *tc) {
 static unit * setup_mail_cmd(void) {
     faction *f;
     
-    test_cleanup();
+    test_setup();
     f = test_create_faction(0);
     return test_create_unit(f, test_create_region(0, 0, 0));
 }
@@ -1283,7 +1273,7 @@ static void test_show_without_item(CuTest *tc)
     item *i;
     struct locale *loc;
 
-    test_cleanup();
+    test_setup();
 
     loc = get_or_create_locale("de");
     locale_setstring(loc, parameters[P_ANY], "ALLE");
@@ -1326,7 +1316,7 @@ static void test_show_elf(CuTest *tc) {
     struct locale *loc;
     message * msg;
 
-    test_cleanup();
+    test_setup();
 
     mt_register(mt_new_va("msg_event", "string:string", 0));
     rc = test_create_race("elf");
@@ -1362,7 +1352,7 @@ static void test_show_race(CuTest *tc) {
     struct locale *loc;
     message * msg;
 
-    test_cleanup();
+    test_setup();
 
     mt_register(mt_new_va("msg_event", "string:string", 0));
     test_create_race("human");
@@ -1406,9 +1396,8 @@ static void test_immigration(CuTest * tc)
     double inject[] = { 1 };
     int (*old_wage)(const region*, const faction*, const race*, int) = global.functions.wage;
 
-    test_cleanup();
-    test_create_world();
-    r = findregion(0, 0);
+    test_setup();
+    r = test_create_region(0, 0, 0);
 
     rsetpeasants(r, 0);
     config_set("rules.economy.repopulate_maximum", 0);
@@ -1442,9 +1431,9 @@ static void test_demon_hunger(CuTest * tc)
     unit *u;
     message* msg;
 
-    test_cleanup();
-    test_create_world();
-    r = findregion(0, 0);
+    test_setup();
+    init_resources();
+    r = test_create_region(0, 0, 0);
     rc = test_create_race("demon");
     f = test_create_faction(rc);
     u = test_create_unit(f, r);
diff --git a/src/magic.test.c b/src/magic.test.c
index a5a842172..a3a199e42 100644
--- a/src/magic.test.c
+++ b/src/magic.test.c
@@ -87,8 +87,8 @@ void test_pay_spell(CuTest * tc)
     int level;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    init_resources();
+    r = test_create_region(0, 0, NULL);
     f = test_create_faction(0);
     u = test_create_unit(f, r);
     CuAssertPtrNotNull(tc, u);
@@ -121,8 +121,8 @@ void test_pay_spell_failure(CuTest * tc)
     int level;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    init_resources();
+    r = test_create_region(0, 0, NULL);
     f = test_create_faction(0);
     u = test_create_unit(f, r);
     CuAssertPtrNotNull(tc, u);
@@ -159,8 +159,7 @@ void test_getspell_unit(CuTest * tc)
     struct locale * lang;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, 0);
     f = test_create_faction(0);
     u = test_create_unit(f, r);
     create_mage(u, M_GRAY);
@@ -168,7 +167,7 @@ void test_getspell_unit(CuTest * tc)
 
     set_level(u, SK_MAGIC, 1);
 
-    lang = get_locale("de");
+    lang = test_create_locale();
     sp = create_spell("testspell", 0);
     locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp");
 
@@ -188,8 +187,7 @@ void test_getspell_faction(CuTest * tc)
     struct locale * lang;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f = test_create_faction(0);
     f->magiegebiet = M_TYBIED;
     u = test_create_unit(f, r);
@@ -198,7 +196,7 @@ void test_getspell_faction(CuTest * tc)
 
     set_level(u, SK_MAGIC, 1);
 
-    lang = get_locale("de");
+    lang = test_create_locale();
     sp = create_spell("testspell", 0);
     locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp");
 
@@ -220,8 +218,7 @@ void test_getspell_school(CuTest * tc)
     struct spellbook * book;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f = test_create_faction(0);
     f->magiegebiet = M_TYBIED;
     u = test_create_unit(f, r);
@@ -229,7 +226,7 @@ void test_getspell_school(CuTest * tc)
     enable_skill(SK_MAGIC, true);
     set_level(u, SK_MAGIC, 1);
 
-    lang = get_locale("de");
+    lang = test_create_locale();
     sp = create_spell("testspell", 0);
     locale_setstring(lang, mkname("spell", sp->sname), "Herp-a-derp");
 
@@ -251,8 +248,7 @@ void test_set_pre_combatspell(CuTest * tc)
     const int index = 0;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f = test_create_faction(0);
     f->magiegebiet = M_TYBIED;
     u = test_create_unit(f, r);
@@ -284,8 +280,7 @@ void test_set_main_combatspell(CuTest * tc)
     const int index = 1;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f = test_create_faction(0);
     f->magiegebiet = M_TYBIED;
     u = test_create_unit(f, r);
@@ -317,8 +312,7 @@ void test_set_post_combatspell(CuTest * tc)
     const int index = 2;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f = test_create_faction(0);
     f->magiegebiet = M_TYBIED;
     u = test_create_unit(f, r);
@@ -349,8 +343,7 @@ void test_hasspell(CuTest * tc)
     struct region * r;
 
     test_setup();
-    test_create_world();
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f = test_create_faction(0);
     f->magiegebiet = M_TYBIED;
     u = test_create_unit(f, r);
diff --git a/src/market.test.c b/src/market.test.c
index b4d5f05f5..b70288e90 100644
--- a/src/market.test.c
+++ b/src/market.test.c
@@ -31,9 +31,7 @@ static void test_market_curse(CuTest * tc)
     luxury_type *lux;
     building_type *btype;
 
-    free_gamedata();
-    test_cleanup();
-    test_create_world();
+    test_setup();
 
     htype = test_create_itemtype("herb");
     htype->flags |= ITF_HERB;
diff --git a/src/move.test.c b/src/move.test.c
index c444fe4a8..bb3b9d88d 100644
--- a/src/move.test.c
+++ b/src/move.test.c
@@ -158,16 +158,14 @@ static void test_ship_has_harbormaster_ally(CuTest * tc) {
 }
 
 static void test_walkingcapacity(CuTest *tc) {
-    region *r;
     unit *u;
     int cap;
     const struct item_type *itype;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
+    init_resources();
 
-    r = findregion(0, 0);
-    u = test_create_unit(test_create_faction(0), r);
+    u = test_create_unit(test_create_faction(NULL), test_create_region(0, 0, NULL));
     cap = u->number * (u->_race->capacity + u->_race->weight);
     CuAssertIntEquals(tc, cap, walkingcapacity(u));
     scale_number(u, 2);
@@ -183,7 +181,7 @@ static void test_walkingcapacity(CuTest *tc) {
     cap += itype->capacity;
     CuAssertIntEquals(tc, cap, walkingcapacity(u));
 
-    itype = it_find("cart");
+    itype = test_create_itemtype("cart");
     assert(itype);
     i_change(&u->items, itype, 1);
     CuAssertIntEquals(tc, cap, walkingcapacity(u));
@@ -265,15 +263,15 @@ struct drift_fixture {
 };
 
 void setup_drift (struct drift_fixture *fix) {
-    test_cleanup();
+    test_setup();
     config_set("rules.ship.storms", "0");
 
-    test_create_world();
     test_create_shiptype("drifter");
     fix->st_boat = st_get_or_create("drifter");
     fix->st_boat->cabins = 20000;
 
-    fix->u = test_create_unit(fix->f = test_create_faction(0), fix->r=findregion(-1,0));
+    test_create_ocean(0, 0);
+    fix->u = test_create_unit(fix->f = test_create_faction(0), fix->r = test_create_ocean(-1, 0));
     assert(fix->r && fix->u && fix->f);
     set_level(fix->u, SK_SAILING, fix->st_boat->sumskill);
     u_set_ship(fix->u, fix->sh = test_create_ship(fix->u->region, fix->st_boat));
@@ -437,9 +435,11 @@ static void test_follow_ship_msg(CuTest * tc) {
     void *p;
     
     test_setup();
-    test_create_world();
+    init_resources();
+
     f = test_create_faction(0);
-    r = findregion(0, 0);
+    r = test_create_plain(0, 0);
+    test_create_ocean(-1, 1); /* D_NORTHWEST */
 
     stype = st_find("boat");
     sh = test_create_ship(r, stype);
@@ -452,7 +452,7 @@ static void test_follow_ship_msg(CuTest * tc) {
     assert(ord);
     unit_addorder(u, ord);
 
-    set_money(u, 999999);
+    set_money(u, 999999); /* overloaded ship */
 
     a = a_add(&(r->attribs), a_new(&at_shiptrail));
     td = (traveldir *)a->data.v;
diff --git a/src/piracy.test.c b/src/piracy.test.c
index d690776f1..40e66af18 100644
--- a/src/piracy.test.c
+++ b/src/piracy.test.c
@@ -116,7 +116,7 @@ static void test_piracy_cmd_errors(CuTest * tc) {
     st_boat = st_get_or_create("boat");
     r = test_create_race("pirates");
     u = test_create_unit(f = test_create_faction(r), test_create_region(0, 0, get_or_create_terrain("ocean")));
-    f->locale = get_or_create_locale("de");
+    f->locale = test_create_locale();
     u->thisorder = create_order(K_PIRACY, f->locale, "");
     assert(u && u->thisorder);
 
diff --git a/src/spy.test.c b/src/spy.test.c
index 0dfaada7a..190cb09a5 100644
--- a/src/spy.test.c
+++ b/src/spy.test.c
@@ -77,23 +77,12 @@ static void test_all_spy_message(CuTest *tc) {
     test_cleanup();
 }
 
-static void setup_sabotage(void) {
-    struct locale *lang;
-
-    test_setup();
-    lang = get_or_create_locale("de");
-    locale_setstring(lang, parameters[P_SHIP], "SCHIFF");
-    locale_setstring(lang, parameters[P_ANY], "ALLE");
-    init_parameters(lang);
-    init_locales();
-}
-
 static void test_sabotage_self(CuTest *tc) {
     unit *u;
     region *r;
     order *ord;
 
-    setup_sabotage();
+    test_setup();
     r = test_create_region(0, 0, 0);
     assert(r);
     u = test_create_unit(test_create_faction(NULL), r);
@@ -115,7 +104,7 @@ static void test_sabotage_other_fail(CuTest *tc) {
     order *ord;
     message *msg;
 
-    setup_sabotage();
+    test_setup();
     r = test_create_region(0, 0, 0);
     assert(r);
     u = test_create_unit(test_create_faction(NULL), r);
@@ -164,7 +153,7 @@ static void test_sabotage_other_success(CuTest *tc) {
     region *r;
     order *ord;
 
-    setup_sabotage();
+    test_setup();
     r = test_create_region(0, 0, 0);
     assert(r);
     u = test_create_unit(test_create_faction(NULL), r);
diff --git a/src/study.test.c b/src/study.test.c
index 3b411c7df..74104704b 100644
--- a/src/study.test.c
+++ b/src/study.test.c
@@ -63,8 +63,6 @@ static void setup_locale(struct locale *lang) {
         if (!locale_getstring(lang, mkname("skill", skillnames[i])))
             locale_setstring(lang, mkname("skill", skillnames[i]), skillnames[i]);
     }
-    locale_setstring(lang, parameters[P_ANY], "ALLE");
-    init_parameters(lang);
     init_skills(lang);
 }
 
@@ -76,10 +74,9 @@ static void setup_study(study_fixture *fix, skill_t sk) {
     assert(fix);
     test_setup();
     config_set("study.random_progress", "0");
-    test_create_world();
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, 0);
     f = test_create_faction(0);
-    lang = get_or_create_locale(locale_name(f->locale));
+    f->locale = lang = test_create_locale();
     setup_locale(lang);
     fix->u = test_create_unit(f, r);
     assert(fix->u);
@@ -145,7 +142,7 @@ static void test_study_bug_2194(CuTest *tc) {
     test_setup();
     random_source_inject_constant(0.0);
     init_resources();
-    loc = get_or_create_locale("de");
+    loc = test_create_locale();
     setup_locale(loc);
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     scale_number(u, 2);
@@ -219,7 +216,7 @@ static void test_academy_building(CuTest *tc) {
 
     random_source_inject_constant(0.0);
     init_resources();
-    loc = get_or_create_locale("de");
+    loc = test_create_locale();
     setup_locale(loc);
     u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0));
     scale_number(u, 2);
diff --git a/src/tests.c b/src/tests.c
index c448a27ae..faa8f6e2e 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -53,9 +53,7 @@ struct region *test_create_region(int x, int y, const terrain_type *terrain)
         r = new_region(x, y, findplane(x, y), 0);
     }
     if (!terrain) {
-        terrain_type *t = get_or_create_terrain("plain");
-        t->size = 1000;
-        fset(t, LAND_REGION|CAVALRY_REGION|FOREST_REGION|FLY_INTO|WALK_INTO);
+        terrain_type *t = test_create_terrain("plain", LAND_REGION | CAVALRY_REGION | FOREST_REGION | FLY_INTO | WALK_INTO);
         terraform_region(r, t);
     }
     else {
@@ -69,12 +67,37 @@ struct region *test_create_region(int x, int y, const terrain_type *terrain)
     return r;
 }
 
+region *test_create_ocean(int x, int y)
+{
+    terrain_type *ter = test_create_terrain("ocean", SEA_REGION | FLY_INTO | SWIM_INTO);
+    return test_create_region(x, y, ter);
+}
+
+region *test_create_plain(int x, int y) {
+    return test_create_region(x, y, NULL);
+}
+
 struct locale * test_create_locale(void) {
     struct locale *loc = get_locale("test");
     if (!loc) {
         int i;
         loc = get_or_create_locale("test");
         locale_setstring(loc, "factiondefault", parameters[P_FACTION]);
+        locale_setstring(loc, "unitdefault", parameters[P_UNIT]);
+        locale_setstring(loc, "money", "Silber");
+        locale_setstring(loc, "money_p", "Silber");
+        locale_setstring(loc, "cart", "Wagen");
+        locale_setstring(loc, "cart_p", "Wagen");
+        locale_setstring(loc, "horse", "Pferd");
+        locale_setstring(loc, "horse_p", "Pferde");
+        locale_setstring(loc, "iron", "Eisen");
+        locale_setstring(loc, "iron_p", "Eisen");
+        locale_setstring(loc, "stone", "Stein");
+        locale_setstring(loc, "stone_p", "Steine");
+        locale_setstring(loc, "plain", "Ebene");
+        locale_setstring(loc, "ocean", "Ozean");
+        locale_setstring(loc, "race::human", "Mensch");
+        locale_setstring(loc, "race::human_p", "Menschen");
         for (i = 0; i < MAXSKILLS; ++i) {
             if (!locale_getstring(loc, mkname("skill", skillnames[i])))
                 locale_setstring(loc, mkname("skill", skillnames[i]), skillnames[i]);
@@ -314,7 +337,7 @@ void test_create_castorder(castorder *co, unit *u, int level, float force, int r
     struct locale * lang;
     order *ord;
 
-    lang = get_or_create_locale("en");
+    lang = test_create_locale();
     create_castorder(co, u, NULL, NULL, u->region, level, force, range, ord = create_order(K_CAST, lang, ""), par);
     free_order(ord);
 }
@@ -373,7 +396,7 @@ void test_create_world(void)
     item_type * itype;
     struct locale * loc;
 
-    loc = get_or_create_locale("de");
+    loc = test_create_locale();
 
     locale_setstring(loc, parameters[P_SHIP], "SCHIFF");
     locale_setstring(loc, parameters[P_ANY], "ALLE");
@@ -381,7 +404,18 @@ void test_create_world(void)
 
     locale_setstring(loc, "status_aggressive", "aggressiv");
     locale_setstring(loc, keyword(K_RESERVE), "RESERVIEREN");
-    locale_setstring(loc, "money", "SILBER");
+    locale_setstring(loc, "money", "Silber");
+    locale_setstring(loc, "money_p", "Silber");
+    locale_setstring(loc, "cart", "Wagen");
+    locale_setstring(loc, "cart_p", "Wagen");
+    locale_setstring(loc, "horse", "Pferd");
+    locale_setstring(loc, "horse_p", "Pferde");
+    locale_setstring(loc, "iron", "Eisen");
+    locale_setstring(loc, "iron_p", "Eisen");
+    locale_setstring(loc, "stone", "Stein");
+    locale_setstring(loc, "stone_p", "Steine");
+    locale_setstring(loc, "plain", "Ebene");
+    locale_setstring(loc, "ocean", "Ozean");
     init_resources();
     get_resourcetype(R_SILVER)->itype->weight = 1;
 
diff --git a/src/tests.h b/src/tests.h
index c99147e6a..669318d99 100644
--- a/src/tests.h
+++ b/src/tests.h
@@ -43,8 +43,9 @@ extern "C" {
     struct locale * test_create_locale(void);
     struct terrain_type * test_create_terrain(const char * name, unsigned int flags);
     struct race *test_create_race(const char *name);
-    struct region *test_create_region(int x, int y,
-        const struct terrain_type *terrain);
+    struct region *test_create_region(int x, int y, const struct terrain_type *terrain);
+    struct region *test_create_ocean(int x, int y);
+    struct region *test_create_plain(int x, int y);
     struct faction *test_create_faction(const struct race *rc);
     struct unit *test_create_unit(struct faction *f, struct region *r);
     void test_create_world(void);
diff --git a/src/tests.test.c b/src/tests.test.c
index 9dd47e4d1..880956e8b 100644
--- a/src/tests.test.c
+++ b/src/tests.test.c
@@ -34,46 +34,9 @@ static void test_resources(CuTest *tc) {
     CuAssertPtrEquals(tc, (void *)rtype, (void *)get_resourcetype(R_STONE));
 }
 
-static void test_recreate_world(CuTest * tc)
-{
-    test_setup();
-    CuAssertPtrEquals(tc, 0, get_locale("de"));
-    CuAssertPtrEquals(tc, 0, (void *)rt_find("horse"));
-
-    test_create_world();
-    CuAssertPtrEquals(tc, default_locale, get_locale("de"));
-    CuAssertPtrNotNull(tc, default_locale);
-    CuAssertPtrNotNull(tc, findregion(0, 0));
-    CuAssertPtrNotNull(tc, get_terrain("plain"));
-    CuAssertPtrNotNull(tc, get_terrain("ocean"));
-    CuAssertPtrNotNull(tc, (void *)rt_find("horse"));
-    CuAssertPtrNotNull(tc, get_resourcetype(R_HORSE));
-    CuAssertPtrNotNull(tc, (void *)rt_find("money"));
-    CuAssertPtrNotNull(tc, get_resourcetype(R_LIFE));
-    CuAssertPtrNotNull(tc, get_resourcetype(R_SILVER));
-    CuAssertPtrNotNull(tc, get_resourcetype(R_AURA));
-    CuAssertPtrNotNull(tc, get_resourcetype(R_PERMAURA));
-    CuAssertPtrNotNull(tc, get_resourcetype(R_PEASANT));
-
-    test_cleanup();
-    CuAssertPtrEquals(tc, 0, get_locale("de"));
-    CuAssertPtrEquals(tc, 0, (void*)get_terrain("plain"));
-    CuAssertPtrEquals(tc, 0, (void*)get_terrain("ocean"));
-    CuAssertPtrEquals(tc, 0, (void*)rt_find("horse"));
-    CuAssertPtrEquals(tc, 0, (void*)get_resourcetype(R_HORSE));
-    CuAssertPtrEquals(tc, 0, (void *)rt_find("money"));
-    CuAssertPtrEquals(tc, 0, (void *)get_resourcetype(R_LIFE));
-    CuAssertPtrEquals(tc, 0, (void *)get_resourcetype(R_SILVER));
-    CuAssertPtrEquals(tc, 0, (void *)get_resourcetype(R_AURA));
-    CuAssertPtrEquals(tc, 0, (void *)get_resourcetype(R_PERMAURA));
-    CuAssertPtrEquals(tc, 0, (void *)get_resourcetype(R_PEASANT));
-    CuAssertPtrEquals(tc, 0, findregion(0, 0));
-}
-
 CuSuite *get_tests_suite(void)
 {
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_resources);
-    SUITE_ADD_TEST(suite, test_recreate_world);
     return suite;
 }
diff --git a/src/upkeep.test.c b/src/upkeep.test.c
index 2a91a0df1..bc53d5bbc 100644
--- a/src/upkeep.test.c
+++ b/src/upkeep.test.c
@@ -20,11 +20,10 @@ void test_upkeep_default(CuTest * tc)
     const item_type *i_silver;
 
     test_setup();
-    test_create_world();
-
+    init_resources();
     i_silver = it_find("money");
     assert(i_silver);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f1 = test_create_faction(test_create_race("human"));
     f2 = test_create_faction(test_create_race("human"));
     assert(f1 && f2);
@@ -51,11 +50,11 @@ void test_upkeep_hunger_damage(CuTest * tc)
     const item_type *i_silver;
 
     test_setup();
-    test_create_world();
+    init_resources();
 
     i_silver = it_find("money");
     assert(i_silver);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f1 = test_create_faction(test_create_race("human"));
     u1 = test_create_unit(f1, r);
     assert(r && u1);
@@ -76,11 +75,11 @@ void test_upkeep_from_pool(CuTest * tc)
     const item_type *i_silver;
 
     test_setup();
-    test_create_world();
+    init_resources();
 
     i_silver = it_find("money");
     assert(i_silver);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     assert(r);
     u1 = test_create_unit(test_create_faction(test_create_race("human")), r);
 	assert(u1);
@@ -110,11 +109,11 @@ void test_upkeep_from_friend(CuTest * tc)
     const item_type *i_silver;
 
     test_setup();
-    test_create_world();
+    init_resources();
 
     i_silver = it_find("money");
     assert(i_silver);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     f1 = test_create_faction(test_create_race("human"));
     f2 = test_create_faction(test_create_race("human"));
     assert(f1 && f2);
@@ -144,11 +143,11 @@ void test_upkeep_free(CuTest * tc)
     const item_type *i_silver;
 
     test_setup();
-    test_create_world();
+    init_resources();
 
     i_silver = it_find("money");
     assert(i_silver);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     u = test_create_unit(test_create_faction(test_create_race("human")), r);
     assert(r && u);
 
diff --git a/src/vortex.test.c b/src/vortex.test.c
index 21ea6596c..b4940b6bc 100644
--- a/src/vortex.test.c
+++ b/src/vortex.test.c
@@ -23,7 +23,7 @@ static void test_move_to_vortex(CuTest *tc) {
     struct locale *lang;
 
     test_setup();
-    lang = get_or_create_locale("en");
+    lang = test_create_locale();
     locale_setstring(lang, "vortex", "wirbel");
     init_locale(lang);
     t_plain = test_create_terrain("plain", LAND_REGION | FOREST_REGION | WALK_INTO | CAVALRY_REGION);

From fe95ddafa112f5cb85bfa81decdf51362e38aa2e Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Fri, 10 Mar 2017 21:43:36 +0100
Subject: [PATCH 44/48] reduce "translation not found" warnings in tests.

---
 src/laws.test.c | 29 ++++++++++++++---------------
 src/move.test.c |  4 ++--
 2 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/src/laws.test.c b/src/laws.test.c
index 672105e08..0f61c7613 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -52,7 +52,7 @@ static void test_rename_building(CuTest * tc)
     building_type *btype;
 
     test_setup();
-
+    test_create_locale();
     btype = test_create_buildingtype("castle");
     r = test_create_region(0, 0, 0);
     b = new_building(btype, r, default_locale);
@@ -74,7 +74,7 @@ static void test_rename_building_twice(CuTest * tc)
     building_type *btype;
 
     test_setup();
-
+    test_create_locale();
     btype = test_create_buildingtype("castle");
     r = test_create_region(0, 0, 0);
     b = new_building(btype, r, default_locale);
@@ -98,7 +98,7 @@ static void test_contact(CuTest * tc)
     ally *al;
 
     test_setup();
-
+    test_create_locale();
     btype = test_create_buildingtype("castle");
     r = test_create_region(0, 0, 0);
     b = new_building(btype, r, default_locale);
@@ -127,9 +127,9 @@ static void test_enter_building(CuTest * tc)
     race * rc;
 
     test_setup();
-
+    test_create_locale();
     r = test_create_region(0, 0, 0);
-    rc = rc_get_or_create("human");
+    rc = test_create_race("human");
     u = test_create_unit(test_create_faction(rc), r);
     b = test_create_building(r, test_create_buildingtype("castle"));
 
@@ -1270,7 +1270,6 @@ static void test_show_without_item(CuTest *tc)
     unit *u;
     order *ord;
     item_type *itype;
-    item *i;
     struct locale *loc;
 
     test_setup();
@@ -1283,26 +1282,26 @@ static void test_show_without_item(CuTest *tc)
     f = test_create_faction(test_create_race("human"));
     u = test_create_unit(f, r);
 
+    itype = it_get_or_create(rt_get_or_create("testitem"));
+
     ord = create_order(K_RESHOW, f->locale, "testname");
 
-    itype = it_get_or_create(rt_get_or_create("testitem"));
-    i = i_new(itype, 1);
-
     reshow_cmd(u, ord);
-    CuAssertTrue(tc, test_find_messagetype(f->msgs, "error21") != NULL);
+    CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error21"));
     test_clear_messages(f);
 
     locale_setstring(loc, "testitem", "testname");
     locale_setstring(loc, "iteminfo::testitem", "testdescription");
+
     reshow_cmd(u, ord);
-    CuAssertTrue(tc, test_find_messagetype(f->msgs, "error21") == NULL);
-    CuAssertTrue(tc, test_find_messagetype(f->msgs, "error36") != NULL);
+    CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error21"));
+    CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error36"));
     test_clear_messages(f);
 
-    i_add(&(u->items), i);
+    i_add(&(u->items), i_new(itype, 1));
     reshow_cmd(u, ord);
-    CuAssertTrue(tc, test_find_messagetype(f->msgs, "error21") == NULL);
-    CuAssertTrue(tc, test_find_messagetype(f->msgs, "error36") == NULL);
+    CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error21"));
+    CuAssertPtrEquals(tc, 0, test_find_messagetype(f->msgs, "error36"));
     test_clear_messages(f);
 
     free_order(ord);
diff --git a/src/move.test.c b/src/move.test.c
index bb3b9d88d..ab30300e8 100644
--- a/src/move.test.c
+++ b/src/move.test.c
@@ -264,10 +264,10 @@ struct drift_fixture {
 
 void setup_drift (struct drift_fixture *fix) {
     test_setup();
+    test_create_locale();
     config_set("rules.ship.storms", "0");
 
-    test_create_shiptype("drifter");
-    fix->st_boat = st_get_or_create("drifter");
+    fix->st_boat = test_create_shiptype("boat");
     fix->st_boat->cabins = 20000;
 
     test_create_ocean(0, 0);

From 8b9f0f08942ef60bed449123cdf5c8843945d434 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Fri, 10 Mar 2017 23:18:09 +0100
Subject: [PATCH 45/48] BUG 2307: report mallorn trees as Mallorn in the CR.
 for legacy compatibility, we cannot call them Mallornbaeume.

---
 res/core/de/strings.xml |  8 ++---
 src/creport.c           |  8 +++--
 src/creport.test.c      | 70 ++++++++++++++++++++++++++++++++++++-----
 src/reports.c           | 28 ++++++++---------
 4 files changed, 87 insertions(+), 27 deletions(-)

diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml
index d69c0919f..a39657580 100644
--- a/res/core/de/strings.xml
+++ b/res/core/de/strings.xml
@@ -484,13 +484,13 @@
   </string>
 
   <string name="mallorntree">
-    <text locale="de">Mallornbaum</text>
-    <text locale="en">mallorn tree</text>
+    <text locale="de">Mallorn</text>
+    <text locale="en">mallorn</text>
   </string>
 
   <string name="mallorntree_p">
-    <text locale="de">Mallornbäume</text>
-    <text locale="en">mallorn trees</text>
+    <text locale="de">Mallorn</text>
+    <text locale="en">mallorn</text>
   </string>
 
   <!--Küsten -->
diff --git a/src/creport.c b/src/creport.c
index f22096f19..d16f87f22 100644
--- a/src/creport.c
+++ b/src/creport.c
@@ -1094,12 +1094,16 @@ static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale
 static char *cr_output_resource(char *buf, const resource_type *rtype,
     const struct locale *loc, int amount, int level)
 {
-    const char * name;
+    const char *name, *tname;
     assert(rtype);
     name = resourcename(rtype, 1);
     assert(name);
     buf += sprintf(buf, "RESOURCE %u\n", hashstring(rtype->_name));
-    buf += sprintf(buf, "\"%s\";type\n", translate(name, LOC(loc, rtype->_name)));
+    tname = LOC(loc, rtype->_name);
+    assert(tname);
+    tname = translate(name, tname);
+    assert(tname);
+    buf += sprintf(buf, "\"%s\";type\n", tname);
     if (amount >= 0) {
         if (level >= 0)
             buf += sprintf(buf, "%d;skill\n", level);
diff --git a/src/creport.test.c b/src/creport.test.c
index acd6201f9..46e6e6967 100644
--- a/src/creport.test.c
+++ b/src/creport.test.c
@@ -50,11 +50,7 @@ static void test_cr_unit(CuTest *tc) {
     test_cleanup();
 }
 
-static void test_cr_resources(CuTest *tc) {
-    stream strm;
-    char line[1024];
-    faction *f;
-    region *r;
+static void setup_resources(void) {
     struct locale *lang;
 
     test_setup();
@@ -70,6 +66,19 @@ static void test_cr_resources(CuTest *tc) {
     locale_setstring(lang, "tree_p", "Blumen");
     locale_setstring(lang, "sapling", "Schoessling");
     locale_setstring(lang, "sapling_p", "Schoesslinge");
+    locale_setstring(lang, "mallornsapling", "Mallornschoessling");
+    locale_setstring(lang, "mallornsapling_p", "Mallornschoesslinge");
+    locale_setstring(lang, "mallorntree", "Mallorn");
+    locale_setstring(lang, "mallorntree_p", "Mallorn");
+}
+
+static void test_cr_resources(CuTest *tc) {
+    stream strm;
+    char line[1024];
+    faction *f;
+    region *r;
+    
+    setup_resources();
 
     f = test_create_faction(0);
     r = test_create_region(0, 0, 0);
@@ -88,6 +97,20 @@ static void test_cr_resources(CuTest *tc) {
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertStrEquals(tc, "2;Schoesslinge", line);
 
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "\"Schoesslinge\";type", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "2;number", line);
+
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "\"Blumen\";type", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "3;number", line);
+
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
@@ -109,17 +132,49 @@ static void test_cr_resources(CuTest *tc) {
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertStrEquals(tc, "1;number", line);
 
+    mstream_done(&strm);
+    test_cleanup();
+}
+
+static void test_cr_mallorn(CuTest *tc) {
+    stream strm;
+    char line[1024];
+    faction *f;
+    region *r;
+    
+    setup_resources();
+
+    f = test_create_faction(0);
+    r = test_create_region(0, 0, 0);
+    r->land->horses = 1;
+    r->land->peasants = 200;
+    r->land->money = 300;
+    r->flags |= RF_MALLORN;
+    rsettrees(r, 0, 1);
+    rsettrees(r, 1, 2);
+    rsettrees(r, 2, 3);
+
+    mstream_init(&strm);
+    cr_output_resources(&strm, f, r, false);
+    strm.api->rewind(strm.handle);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "3;Baeume", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "2;Schoesslinge", line);
+    CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
+    CuAssertStrEquals(tc, "1;Mallorn", line);
+
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
-    CuAssertStrEquals(tc, "\"Schoesslinge\";type", line);
+    CuAssertStrEquals(tc, "\"Mallornschoesslinge\";type", line);
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertStrEquals(tc, "2;number", line);
 
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertIntEquals(tc, 0, memcmp(line, "RESOURCE ", 9));
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
-    CuAssertStrEquals(tc, "\"Blumen\";type", line);
+    CuAssertStrEquals(tc, "\"Mallorn\";type", line);
     CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line)));
     CuAssertStrEquals(tc, "3;number", line);
 
@@ -247,6 +302,7 @@ CuSuite *get_creport_suite(void)
     CuSuite *suite = CuSuiteNew();
     SUITE_ADD_TEST(suite, test_cr_unit);
     SUITE_ADD_TEST(suite, test_cr_resources);
+    SUITE_ADD_TEST(suite, test_cr_mallorn);
     SUITE_ADD_TEST(suite, test_cr_factionstealth);
     return suite;
 }
diff --git a/src/reports.c b/src/reports.c
index 85ab34209..c23809a32 100644
--- a/src/reports.c
+++ b/src/reports.c
@@ -410,6 +410,20 @@ const faction * viewer, bool see_unit)
         bool mallorn = fval(r, RF_MALLORN) != 0;
         const resource_type *rtype;
 
+        if (saplings) {
+            if (n >= size)
+                return -1;
+            rtype = get_resourcetype(mallorn ? R_MALLORN_SAPLING : R_SAPLING);
+            report_resource(result + n, rtype, saplings, -1);
+            ++n;
+        }
+        if (trees) {
+            if (n >= size)
+                return -1;
+            rtype = get_resourcetype(mallorn ? R_MALLORN_TREE : R_TREE);
+            report_resource(result + n, rtype, trees, -1);
+            ++n;
+        }
         if (money) {
             if (n >= size)
                 return -1;
@@ -428,20 +442,6 @@ const faction * viewer, bool see_unit)
             report_resource(result + n, get_resourcetype(R_HORSE), horses, -1);
             ++n;
         }
-        if (saplings) {
-            if (n >= size)
-                return -1;
-            rtype = get_resourcetype(mallorn ? R_MALLORN_SAPLING : R_SAPLING);
-            report_resource(result + n, rtype, saplings, -1);
-            ++n;
-        }
-        if (trees) {
-            if (n >= size)
-                return -1;
-            rtype = get_resourcetype(mallorn ? R_MALLORN_TREE : R_TREE);
-            report_resource(result + n, rtype, trees, -1);
-            ++n;
-        }
     }
 
     if (see_unit) {

From 98a48edb9ad40efe9b333d977a17f8a35a565813 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 11 Mar 2017 12:25:49 +0100
Subject: [PATCH 46/48] I've got a 64-bit CMake on Windows now.

---
 vs2015-build.bat | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/vs2015-build.bat b/vs2015-build.bat
index 6c39659d1..262d498bf 100644
--- a/vs2015-build.bat
+++ b/vs2015-build.bat
@@ -9,5 +9,5 @@ IF exist build-vs%VSVERSION% goto HAVEDIR
 mkdir build-vs%VSVERSION%
 :HAVEDIR
 cd build-vs%VSVERSION%
-"%ProgramFiles(x86)%\CMake\bin\cmake.exe" -G "Visual Studio %VSVERSION%" -DCMAKE_PREFIX_PATH="%ProgramFiles(x86)%/Lua/5.1;%ERESSEA%/dependencies-win32" -DCMAKE_MODULE_PATH="%SRCDIR%/cmake/Modules" -DCMAKE_SUPPRESS_REGENERATION=TRUE ..
+"%ProgramFiles%\CMake\bin\cmake.exe" -G "Visual Studio %VSVERSION%" -DCMAKE_PREFIX_PATH="%ProgramFiles(x86)%/Lua/5.1;%ERESSEA%/dependencies-win32" -DCMAKE_MODULE_PATH="%SRCDIR%/cmake/Modules" -DCMAKE_SUPPRESS_REGENERATION=TRUE ..
 PAUSE

From 41c679396449b09be1da65421f94326ff5fb0b4b Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 11 Mar 2017 12:57:02 +0100
Subject: [PATCH 47/48] matching test_setup and test_cleanup calls.

---
 src/laws.test.c   | 38 ++++++++++++++++++++++++++------------
 src/market.test.c |  1 +
 2 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/src/laws.test.c b/src/laws.test.c
index 0f61c7613..937754988 100644
--- a/src/laws.test.c
+++ b/src/laws.test.c
@@ -41,6 +41,7 @@ static void test_new_building_can_be_renamed(CuTest * tc)
 
     b = test_create_building(r, NULL);
     CuAssertTrue(tc, !renamed_building(b));
+    test_cleanup();
 }
 
 static void test_rename_building(CuTest * tc)
@@ -63,6 +64,7 @@ static void test_rename_building(CuTest * tc)
     rename_building(u, NULL, b, "Villa Nagel");
     CuAssertStrEquals(tc, "Villa Nagel", b->name);
     CuAssertTrue(tc, renamed_building(b));
+    test_cleanup();
 }
 
 static void test_rename_building_twice(CuTest * tc)
@@ -87,6 +89,7 @@ static void test_rename_building_twice(CuTest * tc)
 
     rename_building(u, NULL, b, "Villa Kunterbunt");
     CuAssertStrEquals(tc, "Villa Kunterbunt", b->name);
+    test_cleanup();
 }
 
 static void test_contact(CuTest * tc)
@@ -117,6 +120,7 @@ static void test_contact(CuTest * tc)
     CuAssertIntEquals(tc, HELP_GIVE, can_contact(r, u1, u2));
     u_set_building(u2, b);
     CuAssertIntEquals(tc, 1, can_contact(r, u1, u2));
+    test_cleanup();
 }
 
 static void test_enter_building(CuTest * tc)
@@ -229,6 +233,7 @@ static void test_display_cmd(CuTest *tc) {
 }
 
 static void test_rule_force_leave(CuTest *tc) {
+    test_setup();
     config_set("rules.owners.force_leave", "0");
     CuAssertIntEquals(tc, false, rule_force_leave(FORCE_LEAVE_ALL));
     CuAssertIntEquals(tc, false, rule_force_leave(FORCE_LEAVE_POSTCOMBAT));
@@ -241,6 +246,7 @@ static void test_rule_force_leave(CuTest *tc) {
     config_set("rules.owners.force_leave", "3");
     CuAssertIntEquals(tc, true, rule_force_leave(FORCE_LEAVE_ALL));
     CuAssertIntEquals(tc, true, rule_force_leave(FORCE_LEAVE_POSTCOMBAT));
+    test_cleanup();
 }
 
 static void test_force_leave_buildings(CuTest *tc) {
@@ -249,7 +255,8 @@ static void test_force_leave_buildings(CuTest *tc) {
     unit *u1, *u2, *u3;
     building * b;
     message *msg;
-    test_cleanup();
+
+    test_setup();
     r = test_create_region(0, 0, test_create_terrain("plain", LAND_REGION));
     u1 = test_create_unit(test_create_faction(NULL), r);
     u2 = test_create_unit(u1->faction, r);
@@ -279,7 +286,8 @@ static void test_force_leave_ships(CuTest *tc) {
     unit *u1, *u2;
     ship *sh;
     message *msg;
-    test_cleanup();
+
+    test_setup();
     r = test_create_region(0, 0, test_create_terrain("plain", LAND_REGION));
     u1 = test_create_unit(test_create_faction(NULL), r);
     u2 = test_create_unit(test_create_faction(NULL), r);
@@ -298,7 +306,8 @@ static void test_force_leave_ships_on_ocean(CuTest *tc) {
     region *r;
     unit *u1, *u2;
     ship *sh;
-    test_cleanup();
+
+    test_setup();
     r = test_create_region(0, 0, test_create_terrain("ocean", SEA_REGION));
     u1 = test_create_unit(test_create_faction(NULL), r);
     u2 = test_create_unit(test_create_faction(NULL), r);
@@ -319,7 +328,7 @@ static void test_fishing_feeds_2_people(CuTest * tc)
     unit *u;
     ship *sh;
 
-    test_cleanup();
+    test_setup();
     test_create_world();
     r = findregion(-1, 0);
     CuAssertStrEquals(tc, "ocean", r->terrain->_name);    /* test_create_world needs coverage */
@@ -344,6 +353,7 @@ static void test_fishing_feeds_2_people(CuTest * tc)
     sh->flags |= SF_FISHING;
     get_food(r);
     CuAssertIntEquals(tc, 32, i_get(u->items, rtype->itype));
+    test_cleanup();
 }
 
 static void test_fishing_does_not_give_goblins_money(CuTest * tc)
@@ -354,7 +364,7 @@ static void test_fishing_does_not_give_goblins_money(CuTest * tc)
     unit *u;
     ship *sh;
 
-    test_cleanup();
+    test_setup();
     test_create_world();
     rtype = get_resourcetype(R_SILVER);
 
@@ -370,6 +380,7 @@ static void test_fishing_does_not_give_goblins_money(CuTest * tc)
     sh->flags |= SF_FISHING;
     get_food(r);
     CuAssertIntEquals(tc, 42, i_get(u->items, rtype->itype));
+    test_cleanup();
 }
 
 static void test_fishing_gets_reset(CuTest * tc)
@@ -380,7 +391,7 @@ static void test_fishing_gets_reset(CuTest * tc)
     unit *u;
     ship *sh;
 
-    test_cleanup();
+    test_setup();
     test_create_world();
     rtype = get_resourcetype(R_SILVER);
     r = findregion(-1, 0);
@@ -399,10 +410,12 @@ static void test_fishing_gets_reset(CuTest * tc)
     scale_number(u, 1);
     get_food(r);
     CuAssertIntEquals(tc, 32, i_get(u->items, rtype->itype));
+    test_cleanup();
 }
 
 static void test_unit_limit(CuTest * tc)
 {
+    test_setup();
     config_set("rules.limit.faction", "250");
     CuAssertIntEquals(tc, 250, rule_faction_limit());
 
@@ -411,7 +424,7 @@ static void test_unit_limit(CuTest * tc)
 
     config_set("rules.limit.alliance", "250");
     CuAssertIntEquals(tc, 250, rule_alliance_limit());
-
+    test_cleanup();
 }
 
 extern int checkunitnumber(const faction * f, int add);
@@ -419,7 +432,7 @@ static void test_cannot_create_unit_above_limit(CuTest * tc)
 {
     faction *f;
 
-    test_cleanup();
+    test_setup();
     test_create_world();
     f = test_create_faction(NULL);
     config_set("rules.limit.faction", "4");
@@ -430,6 +443,7 @@ static void test_cannot_create_unit_above_limit(CuTest * tc)
     config_set("rules.limit.alliance", "3");
     CuAssertIntEquals(tc, 0, checkunitnumber(f, 3));
     CuAssertIntEquals(tc, 1, checkunitnumber(f, 4));
+    test_cleanup();
 }
 
 static void test_reserve_cmd(CuTest *tc) {
@@ -439,7 +453,7 @@ static void test_reserve_cmd(CuTest *tc) {
     order *ord;
     const resource_type *rtype;
 
-    test_cleanup();
+    test_setup();
     test_create_world();
 
     rtype = get_resourcetype(R_SILVER);
@@ -499,7 +513,7 @@ static void test_pay_cmd(CuTest *tc) {
     faction *f;
     building *b;
 
-    test_cleanup();
+    test_setup();
     setup_pay_cmd(&fix);
     b = fix.u1->building;
     f = fix.u1->faction;
@@ -542,7 +556,7 @@ static void test_pay_cmd_must_be_owner(CuTest *tc) {
     faction *f;
     building *b;
 
-    test_cleanup();
+    test_setup();
     setup_pay_cmd(&fix);
     b = fix.u1->building;
     f = fix.u1->faction;
@@ -1321,7 +1335,7 @@ static void test_show_elf(CuTest *tc) {
     rc = test_create_race("elf");
     test_create_itemtype("elvenhorse");
 
-    loc = get_or_create_locale("de");
+    loc = test_create_locale();
     locale_setstring(loc, "elvenhorse", "Elfenpferd");
     locale_setstring(loc, "elvenhorse_p", "Elfenpferde");
     locale_setstring(loc, "race::elf_p", "Elfen");
diff --git a/src/market.test.c b/src/market.test.c
index b70288e90..a631dbcb7 100644
--- a/src/market.test.c
+++ b/src/market.test.c
@@ -76,6 +76,7 @@ static void test_market_curse(CuTest * tc)
 
     CuAssertIntEquals(tc, 70, i_get(u->items, htype));
     CuAssertIntEquals(tc, 35, i_get(u->items, ltype));
+    test_cleanup();
 }
 
 static void test_rc_trade(CuTest *tc) {

From cdf13c9fec49288d52e5286d263bdf8329e211d8 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Sat, 11 Mar 2017 14:22:21 +0100
Subject: [PATCH 48/48] stop using test_create_world, use test_setup.

---
 src/economy.test.c                | 24 +++++++++++-------------
 src/give.test.c                   |  3 +--
 src/kernel/faction.test.c         |  6 ++----
 src/reports.test.c                | 15 ++++-----------
 src/spells/magicresistance.test.c | 18 ++++++++----------
 5 files changed, 26 insertions(+), 40 deletions(-)

diff --git a/src/economy.test.c b/src/economy.test.c
index e14b473b4..7534afe7e 100644
--- a/src/economy.test.c
+++ b/src/economy.test.c
@@ -128,12 +128,9 @@ static struct unit *create_recruiter(void) {
     unit *u;
     const resource_type* rtype;
 
-    test_cleanup();
-    test_create_world();
-
-    r=findregion(0, 0);
+    r=test_create_region(0, 0, NULL);
     rsetpeasants(r, 999);
-    f = test_create_faction(rc_find("human"));
+    f = test_create_faction(NULL);
     u = test_create_unit(f, r);
     rtype = get_resourcetype(R_SILVER);
     change_resource(u, rtype, 1000);
@@ -143,9 +140,10 @@ static struct unit *create_recruiter(void) {
 static void test_heroes_dont_recruit(CuTest * tc) {
     unit *u;
 
-    test_cleanup();
-
+    test_setup();
+    init_resources();
     u = create_recruiter();
+
     fset(u, UFL_HERO);
     unit_addorder(u, create_order(K_RECRUIT, default_locale, "1"));
 
@@ -160,8 +158,8 @@ static void test_heroes_dont_recruit(CuTest * tc) {
 static void test_normals_recruit(CuTest * tc) {
     unit *u;
 
-    test_cleanup();
-
+    test_setup();
+    init_resources();
     u = create_recruiter();
     unit_addorder(u, create_order(K_RECRUIT, default_locale, "1"));
 
@@ -193,11 +191,11 @@ static void test_tax_cmd(CuTest *tc) {
     request *taxorders = 0;
 
 
-    test_cleanup();
+    test_setup();
+    init_resources();
     config_set("taxing.perlevel", "20");
-    test_create_world();
     f = test_create_faction(NULL);
-    r = findregion(0, 0);
+    r = test_create_region(0, 0, NULL);
     assert(r && f);
     u = test_create_unit(f, r);
 
@@ -210,7 +208,7 @@ static void test_tax_cmd(CuTest *tc) {
 
     silver = get_resourcetype(R_SILVER)->itype;
 
-    sword = it_get_or_create(rt_get_or_create("sword"));
+    sword = test_create_itemtype("sword");
     new_weapontype(sword, 0, frac_zero, NULL, 0, 0, 0, SK_MELEE, 1);
     i_change(&u->items, sword, 1);
     set_level(u, SK_MELEE, 1);
diff --git a/src/give.test.c b/src/give.test.c
index 33f70fb90..1767dec36 100644
--- a/src/give.test.c
+++ b/src/give.test.c
@@ -324,8 +324,7 @@ static void test_give_herbs(CuTest * tc) {
     struct order *ord;
 
     test_setup_ex(tc);
-    test_create_world();
-    env.f2 = env.f1 = test_create_faction(0);
+    env.f2 = env.f1 = test_create_faction(NULL);
     setup_give(&env);
     i_change(&env.src->items, env.itype, 10);
 
diff --git a/src/kernel/faction.test.c b/src/kernel/faction.test.c
index c01731964..80faba3c1 100644
--- a/src/kernel/faction.test.c
+++ b/src/kernel/faction.test.c
@@ -153,8 +153,7 @@ static void test_set_origin(CuTest *tc) {
     int x = 0, y = 0;
     plane *pl;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
     pl = create_new_plane(0, "", 0, 19, 0, 19, 0);
     f = test_create_faction(0);
     CuAssertPtrEquals(tc, 0, f->ursprung);
@@ -179,8 +178,7 @@ static void test_set_origin_bug(CuTest *tc) {
     plane *pl;
     int x = 17, y = 10;
 
-    test_cleanup();
-    test_create_world();
+    test_setup();
     pl = create_new_plane(0, "", 0, 19, 0, 19, 0);
     f = test_create_faction(0);
     faction_setorigin(f, 0, -10, 3);
diff --git a/src/reports.test.c b/src/reports.test.c
index 976e9dfe1..f66d94684 100644
--- a/src/reports.test.c
+++ b/src/reports.test.c
@@ -45,18 +45,11 @@ static void test_reorder_units(CuTest * tc)
     ship * s;
     unit *u0, *u1, *u2, *u3, *u4;
     struct faction * f;
-    const building_type *btype;
-    const ship_type *stype;
 
-    test_cleanup();
-    test_create_world();
-
-    btype = bt_find("castle");
-    stype = st_find("boat");
-
-    r = findregion(-1, 0);
-    b = test_create_building(r, btype);
-    s = test_create_ship(r, stype);
+    test_setup();
+    r = test_create_region(0, 0, NULL);
+    b = test_create_building(r, NULL);
+    s = test_create_ship(r, NULL);
     f = test_create_faction(0);
 
     u0 = test_create_unit(f, r);
diff --git a/src/spells/magicresistance.test.c b/src/spells/magicresistance.test.c
index e9cc98e34..621d2c3b4 100644
--- a/src/spells/magicresistance.test.c
+++ b/src/spells/magicresistance.test.c
@@ -28,13 +28,12 @@ static void test_magicresistance_unit(CuTest *tc) {
     message *msg;
     curse *c;
 
-    test_cleanup();
-    test_create_world();
-    r=findregion(0, 0);
-    f1 = test_create_faction(test_create_race("human"));
+    test_setup();
+    r = test_create_plain(0, 0);
+    f1 = test_create_faction(NULL);
     u1 = test_create_unit(f1, r);
 
-    f2 = test_create_faction(test_create_race("human"));
+    f2 = test_create_faction(NULL);
     u2 = test_create_unit(f2, r);
 
     c = create_curse(u1, &u2->attribs, ct_find("magicresistance"), 10, 20, 30, u2->number);
@@ -56,13 +55,12 @@ static void test_magicresistance_building(CuTest *tc) {
     message *msg;
     curse *c;
 
-    test_cleanup();
-    test_create_world();
-    r = findregion(0, 0);
-    f1 = test_create_faction(test_create_race("human"));
+    test_setup();
+    r = test_create_plain(0, 0);
+    f1 = test_create_faction(NULL);
     u1 = test_create_unit(f1, r);
 
-    b1 = test_create_building(r, test_create_buildingtype("castle"));
+    b1 = test_create_building(r, NULL);
 
     c = create_curse(u1, &b1->attribs, ct_find("magicresistance"), 10, 20, 30, 0);
     CuAssertPtrNotNull(tc, b1->attribs);