From 260d518fa131bcd30f2a29178bebdc1997c97d0d Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno@eressea.de>
Date: Tue, 26 Jun 2007 09:32:28 +0000
Subject: [PATCH] WIP, does not compile: Unicode (UTF8) conversion of
 absolutely everything. Mi'kmaq hieroglyphic writing FTW!

---
 src/common/gamecode/archetype.c       |   6 +-
 src/common/gamecode/archetype.h       |   2 +-
 src/common/gamecode/creation.c        |   4 +-
 src/common/gamecode/creport.c         |  23 +-
 src/common/gamecode/economy.c         |  80 +++---
 src/common/gamecode/give.c            |  33 ++-
 src/common/gamecode/laws.c            | 170 +++++++++---
 src/common/gamecode/monster.c         |  44 ++--
 src/common/gamecode/randenc.c         | 179 +++++--------
 src/common/gamecode/report.c          |  36 +++
 src/common/gamecode/study.c           |  50 ++--
 src/common/gamecode/study.h           |   2 +-
 src/common/gamecode/xmlreport.c       |   4 +-
 src/common/kernel/alliance.c          |  13 +-
 src/common/kernel/battle.c            |   2 +-
 src/common/kernel/building.c          |   5 +-
 src/common/kernel/building.h          |   6 +-
 src/common/{util => kernel}/command.c |  44 ++--
 src/common/{util => kernel}/command.h |   4 +-
 src/common/kernel/eressea.c           | 112 ++++----
 src/common/kernel/eressea.h           |  46 ++--
 src/common/kernel/faction.c           |  21 +-
 src/common/kernel/faction.h           |  12 +-
 src/common/kernel/item.c              |   6 +-
 src/common/kernel/item.h              |   4 +-
 src/common/kernel/kernel.vcproj       |   6 +
 src/common/kernel/magic.c             |  54 ++--
 src/common/kernel/magic.h             |   8 +-
 src/common/kernel/message.c           |   4 +-
 src/common/kernel/movement.c          |  72 ++---
 src/common/kernel/names.c             |  74 +++---
 src/common/kernel/names.h             |  16 +-
 src/common/kernel/order.c             | 215 ++++++++-------
 src/common/kernel/order.h             |  23 +-
 src/common/kernel/pool.c              |   7 +-
 src/common/kernel/race.c              |   2 +-
 src/common/kernel/race.h              |   6 +-
 src/common/kernel/region.c            |  27 +-
 src/common/kernel/region.h            |   8 +-
 src/common/kernel/reports.c           |  53 +++-
 src/common/kernel/reports.h           |   8 +-
 src/common/kernel/save.c              | 261 +++++++-----------
 src/common/kernel/save.h              |   2 +-
 src/common/kernel/ship.c              |  15 +-
 src/common/kernel/ship.h              |   6 +-
 src/common/kernel/skill.c             |   4 +-
 src/common/kernel/skill.h             |   3 +-
 src/common/kernel/spell.c             |   4 +-
 src/common/kernel/spell.h             |   1 +
 src/common/kernel/teleport.c          |   1 -
 src/common/kernel/unit.c              |  42 +--
 src/common/kernel/unit.h              |  16 +-
 src/common/kernel/xmlreader.c         |   8 +-
 src/common/modules/arena.c            |  52 ++--
 src/common/modules/arena.h            |   2 +
 src/common/modules/autoseed.c         |  10 +-
 src/common/modules/autoseed.h         |   2 +-
 src/common/modules/gmcmd.c            | 202 ++++++--------
 src/common/modules/museum.c           |  10 +-
 src/common/modules/score.c            |   9 +-
 src/common/modules/xecmd.c            |   2 +-
 src/common/spells/alp.c               |  27 +-
 src/common/spells/combatspells.c      |  78 ++----
 src/common/spells/spells.c            | 310 ++++++++--------------
 src/common/triggers/unitmessage.c     |   8 +-
 src/common/util/Jamfile               |   1 +
 src/common/util/language.c            |  25 +-
 src/common/util/language.h            |  11 +-
 src/common/util/language_struct.h     |   2 +-
 src/common/util/nrmessage.c           |   4 +-
 src/common/util/nrmessage.h           |   2 +-
 src/common/util/parser.c              | 121 +++++++--
 src/common/util/parser.h              |   6 +-
 src/common/util/umlaut.c              | 260 +++++++++---------
 src/common/util/umlaut.h              |   4 +-
 src/common/util/unicode.h             |   1 -
 src/common/util/util.vcproj           |  20 +-
 src/config.h                          |   2 +
 src/eressea.sln                       |  13 +
 src/eressea/korrektur.c               |  31 +--
 src/eressea/lua/faction.cpp           |   4 +-
 src/eressea/main.c                    |   2 +-
 src/res/de/strings.xml                | 132 ++++++++++
 src/res/messages.xml                  | 363 ++++++++++++++++++++++++--
 src/res/races.xml                     |  13 +-
 85 files changed, 2006 insertions(+), 1577 deletions(-)
 rename src/common/{util => kernel}/command.c (71%)
 rename src/common/{util => kernel}/command.h (90%)

diff --git a/src/common/gamecode/archetype.c b/src/common/gamecode/archetype.c
index 5587a4494..de16dadc0 100644
--- a/src/common/gamecode/archetype.c
+++ b/src/common/gamecode/archetype.c
@@ -30,7 +30,7 @@ struct attrib_type at_recruit = {
 };
 
 const struct archetype *
-find_archetype(const char * s, const struct locale * lang)
+find_archetype(const xmlChar * s, const struct locale * lang)
 {
   struct tnode * tokens = get_translations(lang, UT_ARCHETYPES);
   variant token;
@@ -57,13 +57,13 @@ init_archetypes(void)
     archetype * arch = archetypes;
     struct tnode * tokens = get_translations(lang, UT_ARCHETYPES);
     for (;arch;arch=arch->next) {
-      const char *s1, *s2;
+      const xmlChar *s1, *s2;
       var.v = arch;
 
       s1 = LOC(lang, arch->name[0]);
       addtoken(tokens, s1, var);
       s2 = LOC(lang, arch->name[1]);
-      if (strcmp(s2, s1)!=0) {
+      if (xmlStrcmp(s2, s1)!=0) {
         addtoken(tokens, s2, var);
       }
     }
diff --git a/src/common/gamecode/archetype.h b/src/common/gamecode/archetype.h
index f500794bc..977ffce5d 100644
--- a/src/common/gamecode/archetype.h
+++ b/src/common/gamecode/archetype.h
@@ -33,7 +33,7 @@ extern "C" {
     struct rule * rules;
   } archetype;
 
-  extern const struct archetype * find_archetype(const char * s, const struct locale * lang);
+  extern const struct archetype * find_archetype(const xmlChar * s, const struct locale * lang);
   extern void init_archetypes(void);
   extern void register_archetype(struct archetype * arch);
   extern void register_archetypes(void);
diff --git a/src/common/gamecode/creation.c b/src/common/gamecode/creation.c
index d7c61c458..69c3d1463 100644
--- a/src/common/gamecode/creation.c
+++ b/src/common/gamecode/creation.c
@@ -68,8 +68,8 @@ createmonsters(void)
 	/* alles ist auf null gesetzt, ausser dem folgenden. achtung - partei
 	 * no 0 muss keine orders einreichen! */
 
-	set_string(&f->email, "monsters@eressea.de");
-	set_string(&f->name, "Monster");
+	f->email = strdup("monsters@eressea.de");
+	set_string(&f->name, (xmlChar*)"Monster");
 	f->alive = 1;
 	f->options = (char)(1<<O_REPORT);
 	addlist(&factions, f);
diff --git a/src/common/gamecode/creport.c b/src/common/gamecode/creport.c
index b8646730d..c6e2c0862 100644
--- a/src/common/gamecode/creport.c
+++ b/src/common/gamecode/creport.c
@@ -229,7 +229,7 @@ print_curses(FILE * F, const faction * viewer, const void * obj, typ_t typ)
     unit *u = (unit *)obj;
     a = u->attribs;
     r = u->region;
-    if (u->faction == viewer){
+    if (u->faction == viewer) {
       self = 2;
     }
   } else if (typ == TYP_REGION) {
@@ -422,6 +422,26 @@ cr_resources(variant var, char * buffer, const void * userdata)
   return 0;
 }
 
+static int
+cr_regions(variant var, char * buffer, const void * userdata)
+{
+  const faction * report = (const faction*)userdata;
+  const arg_regions * rdata = (const arg_regions *)var.v;
+  char * wp = buffer;
+  if (rdata!=NULL && rdata->nregions>0) {
+    region * r = rdata->regions[0];
+    int i, z = r->planep?r->planep->id:0;
+    wp += sprintf(wp, "\"%d %d %d", r->x, r->y, z);
+    for (i=1;i!=rdata->nregions;++i) {
+      r = rdata->regions[i];
+      z = r->planep?r->planep->id:0;
+      wp += sprintf(wp, ", %d %d %d", r->x, r->y, z);
+    }
+    strcat(wp, "\"");
+  }
+  return 0;
+}
+
 static int
 cr_spell(variant var, char * buffer, const void * userdata)
 {
@@ -1495,6 +1515,7 @@ creport_init(void)
   tsf_register("direction", &cr_int);
   tsf_register("alliance", &cr_alliance);
   tsf_register("resources", &cr_resources);
+  tsf_register("regions", &cr_regions);
 
   register_reporttype("cr", &report_computer, 1<<O_COMPUTER);
 }
diff --git a/src/common/gamecode/economy.c b/src/common/gamecode/economy.c
index 2cf6e8871..73453a514 100644
--- a/src/common/gamecode/economy.c
+++ b/src/common/gamecode/economy.c
@@ -64,6 +64,12 @@
 #include <util/parser.h>
 #include <util/rng.h>
 
+#include <attributes/reduceproduction.h>
+#include <attributes/racename.h>
+#include <attributes/orcification.h>
+
+#include <items/seed.h>
+
 /* libs includes */
 #include <math.h>
 #include <stdio.h>
@@ -71,11 +77,6 @@
 #include <assert.h>
 #include <limits.h>
 
-#include <attributes/reduceproduction.h>
-#include <attributes/racename.h>
-#include <attributes/orcification.h>
-
-#include <items/seed.h>
 
 typedef struct request {
   struct request * next;
@@ -443,15 +444,15 @@ recruit(unit * u, struct order * ord, request ** recruitorders)
 
   init_tokens(ord);
   skip_token();
-  n = geti();
+  n = getuint();
   if (f->no==MONSTER_FACTION) {
     /* Monster d�rfen REKRUTIERE 15 dracoid machen */
-    const char * str = getstrtoken();
+    const xmlChar * str = getstrtoken();
     if (str!=NULL && *str) {
       for (rc = races;rc;rc=rc->next) {
-        if (strncasecmp(LOC(f->locale, rc->_name[0]), str, strlen(str))==0)
+        if (xmlStrncasecmp(LOC(f->locale, rc->_name[0]), str, xmlStrlen(str))==0)
           break;
-        if (strncasecmp(LOC(f->locale, rc->_name[1]), str, strlen(str))==0)
+        if (xmlStrncasecmp(LOC(f->locale, rc->_name[1]), str, xmlStrlen(str))==0)
           break;
       }
     }
@@ -571,7 +572,7 @@ give_cmd(unit * u, order * ord)
 {
   region * r = u->region;
   unit *u2;
-  const char *s;
+  const xmlChar *s;
   int i, n;
   const item_type * itype;
   param_t p;
@@ -606,6 +607,8 @@ give_cmd(unit * u, order * ord)
   p = findparam(s, u->faction->locale);
 
   if (p == P_CONTROL) {
+    message * msg;
+
     if (!u2) {
       ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", ""));
       return;
@@ -633,13 +636,12 @@ give_cmd(unit * u, order * ord)
     freset(u, UFL_OWNER);
     fset(u2, UFL_OWNER);
 
-    ADDMSG(&u->faction->msgs,
-      msg_message("givecommand", "unit receipient", u, u2));
+    msg = msg_message("givecommand", "unit receipient", u, u2);
+    add_message(&u->faction->msgs, msg);
     if (u->faction != u2->faction) {
-      ADDMSG(&u2->faction->msgs,
-        msg_message("givecommand", "unit receipient",
-        ucansee(u2->faction, u, u_unknown()), u2));
+      add_message(&u2->faction->msgs, msg);
     }
+    msg_release(msg);
     return;
   }
 
@@ -721,7 +723,7 @@ give_cmd(unit * u, order * ord)
   }
 
   else if (p==P_ANY) {
-    const char * s = getstrtoken();
+    const xmlChar * s = getstrtoken();
 
     if (*s == 0) { /* Alle Gegenst�nde �bergeben */
 
@@ -802,7 +804,7 @@ give_cmd(unit * u, order * ord)
     s = getstrtoken(); /* skip one ahead to get the amount. */
   }
 
-  n = atoip(s);		/* n: anzahl */
+  n = atoip((const char *)s);		/* n: anzahl */
   if (p==P_EACH) {
     n *= u2->number;
   }
@@ -857,7 +859,7 @@ static int
 forget_cmd(unit * u, order * ord)
 {
 	skill_t sk;
-	const char *s;
+	const xmlChar *s;
   
   init_tokens(ord);
   skip_token();
@@ -1061,11 +1063,11 @@ static int
 recruit_archetype(unit * u, order * ord)
 {
   int want;
-  const char * s;
+  const xmlChar * s;
 
   init_tokens(ord);
   skip_token();
-  want = geti();
+  want = getuint();
   s = getstrtoken();
   if (want>0 && s && s[0]) {
     int n = want;
@@ -1733,16 +1735,16 @@ make_cmd(unit * u, struct order * ord)
   param_t p;
   int m;
   const item_type * itype;
-  const char *s;
+  const xmlChar *s;
   const struct locale * lang = u->faction->locale;
 
   init_tokens(ord);
   skip_token();
   s = getstrtoken();
 
-  m = atoi(s);
+  m = atoi((const char *)s);
   sprintf(buf, "%d", m);
-  if (!strcmp(buf, s)) {
+  if (!strcmp(buf, (const char *)s)) {
     /* first came a want-paramter */
     s = getstrtoken();
   } else {
@@ -1797,22 +1799,22 @@ make_cmd(unit * u, struct order * ord)
       /* if the item cannot be made, we probably didn't mean to make it */
       itype = NULL;
     } else if (stype!=NULL) {
-      const char * sname = LOC(lang, stype->name[0]);
-      const char * iname = LOC(lang, resourcename(itype->rtype, 0));
-      if (strlen(iname)<strlen(sname)) stype = NULL;
+      const xmlChar * sname = LOC(lang, stype->name[0]);
+      const xmlChar * iname = LOC(lang, resourcename(itype->rtype, 0));
+      if (xmlStrlen(iname)<xmlStrlen(sname)) stype = NULL;
       else itype = NULL;
     } else {
-      const char * bname = LOC(lang, btype->_name);
-      const char * iname = LOC(lang, resourcename(itype->rtype, 0));
-      if (strlen(iname)<strlen(bname)) btype = NULL;
+      const xmlChar * bname = LOC(lang, btype->_name);
+      const xmlChar * iname = LOC(lang, resourcename(itype->rtype, 0));
+      if (xmlStrlen(iname)<xmlStrlen(bname)) btype = NULL;
       else itype = NULL;
     }
   }
 
   if (btype!=NULL && stype!=NULL) {
-    const char * bname = LOC(lang, btype->_name);
-    const char * sname = LOC(lang, stype->name[0]);
-    if (strlen(sname)<strlen(bname)) btype = NULL;
+    const xmlChar * bname = LOC(lang, btype->_name);
+    const xmlChar * sname = LOC(lang, stype->name[0]);
+    if (xmlStrlen(sname)<xmlStrlen(bname)) btype = NULL;
     else stype = NULL;
   }
 
@@ -1980,7 +1982,7 @@ buy(unit * u, request ** buyorders, struct order * ord)
 
   init_tokens(ord);
   skip_token();
-	n = geti();
+	n = getuint();
 	if (!n) {
 		cmistake(u, ord, 26, MSG_COMMERCE);
 		return;
@@ -2245,7 +2247,7 @@ sell(unit * u, request ** sellorders, struct order * ord)
   const luxury_type * ltype=NULL;
   int n;
   region * r = u->region;
-  const char *s;
+  const xmlChar *s;
   
   if (u->ship && is_guarded(r, u, GUARD_CREWS)) {
 		cmistake(u, ord, 69, MSG_INCOME);
@@ -2268,7 +2270,7 @@ sell(unit * u, request ** sellorders, struct order * ord)
 			return false;
 		}
 	} else {
-		n = atoi(s);
+		n = atoi((const char *)s);
 		if (n==0) {
 			cmistake(u, ord, 27, MSG_COMMERCE);
 			return false;
@@ -2635,7 +2637,7 @@ static void
 breed_cmd(unit *u, struct order * ord)
 {
   int m;
-  const char *s;
+  const xmlChar *s;
   param_t p;
   region *r = u->region;
   const resource_type * rtype = NULL;
@@ -2650,7 +2652,7 @@ breed_cmd(unit *u, struct order * ord)
   skip_token();
   s = getstrtoken();
 
-  m = atoi(s);
+  m = atoi((const char *)s);
   if (m!=0) {
     /* first came a want-paramter */
     s = getstrtoken();
@@ -2936,7 +2938,7 @@ entertain_cmd(unit * u, struct order * ord)
 
   init_tokens(ord);
   skip_token();
-  max_e = geti();
+  max_e = getuint();
   if (max_e != 0) {
     u->wants = min(u->wants,max_e);
   }
@@ -3092,7 +3094,7 @@ tax_cmd(unit * u, struct order * ord, request ** taxorders)
 
   init_tokens(ord);
   skip_token();
-  max = geti();
+  max = getuint();
 
   if (max == 0) max = INT_MAX;
 	if (!playerrace(u->race)) {
diff --git a/src/common/gamecode/give.c b/src/common/gamecode/give.c
index f578d4586..973f79b97 100644
--- a/src/common/gamecode/give.c
+++ b/src/common/gamecode/give.c
@@ -66,16 +66,15 @@ add_give(unit * u, unit * u2, int n, const resource_type * rtype, struct order *
   if (error) {
     cmistake(u, ord, error, MSG_COMMERCE);
   }
-  else if (!u2 || u2->faction!=u->faction) {
-    assert(rtype);
+  else if (u2==NULL) {
     ADDMSG(&u->faction->msgs,
-      msg_message("give", "unit target resource amount",
-      u, u2?ucansee(u->faction, u2, u_unknown()):u_peasants(), rtype, n));
-    if (u2) {
-      ADDMSG(&u2->faction->msgs,
-        msg_message("give", "unit target resource amount",
-        ucansee(u2->faction, u, u_unknown()), u2, rtype, n));
-    }
+      msg_message("give_peasants", "unit resource amount",
+      u, rtype, n));
+  } else if (u2->faction!=u->faction) {
+    message * msg = msg_message("give", "unit target resource amount", u, u2, rtype, n);
+    add_message(&u->faction->msgs, msg);
+    add_message(&u2->faction->msgs, msg);
+    msg_release(msg);
   }
 }
 
@@ -300,14 +299,14 @@ give_men(int n, unit * u, unit * u2, struct order * ord)
   }
   if (error>0) {
     cmistake(u, ord, error, MSG_COMMERCE);
-  }
-  else if (!u2 || u2->faction!=u->faction) {
-    ADDMSG(&u->faction->msgs, msg_message("give_person", "unit target amount",
-      u, u2?ucansee(u->faction, u2, u_unknown()):u_peasants(), n));
-    if (u2) {
-      ADDMSG(&u2->faction->msgs, msg_message("give_person", "unit target amount",
-        ucansee(u2->faction, u, u_unknown()), u2, n));
-    }
+  } else if (!u2) {
+    ADDMSG(&u->faction->msgs,
+      msg_message("give_person_peasants", "unit amount", u, n));
+  } else if (u2->faction!=u->faction) {
+    message * msg = msg_message("give_person", "unit target amount", u, u2, n);
+    add_message(&u->faction->msgs, msg);
+    add_message(&u2->faction->msgs, msg);
+    msg_release(msg);
   }
 }
 
diff --git a/src/common/gamecode/laws.c b/src/common/gamecode/laws.c
index 6b5444084..bfc1f479d 100644
--- a/src/common/gamecode/laws.c
+++ b/src/common/gamecode/laws.c
@@ -81,6 +81,7 @@
 #include <util/rand.h>
 #include <util/rng.h>
 #include <util/sql.h>
+#include <util/umlaut.h>
 #include <util/message.h>
 #include <util/rng.h>
 
@@ -913,7 +914,7 @@ restart_cmd(unit * u, struct order * ord)
   if (!fval(u->region->terrain, LAND_REGION)) {
     ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_onlandonly", ""));
   } else {
-    const char * s_race = getstrtoken(), * s_pass;
+    const xmlChar * s_race = getstrtoken(), * s_pass;
     const race * frace = findrace(s_race, u->faction->locale);
 
     if (!frace) {
@@ -965,7 +966,7 @@ static int
 quit_cmd(unit * u, struct order * ord)
 {
   faction * f = u->faction;
-  const char * passwd;
+  const xmlChar * passwd;
 
   init_tokens(ord);
   skip_token(); /* skip keyword */
@@ -973,8 +974,7 @@ quit_cmd(unit * u, struct order * ord)
   passwd = getstrtoken();
   if (checkpasswd(f, passwd, false)) {
     if (EnhancedQuit()) {
-      const char * token = getstrtoken();
-      int f2_id = atoi36(token);
+      int f2_id = getid();
       if (f2_id>0) {
         faction *f2 = findfaction(f2_id);
 
@@ -988,6 +988,7 @@ quit_cmd(unit * u, struct order * ord)
           cmistake(u, ord, 316, MSG_EVENT);
           return 0;
         } else {
+          const char * token = itoa36(f2_id);
           set_variable(&f->attribs, "quit", token);
         }
       }
@@ -1062,8 +1063,7 @@ parse_restart(void)
       continue;
     }
     if (fval(f, FFL_OVERRIDE)) {
-      free(f->override);
-      f->override = strdup(itoa36(rng_int()));
+      set_string(&f->override, (xmlChar*)strdup(itoa36(rng_int())));
       freset(f, FFL_OVERRIDE);
     }
     if (turn!=f->lastorders) {
@@ -1124,7 +1124,7 @@ ally_cmd(unit * u, struct order * ord)
   ally * sf, ** sfp;
   faction *f;
   int keyword, not_kw;
-  const char *s;
+  const xmlChar *s;
 
   init_tokens(ord);
   skip_token();
@@ -1230,12 +1230,61 @@ ally_cmd(unit * u, struct order * ord)
   return 0;
 }
 
+static struct local_names * pnames;
+
+static void
+init_prefixnames(void)
+{
+  int i;
+  for (i=0;localenames[i];++i) {
+    const struct locale * lang = find_locale(localenames[i]);
+    boolean exist = false;
+    struct local_names * in = pnames;
+
+    while (in!=NULL) {
+      if (in->lang==lang) {
+        exist = true;
+        break;
+      }
+      in = in->next;
+    }
+    if (in==NULL) in = calloc(sizeof(local_names), 1);
+    in->next = pnames;
+    in->lang = lang;
+
+    if (!exist) {
+      int key;
+      for (key=0;race_prefixes[key];++key) {
+        variant var;
+        const xmlChar * pname = locale_string(lang, race_prefixes[key]);
+        if (findtoken(&in->names, pname, &var)==E_TOK_NOMATCH || var.i!=key) {
+          var.i = key;
+          addtoken(&in->names, pname, var);
+          addtoken(&in->names, locale_string(lang, race_prefixes[key]), var);
+        }
+      }
+    }
+    pnames = in;
+  }
+}
+
 static int
 prefix_cmd(unit * u, struct order * ord)
 {
   attrib **ap;
-  int i;
-  const char *s;
+  const xmlChar *s;
+  local_names * in = pnames;
+  variant var;
+  const struct locale * lang = u->faction->locale;
+
+  while (in!=NULL) {
+    if (in->lang==lang) break;
+    in = in->next;
+  }
+  if (in==NULL) {
+    init_prefixnames();
+    for (in=pnames;in->lang!=lang;in=in->next) ;
+  }
 
   init_tokens(ord);
   skip_token();
@@ -1255,34 +1304,65 @@ prefix_cmd(unit * u, struct order * ord)
     return 0;
   }
 
-  for(i=0; race_prefixes[i] != NULL; i++) {
-    const char * tag = mkname("prefix", race_prefixes[i]);
-    if (strncasecmp(s, LOC(u->faction->locale, tag), strlen(s)) == 0) {
-      break;
-    }
-  }
-
-  if (race_prefixes[i] == NULL) {
-    cmistake(u, ord, 299, MSG_EVENT);
+  if (findtoken(&in->names, s, &var)==E_TOK_NOMATCH) {
     return 0;
+  } else if (race_prefixes[var.i] == NULL) {
+    cmistake(u, ord, 299, MSG_EVENT);
+  } else {
+    ap = &u->faction->attribs;
+    if (fval(u, UFL_GROUP)) {
+      attrib * a = a_find(u->attribs, &at_group);
+      group * g = (group*)a->data.v;
+      if (a) ap = &g->attribs;
+    }
+    set_prefix(ap, race_prefixes[var.i]);
   }
-
-  ap = &u->faction->attribs;
-  if (fval(u, UFL_GROUP)) {
-    attrib * a = a_find(u->attribs, &at_group);
-    group * g = (group*)a->data.v;
-    if (a) ap = &g->attribs;
-  }
-  set_prefix(ap, race_prefixes[i]);
-
   return 0;
 }
 
+static struct local_names * synonyms;
+
+static void
+init_synonyms(void)
+{
+  int i;
+  for (i=0;localenames[i];++i) {
+    const struct locale * lang = find_locale(localenames[i]);
+    boolean exist = false;
+    struct local_names * in = synonyms;
+
+    while (in!=NULL) {
+      if (in->lang==lang) {
+        exist = true;
+        break;
+      }
+      in = in->next;
+    }
+    if (in==NULL) in = calloc(sizeof(local_names), 1);
+    in->next = synonyms;
+    in->lang = lang;
+
+    if (!exist) {
+      int key;
+      for (key=0;race_prefixes[key];++key) {
+        variant var;
+        const xmlChar * pname = locale_string(lang, race_prefixes[key]);
+        if (findtoken(&in->names, pname, &var)==E_TOK_NOMATCH || var.i!=key) {
+          var.i = key;
+          addtoken(&in->names, pname, var);
+          addtoken(&in->names, locale_string(lang, race_prefixes[key]), var);
+        }
+      }
+    }
+    synonyms = in;
+  }
+}
+
 static int
 display_cmd(unit * u, struct order * ord)
 {
   building * b = u->building;
-  char **s = NULL;
+  xmlChar **s = NULL;
   region * r = u->region;
 
   init_tokens(ord);
@@ -1332,7 +1412,7 @@ display_cmd(unit * u, struct order * ord)
 
   case P_PRIVAT:
     {
-      const char *d = getstrtoken();
+      const xmlChar *d = getstrtoken();
       if(d == NULL || *d == 0) {
         usetprivate(u, NULL);
       } else {
@@ -1363,10 +1443,10 @@ display_cmd(unit * u, struct order * ord)
   }
 
   if (s!=NULL) {
-    const char * s2 = getstrtoken();
+    const xmlChar * s2 = getstrtoken();
 
     if (strlen(s2)>=DISPLAYSIZE) {
-      char * s3 = strdup(s2);
+      xmlChar * s3 = strdup(s2);
       s3[DISPLAYSIZE] = 0;
       set_string(s, s3);
       free(s3);
@@ -3763,6 +3843,33 @@ static void reset_rng(void) {
   else rng_init(turn);
 }
 
+/** warn about passwords that are not US ASCII.
+ * even though passwords are technically UTF8 strings, the server receives
+ * them as part of the Subject of an email when reports are requested.
+ * This means that we need to limit them to ASCII characters until that
+ * mechanism has been changed.
+ */
+static int
+warn_password(void)
+{
+  faction * f = factions;
+  while (f) {
+    boolean pwok = true;
+    const char * c = f->passw;
+    while (*c) {
+      if (!isalnum((unsigned char)*c)) pwok = false;
+      c++;
+    }
+    if (pwok == false) {
+      free(f->passw);
+      f->passw = strdup(itoa36(rng_int()));
+      ADDMSG(&f->msgs, msg_message("illegal_password", "newpass", f->passw));
+    }
+    f = f->next;
+  }
+  return 0;
+}
+
 void
 processorders (void)
 {
@@ -3938,6 +4045,7 @@ processorders (void)
   /* immer ausf�hren, wenn neue Spr�che dazugekommen sind, oder sich
    * Beschreibungen ge�ndert haben */
   update_spells();
+  warn_password();
 }
 
 int
diff --git a/src/common/gamecode/monster.c b/src/common/gamecode/monster.c
index 6d650c2e7..e4d4aad2a 100644
--- a/src/common/gamecode/monster.c
+++ b/src/common/gamecode/monster.c
@@ -59,6 +59,7 @@
 /* util includes */
 #include <util/attrib.h>
 #include <util/base36.h>
+#include <util/bsdstring.h>
 #include <util/event.h>
 #include <util/lists.h>
 #include <util/rand.h>
@@ -136,7 +137,7 @@ monster_attack(unit * u, const unit * target)
   sprintf(zText, "%s %s",
           locale_string(u->faction->locale, keywords[K_ATTACK]), 
           unitid(target));
-  return parse_order(zText, u->faction->locale);
+  return parse_order((xmlChar*)zText, u->faction->locale);
 }
 
 
@@ -157,7 +158,9 @@ get_money_for_dragon(region * r, unit * u, int wanted)
 	/* falls genug geld in der region ist, treiben wir steuern ein. */
   if (rmoney(r) >= wanted) {
     /* 5% chance, dass der drache aus einer laune raus attackiert */
-    if (chance(1.0-u->race->aggression)) return parse_order(keywords[K_TAX], default_locale);
+    if (chance(1.0-u->race->aggression)) {
+      return parse_order(LOC(default_locale, keywords[K_TAX]), default_locale);
+    }
   }
 
   /* falls der drache launisch ist, oder das regionssilber knapp, greift er alle an */
@@ -179,7 +182,7 @@ get_money_for_dragon(region * r, unit * u, int wanted)
   /* falls die einnahmen erreicht werden, bleibt das monster noch eine
 	 * runde hier. */
   if (n + rmoney(r) >= wanted) {
-    return parse_order(keywords[K_TAX], default_locale);
+    return parse_order(LOC(default_locale, keywords[K_TAX]), default_locale);
   }
 
   /* wenn wir NULL zur�ckliefern, macht der drache was anderes, z.b. weggehen */
@@ -352,6 +355,7 @@ static order *
 monster_move(region * r, unit * u)
 {
   direction_t d = NODIRECTION;
+  xmlChar zOrder[64];
 
   if (is_waiting(u)) return NULL;
   switch(old_race(u->race)) {
@@ -374,11 +378,11 @@ monster_move(region * r, unit * u)
   if (d == NODIRECTION)
     return NULL;
 
-  sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]), 
+  sprintf((char*)zOrder, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]), 
           locale_string(u->faction->locale, directions[d]));
 
   reduce_weight(u);
-  return parse_order(buf, u->faction->locale);
+  return parse_order(zOrder, u->faction->locale);
 }
 
 /* Wir machen das mal autoconf-style: */
@@ -441,9 +445,11 @@ set_new_dragon_target(unit * u, region * r, int range)
 		} else {
 			a->data.v = max_region;
 		}
+#if 0
 		sprintf(buf, "Kommt aus: %s, Will nach: %s", 
       regionname(r, u->faction), regionname(max_region, u->faction));
 		usetprivate(u, buf);
+#endif
 		return a;
 	}
 	return NULL;
@@ -455,27 +461,26 @@ make_movement_order(unit * u, const region * target, int moves, boolean (*allowe
 	region * r = u->region;
 	region ** plan;
 	int position = 0;
-	char * c;
+  xmlChar zOrder[128];
+  char * c = (char*)zOrder;
 
   if (is_waiting(u)) return NULL;
 
   plan = path_find(r, target, DRAGON_RANGE*5, allowed);
 	if (plan==NULL) return NULL;
 
-	strcpy(buf, locale_string(u->faction->locale, keywords[K_MOVE]));
-	c = buf + strlen(buf);
+	c += strlcpy(c, (const char *)LOC(u->faction->locale, keywords[K_MOVE]), sizeof(zOrder));
 
-	while (position!=moves && plan[position+1]) {
+  while (position!=moves && plan[position+1]) {
 		region * prev = plan[position];
 		region * next = plan[++position];
 		direction_t dir = reldirection(prev, next);
 		assert(dir!=NODIRECTION && dir!=D_SPECIAL);
 		*c++ = ' ';
-		strcpy(c, locale_string(u->faction->locale, directions[dir]));
-		c += strlen(c);
+		c += strlcpy(c, (const char *)LOC(u->faction->locale, directions[dir]), sizeof(zOrder)-(c-(const char *)zOrder));
 	}
 
-	return parse_order(buf, u->faction->locale);
+	return parse_order(zOrder, u->faction->locale);
 }
 
 static order *
@@ -486,6 +491,7 @@ monster_seeks_target(region *r, unit *u)
 	int dist, dist2;
 	direction_t i;
 	region *nr;
+  xmlChar zOrder[128];
 
 	/* Das Monster sucht ein bestimmtes Opfer. Welches, steht
 	 * in einer Referenz/attribut
@@ -533,9 +539,9 @@ monster_seeks_target(region *r, unit *u)
   }
   assert(d != NODIRECTION );
   
-  sprintf(buf, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]),
+  sprintf((char *)zOrder, "%s %s", locale_string(u->faction->locale, keywords[K_MOVE]),
           locale_string(u->faction->locale, directions[d]));
-  return parse_order(buf, u->faction->locale);
+  return parse_order(zOrder, u->faction->locale);
 }
 
 unit *
@@ -751,9 +757,10 @@ monster_learn(unit *u)
   for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) {
     if (sv->level>0) {
       if (++c == n) {
-        sprintf(buf, "%s \"%s\"", locale_string(lang, keywords[K_STUDY]),
+        xmlChar zOrder[128];          
+        sprintf((char*)zOrder, "%s \"%s\"", locale_string(lang, keywords[K_STUDY]),
                 skillname(sv->id, lang));
-        return parse_order(buf, lang);
+        return parse_order(zOrder, lang);
       }
     }
   }
@@ -809,12 +816,13 @@ recruit_dracoids(unit * dragon, int size)
   setstatus(un, ST_FIGHT);
   for (weapon=un->items;weapon;weapon=weapon->next) {
     const weapon_type * wtype = weapon->type->rtype->wtype;
+    xmlChar zOrder[128];
     if (wtype && (wtype->flags & WTF_MISSILE)) {
       setstatus(un, ST_BEHIND);
     }
-    sprintf(buf, "%s \"%s\"", keywords[K_STUDY], 
+    sprintf((char*)zOrder, "%s \"%s\"", keywords[K_STUDY], 
       skillname(weapon->type->rtype->wtype->skill, f->locale));
-    new_order = parse_order(buf, default_locale);
+    new_order = parse_order(zOrder, default_locale);
   }
 
   if (new_order!=NULL) {
diff --git a/src/common/gamecode/randenc.c b/src/common/gamecode/randenc.c
index 14e1c8113..d68f2a947 100644
--- a/src/common/gamecode/randenc.c
+++ b/src/common/gamecode/randenc.c
@@ -179,107 +179,78 @@ improve_all(faction * f, skill_t sk, int by_weeks)
 void
 find_manual(region * r, unit * u)
 {
+  char zLocation[32];
+  char zBook[32];
   skill_t skill = NOSKILL;
-  sprintf(buf, "%s stolper%c bei der Erforschung der Region �ber ",
-          unitname(u), "nt"[u->number == 1]);
-  
-  switch (rng_int() % 4) {
-  case 0:
-    scat("die Ruine eines alten Tempels");
-    break;
-  case 1:
-    scat("eine alte Burgruine");
-    break;
-  case 2:
-    scat("ein zerfallenes Bauernhaus");
-    break;
-  case 3:
-    scat("eine Leiche am Wegesrand");
-    break;
-  }
-  
-  scat(". Bei der Durchsuchung ");
-  if (u->number == 1) {
-    scat("st��t");
-  } else {
-    scat("sto�en");
-  }
-  scat(" sie auf das zerfledderte Exemplar eines alten Buches, betitelt ");
-  
+  message * msg;
+
   switch (rng_int() % 36) {
   case 0:
-    scat("\'Magie der Elemente\'");
     skill = SK_MAGIC;
     break;
   case 1:
   case 2:
   case 3:
   case 4:
-    scat("\'Schwerter, Armbr�ste, Langb�gen\'");
     skill = SK_WEAPONSMITH;
     break;
   case 5:
   case 6:
-    scat("\'Gorms Almanach der Rationellen Kriegsf�hrung\'");
     skill = SK_TACTICS;
     break;
   case 7:
   case 8:
   case 9:
   case 10:
-    scat("\'Katamarane, Koggen, Karavellen\'");
     skill = SK_SHIPBUILDING;
     break;
   case 11:
   case 12:
   case 13:
   case 14:
-    scat("\'Wege der Sterne\'");
     skill = SK_SAILING;
     break;
   case 15:
   case 16:
   case 17:
-    scat("\'Nadishahs Kleine Gift- und Kr�uterkunde\'");
     skill = SK_HERBALISM;
     break;
   case 18:
   case 19:
-    scat("\'Mandricks Kompendium der Alchemie\'");
     skill = SK_ALCHEMY;
     break;
   case 20:
   case 21:
   case 22:
   case 23:
-    scat("\'Die Konstruktion der Burgen und Schl�sser von Zentralandune\'");
     skill = SK_BUILDING;
     break;
   case 24:
   case 25:
   case 26:
   case 27:
-    scat("\'Die Esse\'");
     skill = SK_ARMORER;
     break;
   case 28:
   case 29:
   case 30:
   case 31:
-    scat("\'�ber die Gewinnung von Erzen\'");
     skill = SK_MINING;
     break;
   case 32:
   case 33:
   case 34:
   case 35:
-    scat("\'Barinions Lieder, eine Einf�hrung f�r Unbedarfte\'");
     skill = SK_ENTERTAINMENT;
     break;
   }
-  
-  scat(". Der Wissensschub ist enorm.");
-  addmessage(r, u->faction, buf, MSG_EVENT, ML_IMPORTANT);
+
+  sprintf(zLocation, "manual_location_%d", rng_int() % 4);
+  sprintf(zBook, "manual_title_%s", skillnames[skill]);
+
+  msg = msg_message("find_manual", "unit location book", u, zLocation, zBook);
+  r_addmessage(r, u->faction, msg);
+  msg_release(msg);
 
   if (improve_all(u->faction, skill, 3) == 3) {
     int i;
@@ -288,22 +259,17 @@ find_manual(region * r, unit * u)
 }
 
 static void
-get_unit(region * r, unit * u)
+get_villagers(region * r, unit * u)
 {
 	unit *newunit;
-	sprintf(buf, "%s entdeck%s ein kleines Dorf. Die meisten H�user "
-			"wurden durch einen �ber die Ufer getretenen Flu� zerst�rt. Eine "
-			"Gruppe der verzweifelten Menschen schlie�t sich deiner Partei an.",
-			unitname(u), "en\0t" + (3 - 3 * (u->number == 1)));
+  message * msg = msg_message("encounter_villagers", "unit", u);
+  const xmlChar * name = LOC(u->faction->locale, "villagers");
 
-	addmessage(r, u->faction, buf, MSG_EVENT, ML_IMPORTANT);
+  r_addmessage(r, u->faction, msg);
+  msg_release(msg);
 
-	newunit = createunit(r, u->faction, rng_int() % 20 + 3, u->faction->race);
+	newunit = create_unit(r, u->faction, rng_int() % 20 + 3, u->faction->race, 0, name, u);
   fset(newunit, UFL_ISNEW|UFL_MOVED);
-	set_string(&newunit->name, "Dorfbewohner");
-  if (fval(u, UFL_PARTEITARNUNG)) {
-    fset(newunit, UFL_PARTEITARNUNG);
-  }
   equip_unit(newunit, get_equipment("random_villagers"));
 }
 
@@ -311,17 +277,21 @@ static void
 get_allies(region * r, unit * u)
 {
 	unit *newunit = NULL;
+  const char * name;
+  const char * equip;
+  int number;
+  message * msg;
+
   assert(u->number);
 
-	switch (rterrain(r)) {
-
+  switch (rterrain(r)) {
 	case T_PLAIN:
 		if (!r_isforest(r)) {
 			if (get_money(u) / u->number < 100 + rng_int() % 200)
 				return;
-			newunit = createunit(r, u->faction, rng_int() % 8 + 2, u->faction->race);
-			set_string(&newunit->name, "S�ldner");
-      equip_unit(newunit, get_equipment("random_plain"));
+      name = "random_plain_men";
+      equip = "random_plain";
+      number = rng_int() % 8 + 2;
 			break;
 		} else {
 			if (eff_skill(u, SK_LONGBOW, r) < 3
@@ -329,9 +299,9 @@ get_allies(region * r, unit * u)
 				&& eff_skill(u, SK_MAGIC, r) < 2) {
 				return;
 			}
-			newunit = createunit(r, u->faction, rng_int() % 6 + 2, u->faction->race);
-			set_string(&newunit->name, "Waldbewohner");
-      equip_unit(newunit, get_equipment("random_forest"));
+      name = "random_forest_men";
+      equip = "random_forest";
+      number = rng_int() % 6 + 2;
 		}
 		break;
 
@@ -339,67 +309,65 @@ get_allies(region * r, unit * u)
 		if (eff_skill(u, SK_OBSERVATION, r) <= 3) {
 			return;
 		}
-		newunit = createunit(r, u->faction, rng_int() % 6 + 2, u->faction->race);
-		set_string(&newunit->name, "Sumpfbewohner");
-    equip_unit(newunit, get_equipment("random_swamp"));
+    name = "random_swamp_men";
+    equip = "random_swamp";
+    number = rng_int() % 6 + 2;
 		break;
 
 	case T_DESERT:
 		if (eff_skill(u, SK_RIDING, r) <= 2) {
 			return;
 		}
-		newunit = createunit(r, u->faction, rng_int() % 12 + 2, u->faction->race);
-		set_string(&newunit->name, "Berber");
-    equip_unit(newunit, get_equipment("random_desert"));
+    name = "random_desert_men";
+    equip = "random_desert";
+    number = rng_int() % 12 + 2;
 		break;
 
 	case T_HIGHLAND:
 		if (eff_skill(u, SK_MELEE, r) <= 1) {
 			return;
 		}
-		newunit = createunit(r, u->faction, rng_int() % 8 + 2, u->faction->race);
-		set_string(&newunit->name, "Hochlandbarbaren");
-    equip_unit(newunit, get_equipment("random_highland"));
+    name = "random_highland_men";
+    equip = "random_highland";
+    number = rng_int() % 8 + 2;
 		break;
 
 	case T_MOUNTAIN:
-		if (eff_skill(u, SK_MELEE, r) <= 1
-			|| eff_skill(u, SK_TRADE, r) <= 2) {
-			return;
-		}
-		newunit = createunit(r, u->faction, rng_int() % 6 + 2, u->faction->race);
-		set_string(&newunit->name, "Bergbewohner");
-    equip_unit(newunit, get_equipment("random_mountain"));
-
+    if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 2) {
+      return;
+    }
+    name = "random_mountain_men";
+    equip = "random_mountain";
+    number = rng_int() % 6 + 2;
 		break;
 
 	case T_GLACIER:
-		if (eff_skill(u, SK_MELEE, r) <= 1
-			|| eff_skill(u, SK_TRADE, r) <= 1) {
+		if (eff_skill(u, SK_MELEE, r) <= 1 || eff_skill(u, SK_TRADE, r) <= 1) {
 			return;
 		}
-		newunit = createunit(r, u->faction, rng_int() % 4 + 2, u->faction->race);
-		set_string(&newunit->name, "Eisleute");
-    equip_unit(newunit, get_equipment("random_glacier"));
-
+    name = "random_glacier_men";
+    equip = "random_glacier";
+    number = rng_int() % 4 + 2;
 		break;
+
+  default:
+    return;
 	}
 
-  if (newunit!=NULL) {
-	  u_setfaction(newunit, u->faction);
-	  set_racename(&newunit->attribs, get_racename(u->attribs));
-	  if(u->race->flags & RCF_SHAPESHIFT) {
-		  newunit->irace = u->irace;
-	  }
-	  if (fval(u, UFL_PARTEITARNUNG)) fset(newunit, UFL_PARTEITARNUNG);
-	  fset(newunit, UFL_ISNEW);
+  newunit = create_unit(r, u->faction, number, u->faction->race, 0, LOC(u->faction->locale, name), u);
+  equip_unit(newunit, get_equipment(equip));
 
-	  sprintf(buf, "Pl�tzlich stolper%c %s �ber einige %s. Nach kurzem "
-		  "Z�gern entschlie�en sich die %s, sich Deiner Partei anzuschlie�en.",
-	  u->number == 1 ? 't' : 'n', unitname(u), newunit->name, newunit->name);
+	u_setfaction(newunit, u->faction);
+	set_racename(&newunit->attribs, get_racename(u->attribs));
+	if(u->race->flags & RCF_SHAPESHIFT) {
+		newunit->irace = u->irace;
+	}
+	if (fval(u, UFL_PARTEITARNUNG)) fset(newunit, UFL_PARTEITARNUNG);
+	fset(newunit, UFL_ISNEW);
 
-	  addmessage(r, u->faction, buf, MSG_EVENT, ML_IMPORTANT);
-  }
+  msg = msg_message("encounter_allies", "unit name", u, name);
+  r_addmessage(r, u->faction, msg);
+  msg_release(msg);
 }
 
 static void
@@ -413,7 +381,7 @@ encounter(region * r, unit * u)
 		find_manual(r, u);
 		break;
 	case 1:
-		get_unit(r, u);
+		get_villagers(r, u);
 		break;
 	case 2:
 		get_allies(r, u);
@@ -484,9 +452,7 @@ chaos(region * r)
 			if (!fval(r->terrain, SEA_REGION)) {
 				u = random_unit(r);
 				if (u && playerrace(u->race)) {
-					sprintf(buf, "%s scheint von einer seltsamen Krankheit befallen.",
-							unitname(u));
-					addmessage(0, u->faction, buf, MSG_EVENT, ML_IMPORTANT);
+          ADDMSG(&u->faction->msgs, msg_message("chaos_disease", "unit", u));
 					u_setfaction(u, findfaction(MONSTER_FACTION));
 					u->race = new_race[RC_GHOUL];
 				}
@@ -499,29 +465,14 @@ chaos(region * r)
 				case 0:
 					mfac = 100;
 					u = createunit(r, findfaction(MONSTER_FACTION), rng_int() % 8 + 1, new_race[RC_FIREDRAGON]);
-					if (u->number == 1) {
-						set_string(&u->name, "Feuerdrache");
-					} else {
-						set_string(&u->name, "Feuerdrachen");
-					}
 					break;
 				case 1:
 					mfac = 500;
 					u = createunit(r, findfaction(MONSTER_FACTION), rng_int() % 4 + 1, new_race[RC_DRAGON]);
-					if (u->number == 1) {
-						set_string(&u->name, "Drache");
-					} else {
-						set_string(&u->name, "Drachen");
-					}
 					break;
 				case 2:
 					mfac = 1000;
 					u = createunit(r, findfaction(MONSTER_FACTION), rng_int() % 2 + 1, new_race[RC_WYRM]);
-					if (u->number == 1) {
-						set_string(&u->name, "Wyrm");
-					} else {
-						set_string(&u->name, "Wyrme");
-					}
 					break;
 				}
 				if (mfac) set_money(u, u->number * (rng_int() % mfac));
diff --git a/src/common/gamecode/report.c b/src/common/gamecode/report.c
index d42c128cd..27f3318da 100644
--- a/src/common/gamecode/report.c
+++ b/src/common/gamecode/report.c
@@ -3057,6 +3057,41 @@ eval_resources(struct opstack ** stack, const void * userdata) /* order -> strin
   opush(stack, var);
 }
 
+static void
+eval_regions(struct opstack ** stack, const void * userdata) /* order -> string */
+{
+  const faction * report = (const faction*)userdata;
+  int i = opop(stack).i;
+  int end, begin = opop(stack).i;
+  const arg_regions * regions = (const arg_regions *)opop(stack).v;
+  static char buf[256];
+  size_t len = sizeof(buf);
+  variant var;
+  char * edit = buf;
+
+  if (regions==NULL) {
+    end = begin;
+  } else {
+    if (i>=0) end = begin+i;
+    else end = regions->nregions+i;
+  }
+  for (i=begin;i<end;++i) {
+    const char * rname = (const char*)regionname(regions->regions[i], report);
+    size_t written = strlcpy(edit, rname, len);
+    len -= written;
+    edit += written;
+
+    if (i+1<end && len>2) {
+      strcat(edit, ", ");
+      edit += 2;
+      len -= 2;
+    }
+  }
+  *edit = 0;
+  var.v = strcpy(balloc(edit-buf+1), buf);
+  opush(stack, var);
+}
+
 static void
 eval_direction(struct opstack ** stack, const void * userdata)
 {
@@ -3122,6 +3157,7 @@ report_init(void)
   add_function("localize", &eval_localize);
   add_function("spell", &eval_spell);
   add_function("resources", &eval_resources);
+  add_function("regions", &eval_regions);
 
   register_reporttype("nr", &report_plaintext, 1<<O_REPORT);
   register_reporttype("txt", &report_template, 1<<O_ZUGVORLAGE);
diff --git a/src/common/gamecode/study.c b/src/common/gamecode/study.c
index d2564900f..6ede37837 100644
--- a/src/common/gamecode/study.c
+++ b/src/common/gamecode/study.c
@@ -48,6 +48,7 @@
 #include <util/base36.h>
 #include <util/parser.h>
 #include <util/rand.h>
+#include <util/umlaut.h>
 
 /* libc includes */
 #include <assert.h>
@@ -65,16 +66,17 @@ getskill(const struct locale * lang)
 	return findskill(getstrtoken(), lang);
 }
 
-static magic_t
-findmagicskill(const char *s)
-{
-	return (char) findstr(magietypen, s, MAXMAGIETYP);
-}
-
 magic_t
-getmagicskill(void)
+getmagicskill(const struct locale * lang)
 {
-	return findmagicskill(getstrtoken());
+  struct tnode * tokens = get_translations(lang, UT_MAGIC);
+  variant token;
+  const xmlChar * s = getstrtoken();
+
+  if (findtoken(tokens, s, &token)==E_TOK_SUCCESS) {
+    return (magic_t)token.i;
+  }
+  return M_NONE;
 }
 
 /* ------------------------------------------------------------- */
@@ -346,13 +348,13 @@ teach_cmd(unit * u, struct order * ord)
   else
 #endif
   {
-    static char zOrder[BUFSIZE];
+    static xmlChar zOrder[BUFSIZE];
     order * new_order;
 
     init_tokens(ord);
     skip_token();
 
-    strcpy(zOrder, locale_string(u->faction->locale, keywords[K_TEACH]));
+    strcpy((char*)zOrder, (const char *)locale_string(u->faction->locale, keywords[K_TEACH]));
 
     while (!parser_end()) {
       unit * u2 = getunit(r, u->faction);
@@ -361,7 +363,9 @@ teach_cmd(unit * u, struct order * ord)
       /* Falls die Unit nicht gefunden wird, Fehler melden */
 
       if (!u2) {
-        const char * token;
+        xmlChar tbuf[20];
+        const xmlChar * uid;
+        const xmlChar * token;
         /* Finde den string, der den Fehler verursacht hat */
         parser_pushstate();
         init_tokens(ord);
@@ -377,16 +381,16 @@ teach_cmd(unit * u, struct order * ord)
         /* Beginne die Fehlermeldung */
         strcpy(buf, "Die Einheit '");
 
-        if (findparam(token, u->faction->locale) == P_TEMP) {
-          /* F�r: "Die Einheit 'TEMP ZET' wurde nicht gefunden" oder "Die Einheit
-          * 'TEMP' wurde nicht gefunden" */
-          scat(token);
+        if (findparam(token, u->faction->locale) != P_TEMP) {
+          uid = token;
+        } else {
           token = getstrtoken();
-          if (*token) scat(" ");
+          sprintf((char*)tbuf, "%s %s", LOC(u->faction->locale,
+            parameters[P_TEMP]), token);
+          uid = tbuf;
         }
-        scat(token);
-        scat("' wurde nicht gefunden");
-        mistake(u, ord, buf, MSG_EVENT);
+        ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "unitnotfound_id",
+          "id", uid));
 
         parser_popstate();
         continue;
@@ -394,8 +398,8 @@ teach_cmd(unit * u, struct order * ord)
 
       /* Neuen Befehl zusammenbauen. TEMP-Einheiten werden automatisch in
        * ihre neuen Nummern �bersetzt. */
-      strcat(zOrder, " ");
-      strcat(zOrder, unitid(u2));
+      strcat((char*)zOrder, " ");
+      strcat((char*)zOrder, unitid(u2));
 
       if (get_keyword(u2->thisorder) != K_STUDY) {
         ADDMSG(&u->faction->msgs,
@@ -558,7 +562,7 @@ learn_cmd(unit * u, order * ord)
         mistake(u, ord, buf, MSG_EVENT);
         return 0;
       }
-      mtyp = getmagicskill();
+      mtyp = getmagicskill(u->faction->locale);
       if (mtyp == M_NONE || mtyp == M_GRAU) {
         /* wurde kein Magiegebiet angegeben, wird davon
         * ausgegangen, da� das normal gelernt werden soll */
@@ -588,7 +592,7 @@ learn_cmd(unit * u, order * ord)
       /* ist schon ein Magier und kein Vertrauter */
       if(u->faction->magiegebiet == 0){
         /* die Partei hat noch kein Magiegebiet gew�hlt. */
-        mtyp = getmagicskill();
+        mtyp = getmagicskill(u->faction->locale);
         if (mtyp == M_NONE){
           cmistake(u, ord, 178, MSG_MAGIC);
           return 0;
diff --git a/src/common/gamecode/study.h b/src/common/gamecode/study.h
index 0397f1a7a..efbaa8c8c 100644
--- a/src/common/gamecode/study.h
+++ b/src/common/gamecode/study.h
@@ -22,7 +22,7 @@ extern "C" {
 extern int teach_cmd(struct unit * u, struct order * ord);
 extern int learn_cmd(struct unit * u, struct order * ord);
 
-extern magic_t getmagicskill(void);
+extern magic_t getmagicskill(const struct locale * lang);
 extern boolean is_migrant(struct unit *u);
 extern int study_cost(struct unit *u, skill_t talent);
 
diff --git a/src/common/gamecode/xmlreport.c b/src/common/gamecode/xmlreport.c
index edaaf6abb..9953d37b9 100644
--- a/src/common/gamecode/xmlreport.c
+++ b/src/common/gamecode/xmlreport.c
@@ -107,9 +107,9 @@ report_faction(report_context * ctx, faction * f)
 {
   xmlNodePtr node = xmlNewNode(NULL, BAD_CAST "faction");
   xmlNewProp(node, BAD_CAST "id", xml_i(f->no));
-  xmlNewProp(node, BAD_CAST "name", xml_s(f->name));
+  xmlNewProp(node, BAD_CAST "name", f->name);
   xmlNewProp(node, BAD_CAST "email", xml_s(f->email));
-  if (f->banner && *f->banner) xmlNewProp(node, BAD_CAST "banner", xml_s(f->banner));
+  if (f->banner && *f->banner) xmlNewProp(node, BAD_CAST "banner", f->banner);
   if (f==ctx->f) {
     const char * s;
     xmlNewProp(node, BAD_CAST "locale", BAD_CAST locale_name(f->locale));
diff --git a/src/common/kernel/alliance.c b/src/common/kernel/alliance.c
index 787eafdd2..074520dc6 100644
--- a/src/common/kernel/alliance.c
+++ b/src/common/kernel/alliance.c
@@ -24,12 +24,13 @@
 #include <kernel/region.h>
 #include <kernel/unit.h>
 #include <kernel/item.h>
+#include <kernel/command.h>
 
 /* util includes */
 #include <util/attrib.h>
 #include <util/base36.h>
-#include <util/command.h>
 #include <util/lists.h>
+#include <util/parser.h>
 #include <util/umlaut.h>
 
 /* libc includes */
@@ -88,10 +89,10 @@ add_kick(attrib * a, const faction * f)
 }
 
 static void
-alliance_kick(const tnode * tnext, const char * str, void * data, struct order * ord)
+alliance_kick(const tnode * tnext, void * data, struct order * ord)
 {
 	unit * u = (unit*)data;
-	faction * f = findfaction(atoi36(igetstrtoken(str)));
+	faction * f = findfaction(getid());
 	attrib * a;
 	unused(tnext);
 
@@ -105,10 +106,10 @@ alliance_kick(const tnode * tnext, const char * str, void * data, struct order *
 }
 
 static void
-alliance_join(const tnode * tnext, const char * str, void * data, struct order * ord)
+alliance_join(const tnode * tnext, void * data, struct order * ord)
 {
 	unit * u = (unit*)data;
-	alliance * al = findalliance(atoi36(igetstrtoken(str)));
+	alliance * al = findalliance(getid());
 	unused(tnext);
 
 	if (u->faction->alliance!=NULL || al==NULL) {
@@ -236,7 +237,7 @@ alliancename(const alliance * al)
   char *ibuf = idbuf[(++nextbuf) % 8];
 
   if (al && al->name) {
-    snprintf(ibuf, sizeof(name), "%s (%s)", strcheck(al->name, NAMESIZE), itoa36(al->id));
+    snprintf(ibuf, sizeof(name), "%s (%s)", al->name, itoa36(al->id));
     ibuf[sizeof(name)-1] = 0;
   } else {
     return NULL;
diff --git a/src/common/kernel/battle.c b/src/common/kernel/battle.c
index 69732fe30..b0cdc9a03 100644
--- a/src/common/kernel/battle.c
+++ b/src/common/kernel/battle.c
@@ -2879,7 +2879,7 @@ print_stats(battle * b)
       faction * f = bf->faction;
       const char * loc_army = LOC(f->locale, "battle_army");
       char * bufp;
-      const char * header;
+      const xmlChar * header;
       size_t rsize, size;
       int komma;
 
diff --git a/src/common/kernel/building.c b/src/common/kernel/building.c
index f0b8ab015..e38ede2bb 100644
--- a/src/common/kernel/building.c
+++ b/src/common/kernel/building.c
@@ -344,7 +344,7 @@ wdw_pyramid_level(const struct building *b)
 static local_names * bnames;
 
 const building_type *
-findbuildingtype(const char * name, const struct locale * lang)
+findbuildingtype(const xmlChar * name, const struct locale * lang)
 {
   variant type;
 	local_names * bn = bnames;
@@ -359,7 +359,7 @@ findbuildingtype(const char * name, const struct locale * lang)
 		bn->next = bnames;
 		bn->lang = lang;
 		while (btl) {
-			const char * n = locale_string(lang, btl->type->_name);
+			const xmlChar * n = locale_string(lang, btl->type->_name);
       type.v = (void*)btl->type;
 			addtoken(&bn->names, n, type);
 			btl=btl->next;
@@ -440,7 +440,6 @@ new_building(const struct building_type * btype, region * r, const struct locale
 	bhash(b);
 
 	b->type = btype;
-	set_string(&b->display, "");
 	b->region = r;
 	addlist(&r->buildings, b);
 
diff --git a/src/common/kernel/building.h b/src/common/kernel/building.h
index 239d336e7..3b8c29f2b 100644
--- a/src/common/kernel/building.h
+++ b/src/common/kernel/building.h
@@ -89,8 +89,8 @@ typedef struct building {
 
 	const struct building_type * type;
 	struct region *region;
-	char *name;
-	char *display;
+	xmlChar *name;
+	xmlChar *display;
 	struct attrib * attribs;
 	int no;
 	int size;
@@ -123,7 +123,7 @@ void bunhash(struct building * b);
 int buildingcapacity(const struct building * b);
 void destroy_building(struct building * b);
 
-const struct building_type * findbuildingtype(const char * name, const struct locale * lang);
+const struct building_type * findbuildingtype(const xmlChar * name, const struct locale * lang);
 
 #include "build.h"
 #define NOBUILDING NULL
diff --git a/src/common/util/command.c b/src/common/kernel/command.c
similarity index 71%
rename from src/common/util/command.c
rename to src/common/kernel/command.c
index 556ebe7bf..2e6e39ee3 100644
--- a/src/common/util/command.c
+++ b/src/common/kernel/command.c
@@ -11,11 +11,15 @@
  
  */
 #include <config.h>
+#include "eressea.h"
 #include "command.h"
 
-#include "umlaut.h"
-#include "language.h"
-#include "log.h"
+#include <kernel/order.h>
+
+#include <util/umlaut.h>
+#include <util/language.h>
+#include <util/log.h>
+#include <util/parser.h>
 
 /* libc includes */
 #include <assert.h>
@@ -55,7 +59,7 @@ stree_create(void)
 
 void
 add_command(struct tnode * keys, struct tnode * tnext, 
-				const char * str, parser fun)
+				const xmlChar * str, parser fun)
 {
 	command * cmd = (command *)malloc(sizeof(command));
   variant var;
@@ -67,43 +71,33 @@ add_command(struct tnode * keys, struct tnode * tnext,
 }
 
 static int
-do_command_i(const struct tnode * keys, void * u, const char * str, struct order * ord)
+do_command_i(const struct tnode * keys, void * u, struct order * ord)
 {
-  size_t i;
-  char zText[16];
-  const char * c;
+  const xmlChar * c;
   variant var;
 
-  while (isspace(*str)) ++str;
-  c = str;
-  while (isalnum(*c)) ++c;
-  i = min(16, c-str);
-  strncpy(zText, str, i);
-  zText[i]=0;
-  if (findtoken(keys, zText, &var)==E_TOK_SUCCESS) {
+  c = getstrtoken();
+  if (findtoken(keys, c, &var)==E_TOK_SUCCESS) {
     command * cmd = (command *)var.v;
     if (cmd->nodes && *c) {
       assert(!cmd->fun);
-      return do_command_i(cmd->nodes, u, ++c, ord);
+      return do_command_i(cmd->nodes, u, ord);
     } else if (cmd->fun) {
-      cmd->fun(cmd->nodes, ++c, u, ord);
+      cmd->fun(cmd->nodes, u, ord);
       return E_TOK_SUCCESS;
     }
   }
   return E_TOK_NOMATCH;
 }
 
-struct unit;
-struct order;
-extern char * getcommand(struct order * ord);
-extern char * unitname(struct unit * u);
-
 void
 do_command(const struct tnode * keys, void * u, struct order * ord)
 {
-  char * cmd = getcommand(ord);
-  if (do_command_i(keys, u, cmd, ord)!=E_TOK_SUCCESS) {
+  init_tokens(ord);
+  skip_token();
+  if (do_command_i(keys, u, ord)!=E_TOK_SUCCESS) {
+    xmlChar * cmd = getcommand(ord);
     log_warning(("%s failed GM command '%s'\n", unitname(u), cmd));
+    free(cmd);
   }
-  free(cmd);
 }
diff --git a/src/common/util/command.h b/src/common/kernel/command.h
similarity index 90%
rename from src/common/util/command.h
rename to src/common/kernel/command.h
index 33fe98d10..cfdb8267d 100644
--- a/src/common/util/command.h
+++ b/src/common/kernel/command.h
@@ -26,8 +26,8 @@ typedef struct syntaxtree {
 	struct syntaxtree * next;
 } syntaxtree;
 
-typedef void (*parser)(const struct tnode *, const char*, void *, struct order*);
-extern void add_command(struct tnode * troot, struct tnode * tnext, const char * str, parser fun);
+typedef void (*parser)(const struct tnode *, void *, struct order*);
+extern void add_command(struct tnode * troot, struct tnode * tnext, const xmlChar * str, parser fun);
 extern void do_command(const struct tnode * troot, void * u, struct order *);
 
 extern struct syntaxtree * stree_create(void);
diff --git a/src/common/kernel/eressea.c b/src/common/kernel/eressea.c
index 3fab50fea..103b0c741 100644
--- a/src/common/kernel/eressea.c
+++ b/src/common/kernel/eressea.c
@@ -91,7 +91,6 @@
 region  *regions;
 faction *factions;
 settings global;
-char     buf[BUFSIZE + 1];
 FILE    *logfile;
 FILE    *updatelog;
 const struct race * new_race[MAXRACES];
@@ -252,12 +251,16 @@ const char *directions[MAXDIRECTIONS+2] =
   "pause"
 };
 
+/** Returns the English name of the race, which is what the database uses.
+ */
 const char *
 dbrace(const struct race * rc)
 {
   static char zText[32];
   char * zPtr = zText;
-  strcpy(zText, LOC(find_locale("en"), rc_name(rc, 0)));
+
+  /* the english names are all in ASCII, so we don't need to worry about UTF8 */
+  strcpy(zText, (const char*)LOC(find_locale("en"), rc_name(rc, 0)));
   while (*zPtr) {
     *zPtr = (char)(toupper(*zPtr));
     ++zPtr;
@@ -785,7 +788,7 @@ change_hitpoints (unit * u, int value)
   return hp;
 }
 
-int
+unsigned int
 atoip(const char *s)
 {
   int n;
@@ -798,22 +801,6 @@ atoip(const char *s)
   return n;
 }
 
-void
-scat (const char *s)
-{
-  strncat (buf, s, BUFSIZE - strlen (buf));
-}
-
-void
-icat (int n)
-{
-  char s[12];
-
-  sprintf (s, "%d", n);
-  scat (s);
-}
-
-
 region *
 findunitregion (const unit * su)
 {
@@ -1291,7 +1278,7 @@ count_maxmigrants(const faction * f)
 void
 init_tokens(const struct order * ord)
 {
-  char * cmd = getcommand(ord);
+  xmlChar * cmd = getcommand(ord);
   init_tokens_str(cmd, cmd);
 }
 
@@ -1320,8 +1307,8 @@ parse(keyword_t kword, int (*dofun)(unit *, struct order *), boolean thisorder)
   }
 }
 
-const char *
-igetstrtoken(const char * initstr)
+const xmlChar *
+igetstrtoken(const xmlChar * initstr)
 {
   if (initstr!=NULL) {
     init_tokens_str(initstr, NULL);
@@ -1330,36 +1317,20 @@ igetstrtoken(const char * initstr)
   return getstrtoken();
 }
 
-int
-geti (void)
+unsigned int
+getuint (void)
 {
-  return atoip (getstrtoken ());
+  return atoip((const char *)getstrtoken());
 }
 
-/* GET KEYWORD, SKILL, ITEM, SPELL benutzen FINDSTR - welche Item um Item eine
- * Liste durchsucht.
- *
- * FIND wird immer von GET aufgerufen. GET braucht keine Parameter, IGET braucht
- * einen String aus dem gelesen wird. In FIND stehen dann listen etc drinnen.
- * FIND kann man auch allein verwenden, wenn der string _nur_ noch das gesuchte
- * object enthaelt. Steht noch weitere info darin, sollte man GET verwenden,
- * bzw. GETI wenn die info am Anfang eines neuen Stringes steht. */
-
 int
-findstr(const char **v, const char *s, unsigned char n)
+getint (void)
 {
-  int i;
-  size_t ss = strlen(s);
-  if (!ss)
-    return -1;
-  for (i = 0; i != n; i++)
-    if (!strncasecmp(s, v[i], ss))
-      return i;
-  return -1;
+  return atoi((const char *)getstrtoken());
 }
 
 const struct race *
-findrace(const char * s, const struct locale * lang)
+findrace(const xmlChar * s, const struct locale * lang)
 {
   struct tnode * tokens = get_translations(lang, UT_RACES);
   variant token;
@@ -1371,7 +1342,7 @@ findrace(const char * s, const struct locale * lang)
 }
 
 int
-findoption(const char *s, const struct locale * lang)
+findoption(const xmlChar *s, const struct locale * lang)
 {
   struct tnode * tokens = get_translations(lang, UT_OPTIONS);
   variant token;
@@ -1383,7 +1354,7 @@ findoption(const char *s, const struct locale * lang)
 }
 
 skill_t
-findskill(const char *s, const struct locale * lang)
+findskill(const xmlChar *s, const struct locale * lang)
 {
   struct tnode * tokens = get_translations(lang, UT_SKILLS);
   variant token;
@@ -1393,7 +1364,7 @@ findskill(const char *s, const struct locale * lang)
 }
 
 keyword_t
-findkeyword(const char *s, const struct locale * lang)
+findkeyword(const xmlChar *s, const struct locale * lang)
 {
   struct tnode * tokens = get_translations(lang, UT_KEYWORDS);
   variant token;
@@ -1405,7 +1376,7 @@ findkeyword(const char *s, const struct locale * lang)
 }
 
 param_t
-findparam(const char *s, const struct locale * lang)
+findparam(const xmlChar *s, const struct locale * lang)
 {
   struct tnode * tokens = get_translations(lang, UT_PARAMS);
   variant token;
@@ -1518,19 +1489,19 @@ read_newunitid (const faction * f, const region * r)
 int
 read_unitid (const faction * f, const region * r)
 {
-  const char * s = getstrtoken ();
+  const xmlChar * s = getstrtoken();
 
   /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der
    * paramliste. machen wir das nicht, dann wird getnewunit in s nach der
    * nummer suchen, doch dort steht bei temp-units nur "temp" drinnen! */
 
-  switch (findparam (s, f->locale)) {
+  switch (findparam(s, f->locale)) {
   case P_TEMP:
     return read_newunitid(f, r);
   }
   if (!s || *s == 0)
     return -1;
-  return atoi36(s);
+  return atoi36((const char *)s);
 }
 
 /* exported symbol */
@@ -1647,7 +1618,7 @@ buildingname (const building * b)
 {
   char *ibuf = idbuf[(++nextbuf) % 8];
 
-  snprintf(ibuf, sizeof(name), "%s (%s)", strcheck(b->name, NAMESIZE), itoa36(b->no));
+  snprintf(ibuf, sizeof(name), "%s (%s)", b->name, itoa36(b->no));
   ibuf[sizeof(name)-1] = 0;
   return ibuf;
 }
@@ -1679,7 +1650,7 @@ const char *
 unitname(const unit * u)
 {
   char *ubuf = idbuf[(++nextbuf) % 8];
-  snprintf(ubuf, sizeof(name), "%s (%s)", strcheck(u->name, NAMESIZE), itoa36(u->no));
+  snprintf(ubuf, sizeof(name), "%s (%s)", u->name, itoa36(u->no));
   ubuf[sizeof(name)-1] = 0;
   return ubuf;
 }
@@ -1988,17 +1959,17 @@ use_birthdayamulet(region * r, unit * magician, order * ord)
 {
   region *tr;
   direction_t d;
+  message * msg = msg_message("meow", "");
 
   unused(ord);
   unused(magician);
 
+  add_message(&r->msgs, msg);
   for(d=0;d<MAXDIRECTIONS;d++) {
     tr = rconnect(r, d);
-    if(tr) addmessage(tr, 0, "Miiauuuuuu...", MSG_MESSAGE, ML_IMPORTANT);
+    if (tr) add_message(&tr->msgs, msg);
   }
-
-  tr = r;
-  addmessage(r, 0, "Miiauuuuuu...", MSG_MESSAGE, ML_IMPORTANT);
+  msg_release(msg);
 }
 
 static void
@@ -2036,7 +2007,7 @@ init_directions(tnode * root, const struct locale * lang)
 }
 
 direction_t
-finddirection(const char *s, const struct locale * lang)
+finddirection(const xmlChar *s, const struct locale * lang)
 {
   struct tnode * tokens = get_translations(lang, UT_DIRECTIONS);
   variant token;
@@ -2054,6 +2025,13 @@ init_locale(const struct locale * lang)
   int i;
   const struct race * rc;
   struct tnode * tokens;
+  const terrain_type * terrain;
+
+  tokens = get_translations(lang, UT_MAGIC);
+  for (i=0;i!=MAXMAGIETYP;++i) {
+    var.i = i;
+    addtoken(tokens, LOC(lang, magietypen[i]), var);
+  }
 
   tokens = get_translations(lang, UT_DIRECTIONS);
   init_directions(tokens, lang);
@@ -2074,7 +2052,7 @@ init_locale(const struct locale * lang)
   tokens = get_translations(lang, UT_SKILLS);
   for (i=0;i!=MAXSKILLS;++i) {
     if (i!=SK_TRADE || !TradeDisabled()) {
-      const char * skname = skillname((skill_t)i, lang);
+      const xmlChar * skname = skillname((skill_t)i, lang);
       if (skname!=NULL) {
         var.i = i;
         addtoken(tokens, skname, var);
@@ -2093,6 +2071,12 @@ init_locale(const struct locale * lang)
     var.i = i;
     addtoken(tokens, LOC(lang, options[i]), var);
   }
+
+  tokens = get_translations(lang, UT_TERRAINS);
+  for (terrain=terrains();terrain!=NULL;terrain=terrain->next) {
+    var.v = terrain;
+    addtoken(tokens, LOC(lang, terrain->_name), var);
+  }
 }
 
 typedef struct param {
@@ -2633,16 +2617,16 @@ wage(const region *r, const faction * f, const race * rc)
 
 
 static region *
-findspecialdirection(const region *r, const char *token)
+findspecialdirection(const region *r, const xmlChar *token)
 {
   attrib *a;
   spec_direction *d;
 
-  if (strlen(token)==0) return NULL;
+  if (xmlStrlen(token)==0) return NULL;
   for (a = a_find(r->attribs, &at_direction);a && a->type==&at_direction;a=a->next) {
     d = (spec_direction *)(a->data.v);
 
-    if (d->active && strncasecmp(d->keyword, token, strlen(token)) == 0) {
+    if (d->active && xmlStrncasecmp(d->keyword, token, xmlStrlen(token)) == 0) {
       return findregion(d->x, d->y);
     }
   }
@@ -2663,7 +2647,7 @@ maintenance_cost(const struct unit * u)
 }
 
 message *
-movement_error(unit * u, const char * token, order * ord, int error_code)
+movement_error(unit * u, const xmlChar * token, order * ord, int error_code)
 {
   direction_t d;
   switch (error_code) {
@@ -2677,7 +2661,7 @@ movement_error(unit * u, const char * token, order * ord, int error_code)
 }
 
 int
-movewhere(const unit *u, const char * token, region * r, region** resultp)
+movewhere(const unit *u, const xmlChar * token, region * r, region** resultp)
 {
   region * r2;
   direction_t d;
diff --git a/src/common/kernel/eressea.h b/src/common/kernel/eressea.h
index d7bdae1fb..eb6ca25db 100644
--- a/src/common/kernel/eressea.h
+++ b/src/common/kernel/eressea.h
@@ -177,13 +177,9 @@ extern int count_skill(struct faction * f, skill_t sk);
 
 /* direction, geography */
 extern const char *directions[];
-extern direction_t finddirection(const char *s, const struct locale *);
+extern direction_t finddirection(const xmlChar *s, const struct locale *);
 
-extern int findoption(const char *s, const struct locale * lang);
-
-/* shared character-buffer */
-#define BUFSIZE 32765
-extern char buf[BUFSIZE + 1];
+extern int findoption(const xmlChar *s, const struct locale * lang);
 
 /* special units */
 void make_undead_unit(struct unit *);
@@ -195,27 +191,22 @@ void addstrlist(strlist ** SP, const char *s);
 
 int armedmen(const struct unit * u);
 
-void scat(const char *s);
-void icat(int n);
+unsigned int atoip(const char *s);
+unsigned int getuint(void);
+int getint(void);
 
-int atoip(const char *s);
-int geti(void);
-
-extern int findstr(const char **v, const char *s, unsigned char n);
-
-extern const char *igetstrtoken(const char *s);
+extern const xmlChar *igetstrtoken(const xmlChar *s);
 
 extern void init_tokens(const struct order * ord); /* initialize token parsing */
-extern skill_t findskill(const char *s, const struct locale * lang);
+extern skill_t findskill(const xmlChar *s, const struct locale * lang);
 
-extern keyword_t findkeyword(const char *s, const struct locale * lang);
+extern keyword_t findkeyword(const xmlChar *s, const struct locale * lang);
 
-extern param_t findparam(const char *s, const struct locale * lang);
+extern param_t findparam(const xmlChar *s, const struct locale * lang);
 extern param_t getparam(const struct locale * lang);
 
 extern int atoi36(const char * s);
-#define getid() atoi36(getstrtoken())
-#define getstruct unitid() getid()
+#define getid() atoi36((const char *)getstrtoken())
 #define unitid(x) itoa36((x)->no)
 
 #define getshipid() getid()
@@ -276,14 +267,14 @@ extern int count_migrants (const struct faction * f);
 extern int count_maxmigrants(const struct faction * f);
 
 extern boolean teure_talente(const struct unit * u);
-extern const struct race * findrace(const char *, const struct locale *);
+extern const struct race * findrace(const xmlChar *, const struct locale *);
 
 int eff_stealth(const struct unit * u, const struct region * r);
 void scale_number(struct unit * u, int n);
 int unit_max_hp(const struct unit * u);
 int ispresent(const struct faction * f, const struct region * r);
 
-char * set_string(char **s, const char *neu);
+xmlChar * set_string(xmlChar **s, const xmlChar *neu);
 
 int check_option(struct faction * f, int option);
 extern void parse(keyword_t kword, int (*dofun)(struct unit *, struct order *), boolean thisorder);
@@ -313,19 +304,12 @@ struct unit *ufindhash(int i);
 void fhash(struct faction * f);
 void funhash(struct faction * f);
 
-#ifndef NDEBUG
-const char *strcheck(const char *s, size_t maxlen);
-
-#else
-#define strcheck(s, ml) (s)
-#endif
-
 boolean idle(struct faction * f);
 boolean unit_has_cursed_item(struct unit *u);
 
 /* simple garbage collection: */
 void * gc_add(void * p);
-void addmessage(struct region * r, struct faction * f, const char *s, msg_t mtype, int level);
+void addmessage(struct region * r, struct faction * f, const xmlChar *s, msg_t mtype, int level);
 
 /* grammatik-flags: */
 #define GF_NONE 0
@@ -376,7 +360,7 @@ extern int maxworkingpeasants(const struct region * r);
 
 extern int wage(const struct region *r, const struct faction *f, const struct race * rc);
 extern int maintenance_cost(const struct unit * u);
-extern struct message * movement_error(struct unit * u, const char * token, struct order * ord, int error_code);
+extern struct message * movement_error(struct unit * u, const xmlChar * token, struct order * ord, int error_code);
 extern boolean move_blocked(const struct unit * u, const struct region *src, const struct region *dest);
 extern void add_income(struct unit * u, int type, int want, int qty);
 
@@ -386,7 +370,7 @@ enum {
   E_MOVE_NOREGION, /* no region exists in this direction */
   E_MOVE_BLOCKED   /* cannot see this region, there is a blocking border. */
 };
-extern int movewhere(const struct unit *u, const char * token, struct region * r, struct region** resultp);
+extern int movewhere(const struct unit *u, const xmlChar * token, struct region * r, struct region** resultp);
 
 extern const char * basepath(void);
 extern const char * resourcepath(void);
diff --git a/src/common/kernel/faction.c b/src/common/kernel/faction.c
index 125872f3f..8859e191c 100644
--- a/src/common/kernel/faction.c
+++ b/src/common/kernel/faction.c
@@ -72,7 +72,7 @@ factionname(const faction * f)
   char *ibuf = idbuf[(++nextbuf) % 8];
 
   if (f && f->name) {
-    snprintf(ibuf, sizeof(name), "%s (%s)", strcheck(f->name, NAMESIZE), itoa36(f->no));
+    snprintf(ibuf, sizeof(name), "%s (%s)", f->name, itoa36(f->no));
     ibuf[sizeof(name)-1] = 0;
   } else {
     strcpy(ibuf, "Unbekannte Partei (?)");
@@ -100,12 +100,12 @@ unused_faction_id(void)
 }
 
 faction *
-addfaction(const char *email, const char * password,
+addfaction(const char *email, const xmlChar * password,
            const struct race * frace, const struct locale *loc,
            int subscription)
 {
-  int i;
   faction * f = calloc(sizeof(faction), 1);
+  const char * pass = itoa36(rng_int());
 
   assert(frace && frace != new_race[RC_ORC]);
 
@@ -113,14 +113,13 @@ addfaction(const char *email, const char * password,
     log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email));
   }
 
+  set_string(&f->override, (const xmlChar *)pass);
   if (password) {
     set_string(&f->passw, password);
   } else {
-    for (i = 0; i < 6; i++) buf[i] = (char) (97 + rng_int() % 26); buf[i] = 0;
-    set_string(&f->passw, buf);
+    pass = itoa36(rng_int());
+    set_string(&f->passw, (const xmlChar *)pass);
   }
-  for (i = 0; i < 6; i++) buf[i] = (char) (97 + rng_int() % 26); buf[i] = 0;
-  set_string(&f->override, buf);
 
   f->lastorders = turn;
   f->alive = 1;
@@ -137,7 +136,7 @@ addfaction(const char *email, const char * password,
   fhash(f);
 
   sprintf(buf, "%s %s", LOC(loc, "factiondefault"), factionid(f));
-  set_string(&f->name, buf);
+  set_string(&f->name, (const xmlChar*)buf);
 
   return f;
 }
@@ -166,7 +165,7 @@ addplayer(region *r, faction * f)
 }
 
 boolean
-checkpasswd(const faction * f, const char * passwd, boolean shortp)
+checkpasswd(const faction * f, const xmlChar * passwd, boolean shortp)
 {
 #ifdef SHORTPWDS
   shortpwd * slist = f->shortpwds;
@@ -178,8 +177,8 @@ checkpasswd(const faction * f, const char * passwd, boolean shortp)
     slist = slist->next;
   }
 #endif
-  if (strcasecmp(f->passw, passwd)==0) return true;
-  if (strcasecmp(f->override, passwd)==0) return true;
+  if (xmlStrcmp(f->passw, passwd)==0) return true;
+  if (xmlStrcmp(f->override, passwd)==0) return true;
   return false;
 }
 
diff --git a/src/common/kernel/faction.h b/src/common/kernel/faction.h
index dea2ab082..1b2f43903 100644
--- a/src/common/kernel/faction.h
+++ b/src/common/kernel/faction.h
@@ -64,11 +64,11 @@ typedef struct faction {
 	int no;
 	int subscription;
 	unsigned int flags;
-	char *name;
-	char *banner;
+	xmlChar *name;
+	xmlChar *banner;
 	char *email;
-	char *passw;
-	char *override;
+	xmlChar *passw;
+	xmlChar *override;
 #ifdef SHORTPWDS
   struct shortpwd * shortpwds;
 #endif
@@ -121,10 +121,10 @@ extern const struct unit * random_unit_in_faction(const struct faction *f);
 extern const char * factionname(const struct faction * f);
 extern void * resolve_faction(variant data);
 extern struct unit * addplayer(struct region *r, faction * f);
-extern struct faction * addfaction(const char *email, const char* password, 
+extern struct faction * addfaction(const char *email, const xmlChar* password, 
                                    const struct race * frace, 
                                    const struct locale *loc, int subscription);
-extern boolean checkpasswd(const faction * f, const char * passwd, boolean shortp);
+extern boolean checkpasswd(const faction * f, const xmlChar * passwd, boolean shortp);
 extern void destroyfaction(faction * f);
 
 extern void set_alliance(struct faction * a, struct faction * b, int status);
diff --git a/src/common/kernel/item.c b/src/common/kernel/item.c
index 206b83cf4..e3fcbf0ed 100644
--- a/src/common/kernel/item.c
+++ b/src/common/kernel/item.c
@@ -952,7 +952,7 @@ change_money(unit * u, int v)
 static local_names * rnames;
 
 const resource_type *
-findresourcetype(const char * name, const struct locale * lang)
+findresourcetype(const xmlChar * name, const struct locale * lang)
 {
   local_names * rn = rnames;
   variant token;
@@ -1011,7 +1011,7 @@ init_itemnames(void)
         const item_type * itl;
         for (itl=itemtypes[key];itl;itl=itl->next) {
           variant var;
-          const char * iname = locale_string(lang, itl->rtype->_name[0]);
+          const xmlChar * iname = locale_string(lang, itl->rtype->_name[0]);
           if (findtoken(&in->names, iname, &var)==E_TOK_NOMATCH || var.v!=itl) {
             var.v = (void*)itl;
             addtoken(&in->names, iname, var);
@@ -1025,7 +1025,7 @@ init_itemnames(void)
 }
 
 const item_type *
-finditemtype(const char * name, const struct locale * lang)
+finditemtype(const xmlChar * name, const struct locale * lang)
 {
   local_names * in = inames;
   variant var;
diff --git a/src/common/kernel/item.h b/src/common/kernel/item.h
index fe2c4ef26..6d2286967 100644
--- a/src/common/kernel/item.h
+++ b/src/common/kernel/item.h
@@ -73,7 +73,7 @@ typedef struct resource_type {
 } resource_type;
 extern resource_type * resourcetypes;
 extern const char* resourcename(const resource_type * rtype, int flags);
-extern const resource_type * findresourcetype(const char * name, const struct locale * lang);
+extern const resource_type * findresourcetype(const xmlChar * name, const struct locale * lang);
 
 /* resource-limits for regions */
 #define RMF_SKILL         0x01 /* int, bonus on resource production skill */
@@ -135,7 +135,7 @@ typedef struct item_type {
   struct item_type * next;
 } item_type;
 
-extern const item_type * finditemtype(const char * name, const struct locale * lang);
+extern const item_type * finditemtype(const xmlChar * name, const struct locale * lang);
 extern void init_itemnames(void);
 
 typedef struct luxury_type {
diff --git a/src/common/kernel/kernel.vcproj b/src/common/kernel/kernel.vcproj
index 02f6af4a7..9a0f0058d 100644
--- a/src/common/kernel/kernel.vcproj
+++ b/src/common/kernel/kernel.vcproj
@@ -195,6 +195,9 @@
 			<File
 				RelativePath=".\calendar.h">
 			</File>
+			<File
+				RelativePath=".\command.h">
+			</File>
 			<File
 				RelativePath=".\creation.h">
 			</File>
@@ -316,6 +319,9 @@
 		<File
 			RelativePath=".\calendar.c">
 		</File>
+		<File
+			RelativePath=".\command.c">
+		</File>
 		<File
 			RelativePath=".\curse.c">
 		</File>
diff --git a/src/common/kernel/magic.c b/src/common/kernel/magic.c
index be5c536c7..9b9dc9313 100644
--- a/src/common/kernel/magic.c
+++ b/src/common/kernel/magic.c
@@ -1535,7 +1535,7 @@ msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spll
       parameters[P_TEMP]), itoa36(spobj->data.i));
     uid = tbuf;
   }
-  return msg_message("spellunitnotfound", 
+  return msg_message("unitnotfound_id", 
     "unit region command id", mage, mage->region, ord, uid);
 }
 
@@ -1791,34 +1791,34 @@ free_spellparameter(spellparameter *pa)
 }
 
 static int
-addparam_string(char ** param, spllprm ** spobjp)
+addparam_string(const xmlChar ** param, spllprm ** spobjp)
 {
   spllprm * spobj = *spobjp = malloc(sizeof(spllprm));
   assert(param[0]);
 
   spobj->flag = 0;
   spobj->typ = SPP_STRING;
-  spobj->data.s = strdup(param[0]);
+  spobj->data.xs = xmlStrdup(param[0]);
   return 1;
 }
 
 static int
-addparam_int(char ** param, spllprm ** spobjp)
+addparam_int(const xmlChar ** param, spllprm ** spobjp)
 {
   spllprm * spobj = *spobjp = malloc(sizeof(spllprm));
   assert(param[0]);
 
   spobj->flag = 0;
   spobj->typ = SPP_INT;
-  spobj->data.i = atoi(param[0]);
+  spobj->data.i = atoi((char*)param[0]);
   return 1;
 }
 
 static int
-addparam_ship(char ** param, spllprm ** spobjp)
+addparam_ship(const xmlChar ** param, spllprm ** spobjp)
 {
   spllprm * spobj = *spobjp = malloc(sizeof(spllprm));
-  int id = atoi36(param[0]);
+  int id = atoi36((const char *)param[0]);
 
   spobj->flag = 0;
   spobj->typ = SPP_SHIP;
@@ -1827,10 +1827,10 @@ addparam_ship(char ** param, spllprm ** spobjp)
 }
 
 static int
-addparam_building(char ** param, spllprm ** spobjp)
+addparam_building(const xmlChar ** param, spllprm ** spobjp)
 {
   spllprm * spobj = *spobjp = malloc(sizeof(spllprm));
-  int id = atoi36(param[0]);
+  int id = atoi36((const char *)param[0]);
   
   spobj->flag = 0;
   spobj->typ = SPP_BUILDING;
@@ -1839,7 +1839,7 @@ addparam_building(char ** param, spllprm ** spobjp)
 }
 
 static int
-addparam_region(char ** param, spllprm ** spobjp, const unit * u, order * ord)
+addparam_region(const xmlChar ** param, spllprm ** spobjp, const unit * u, order * ord)
 {
   assert(param[0]);
   if (param[1]==0) {
@@ -1847,7 +1847,7 @@ addparam_region(char ** param, spllprm ** spobjp, const unit * u, order * ord)
     cmistake(u, ord, 194, MSG_MAGIC);
     return -1;
   } else {
-    int tx = atoi(param[0]), ty = atoi(param[1]);
+    int tx = atoi((const char*)param[0]), ty = atoi((const char*)param[1]);
     short x = rel_to_abs(0, u->faction, (short)tx, 0);
     short y = rel_to_abs(0, u->faction, (short)ty, 1);
     region *rt = findregion(x,y);
@@ -1869,7 +1869,7 @@ addparam_region(char ** param, spllprm ** spobjp, const unit * u, order * ord)
 
 
 static int
-addparam_unit(char ** param, spllprm ** spobjp, const unit * u, order * ord)
+addparam_unit(const xmlChar ** param, spllprm ** spobjp, const unit * u, order * ord)
 {
   spllprm *spobj;
   int i = 0;
@@ -1889,13 +1889,13 @@ addparam_unit(char ** param, spllprm ** spobjp, const unit * u, order * ord)
   spobj = *spobjp = malloc(sizeof(spllprm));
   spobj->flag = 0;
   spobj->typ = otype;
-  spobj->data.i = atoi36(param[i]);
+  spobj->data.i = atoi36((const char*)param[i]);
 
   return i+1;
 }
 
 static spellparameter *
-add_spellparameter(region *target_r, unit *u, const char *syntax, char ** param, int size, struct order * ord)
+add_spellparameter(region *target_r, unit *u, const char *syntax, xmlChar ** param, int size, struct order * ord)
 {
   boolean fail = false;
   int i = 0;
@@ -2443,7 +2443,7 @@ cast_cmd(unit * u, order * ord)
   region * target_r = r;
   int level, range;
   unit *familiar = NULL, *mage = u;
-  const char * s;
+  const xmlChar * s;
   spell * sp;
   spellparameter *args = NULL;
 
@@ -2462,8 +2462,8 @@ cast_cmd(unit * u, order * ord)
   s = getstrtoken();
   /* f�r Syntax ' STUFE x REGION y z ' */
   if (findparam(s, u->faction->locale) == P_LEVEL) {
-    s = getstrtoken();
-    level = min(atoip(s), level);
+    int p = getint();
+    level = min(p, level);
     if (level < 1) {
       /* Fehler "Das macht wenig Sinn" */
       cmistake(u, ord, 10, MSG_MAGIC);
@@ -2472,8 +2472,8 @@ cast_cmd(unit * u, order * ord)
     s = getstrtoken();
   }
   if (findparam(s, u->faction->locale) == P_REGION) {
-    short t_x = (short)atoi(getstrtoken());
-    short t_y = (short)atoi(getstrtoken());
+    short t_x = (short)getint();
+    short t_y = (short)getint();
     t_x = rel_to_abs(getplane(u->region),u->faction,t_x,0);
     t_y = rel_to_abs(getplane(u->region),u->faction,t_y,1);
     target_r = findregion(t_x, t_y);
@@ -2488,16 +2488,16 @@ cast_cmd(unit * u, order * ord)
   /* f�r Syntax ' REGION x y STUFE z '
   * hier nach REGION nochmal auf STUFE pr�fen */
   if (findparam(s, u->faction->locale) == P_LEVEL) {
-    s = getstrtoken();
-    level = min(atoip(s), level);
-    s = getstrtoken();
+    int p = getint();
+    level = min(p, level);
     if (level < 1) {
       /* Fehler "Das macht wenig Sinn" */
       cmistake(u, ord, 10, MSG_MAGIC);
       return 0;
     }
+    s = getstrtoken();
   }
-  if (!s[0] || strlen(s) == 0) {
+  if (!s[0] || xmlStrlen(s) == 0) {
     /* Fehler "Es wurde kein Zauber angegeben" */
     cmistake(u, ord, 172, MSG_MAGIC);
     return 0;
@@ -2619,7 +2619,7 @@ cast_cmd(unit * u, order * ord)
   }
   /* Weitere Argumente zusammenbasten */
   if (sp->parameter) {
-    char ** params = malloc(2*sizeof(char*));
+    xmlChar ** params = malloc(2*sizeof(char*));
     int p = 0, size = 2;
     for (;;) {
       s = getstrtoken();
@@ -2628,7 +2628,7 @@ cast_cmd(unit * u, order * ord)
         size*=2;
         params = realloc(params, sizeof(char*)*size);
       }
-      params[p++] = strdup(s);
+      params[p++] = xmlStrdup(s);
     }
     params[p] = 0;
     args = add_spellparameter(target_r, mage, sp->parameter, params, p, ord);
@@ -2818,13 +2818,13 @@ magic(void)
   remove_empty_units();
 }
 
-const char *
+const xmlChar *
 spell_info(const spell * sp, const struct locale * lang)
 {
   return LOC(lang, mkname("spellinfo", sp->sname));
 }
 
-const char *
+const xmlChar *
 spell_name(const spell * sp, const struct locale * lang)
 {
   return LOC(lang, mkname("spell", sp->sname));
diff --git a/src/common/kernel/magic.h b/src/common/kernel/magic.h
index a5a66eb9b..215a954d4 100644
--- a/src/common/kernel/magic.h
+++ b/src/common/kernel/magic.h
@@ -60,6 +60,7 @@ typedef struct spllprm{
 		struct building *b;
 		struct ship *sh;
 		char *s;
+    xmlChar * xs;
 		int i;
 	} data;
 } spllprm;
@@ -269,9 +270,6 @@ boolean is_familiar(const struct unit *u);
 	/*	gibt true, wenn eine Familiar-Relation besteht.  */
 
 /* Spr�che */
-spell *get_spellfromtoken(struct unit *u, const char *s, const struct locale * lang);
-	/*	versucht einen Spruch �ber den Namen zu identifizieren, gibt
-	 *	ansonsten NULL zur�ck */
 int get_combatspelllevel(const struct unit *u, int nr);
 	/*  versucht, eine eingestellte maximale Kampfzauberstufe
 	 *  zur�ckzugeben. 0 = Maximum, -1 u ist kein Magier. */
@@ -373,8 +371,8 @@ extern boolean create_newfamiliar(struct unit * mage, struct unit * familiar);
 extern void create_newclone(struct unit * mage, struct unit * familiar);
 extern struct unit * has_clone(struct unit * mage);
 
-extern const char * spell_info(const struct spell * sp, const struct locale * lang);
-extern const char * spell_name(const struct spell * sp, const struct locale * lang);
+extern const xmlChar * spell_info(const struct spell * sp, const struct locale * lang);
+extern const xmlChar * spell_name(const struct spell * sp, const struct locale * lang);
 
 extern struct message * msg_unitnotfound(const struct unit * mage, struct order * ord, const struct spllprm * spobj);
 
diff --git a/src/common/kernel/message.c b/src/common/kernel/message.c
index 2909fd77d..a1d5c56ae 100644
--- a/src/common/kernel/message.c
+++ b/src/common/kernel/message.c
@@ -177,7 +177,7 @@ msg_message(const char * name, const char* sig, ...)
 }
 
 static void
-caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level)
+caddmessage(region * r, faction * f, const xmlChar *s, msg_t mtype, int level)
 {
   message * m = NULL;
 
@@ -230,7 +230,7 @@ caddmessage(region * r, faction * f, const char *s, msg_t mtype, int level)
 }
 
 void
-addmessage(region * r, faction * f, const char *s, msg_t mtype, int level)
+addmessage(region * r, faction * f, const xmlChar *s, msg_t mtype, int level)
 {
   caddmessage(r, f, s, mtype, level);
 }
diff --git a/src/common/kernel/movement.c b/src/common/kernel/movement.c
index b4ec71953..a563a6cfb 100644
--- a/src/common/kernel/movement.c
+++ b/src/common/kernel/movement.c
@@ -48,6 +48,7 @@
 /* util includes */
 #include <util/attrib.h>
 #include <util/base36.h>
+#include <util/bsdstring.h>
 #include <util/goodies.h>
 #include <util/language.h>
 #include <util/lists.h>
@@ -55,18 +56,18 @@
 #include <util/rand.h>
 #include <util/rng.h>
 
-/* libc includes */
-#include <assert.h>
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
-
 /* attributes includes */
 #include <attributes/follow.h>
 #include <attributes/targetregion.h>
 #include <attributes/movement.h>
 #include <attributes/otherfaction.h>
 
+/* libc includes */
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
 int * storms;
 
 typedef struct traveldir {
@@ -907,18 +908,19 @@ static void
 cycle_route(order * ord, unit *u, int gereist)
 {
 	int cm = 0;
-	char tail[1024];
-	char neworder[2048];
-	const char *token;
+	xmlChar tail[1024];
+	xmlChar neworder[2048];
+	const xmlChar *token;
 	direction_t d = NODIRECTION;
 	boolean paused = false;
 	boolean pause;
   order * norder;
+  xmlChar * tail_end = tail;
 
 	if (get_keyword(ord) != K_ROUTE) return;
 	tail[0] = '\0';
 
-	strcpy(neworder, locale_string(u->faction->locale, keywords[K_ROUTE]));
+	xmlStrcpy(neworder, locale_string(u->faction->locale, keywords[K_ROUTE]));
 
   init_tokens(ord);
   skip_token();
@@ -936,24 +938,34 @@ cycle_route(order * ord, unit *u, int gereist)
 		if (cm<gereist) {
 			/* hier sollte keine PAUSE auftreten */
 			assert(!pause);
-			if (!pause) strcat(strcat(tail, " "), LOC(lang, shortdirections[d]));
+      if (!pause) {
+        size_t size = sizeof(tail)-(tail_end-tail);
+        const xmlChar * loc = LOC(lang, shortdirections[d]);
+        *tail_end++ = ' ';
+        tail_end += strlcpy((char*)tail_end, (const char *)loc, size-1);
+      }
 		}
-		else if (strlen(neworder)>sizeof(neworder)/2) break;
+		else if (xmlStrlen(neworder)>sizeof(neworder)/2) break;
 		else if (cm == gereist && !paused && pause) {
-			strcat(strcat(tail, " "), LOC(lang, parameters[P_PAUSE]));
-			paused=true;
+      size_t size = sizeof(tail)-(tail_end-tail);
+      const xmlChar * loc = LOC(lang, parameters[P_PAUSE]);
+      *tail_end++ = ' ';
+      tail_end += strlcpy((char*)tail_end, (const char *)loc, size-1);
+			paused = true;
 		}
 		else if (pause) {
 			/* da PAUSE nicht in ein shortdirections[d] umgesetzt wird (ist
 			 * hier keine normale direction), muss jede PAUSE einzeln
 			 * herausgefiltert und explizit gesetzt werden */
-			strcat(strcat(neworder, " "), LOC(lang, parameters[P_PAUSE]));
+      strcat((char *)neworder, " ");
+      strcat((char *)neworder, (const char *)LOC(lang, parameters[P_PAUSE]));
 		} else {
-			strcat(strcat(neworder, " "), LOC(lang, shortdirections[d]));
+      strcat((char *)neworder, " ");
+			strcat((char *)neworder, (const char *)LOC(lang, shortdirections[d]));
 		}
 	}
 
-	strcat(neworder, tail);
+	strcat((char *)neworder, (const char *)tail);
   norder = parse_order(neworder, u->faction->locale);
 #ifdef LASTORDER
 	set_order(&u->lastorder, norder);
@@ -1217,7 +1229,7 @@ make_route(unit * u, order * ord, region_list ** routep)
   region_list **iroute = routep;
   region * current = u->region;
   region * next = NULL;
-  const char * token = getstrtoken();
+  const xmlChar * token = getstrtoken();
   int error = movewhere(u, token, current, &next);
 
   if (error!=E_MOVE_OK) {
@@ -1472,8 +1484,7 @@ travel_route(unit * u, region_list * route_begin, region_list * route_end, order
   if (iroute!=route_begin) {
     /* the unit has moved at least one region */
     int walkmode;
-    region_list *rlist = route_begin;
-    char * p = buf;
+    region_list **rlist = &route_begin;
     region * next = r;
 
     setguard(u, GUARD_NONE);
@@ -1490,23 +1501,22 @@ travel_route(unit * u, region_list * route_begin, region_list * route_end, order
 
     /* Berichte �ber Durchreiseregionen */
 
-    *p = 0;
-    while (rlist!=iroute) {
+    while (*rlist!=iroute) {
       if (next!=u->region && next!=current) {
         MSG(("travelthru_trail", "region", next), 
           p, sizeof(buf) - (p-buf), u->faction->locale, u->faction);
-        if (rlist->data!=current) {
-          if (rlist->next->data == current) scat(" und ");
-          else scat(", ");
-        }
-        p += strlen(p);
       }
       next = rlist->data;
       rlist = rlist->next;
     }
+    /* remove excess regions */
+    *rlist = NULL;
+    free_regionlist(iroute);
+    iroute = NULL;
+
     if (mode!=TRAVEL_TRANSPORTED) {
       ADDMSG(&u->faction->msgs, msg_message("travel", 
-        "unit mode start end regions", u, walkmode, r, current, buf));
+        "unit mode start end regions", u, walkmode, r, current, route_begin));
     }
 
     mark_travelthru(u, r, route_begin, iroute);
@@ -1621,7 +1631,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep)
   faction * f = u->faction;
   region * next_point = NULL;
   int error;
-  const char * token = getstrtoken();
+  const xmlChar * token = getstrtoken();
 
   if (routep) *routep = NULL;
 
@@ -1653,7 +1663,7 @@ sail(unit * u, order * ord, boolean move_on_land, region_list **routep)
   * befahrene Region. */
 
   while (next_point && current_point!=next_point && step < k) {
-    const char * token;
+    const xmlChar * token;
     int error;
     const terrain_type * tthis = current_point->terrain;
     /* these values need to be updated if next_point changes (due to storms): */
@@ -2327,7 +2337,7 @@ hunt(unit *u, order * ord)
     locale_string(u->faction->locale, directions[dir]));
   moves = 1;
 
-  speed = geti();
+  speed = getuint();
   if (speed==0) {
     speed = shipspeed(u->ship, u);
   } else {
diff --git a/src/common/kernel/names.c b/src/common/kernel/names.c
index 6dc33d3ec..c5a1593a9 100644
--- a/src/common/kernel/names.c
+++ b/src/common/kernel/names.c
@@ -47,7 +47,7 @@
 
 #define UNTOT_VOR 23
 
-static const char *untot_vor[UNTOT_VOR] =
+static const xmlChar *untot_vor[UNTOT_VOR] =
 {
 	"Grausige ",
 	"St�hnende ",
@@ -76,7 +76,7 @@ static const char *untot_vor[UNTOT_VOR] =
 
 #define UNTOT	13
 
-static const char *untot[UNTOT] =
+static const xmlChar *untot[UNTOT] =
 {
 	"Geister",
 	"Phantome",
@@ -95,7 +95,7 @@ static const char *untot[UNTOT] =
 
 #define UNTOT_NACH 14
 
-static const char *untot_nach[UNTOT_NACH] =
+static const xmlChar *untot_nach[UNTOT_NACH] =
 {
 	" der Nacht",
 	" der Schatten",
@@ -113,7 +113,7 @@ static const char *untot_nach[UNTOT_NACH] =
 	" aus der Unterwelt"
 };
 
-static const char *
+const xmlChar *
 describe_braineater(unit * u, const struct locale * lang)
 {
   return LOC(lang, "describe_braineater");
@@ -151,7 +151,7 @@ untoten_name(const unit * u)
 
 #define SKEL_VOR 19
 
-static const char *skel_vor[SKEL_VOR] =
+static const xmlChar *skel_vor[SKEL_VOR] =
 {
 	"Klapperige ",
 	"St�hnende ",
@@ -176,7 +176,7 @@ static const char *skel_vor[SKEL_VOR] =
 
 #define SKEL	5
 
-static const char *skel[SKEL] =
+static const xmlChar *skel[SKEL] =
 {
 	"Skelette",
 	"Kreaturen",
@@ -187,7 +187,7 @@ static const char *skel[SKEL] =
 
 #define SKEL_NACH 14
 
-static const char *skel_nach[SKEL_NACH] =
+static const xmlChar *skel_nach[SKEL_NACH] =
 {
 	" der Nacht",
 	" der Schatten",
@@ -205,7 +205,7 @@ static const char *skel_nach[SKEL_NACH] =
 	" aus der Unterwelt"
 };
 
-const char *
+const xmlChar *
 skeleton_name(const unit * u)
 {
 	int uv, uu, un;
@@ -238,7 +238,7 @@ skeleton_name(const unit * u)
 
 #define ZOM_VOR 16
 
-static const char *zombie_vor[ZOM_VOR] =
+static const xmlChar *zombie_vor[ZOM_VOR] =
 {
 	"Faulende ",
 	"Zerschlagene ",
@@ -260,7 +260,7 @@ static const char *zombie_vor[ZOM_VOR] =
 
 #define ZOM	5
 
-static const char *zombie[ZOM] =
+static const xmlChar *zombie[ZOM] =
 {
 	"Zombies",
 	"Kreaturen",
@@ -271,7 +271,7 @@ static const char *zombie[ZOM] =
 
 #define ZOM_NACH 13
 
-static const char *zombie_nach[ZOM_NACH] =
+static const xmlChar *zombie_nach[ZOM_NACH] =
 {
 	" der Nacht",
 	" der Schatten",
@@ -288,7 +288,7 @@ static const char *zombie_nach[ZOM_NACH] =
 	" aus der Unterwelt"
 };
 
-const char *
+const xmlChar *
 zombie_name(const unit * u)
 {
 	int uv, uu, un;
@@ -321,7 +321,7 @@ zombie_name(const unit * u)
 
 #define GHOUL_VOR 17
 
-static const char *ghoul_vor[GHOUL_VOR] =
+static const xmlChar *ghoul_vor[GHOUL_VOR] =
 {
 	"Faulende ",
 	"Angsteinfl��ende ",
@@ -344,7 +344,7 @@ static const char *ghoul_vor[GHOUL_VOR] =
 
 #define GHOUL	6
 
-static const char *ghoul[GHOUL] =
+static const xmlChar *ghoul[GHOUL] =
 {
 	"Ghoule",
 	"Kreaturen",
@@ -356,7 +356,7 @@ static const char *ghoul[GHOUL] =
 
 #define GHOUL_NACH 13
 
-static const char *ghoul_nach[GHOUL_NACH] =
+static const xmlChar *ghoul_nach[GHOUL_NACH] =
 {
 	" der Nacht",
 	" der Schatten",
@@ -373,7 +373,7 @@ static const char *ghoul_nach[GHOUL_NACH] =
 	" aus der Unterwelt"
 };
 
-const char *
+const xmlChar *
 ghoul_name(const unit * u)
 {
 	int uv, uu, un;
@@ -407,7 +407,7 @@ ghoul_name(const unit * u)
 
 #define SIL1 15
 
-const char *silbe1[SIL1] = {
+const xmlChar *silbe1[SIL1] = {
 	"Tar",
 	"Ter",
 	"Tor",
@@ -427,7 +427,7 @@ const char *silbe1[SIL1] = {
 
 #define SIL2 19
 
-const char *silbe2[SIL2] = {
+const xmlChar *silbe2[SIL2] = {
 	"da",
 	"do",
 	"dil",
@@ -451,7 +451,7 @@ const char *silbe2[SIL2] = {
 
 #define SIL3 14
 
-const char *silbe3[SIL3] = {
+const xmlChar *silbe3[SIL3] = {
 	"gul",
 	"gol",
 	"dol",
@@ -470,7 +470,7 @@ const char *silbe3[SIL3] = {
 
 #define DTITEL 5
 
-const char *dtitel[6][DTITEL] =
+const xmlChar *dtitel[6][DTITEL] =
 {
 	{							/* Ebene, Hochland */
 		"der Weise",
@@ -516,21 +516,21 @@ const char *dtitel[6][DTITEL] =
 	}
 };
 
-const char *
-shadow_name(const unit *u)
+const xmlChar *
+generic_name(const unit *u)
 {
-	if(u->no == 1) {
-		return "Schattend�mon";
-	}
-	return "Schattend�monen";
+  if (u->no == 1) {
+    return LOC(u->faction->locale, u->race->_name[0]);
+  }
+  return LOC(u->faction->locale, u->race->_name[1]);
 }
 
-const char *
+const xmlChar *
 drachen_name(const unit *u)
 {
 	static char name[NAMESIZE + 1];
 	int rnd = rng_int() % DTITEL;
-	const char *t = dtitel[0][rnd];
+	const xmlChar *t = dtitel[0][rnd];
 	int anzahl = 1;
 
 	if (u) {
@@ -583,7 +583,7 @@ drachen_name(const unit *u)
 /* Dracoide */
 
 #define DRAC_PRE 13
-static const char *drac_pre[DRAC_PRE] = {
+static const xmlChar *drac_pre[DRAC_PRE] = {
 		"Siss",
 		"Xxaa",
 		"Shht",
@@ -600,7 +600,7 @@ static const char *drac_pre[DRAC_PRE] = {
 };
 
 #define DRAC_MID 12
-static const char *drac_mid[DRAC_MID] = {
+static const xmlChar *drac_mid[DRAC_MID] = {
 		"siss",
 		"xxaa",
 		"shht",
@@ -616,7 +616,7 @@ static const char *drac_mid[DRAC_MID] = {
 };
 
 #define DRAC_SUF 10
-static const char *drac_suf[DRAC_SUF] = {
+static const xmlChar *drac_suf[DRAC_SUF] = {
 		"xil",
 		"shh",
 		"s",
@@ -629,7 +629,7 @@ static const char *drac_suf[DRAC_SUF] = {
 		"k"
 };
 
-const char *
+const xmlChar *
 dracoid_name(const unit *u)
 {
 	static char name[NAMESIZE + 1];
@@ -650,11 +650,11 @@ dracoid_name(const unit *u)
 	return name;
 }
 
-const char *
-abkz(const char *s, size_t max)
+const xmlChar *
+abkz(const xmlChar *s, size_t max)
 {
 	static char buf[32];
-	const char *p = s;
+	const xmlChar *p = s;
 	unsigned int c = 0;
 	size_t bpt, i;
 
@@ -662,7 +662,7 @@ abkz(const char *s, size_t max)
 
 	/* Pr�fen, ob Kurz genug */
 
-	if (strlen(s) <= max) {
+	if (xmlStrlen(s) <= max) {
 		return s;
 	}
 	/* Anzahl der W�rter feststellen */
@@ -728,7 +728,7 @@ register_names(void)
   register_function((pf_generic)ghoul_name, "nameghoul");
   register_function((pf_generic)drachen_name, "namedragon");
   register_function((pf_generic)dracoid_name, "namedracoid");
-  register_function((pf_generic)shadow_name, "nameshadow");
+  register_function((pf_generic)generic_name, "namegeneric");
 }
 
 
diff --git a/src/common/kernel/names.h b/src/common/kernel/names.h
index 4ff7af503..cb2daf475 100644
--- a/src/common/kernel/names.h
+++ b/src/common/kernel/names.h
@@ -19,14 +19,14 @@
 extern "C" {
 #endif
 extern void register_names(void);
-const char *untoten_name(const struct unit * u);
-const char *skeleton_name(const struct unit * u);
-const char *zombie_name(const struct unit * u);
-const char *ghoul_name(const struct unit * u);
-const char *drachen_name(const struct unit *u);
-const char *dracoid_name(const struct unit *u);
-const char *shadow_name(const struct unit *u);
-const char *abkz(const char *s, size_t max);
+const xmlChar *untoten_name(const struct unit * u);
+const xmlChar *skeleton_name(const struct unit * u);
+const xmlChar *zombie_name(const struct unit * u);
+const xmlChar *ghoul_name(const struct unit * u);
+const xmlChar *drachen_name(const struct unit *u);
+const xmlChar *dracoid_name(const struct unit *u);
+const xmlChar *generic_name(const struct unit *u);
+const xmlChar *abkz(const xmlChar *s, size_t max);
 
 #ifdef __cplusplus
 }
diff --git a/src/common/kernel/order.c b/src/common/kernel/order.c
index 35e865de6..63faa87e1 100644
--- a/src/common/kernel/order.c
+++ b/src/common/kernel/order.c
@@ -16,6 +16,7 @@
 
 #include "skill.h"
 
+#include <util/base36.h>
 #include <util/bsdstring.h>
 #include <util/language.h>
 #include <util/parser.h>
@@ -26,40 +27,27 @@
 #include <stdlib.h>
 #include <string.h>
 
-#define SHORT_STRINGS
-
-#ifdef SHARE_ORDERS
 # define ORD_KEYWORD(ord) (ord)->data->_keyword
 # define ORD_LOCALE(ord) locale_array[(ord)->data->_lindex]->lang
 # define ORD_STRING(ord) (ord)->data->_str
-#else
-# define ORD_KEYWORD(ord) (ord)->data._keyword
-# define ORD_LOCALE(ord) locale_array[ord->data._lindex]->lang
-# define ORD_STRING(ord) (ord)->data._str
-#endif
 
 
 typedef struct locale_data {
-#ifdef SHARE_ORDERS
   struct order_data * short_orders[MAXKEYWORDS];
   struct order_data * study_orders[MAXSKILLS];
-#endif
   const struct locale * lang;
 } locale_data;
 
 static struct locale_data * locale_array[16];
 static int nlocales = 0;
 
-#ifdef SHARE_ORDERS
 typedef struct order_data {
-  char * _str; 
+  xmlChar * _str; 
   int _refcount : 20;
   int _lindex : 4;
   keyword_t _keyword;
 } order_data;
-#endif
 
-#ifdef SHARE_ORDERS
 static void
 release_data(order_data * data)
 {
@@ -70,7 +58,6 @@ release_data(order_data * data)
     }
   }
 }
-#endif
 
 void
 replace_order(order ** dlist, order * orig, const order * src)
@@ -97,38 +84,34 @@ get_keyword(const order * ord)
   return ORD_KEYWORD(ord);
 }
 
-static char *
-get_command(const order * ord, char * sbuffer, size_t bufsize)
+static xmlChar *
+get_command(const order * ord, xmlChar * sbuffer, size_t bufsize)
 {
-  char * str = sbuffer;
-  const char * text = ORD_STRING(ord);
-#ifdef SHORT_STRINGS
+  xmlChar * str = sbuffer;
+  const xmlChar * text = ORD_STRING(ord);
   keyword_t kwd = ORD_KEYWORD(ord);
-#endif
 
   if (ord->_persistent) *str++ = '@';
-#ifdef SHORT_STRINGS
   if (kwd!=NOKEYWORD) {
     const struct locale * lang = ORD_LOCALE(ord);
     size_t size = bufsize-(str-sbuffer);
     if (text) --size;
-    str += strlcpy(str, LOC(lang, keywords[kwd]), size);
+    str += strlcpy((char*)str, (const char*)LOC(lang, keywords[kwd]), size);
     if (text) {
       *str++ = ' ';
     }
   }
-#endif
   if (text) {
-    str += strlcpy(str, text, bufsize-(str-sbuffer));
+    str += strlcpy((char*)str, (const char *)text, bufsize-(str-sbuffer));
   }
   return sbuffer;
 }
 
-char *
+xmlChar *
 getcommand(const order * ord)
 {
-  char sbuffer[DISPLAYSIZE*2];
-  return strdup(get_command(ord, sbuffer, sizeof(sbuffer)));
+  xmlChar sbuffer[DISPLAYSIZE*2];
+  return xmlStrdup(get_command(ord, sbuffer, sizeof(sbuffer)));
 }
 
 void 
@@ -137,11 +120,7 @@ free_order(order * ord)
   if (ord!=NULL) {
     assert(ord->next==0);
 
-#ifdef SHARE_ORDERS
     release_data(ord->data);
-#else
-    if (ord->data._str) free(ord->data._str);
-#endif
     free(ord);
   }
 }
@@ -154,9 +133,7 @@ copy_order(const order * src)
     ord->next = NULL;
     ord->_persistent = src->_persistent;
     ord->data = src->data;
-#ifdef SHARE_ORDERS
     ++ord->data->_refcount;
-#endif
     return ord;
   }
   return NULL;
@@ -181,13 +158,15 @@ free_orders(order ** olist)
 	}
 }
 
-#ifdef SHARE_ORDERS
 static order_data *
-create_data(keyword_t kwd, const char * s, const char * sptr, int lindex)
+create_data(keyword_t kwd, const xmlChar * sptr, int lindex)
 {
+  const xmlChar * s = sptr;
   order_data * data;
   const struct locale * lang = locale_array[lindex]->lang;
 
+  if (kwd!=NOKEYWORD) s = (*sptr)?sptr:NULL;
+
   /* learning, only one order_data per skill required */
   if (kwd==K_STUDY) {
     skill_t sk = findskill(parse_token(&sptr), lang);
@@ -199,26 +178,21 @@ create_data(keyword_t kwd, const char * s, const char * sptr, int lindex)
       default: /* nur skill als Parameter, keine extras */
         data = locale_array[lindex]->study_orders[sk];
         if (data==NULL) {
-          const char * skname = skillname(sk, lang);
+          const xmlChar * skname = skillname(sk, lang);
           data = (order_data*)malloc(sizeof(order_data));
           locale_array[lindex]->study_orders[sk] = data;
           data->_keyword = kwd;
           data->_lindex = lindex;
-#ifdef SHORT_STRINGS
-          if (strchr(skname, ' ')!=NULL) {
-            sprintf(buf, "\"%s\"", skname);
-            data->_str = strdup(buf);
+          if (xmlStrchr(skname, ' ')!=NULL) {
+            size_t len = xmlStrlen(skname);
+            data->_str = (xmlChar*)malloc(len+3);
+            data->_str[0]='\"';
+            memcpy(data->_str+1, skname, len);
+            data->_str[len+1]='\"';
+            data->_str[len+2]='\0';
           } else {
-            data->_str = strdup(skname);
+            data->_str = xmlStrdup(skname);
           }
-#else
-          if (strchr(skname, ' ')!=NULL) {
-            sprintf(buf, "%s \"%s\"", LOC(lang, keywords[kwd]), skname);
-          } else {
-            sprintf(buf, "%s %s", LOC(lang, keywords[kwd]), skname);
-          }
-          data->_str = strdup(buf);
-#endif
           data->_refcount = 1;
         }
         ++data->_refcount;
@@ -234,11 +208,7 @@ create_data(keyword_t kwd, const char * s, const char * sptr, int lindex)
       locale_array[lindex]->short_orders[kwd] = data;
       data->_keyword = kwd;
       data->_lindex = lindex;
-#ifdef SHORT_STRINGS
       data->_str = NULL;
-#else
-      data->_str = strdup(LOC(lang, keywords[kwd]));
-#endif
       data->_refcount = 1;
     }
     ++data->_refcount;
@@ -247,23 +217,88 @@ create_data(keyword_t kwd, const char * s, const char * sptr, int lindex)
   data = (order_data*)malloc(sizeof(order_data));
   data->_keyword = kwd;
   data->_lindex = lindex;
-  data->_str = s?strdup(s):NULL;
+  data->_str = s?xmlStrdup(s):NULL;
   data->_refcount = 1;
   return data;
 }
-#endif
+
+static order *
+create_order_i(keyword_t kwd, const xmlChar * sptr, int persistent, const struct locale * lang)
+{
+  order * ord = NULL;
+  int lindex;
+
+  /* if this is just nonsense, then we skip it. */
+  if (lomem) {
+    switch (kwd) {
+        case K_KOMMENTAR:
+        case NOKEYWORD:
+          return NULL;
+        case K_LIEFERE:
+          kwd = K_GIVE;
+          persistent = 1;
+          break;
+        default:
+          break;
+    }
+  }
+
+  for (lindex=0;lindex!=nlocales;++lindex) {
+    if (locale_array[lindex]->lang==lang) break;
+  }
+  if (lindex==nlocales) {
+    locale_array[nlocales] = (locale_data*)calloc(1, sizeof(locale_data));
+    locale_array[nlocales]->lang = lang;
+    ++nlocales;
+  }
+
+  ord = (order*)malloc(sizeof(order));
+  ord->_persistent = persistent;
+  ord->next = NULL;
+
+  ord->data = create_data(kwd, sptr, lindex);
+
+  return ord;
+}
+
+order *
+create_order(keyword_t kwd, const struct locale * lang, const char * params, ...)
+{
+  va_list marker;
+  char zBuffer[DISPLAYSIZE];
+  char * sptr = zBuffer;
+
+  va_start(marker, params);
+  while (params) {
+    switch (*params) {
+      case '%':
+      case ' ':
+        /* ignore these, they are syntactical sugar */
+        break;
+      case 's':
+        sptr += strlcpy(sptr, va_arg(marker, const char *), sizeof(zBuffer)-(sptr-zBuffer));
+        break;
+      case 'd':
+        sptr += strlcpy(sptr, itoa10(va_arg(marker, int)), sizeof(zBuffer)-(sptr-zBuffer));
+        break;
+      case 'i':
+        sptr += strlcpy(sptr, itoa36(va_arg(marker, int)), sizeof(zBuffer)-(sptr-zBuffer));
+        break;
+    }
+  }
+  va_end(marker);
+
+  return create_order_i(kwd, (const xmlChar*)sptr, 0, lang);
+}
 
 order * 
-parse_order(const char * s, const struct locale * lang)
+parse_order(const xmlChar * s, const struct locale * lang)
 {
   while (*s && !isalnum(*(unsigned char*)s) && !ispunct(*(unsigned char*)s)) ++s;
-  if (*s==0) return NULL;
-  else {
+  if (*s!=0) {
     keyword_t kwd;
-    const char * sptr;
-    order * ord = NULL;
+    const xmlChar * sptr;
     int persistent = 0;
-    int lindex;
 
     while (*s=='@') {
       persistent = 1;
@@ -271,51 +306,13 @@ parse_order(const char * s, const struct locale * lang)
     }
     sptr = s;
     kwd = findkeyword(parse_token(&sptr), lang);
-    while (isspace(*(unsigned char*)sptr)) ++sptr;
-
-    /* if this is just nonsense, then we skip it. */
-    if (lomem) {
-      switch (kwd) {
-        case K_KOMMENTAR:
-        case NOKEYWORD:
-          return NULL;
-#ifdef SHORT_STRINGS
-        case K_LIEFERE:
-          kwd = K_GIVE;
-          persistent = 1;
-          break;
-#endif
-        default:
-          break;
-      }
+    if (kwd!=NOKEYWORD) {
+      while (isspace(*(unsigned char*)sptr)) ++sptr;
+      s = sptr;
     }
-
-    for (lindex=0;lindex!=nlocales;++lindex) {
-      if (locale_array[lindex]->lang==lang) break;
-    }
-    if (lindex==nlocales) {
-      locale_array[nlocales] = (locale_data*)calloc(1, sizeof(locale_data));
-      locale_array[nlocales]->lang = lang;
-      ++nlocales;
-    }
-
-    ord = (order*)malloc(sizeof(order));
-    ord->_persistent = persistent;
-    ord->next = NULL;
-
-#ifdef SHORT_STRINGS
-    if (kwd!=NOKEYWORD) s = (*sptr)?sptr:NULL;
-#endif
-#ifdef SHARE_ORDERS
-    ord->data = create_data(kwd, s, sptr, lindex);
-#else
-    ord->data._keyword = kwd;
-    ord->data._lindex = lindex;
-    ord->data._str = s?strdup(s):NULL;
-#endif
-
-    return ord;
+    return create_order_i(kwd, s, persistent, lang);
   }
+  return NULL;
 }
 
 boolean
@@ -456,16 +453,16 @@ is_persistent(const order * ord)
 	return persist || is_repeated(ord);
 }
 
-char * 
-write_order(const order * ord, const struct locale * lang, char * buffer, size_t size)
+xmlChar * 
+write_order(const order * ord, const struct locale * lang, xmlChar * buffer, size_t size)
 {
   if (ord==0) {
     buffer[0]=0;
   } else {
     keyword_t kwd = ORD_KEYWORD(ord);
     if (kwd==NOKEYWORD) {
-      const char * text = ORD_STRING(ord);
-      strlcpy(buffer, text, size);
+      const xmlChar * text = ORD_STRING(ord);
+      strlcpy((char *)buffer, (const char *)text, size);
     } else {
       get_command(ord, buffer, size);
     }
diff --git a/src/common/kernel/order.h b/src/common/kernel/order.h
index fd3d1fcc1..02d56adb3 100644
--- a/src/common/kernel/order.h
+++ b/src/common/kernel/order.h
@@ -25,9 +25,6 @@ extern "C" {
  * implemented yet) saving approx. 50% of all string-related memory.
  */
 
-#define SHARE_ORDERS
-
-#ifdef SHARE_ORDERS
 struct order_data;
 
 typedef struct order {
@@ -36,23 +33,9 @@ typedef struct order {
   struct order_data * data;
   int _persistent : 1;
 } order;
-#else
-typedef struct order_data {
-  char * _str; 
-  int _lindex : 8;
-  keyword_t _keyword;
-} order_data;
-
-typedef struct order {
-  struct order * next;
-  /* do not access this data: */
-  struct order_data data;
-  int _persistent : 1;
-} order;
-#endif
 
 /* constructor */
-extern order * parse_order(const char * s, const struct locale * lang);
+extern order * parse_order(const xmlChar * s, const struct locale * lang);
 extern void replace_order(order ** dst, order * orig, const order * src);
 
 /* reference counted copies of orders: */
@@ -63,12 +46,12 @@ extern void free_orders(order ** olist);
 /* access functions for orders */
 extern keyword_t get_keyword(const order * ord);
 extern void set_order(order ** destp, order * src);
-extern char * getcommand(const order * ord);
+extern xmlChar * getcommand(const order * ord);
 extern boolean is_persistent(const order *ord);
 extern boolean is_exclusive(const order *ord);
 extern boolean is_repeated(const order * ord);
 
-extern char * write_order(const order * ord, const struct locale * lang, char * buffer, size_t size);
+extern xmlChar * write_order(const order * ord, const struct locale * lang, xmlChar * buffer, size_t size);
 
 
 #ifdef __cplusplus
diff --git a/src/common/kernel/pool.c b/src/common/kernel/pool.c
index 60b4a8bf8..e20c6aec6 100644
--- a/src/common/kernel/pool.c
+++ b/src/common/kernel/pool.c
@@ -270,16 +270,15 @@ reserve_cmd(unit * u, struct order *ord)
   if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) {
     int use, count;
     const resource_type * rtype;
-    const char * s;
+    const xmlChar * s;
 
     init_tokens(ord);
     skip_token();
     s = getstrtoken();
-    count = atoip(s);
+    count = atoip((const char *)s);
 
     if (count == 0 && findparam(s, u->faction->locale)==P_EACH) {
-      s = getstrtoken();
-      count = atoip(s) * u->number;
+      count = getint() * u->number;
     }
 
     rtype = findresourcetype(getstrtoken(), u->faction->locale);
diff --git a/src/common/kernel/race.c b/src/common/kernel/race.c
index b4a609437..d9b1b6bcc 100644
--- a/src/common/kernel/race.c
+++ b/src/common/kernel/race.c
@@ -284,7 +284,7 @@ raceprefix(const unit *u)
   return get_prefix(asource);
 }
 
-const char *
+const xmlChar *
 racename(const struct locale *loc, const unit *u, const race * rc)
 {
   const char * prefix = raceprefix(u);
diff --git a/src/common/kernel/race.h b/src/common/kernel/race.h
index 792fdcf9a..37e85cd90 100644
--- a/src/common/kernel/race.h
+++ b/src/common/kernel/race.h
@@ -78,8 +78,8 @@ typedef struct race {
 	int ec_flags;
 	race_t oldfamiliars[MAXMAGIETYP];
 
-	const char *(*generate_name) (const struct unit *);
-	const char *(*describe) (const struct unit *, const struct locale *);
+	const xmlChar *(*generate_name) (const struct unit *);
+	const xmlChar *(*describe) (const struct unit *, const struct locale *);
 	void (*age)(struct unit *u);
 	boolean (*move_allowed)(const struct region *, const struct region *);
 	struct item * (*itemdrop)(const struct race *, int size);
@@ -155,7 +155,7 @@ extern int rc_specialdamage(const race *, const race *, const struct weapon_type
 #define BF_CANATTACK    (1<<6) /* Kann keine ATTACKIERE Befehle ausfuehren */
 
 extern int unit_old_max_hp(struct unit * u);
-extern const char * racename(const struct locale *lang, const struct unit *u, const race * rc);
+extern const xmlChar * racename(const struct locale *lang, const struct unit *u, const race * rc);
 
 #define omniscient(f) (((f)->race)==new_race[RC_ILLUSION] || ((f)->race)==new_race[RC_TEMPLATE])
 
diff --git a/src/common/kernel/region.c b/src/common/kernel/region.c
index 1dab44237..183e31d8c 100644
--- a/src/common/kernel/region.c
+++ b/src/common/kernel/region.c
@@ -100,7 +100,8 @@ dir_invert(direction_t dir)
   assert(!"illegal direction");
   return NODIRECTION;
 }
-const char *
+
+const xmlChar *
 regionname(const region * r, const faction * f)
 {
   static char buf[65];
@@ -729,7 +730,6 @@ new_region(short x, short y)
   r->y = y;
   r->age = 1;
   r->planep = findplane(x, y);
-  set_string(&r->display, "");
   rhash(r);
   if (last)
     addlist(&last, r);
@@ -1074,18 +1074,21 @@ r_getmessages(const struct region * r, const struct faction * viewer)
 struct message *
 r_addmessage(struct region * r, const struct faction * viewer, struct message * msg)
 {
-  struct individual_message * imsg;
   assert(r);
-  imsg = r->individual_messages;
-  while (imsg && imsg->viewer!=viewer) imsg = imsg->next;
-  if (imsg==NULL) {
-    imsg = malloc(sizeof(struct individual_message));
-    imsg->next = r->individual_messages;
-    imsg->msgs = NULL;
-    r->individual_messages = imsg;
-    imsg->viewer = viewer;
+  if (viewer) {
+    struct individual_message * imsg;
+    imsg = r->individual_messages;
+    while (imsg && imsg->viewer!=viewer) imsg = imsg->next;
+    if (imsg==NULL) {
+      imsg = malloc(sizeof(struct individual_message));
+      imsg->next = r->individual_messages;
+      imsg->msgs = NULL;
+      r->individual_messages = imsg;
+      imsg->viewer = viewer;
+    }
+    return add_message(&imsg->msgs, msg);
   }
-  return add_message(&imsg->msgs, msg);
+  return add_message(&r->msgs, msg);
 }
 
 struct faction *
diff --git a/src/common/kernel/region.h b/src/common/kernel/region.h
index 38c5fc47b..68fe4df52 100644
--- a/src/common/kernel/region.h
+++ b/src/common/kernel/region.h
@@ -97,7 +97,7 @@ typedef struct region {
      and lastregion */
   short x, y;
   struct plane *planep;
-  char *display;
+  xmlChar *display;
   unsigned int flags;
   unsigned short age;
   struct message_list *msgs;
@@ -131,8 +131,8 @@ typedef struct spec_direction {
   short x, y;
   int  duration;
   boolean active;
-  char *desc;
-  char *keyword;
+  xmlChar *desc;
+  xmlChar *keyword;
 } spec_direction;
 
 typedef struct {
@@ -217,7 +217,7 @@ extern const char * rname(const struct region * r, const struct locale * lang);
 extern void r_setdemand(struct region * r, const struct luxury_type * ltype, int value);
 extern int r_demand(const struct region * r, const struct luxury_type * ltype);
 
-extern const char * regionname(const struct region * r, const struct faction * f);
+extern const xmlChar * regionname(const struct region * r, const struct faction * f);
 extern void * resolve_region(variant data);
 extern struct region * new_region(short x, short y);
 extern void terraform(struct region * r, terrain_t terrain);
diff --git a/src/common/kernel/reports.c b/src/common/kernel/reports.c
index e3444492b..3304fbdff 100644
--- a/src/common/kernel/reports.c
+++ b/src/common/kernel/reports.c
@@ -231,7 +231,7 @@ buforder(char * bufp, size_t size, const order * ord, int mode)
 }
 
 int
-bufunit(const faction * f, const unit * u, int indent, int mode)
+bufunit(const faction * f, const unit * u, int indent, int mode, char * buf, size_t size)
 {
   int i, dh;
   int getarnt = fval(u, UFL_PARTEITARNUNG);
@@ -247,7 +247,7 @@ bufunit(const faction * f, const unit * u, int indent, int mode)
   boolean itemcloak = false;
   static const curse_type * itemcloak_ct = 0;
   static boolean init = false;
-  size_t size = sizeof(buf), rsize;
+  size_t rsize;
 
   if (!init) {
     init = true;
@@ -1319,9 +1319,10 @@ write_reports(faction * f, time_t ltime)
     }
 
     if (errno) {
+      char zText[64];
       puts(" ERROR");
-      sprintf(buf, "Waiting %u seconds before retry", backup);
-      perror(buf);
+      sprintf(zText, "Waiting %u seconds before retry", backup);
+      perror(zText);
       sleep(backup);
       if (backup<maxbackup) {
         backup *= 2;
@@ -1387,6 +1388,7 @@ static void
 write_script(FILE * F, const faction * f)
 {
   report_type * rtype;
+  char buf[1024];
 
   fprintf(F, "faction=%s:email=%s", factionid(f), f->email);
   if (f->options & (1<<O_BZIP2)) fputs(":compression=bz2", F);
@@ -1446,15 +1448,16 @@ reports(void)
   time_t ltime = time(NULL);
   const char * str;
   int retval = 0;
+  char path[MAX_PATH];
 
   nmr_warnings();
   report_donations();
   remove_empty_units();
 
-  sprintf(buf, "%s/reports.txt", reportpath());
-  mailit = fopen(buf, "w");
+  sprintf(path, "%s/reports.txt", reportpath());
+  mailit = fopen(path, "w");
   if (mailit == NULL) {
-    log_error(("%s konnte nicht ge�ffnet werden!\n", buf));
+    log_error(("%s konnte nicht ge�ffnet werden!\n", path));
   }
 
   for (f = factions; f; f = f->next) {
@@ -1467,8 +1470,8 @@ reports(void)
   str = get_param(global.parameters, "globalreport"); 
 #ifdef GLOBAL_REPORT
   if (str!=NULL) {
-    sprintf(buf, "%s/%s.%u.cr", reportpath(), str, turn);
-    global_report(buf);
+    sprintf(path, "%s/%s.%u.cr", reportpath(), str, turn);
+    global_report(path);
   }
 #endif
   return retval;
@@ -1529,6 +1532,37 @@ var_free_resources(variant x)
   }
 }
 
+static variant
+var_copy_regions(variant x)
+{
+  region_list * rsrc;
+  size_t size = 0;
+
+  for (rsrc = (region_list*)x.v; rsrc!=NULL; rsrc=rsrc->next) {
+    ++size;
+  }
+
+  if (size>0) {
+    arg_regions * dst = (arg_regions *)malloc(sizeof(arg_regions) + sizeof(region*) * size);
+    dst->nregions = size;
+    dst->regions = (region**)(dst+1);
+    size = 0;
+    for (rsrc = (region_list*)x.v; rsrc!=NULL; rsrc=rsrc->next) {
+      dst->regions[size++] = rsrc->data;
+    }
+    x.v = dst;
+  } else {
+    x.v = NULL;
+  }
+  return x;
+}
+
+static void
+var_free_regions(variant x)
+{
+  free(x.v);
+}
+
 void
 reports_init(void)
 {
@@ -1549,6 +1583,7 @@ reports_init(void)
   register_argtype("order", var_free_order, var_copy_order, VAR_VOIDPTR);
   register_argtype("resources", var_free_resources, NULL, VAR_VOIDPTR);
   register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR);
+  register_argtype("regions", var_free_regions, var_copy_regions, VAR_VOIDPTR);
 
   /* register alternative visibility functions */
   register_function((pf_generic)view_neighbours, "view_neighbours");
diff --git a/src/common/kernel/reports.h b/src/common/kernel/reports.h
index f0cd9e044..5182397e4 100644
--- a/src/common/kernel/reports.h
+++ b/src/common/kernel/reports.h
@@ -99,7 +99,7 @@ extern void register_reporttype(const char * extension, report_fun write, int fl
   
 extern void report_item(const struct unit * owner, const struct item * i, const struct faction * viewer, const char ** name, const char ** basename, int * number, boolean singular);
 extern void report_building(FILE *F, const struct region * r, const struct building * b, const struct faction * f, int mode);
-extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode);
+extern int bufunit(const struct faction * f, const struct unit * u, int indent, int mode, char * buf, size_t size);
 
 extern const char * reportpath(void);
 extern const char * trailinto(const struct region * r, const struct locale * lang);
@@ -112,6 +112,12 @@ extern const char * report_kampfstatus(const struct unit * u, const struct local
 
   extern struct message * msg_curse(const struct curse * c, const void * obj, typ_t typ, int slef);
 
+  typedef struct arg_regions {
+    int nregions;
+    struct region ** regions;
+  } arg_regions;
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/common/kernel/save.c b/src/common/kernel/save.c
index 6a2f7749d..edf677c67 100644
--- a/src/common/kernel/save.c
+++ b/src/common/kernel/save.c
@@ -57,6 +57,7 @@
 #include <util/base36.h>
 #include <util/bsdstring.h>
 #include <util/event.h>
+#include <util/filereader.h>
 #include <util/goodies.h>
 #include <util/lists.h>
 #include <util/parser.h>
@@ -66,6 +67,8 @@
 #include <util/rng.h>
 #include <util/umlaut.h>
 
+#include <libxml/encoding.h>
+
 /* libc includes */
 #include <string.h>
 #include <stdio.h>
@@ -328,6 +331,8 @@ rs(FILE * F, char *s)
 	*s = 0;
 }
 
+#define rss(F, buf, size) rs(F, buf) /* should check size but doesn't */
+
 static int
 ri(FILE * F)
 {
@@ -355,12 +360,14 @@ ri(FILE * F)
 static int
 ri36(FILE * F)
 {
-	char buf[64];
+	char buf[10];
 	int i = 0;
 	rc(F);
 	while (!isalnum(nextc)) rc(F);
 	while (isalnum(nextc)) {
-		buf[i++]=(char)nextc;
+    if (i+1<sizeof(buf)) {
+  		buf[i++]=(char)nextc;
+    }
 		rc(F);
 	}
 	buf[i]=0;
@@ -368,92 +375,6 @@ ri36(FILE * F)
 	return i;
 }
 
-#define MAXLINE 4096*16
-static char lbuf[MAXLINE];
-static char *
-getbuf(FILE * F)
-{
-  boolean cont = false;
-  boolean quote = false;
-  boolean comment = false;
-  char * cp = buf;
-  
-  lbuf[MAXLINE-1] = '@';
-  
-  do {
-    boolean eatwhite = true;
-    boolean start = true;
-    unsigned char * end;
-    unsigned char * bp = (unsigned char * )fgets(lbuf, MAXLINE, F);
-    
-    comment = (boolean)(comment && cont);
-    
-    if (!bp) return NULL;
-    
-    end = bp + strlen((const char *)bp);
-    if (*(end-1)=='\n') *(--end) = 0;
-    else {
-      /* wenn die zeile l�nger als erlaubt war, ist sie ung�ltig,
-       * und wird mit dem rest weggeworfen: */
-      for (;;) {
-        bp = (unsigned char *)fgets(lbuf, MAXLINE, F);
-        if (bp==NULL) break;
-        end = bp + strlen((const char *)bp);
-        if (*(end-1)=='\n') break;
-        lbuf[MAXLINE-1] = 0;
-      }
-      comment = false;
-      bp = NULL;
-    }
-    cont = false;
-    while (bp!=NULL && *bp && cp!=buf+MAXLINE && (char*)bp!=lbuf+MAXLINE) {
-      if (isspace(*bp)) {
-        if (cont) ++bp; /* removes spaces and \r afer a backslash */
-        else if (eatwhite) {
-          do { ++bp; } while ((char*)bp!=lbuf+MAXLINE && isspace(*bp));
-          if (!quote && !start && !comment) *(cp++)=' ';
-        }
-        else {
-          if (!comment) *(cp++)=*(bp++);
-          while (cp!=buf+MAXLINE && (char*)bp!=lbuf+MAXLINE && isspace(*bp)) {
-            if (!comment) *(cp++)=*bp;
-            ++bp;
-          }
-          if (*bp==0) --cp;
-        }
-      }
-      else if (iscntrl(*bp)) {
-        *(cp++) = '?';
-        ++bp;
-      } else {
-        cont = false;
-        if (*bp==COMMENT_CHAR && !quote) {
-          comment=true;
-        }
-        else {
-          if (*bp=='"') {
-            quote = (boolean)!quote;
-            *cp++ = *bp;
-            eatwhite=true;
-          }
-          else if (*bp=='\\') cont=true;
-          else {
-            if (!comment) *(cp++) = *bp;
-            eatwhite = (boolean)!quote;
-          }
-        }
-        ++bp;
-      }
-      start = false;
-    }
-    if (cp==buf+MAXLINE) {
-      --cp;
-    }
-    *cp=0;
-  } while (cont || cp==buf);
-  return buf;
-}
-
 #ifdef ENEMIES
 static void
 read_enemies(FILE * F, faction * f)
@@ -485,7 +406,7 @@ write_enemies(FILE * F, const faction_list * flist)
 #endif
 
 static unit *
-unitorders(FILE * F, struct faction * f)
+unitorders(FILE * F, int enc, struct faction * f)
 {
   int i;
   unit *u;
@@ -527,14 +448,15 @@ unitorders(FILE * F, struct faction * f)
     ordp = &u->orders;
 
     for (;;) {
-      const char * s;
+      const xmlChar * s;
       /* Erst wenn wir sicher sind, dass kein Befehl
       * eingegeben wurde, checken wir, ob nun eine neue
       * Einheit oder ein neuer Spieler drankommt */
 
-      if (!getbuf(F)) break;
+      s = getbuf(F, enc);
+      if (s==NULL) break;
 
-      init_tokens_str(buf, NULL);
+      init_tokens_str(s, NULL);
       s = getstrtoken();
 
       if (findkeyword(s, u->faction->locale) == NOKEYWORD) {
@@ -549,9 +471,9 @@ unitorders(FILE * F, struct faction * f)
         }
         if (quit) break;
       }
-      if (buf[0]) {
+      if (s[0]) {
         /* Nun wird der Befehl erzeut und eingeh�ngt */
-        *ordp = parse_order(buf, u->faction->locale);
+        *ordp = parse_order(s, u->faction->locale);
         if (*ordp) ordp = &(*ordp)->next;
       }
     }
@@ -619,25 +541,26 @@ version(void)
 /* ------------------------------------------------------------- */
 
 static param_t
-igetparam (const char *s, const struct locale *lang)
+igetparam (const xmlChar *s, const struct locale *lang)
 {
   return findparam (igetstrtoken (s), lang);
 }
 
 int
-readorders(const char *filename)
+readorders(const char *filename, const char * encoding)
 {
 	FILE * F = NULL;
 	char *b;
 	int nfactions=0;
 	struct faction *f = NULL;
+  int enc = xmlParseCharEncoding(encoding);
 
 	if (filename) F = cfopen(filename, "rt");
 	if (F==NULL) return 0;
 
 	puts(" - lese Befehlsdatei...\n");
 
-	b = getbuf(F);
+	b = getbuf(F, enc);
 
 	/* Auffinden der ersten Partei, und danach abarbeiten bis zur letzten
 	 * Partei */
@@ -657,7 +580,7 @@ readorders(const char *filename)
 			}
 #endif
 
-			b = getbuf(F);
+			b = getbuf(F, enc);
 			break;
 		case P_GAMENAME:
 		case P_FACTION:
@@ -666,7 +589,7 @@ readorders(const char *filename)
 				++nfactions;
 			}
 
-			b = getbuf(F);
+			b = getbuf(F, enc);
 			break;
 
 			/* in factionorders wird nur eine zeile gelesen:
@@ -675,8 +598,8 @@ readorders(const char *filename)
 			 * vermerkt. */
 
 		case P_UNIT:
-			if (!f || !unitorders(F, f)) do {
-				b = getbuf(F);
+			if (!f || !unitorders(F, enc, f)) do {
+				b = getbuf(F, enc);
 				if (!b) break;
 				p = igetparam(b, lang);
 			} while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT && p != P_GAMENAME);
@@ -691,11 +614,11 @@ readorders(const char *filename)
 
 		case P_NEXT:
 			f = NULL;
-      b = getbuf(F);
+      b = getbuf(F, enc);
       break;
 
     default:
-			b = getbuf(F);
+			b = getbuf(F, enc);
       break;
 		}
 	}
@@ -781,10 +704,11 @@ void
 read_items(FILE *F, item **ilist)
 {
 	for (;;) {
+    char ibuf[32];
     const item_type * itype;
-		rs(F, buf);
-		if (!strcmp("end", buf)) break;
-    itype = it_find(buf);
+		rss(F, ibuf, sizeof(ibuf));
+		if (!strcmp("end", ibuf)) break;
+    itype = it_find(ibuf);
     assert(itype!=NULL);
     if (itype!=NULL) {
       i_change(ilist, itype, ri(F));
@@ -801,10 +725,11 @@ read_alliances(FILE * F)
     if (!AllianceRestricted() && !AllianceAuto()) return;
   }
 
-  rs(F, pbuf);
+  rss(F, pbuf, sizeof(pbuf));
 	while (strcmp(pbuf, "end")!=0) {
-		rs(F, buf);
-		makealliance(atoi36(pbuf), buf);
+    char aname[128];
+		rss(F, aname, sizeof(aname));
+		makealliance(atoi36(pbuf), aname);
 		rs(F, pbuf);
 	}
 }
@@ -943,8 +868,9 @@ lastturn(void)
 void
 fwriteorder(FILE * F, const struct order * ord, const struct locale * lang)
 {
-  write_order(ord, lang, buf, sizeof(buf));
-  if (buf[0]) fwritestr(F, buf);
+  char obuf[1024];
+  write_order(ord, lang, obuf, sizeof(obuf));
+  if (obuf[0]) fwritestr(F, obuf);
 }
 
 unit *
@@ -954,6 +880,7 @@ readunit(FILE * F)
   unit * u;
   int number, n, p;
   order ** orderp;
+  char obuf[1024];
 
   n = rid(F);
   u = findunit(n);
@@ -990,9 +917,10 @@ readunit(FILE * F)
     u->irace = new_race[(race_t)ri(F)];
   } else {
     char * space;
+    char rname[32];
     
-    rs(F, buf);
-    space = strchr(buf, ' ');
+    rss(F, rname, sizeof(rname));
+    space = strchr(rname, ' ');
     if (space!=NULL) {
       char * inc = space+1;
       char * outc = space;
@@ -1005,10 +933,10 @@ readunit(FILE * F)
       } while (*inc);
       *outc = 0;
     }
-    u->race = rc_find(buf);
+    u->race = rc_find(rname);
     assert(u->race);
-    rs(F, buf);
-    if (strlen(buf)) u->irace = rc_find(buf);
+    rss(F, rname, sizeof(rname));
+    if (strlen(rname)) u->irace = rc_find(rname);
     else u->irace = u->race;
   }
   if (u->race->describe) {
@@ -1069,11 +997,11 @@ readunit(FILE * F)
   }
   /* Persistente Befehle einlesen */
   free_orders(&u->orders);
-  freadstr(F, buf, sizeof(buf));
+  freadstr(F, obuf, sizeof(obuf));
   p = n = 0;
   orderp = &u->orders;
-  while (*buf != 0) {
-    order * ord = parse_order(buf, u->faction->locale);
+  while (obuf[0]) {
+    order * ord = parse_order(obuf, u->faction->locale);
     if (ord!=NULL) {
       if (++n<MAXORDERS) {
         if (!is_persistent(ord) || ++p<MAXPERSISTENT) {
@@ -1088,12 +1016,12 @@ readunit(FILE * F)
       }
       if (ord!=NULL) free_order(ord);
     }
-    freadstr(F, buf, sizeof(buf));
+    freadstr(F, obuf, sizeof(obuf));
   }
   if (global.data_version<NOLASTORDER_VERSION) {
     order * ord;
-    freadstr(F, buf, sizeof(buf));
-    ord = parse_order(buf, u->faction->locale);
+    freadstr(F, obuf, sizeof(obuf));
+    ord = parse_order(obuf, u->faction->locale);
     if (ord!=NULL) {
 #ifdef LASTORDER
       set_order(&u->lastorder, ord);
@@ -1250,6 +1178,7 @@ readregion(FILE * F, short x, short y)
 {
 	region * r = findregion(x, y);
 	const terrain_type * terrain;
+  char token[32];
 
 	if (r==NULL) {
 		r = new_region(x, y);
@@ -1338,12 +1267,12 @@ readregion(FILE * F, short x, short y)
 			assert(*pres==NULL);
 			for (;;) {
 				rawmaterial * res;
-				rs(F, buf);
-				if (strcmp(buf, "end")==0) break;
+				rss(F, token, sizeof(token));
+				if (strcmp(token, "end")==0) break;
 				res = calloc(sizeof(rawmaterial), 1);
-				res->type = rmt_find(buf);
+				res->type = rmt_find(token);
         if (res->type==NULL) {
-          log_error(("invalid resourcetype %s in data.\n", buf));
+          log_error(("invalid resourcetype %s in data.\n", token));
         }
 				assert(res->type!=NULL);
 				res->level = ri(F);
@@ -1368,9 +1297,9 @@ readregion(FILE * F, short x, short y)
 				pres=&res->next;
 			}
 		}
-		rs(F, buf);
-		if (strcmp(buf, "noherb") != 0) {
-      const resource_type * rtype = rt_find(buf);
+		rss(F, token, sizeof(token));
+		if (strcmp(token, "noherb") != 0) {
+      const resource_type * rtype = rt_find(token);
       assert(rtype && rtype->itype && fval(rtype->itype, ITF_HERB));
       rsetherbtype(r, rtype->itype);
 		} else {
@@ -1389,9 +1318,9 @@ readregion(FILE * F, short x, short y)
 	if (r->land) {
 		for (;;) {
       const struct item_type * itype;
-			rs(F, buf);
-			if (!strcmp(buf, "end")) break;
-      itype = it_find(buf);
+			rss(F, token, sizeof(token));
+			if (!strcmp(token, "end")) break;
+      itype = it_find(token);
       assert(itype->rtype->ltype);
 			r_setdemand(r, itype->rtype->ltype, ri(F));
 		}
@@ -1498,6 +1427,7 @@ readfaction(FILE * F)
   int i = rid(F);
   faction * f = findfaction(i);
   char * email = NULL;
+  char token[32];
 
   if (f==NULL) {
     f = (faction *) calloc(1, sizeof(faction));
@@ -1544,8 +1474,8 @@ readfaction(FILE * F)
   if (global.data_version < LOCALE_VERSION) {
     f->locale = find_locale("de");
   } else {
-    rs(F, buf);
-    f->locale = find_locale(buf);
+    rss(F, token, sizeof(token));
+    f->locale = find_locale(token);
   }
   f->lastorders = ri(F);
   f->age = ri(F);
@@ -1553,8 +1483,8 @@ readfaction(FILE * F)
     race_t rc = (char) ri(F);
     f->race = new_race[rc];
   } else {
-    rs(F, buf);
-    f->race = rc_find(buf);
+    rss(F, token, sizeof(token));
+    f->race = rc_find(token);
     assert(f->race);
   }
 #ifdef CONVERT_DBLINK
@@ -1577,8 +1507,8 @@ readfaction(FILE * F)
   }
   for (;;) {
     int level;
-    fscanf(F, "%s", buf);
-    if (strcmp("end", buf)==0) break;
+    fscanf(F, "%s", token);
+    if (strcmp("end", token)==0) break;
     fscanf(F, "%d ", &level);
   } 
   planes = ri(F);
@@ -1619,10 +1549,10 @@ readfaction(FILE * F)
     }
   } else {
     for (;;) {
-      rs(F, buf);
-      if (strcmp(buf, "end")==0) break;
+      rs(F, token);
+      if (strcmp(token, "end")==0) break;
       else {
-        int aid = atoi36(buf);
+        int aid = atoi36(token);
         int state = ri(F);
         sfp = addally(f, sfp, aid, state);
       }
@@ -1711,11 +1641,13 @@ readgame(const char * filename, int backup)
   unit *u;
   FILE * F;
   int rmax = maxregions;
+  char path[MAX_PATH];
+  char token[32];
 
-  sprintf(buf, "%s/%s", datapath(), filename);
+  sprintf(path, "%s/%s", datapath(), filename);
   log_printf("- reading game data from %s\n", filename);
-  if (backup) create_backup(buf);
-  F = cfopen(buf, "r");
+  if (backup) create_backup(path);
+  F = cfopen(path, "r");
   if (F==NULL) {
     log_error(("Keine Spieldaten gefunden.\n"));
     return -1;
@@ -1767,16 +1699,16 @@ readgame(const char * filename, int backup)
     pl->maxy = (short)ri(F);
     pl->flags = ri(F);
     if (global.data_version>WATCHERS_VERSION) {
-      rs(F, buf);
-      while (strcmp(buf, "end")!=0) {
+      rss(F, token, sizeof(token));
+      while (strcmp(token, "end")!=0) {
         watcher * w = calloc(sizeof(watcher),1);
         variant fno;
-        fno.i = atoi36(buf);
+        fno.i = atoi36(token);
         w->mode = (unsigned char)ri(F);
         w->next = pl->watchers;
         pl->watchers = w;
         ur_add(fno, (void**)&w->faction, resolve_faction);
-        rs(F, buf);
+        rss(F, token, sizeof(token));
       }
     }
     a_read(F, &pl->attribs);
@@ -1845,9 +1777,10 @@ readgame(const char * filename, int backup)
     }
     if (skip) {
       char * r;
+      char buffer[128];
       do {
-        r = fgets(buf, BUFSIZE, F); /* skip region */
-      } while (r && buf[0]!='\n');
+        r = fgets(buffer, sizeof(buffer), F); /* skip region */
+      } while (r && buffer[0]!='\n');
       continue;
     }
     --rmax;
@@ -1878,8 +1811,8 @@ readgame(const char * filename, int backup)
         /* b->type = oldbuildings[ri(F)]; */
       }
       else {
-        rs(F, buf);
-        b->type = bt_find(buf);
+        rss(F, token, sizeof(token));
+        b->type = bt_find(token);
       }
       b->region = r;
       a_read(F, &b->attribs);
@@ -1904,8 +1837,12 @@ readgame(const char * filename, int backup)
       if (sh->display && strlen(sh->display)>=DISPLAYSIZE) sh->display[DISPLAYSIZE] = 0;
 #endif
 
-      rs(F, buf);
-      sh->type = st_find(buf);
+      rss(F, token, sizeof(token));
+      sh->type = st_find(token);
+      if (sh->type==NULL) {
+        /* old datafiles */
+        sh->type = st_find(locale_string(default_locale, token));
+      }
       assert(sh->type || !"ship_type not registered!");
       sh->size = ri(F);
       sh->damage = ri(F);
@@ -1999,23 +1936,21 @@ writegame(const char *filename, int quiet)
   unit *u;
   plane *pl;
   FILE * F;
-#ifdef USE_PLAYERS
-  char playerfile[MAX_PATH];
-#endif
+  char path[MAX_PATH];
 
 #ifdef USE_PLAYERS
-  sprintf(buf, "%s/%d.players", datapath(), turn);
-  export_players(playerfile);
+  sprintf(path, "%s/%d.players", datapath(), turn);
+  export_players(path);
 #endif
 
-  sprintf(buf, "%s/%s", datapath(), filename);
+  sprintf(path, "%s/%s", datapath(), filename);
 #ifdef HAVE_UNISTD_H
-  if (access(buf, R_OK) == 0) {
+  if (access(path, R_OK) == 0) {
     /* make sure we don't overwrite some hardlinkedfile */
-    unlink(buf);
+    unlink(path);
   }
 #endif
-  F = cfopen(buf, "w");
+  F = cfopen(path, "w");
   if (F==NULL)
     return -1;
 
diff --git a/src/common/kernel/save.h b/src/common/kernel/save.h
index e3852d81d..36c49b982 100644
--- a/src/common/kernel/save.h
+++ b/src/common/kernel/save.h
@@ -34,7 +34,7 @@ double version(void);
  * dass hier ein Fehler (fehlende ") vorliegt */
 
 FILE * cfopen(const char *filename, const char *mode);
-int readorders(const char *);
+int readorders(const char *filename, const char * encoding);
 int creategame(void);
 extern int readgame(const char * filename, int backup);
 int writegame(const char *filename, int quiet);
diff --git a/src/common/kernel/ship.c b/src/common/kernel/ship.c
index bded2a964..643b2db0b 100644
--- a/src/common/kernel/ship.c
+++ b/src/common/kernel/ship.c
@@ -41,7 +41,7 @@ ship_typelist *shiptypes = NULL;
 static local_names * snames;
 
 const ship_type *
-findshiptype(const char * name, const struct locale * lang)
+findshiptype(const xmlChar * name, const struct locale * lang)
 {
 	local_names * sn = snames;
 	variant var;
@@ -57,7 +57,7 @@ findshiptype(const char * name, const struct locale * lang)
 		sn->lang = lang;
 		while (stl) {
       variant var;
-			const char * n = locale_string(lang, stl->type->name[0]);
+			const xmlChar * n = locale_string(lang, stl->type->name[0]);
       var.v = (void*)stl->type;
 			addtoken(&sn->names, n, var);
 			stl = stl->next;
@@ -73,10 +73,6 @@ st_find(const char* name)
 {
 	const struct ship_typelist * stl = shiptypes;
 	while (stl && strcasecmp(stl->type->name[0], name)) stl = stl->next;
-	if (!stl) { /* compatibility for old datafiles */
-		stl = shiptypes;
-		while (stl && strcasecmp(locale_string(default_locale, stl->type->name[0]), name)) stl = stl->next;
-	}
 	return stl?stl->type:NULL;
 }
 
@@ -170,7 +166,7 @@ captain(ship *sh, region *r)
 ship *
 new_ship(const ship_type * stype, const struct locale * lang, region * r)
 {
-	static char buffer[7 + IDSIZE + 1];
+	static xmlChar buffer[7 + IDSIZE + 1];
 	ship *sh = (ship *) calloc(1, sizeof(ship));
 
 	sh->no = newcontainerid();
@@ -178,9 +174,8 @@ new_ship(const ship_type * stype, const struct locale * lang, region * r)
 	sh->type = stype;
 	sh->region = r;
 
-	sprintf(buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh));
+	sprintf((char*)buffer, "%s %s", LOC(lang, stype->name[0]), shipid(sh));
 	set_string(&sh->name, buffer);
-	set_string(&sh->display, "");
 	shash(sh);
   addlist(&r->ships, sh);
 	return sh;
@@ -210,7 +205,7 @@ shipname(const ship * sh)
   static name idbuf[8];
   static int nextbuf = 0;
   char *ibuf = idbuf[(++nextbuf) % 8];
-  sprintf(ibuf, "%s (%s)", strcheck(sh->name, NAMESIZE), itoa36(sh->no));
+  sprintf(ibuf, "%s (%s)", sh->name, itoa36(sh->no));
   return ibuf;
 }
 
diff --git a/src/common/kernel/ship.h b/src/common/kernel/ship.h
index 2ed7e0eb8..34bcdf137 100644
--- a/src/common/kernel/ship.h
+++ b/src/common/kernel/ship.h
@@ -70,8 +70,8 @@ typedef struct ship {
 	struct ship *nexthash;
 	int no;
 	struct region *region;
-	char *name;
-	char *display;
+	xmlChar *name;
+	xmlChar *display;
 	struct attrib * attribs;
 	int size;
 	int damage; /* damage in 100th of a point of size */
@@ -91,7 +91,7 @@ extern const char *shipname(const struct ship * sh);
 extern struct ship *findship(int n);
 extern struct ship *findshipr(const struct region *r, int n);
 
-extern const struct ship_type * findshiptype(const char *s, const struct locale * lang);
+extern const struct ship_type * findshiptype(const xmlChar *s, const struct locale * lang);
 
 extern void register_ships(void);
 
diff --git a/src/common/kernel/skill.c b/src/common/kernel/skill.c
index 352753eef..a51309231 100644
--- a/src/common/kernel/skill.c
+++ b/src/common/kernel/skill.c
@@ -44,7 +44,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-static const char *skillnames[MAXSKILLS] =
+const char *skillnames[MAXSKILLS] =
 {
 	"alchemy",
 	"crossbow",
@@ -79,7 +79,7 @@ static const char *skillnames[MAXSKILLS] =
 
 static boolean skill_enabled[MAXSKILLS];
 
-const char * 
+const xmlChar * 
 skillname(skill_t sk, const struct locale * lang)
 {
   if (skill_enabled[sk]) {
diff --git a/src/common/kernel/skill.h b/src/common/kernel/skill.h
index a04022e7a..beca07b3f 100644
--- a/src/common/kernel/skill.h
+++ b/src/common/kernel/skill.h
@@ -46,7 +46,7 @@ extern void skill_init(void);
 extern void skill_done(void);
 extern struct attrib * make_skillmod(skill_t sk, unsigned int flags, skillmod_fun special, double multiplier, int bonus);
 
-extern const char * skillname(skill_t, const struct locale *);
+extern const xmlChar * skillname(skill_t, const struct locale *);
 extern skill_t sk_find(const char * name);
 extern void enable_skill(const char * name, boolean value);
 extern int level_days(int level);
@@ -59,6 +59,7 @@ extern int skill_compare(const skill * sk, const skill * sc);
 
 extern void sk_set(skill * sv, int level);
 
+extern const char *skillnames[];
 
 #ifdef __cplusplus
 }
diff --git a/src/common/kernel/spell.c b/src/common/kernel/spell.c
index 45c86a864..d4ad9e3b7 100644
--- a/src/common/kernel/spell.c
+++ b/src/common/kernel/spell.c
@@ -124,7 +124,7 @@ get_spellnames(const struct locale * lang, magic_t mtype)
 }
 
 static spell *
-get_spellfromtoken_i(const char *name, const struct locale * lang, magic_t mtype)
+get_spellfromtoken_i(const xmlChar *name, const struct locale * lang, magic_t mtype)
 {
   variant token = { 0 };
   spell_names * sn;
@@ -147,7 +147,7 @@ get_spellfromtoken_i(const char *name, const struct locale * lang, magic_t mtype
 }
 
 spell *
-get_spellfromtoken(unit *u, const char *name, const struct locale * lang)
+get_spellfromtoken(unit *u, const xmlChar *name, const struct locale * lang)
 {
   sc_mage * m = get_mage(u);
   spell * sp;
diff --git a/src/common/kernel/spell.h b/src/common/kernel/spell.h
index c636ee118..3ef5b2123 100644
--- a/src/common/kernel/spell.h
+++ b/src/common/kernel/spell.h
@@ -44,6 +44,7 @@ extern "C" {
   extern void register_spell(struct spell * sp);
   extern struct spell * find_spell(magic_t mtype, const char * name);
   extern struct spell * find_spellbyid(magic_t mtype, spellid_t i);
+  extern struct spell *get_spellfromtoken(struct unit *u, const xmlChar *s, const struct locale * lang);
 
 #ifdef __cplusplus
 }
diff --git a/src/common/kernel/teleport.c b/src/common/kernel/teleport.c
index 7772cff82..b2fbbba23 100644
--- a/src/common/kernel/teleport.c
+++ b/src/common/kernel/teleport.c
@@ -153,7 +153,6 @@ spawn_braineaters(float chance)
     if (next-- == 0) {
       unit *u = createunit(r, f0, 1+rng_int()%10+rng_int()%10, new_race[RC_HIRNTOETER]);
 
-      set_string(&u->name, "Hirnt�ter");
       set_level(u, SK_STEALTH, 1);
       set_level(u, SK_OBSERVATION, 1);
       next = rng_int() % (int)(chance*100);
diff --git a/src/common/kernel/unit.c b/src/common/kernel/unit.c
index bd46bd3a1..1b15c1171 100644
--- a/src/common/kernel/unit.c
+++ b/src/common/kernel/unit.c
@@ -66,28 +66,6 @@ attrib_type at_creator = {
     /* Rest ist NULL; tempor�res, nicht alterndes Attribut */
 };
 
-const unit *
-u_peasants(void)
-{
-	static unit peasants = { 0 };
-	if (peasants.name==NULL) {
-		peasants.name = strdup("die Bauern");
-    peasants.no = 2;
-	}
-	return &peasants;
-}
-
-const unit *
-u_unknown(void)
-{
-	static unit unknown = { 0 };
-	if (unknown.name==NULL) {
-		unknown.name =strdup("eine unbekannte Einheit");
-    unknown.no = 1;
-	}
-	return &unknown;
-}
-
 #define DMAXHASH 7919
 typedef struct dead {
 	struct dead * nexthash;
@@ -237,7 +215,7 @@ destroy_unit(unit * u)
       }
       if (*p_item == item) p_item=&item->next;
     }
-    if (u->items && (u->faction==NULL || strlen(u->faction->passw)>0)) {
+    if (u->items && (u->faction==NULL || u->faction->passw[0])) {
       distribute_items(u);
     }
   }
@@ -346,7 +324,7 @@ attrib_type at_private = {
 	a_readstring
 };
 
-const char *
+const xmlChar *
 u_description(const unit * u, const struct locale * lang)
 {
   if (u->display && u->display[0]) {
@@ -357,15 +335,15 @@ u_description(const unit * u, const struct locale * lang)
   return NULL;
 }
 
-const char *
+const xmlChar *
 uprivate(const unit * u) {
 	attrib * a = a_find(u->attribs, &at_private);
 	if (!a) return NULL;
-	return (const char*)a->data.v;
+	return (const xmlChar*)a->data.v;
 }
 
 void
-usetprivate(unit * u, const char * str) {
+usetprivate(unit * u, const xmlChar * str) {
 	attrib * a = a_find(u->attribs, &at_private);
 
 	if(str == NULL) {
@@ -374,7 +352,7 @@ usetprivate(unit * u, const char * str) {
 	}
 	if (!a) a = a_add(&u->attribs, a_new(&at_private));
 	if (a->data.v) free(a->data.v);
-	a->data.v = strdup(str);
+	a->data.v = strdup((const char*)str);
 }
 
 /*********************/
@@ -1293,12 +1271,11 @@ createunitid(unit *u, int id)
 void
 name_unit(unit *u)
 {
-	char name[16];
-
 	if (u->race->generate_name) {
 		set_string(&u->name, (u->race->generate_name(u)));
 	} else {
-		sprintf(name, "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no));
+    xmlChar name[16];
+		sprintf((char*)name, "%s %s", LOC(u->faction->locale, "unitdefault"), itoa36(u->no));
 		set_string(&u->name, name);
 	}
 }
@@ -1309,7 +1286,7 @@ name_unit(unit *u)
 * @param creator: unit to inherit stealth, group, building, ship, etc. from
 */
 unit *
-create_unit(region * r, faction * f, int number, const struct race *urace, int id, const char * dname, unit *creator)
+create_unit(region * r, faction * f, int number, const struct race *urace, int id, const xmlChar * dname, unit *creator)
 {
   unit * u = calloc(1, sizeof(unit));
   order * deford = default_order(f->locale);
@@ -1346,7 +1323,6 @@ create_unit(region * r, faction * f, int number, const struct race *urace, int i
     name_unit(u);
   }
   else set_string(&u->name, dname);
-  set_string(&u->display, "");
 
   if (count_unit(u)) f->no_units++;
 
diff --git a/src/common/kernel/unit.h b/src/common/kernel/unit.h
index 4f355e143..0f9a8f945 100644
--- a/src/common/kernel/unit.h
+++ b/src/common/kernel/unit.h
@@ -82,8 +82,8 @@ typedef struct unit {
 	struct region *region;
   int no;
   int hp;
-	char *name;
-	char *display;
+	xmlChar *name;
+	xmlChar *display;
 	struct faction *faction;
 	struct building *building;
 	struct ship *ship;
@@ -155,8 +155,8 @@ void usettarget(struct unit * u, const struct unit * b);
 
 extern const struct race * urace(const struct unit * u);
 
-const char* uprivate(const struct unit * u);
-void usetprivate(struct unit * u, const char * c);
+const xmlChar* uprivate(const struct unit * u);
+void usetprivate(struct unit * u, const xmlChar * c);
 
 const struct potion_type * ugetpotionuse(const struct unit * u); /* benutzt u einein trank? */
 void usetpotionuse(struct unit * u, const struct potion_type * p); /* u benutzt trank p (es darf halt nur einer pro runde) */
@@ -166,12 +166,8 @@ void usetcontact(struct unit * u, const struct unit * c);
 
 struct unit * findnewunit (const struct region * r, const struct faction *f, int alias);
 
-#define upotions(u) fval(u, UFL_POTIONS)
-extern const struct unit * u_peasants(void);
-extern const struct unit * u_unknown(void);
-
 extern struct unit * udestroy;
-extern const char * u_description(const unit * u, const struct locale * lang);
+extern const xmlChar * u_description(const unit * u, const struct locale * lang);
 extern struct skill * add_skill(struct unit * u, skill_t id);
 extern void remove_skill(struct unit *u, skill_t sk);
 extern struct skill * get_skill(const struct unit * u, skill_t id);
@@ -219,7 +215,7 @@ extern int invisible(const struct unit *target, const struct unit * viewer);
 extern void stripunit(struct unit * u);
 
 extern void name_unit(struct unit *u);
-extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const char * dname, struct unit *creator);
+extern struct unit * create_unit(struct region * r1, struct faction * f, int number, const struct race * rc, int id, const xmlChar * dname, struct unit *creator);
 
 extern struct attrib_type at_creator;
 #ifdef __cplusplus
diff --git a/src/common/kernel/xmlreader.c b/src/common/kernel/xmlreader.c
index a98695a04..efc1176ef 100644
--- a/src/common/kernel/xmlreader.c
+++ b/src/common/kernel/xmlreader.c
@@ -86,7 +86,7 @@ xml_to_locale(const xmlChar * xmlStr)
   static char zText[1024];
   const xmlChar * inbuf = xmlStr;
   char * outbuf = zText;
-  int inbytes = (int)strlen((const char*)xmlStr)+1;
+  int inbytes = (int)xmlStrlen(xmlStr)+1;
   int outbytes = (int)sizeof(zText);
 
   if (UTF8Toisolat1((xmlChar*)outbuf, &outbytes, inbuf, &inbytes)<0) {
@@ -1531,9 +1531,9 @@ parse_races(xmlDocPtr doc)
         }
         assert(property!=NULL);
         if (strcmp((const char*)property, "name")==0) {
-          rc->generate_name = (const char* (*)(const struct unit*))fun;
+          rc->generate_name = (const xmlChar* (*)(const struct unit*))fun;
         } else if (strcmp((const char*)property, "describe")==0) {
-          rc->describe = (const char* (*)(const struct unit*, const struct locale *))fun;
+          rc->describe = (const xmlChar* (*)(const struct unit*, const struct locale *))fun;
         } else if (strcmp((const char*)property, "age")==0) {
           rc->age = (void(*)(struct unit*))fun;
         } else if (strcmp((const char*)property, "move")==0) {
@@ -1852,7 +1852,7 @@ xml_readstrings(xmlXPathContextPtr xpath, xmlNodePtr * nodeTab, int nodeNr, bool
       if (text!=NULL) {
         assert(strcmp(zName, (const char*)xml_cleanup_string(BAD_CAST zName))==0);
         xml_cleanup_string(text);
-        locale_setstring(lang, zName, xml_to_locale(text));
+        locale_setstring(lang, zName, text);
         xmlFree(text);
       } else {
         log_warning(("string %s has no text in locale %s\n",
diff --git a/src/common/modules/arena.c b/src/common/modules/arena.c
index b72fe8cf8..aee9bbf3b 100644
--- a/src/common/modules/arena.c
+++ b/src/common/modules/arena.c
@@ -75,19 +75,21 @@ static region * start_region[6];
 static int newarena = 0;
 
 static region *
-arena_region(int magic) {
+arena_region(int magic)
+{
 	return tower_region[magic];
 }
 
 static building *
-arena_tower(int magic) {
+arena_tower(int magic)
+{
 	return arena_region(magic)->buildings;
 }
 
 static int
-leave_fail(unit * u) {
-	sprintf(buf, "Der Versuch, die Greifenschwingen zu benutzen, schlug fehl. %s konnte die Ebene der Herausforderung nicht verlassen.", unitname(u));
-	addmessage(NULL, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT);
+leave_fail(unit * u)
+{
+  ADDMSG(&u->faction->msgs, msg_message("arena_leave_fail", "unit", u));
 	return 1;
 }
 
@@ -104,9 +106,9 @@ leave_arena(struct unit * u, const struct item_type * itype, int amount, order *
 }
 
 static int
-enter_fail(unit * u) {
-	sprintf(buf, "In %s erklingt die Stimme des Torw�chters: 'Nur wer ohne materielle G�ter und noch lernbegierig ist, der darf die Ebene der Herausforderung betreten. Und vergi� nicht mein Trinkgeld.'. %s erhielt keinen Einla�.", regionname(u->region, u->faction), unitname(u));
-	addmessage(NULL, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT);
+enter_fail(unit * u)
+{
+  ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u));
 	return 1;
 }
 
@@ -146,8 +148,7 @@ enter_arena(unit * u, const item_type * itype, int amount, order * ord)
     if (u2) change_money(u2, get_money(u) - fee);
     else if (enter_fail(u)) return -1;
   }
-  sprintf(buf, "In %s �ffnet sich ein Portal. Eine Stimme ert�nt, und spricht: 'Willkommen in der Ebene der Herausforderung'. %s durchschreitet das Tor zu einer anderen Welt.", regionname(u->region, u->faction), unitname(u));
-  addmessage(NULL, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT);
+  ADDMSG(&u->faction->msgs, msg_message("arena_enter_fail", "region unit", u->region, u));
   use_pooled(u, itype->rtype, GET_SLACK|GET_RESERVE, 1);
   use_pooled(u, oldresourcetype[R_SILVER], GET_DEFAULT, fee);
   set_money(u, 109);
@@ -233,6 +234,7 @@ static attrib_type at_hurting = {
 	"hurting", NULL, NULL, age_hurting, write_hurting, read_hurting
 };
 
+#ifdef ARENA_CREATION
 static void
 make_temple(region * r)
 {
@@ -253,10 +255,12 @@ make_temple(region * r)
 	b->display = strdup("Ein Schrein aus spitzen Knochen und lodernden Flammen, gewidmet dem Wyrm der Wyrme");
 	a_add(&b->attribs, a_new(&at_hurting))->data.v=b;
 }
+#endif
 
 /**
  * Initialisierung T�rme */
 
+#ifdef ARENA_CREATION
 static void
 tower_init(void)
 {
@@ -294,7 +298,9 @@ tower_init(void)
 		set_string(&b->name, "H�hle des Greifen");
 	}
 }
+#endif
 
+#ifdef ARENA_CREATION
 static void
 guardian_faction(plane * pl, int id)
 {
@@ -342,9 +348,11 @@ guardian_faction(plane * pl, int id)
 		set_money(u, 1000);
 	}
 }
+#endif
 
 #define BLOCKSIZE           9
 
+#ifdef ARENA_CREATION
 static void 
 block_create(short x1, short y1, char terrain)
 {
@@ -356,6 +364,7 @@ block_create(short x1, short y1, char terrain)
 		}
 	}
 }
+#endif
 
 #ifdef CENTRAL_VOLCANO
 
@@ -371,28 +380,26 @@ caldera_handle(trigger * t, void * data)
 		while (*up) {
 			unit * u = *up;
 			if (u->building==b) {
-				sprintf(buf, "%s springt in die ewigen Feuer des Kraters.", unitname(u));
+        message * msg;
 				if (u->items) {
 					item ** ip = &u->items;
-					strcat(buf, " Mit der sterblichen H�lle des Helden vergl�hen");
+          msg = msg_message("caldera_handle_1", "unit items", u, u->items);
 					while (*ip) {
 						item * i = *ip;
-						char zText[10];
-						sprintf(zText, " %d %s", i->number, locale_string(default_locale, resourcename(i->type->rtype, i->number!=1)));
-						strcat(buf, zText);
 						i_remove(ip, i);
 						if (*ip==i) ip=&i->next;
-						if (i->next) strcat(buf, ",");
 					}
-					strcat(buf, ".");
-				}
-				addmessage(u->region, NULL, buf, MSG_MESSAGE, ML_IMPORTANT);
+        } else {
+          msg = msg_message("caldera_handle_0", "unit", u);
+        }
+				add_message(&u->region->msgs, msg);
 				set_number(u, 0);
 			}
 			if (*up==u) up = &u->next;
 		}
-	} else
+  } else {
 		log_error(("could not perform caldera::handle()\n"));
+  }
 	unused(data);
 	return 0;
 }
@@ -435,6 +442,7 @@ trigger_caldera(building * b)
 	return t;
 }
 
+#ifdef ARENA_CREATION
 static void
 init_volcano(void)
 {
@@ -451,7 +459,9 @@ init_volcano(void)
 	tt_register(&tt_caldera);
 }
 #endif
+#endif
 
+#ifdef ARENA_CREATION
 void
 create_arena(void)
 {
@@ -500,7 +510,7 @@ create_arena(void)
 	rsetpeasants(arena_center, 0);
 	tower_init();
 }
-
+#endif
 void
 register_arena(void)
 {
diff --git a/src/common/modules/arena.h b/src/common/modules/arena.h
index 4ddf92873..368fab09f 100644
--- a/src/common/modules/arena.h
+++ b/src/common/modules/arena.h
@@ -25,7 +25,9 @@ extern "C" {
 extern struct plane * arena;
 
 extern void register_arena(void);
+#ifdef ARENA_CREATION
 extern void create_arena(void);
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/src/common/modules/autoseed.c b/src/common/modules/autoseed.c
index 6f32e55ca..66a4621cb 100644
--- a/src/common/modules/autoseed.c
+++ b/src/common/modules/autoseed.c
@@ -185,6 +185,8 @@ read_newfactions(const char * filename)
 {
   newfaction * newfactions = NULL;
   FILE * F = fopen(filename, "r");
+  char buf[1024];
+
   if (F==NULL) return NULL;
   for (;;) {
     faction * f;
@@ -218,7 +220,7 @@ read_newfactions(const char * filename)
                  itoa36(subscription), email));
       continue;
     }
-    nf->password = strdup(password);
+    nf->password = (xmlChar *)strdup(password);
     nf->race = rc_find(race);
     nf->subscription = subscription;
     if (alliances!=NULL) {
@@ -232,7 +234,11 @@ read_newfactions(const char * filename)
     } else {
       nf->allies = NULL;
     }
-    if (nf->race==NULL) nf->race = findrace(race, default_locale);
+    if (nf->race==NULL) {
+      /* if the script didn't supply the race as a token, then it gives us a
+       * race in the default locale (which means that itis a UTF8 string) */
+      nf->race = findrace((const xmlChar*)race, default_locale);
+    }
     nf->lang = find_locale(lang);
     nf->bonus = bonus;
     assert(nf->race && nf->email && nf->lang);
diff --git a/src/common/modules/autoseed.h b/src/common/modules/autoseed.h
index 3b807d2d1..4c0e3d49c 100644
--- a/src/common/modules/autoseed.h
+++ b/src/common/modules/autoseed.h
@@ -23,7 +23,7 @@ struct newfaction;
 typedef struct newfaction {
   struct newfaction * next;
   char * email;
-  char * password;
+  xmlChar * password;
   const struct locale * lang;
   const struct race * race;
   int bonus;
diff --git a/src/common/modules/gmcmd.c b/src/common/modules/gmcmd.c
index d6e04426b..c05538510 100644
--- a/src/common/modules/gmcmd.c
+++ b/src/common/modules/gmcmd.c
@@ -139,17 +139,17 @@ make_atgmcreate(const struct item_type * itype)
 }
 
 static void
-gm_create(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_create(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
   int i;
   attrib * permissions = a_find(u->faction->attribs, &at_permissions);
   if (permissions) permissions = (attrib*)permissions->data.v;
   if (!permissions) return;
-  i = atoi(igetstrtoken(str));
+  i = getint();
 
   if (i>0) {
-    const char * iname = getstrtoken();
+    const xmlChar * iname = getstrtoken();
     const item_type * itype = finditemtype(iname, u->faction->locale);
     if (itype==NULL) {
       mistake(u, ord, "Unbekannter Gegenstand.", 0);
@@ -175,13 +175,13 @@ has_permission(const attrib * permissions, unsigned int key)
  ** requires: permission-key "gmgate"
  **/
 static void
-gm_gate(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_gate(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
   const struct plane * p = rplane(u->region);
-  int id = atoi36(igetstrtoken(str));
-  short x = rel_to_abs(p, u->faction, (short)atoi(getstrtoken()), 0);
-  short y = rel_to_abs(p, u->faction, (short)atoi(getstrtoken()), 1);
+  int id = getid();
+  short x = rel_to_abs(p, u->faction, (short)getint(), 0);
+  short y = rel_to_abs(p, u->faction, (short)getint(), 1);
   region * r = findregion(x, y);
   building * b = findbuilding(id);
   if (b==NULL || r==NULL || p!=rplane(b->region) || p!=rplane(r)) {
@@ -208,15 +208,16 @@ gm_gate(const tnode * tnext, const char * str, void * data, struct order * ord)
  ** requires: permission-key "gmterf"
  **/
 static void
-gm_terraform(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_terraform(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
   const struct plane * p = rplane(u->region);
-  short x = rel_to_abs(p, u->faction, (short)atoi(igetstrtoken(str)), 0);
-  short y = rel_to_abs(p, u->faction, (short)atoi(getstrtoken()), 1);
-  const char * c = getstrtoken();
+  short x = rel_to_abs(p, u->faction, (short)getint(), 0);
+  short y = rel_to_abs(p, u->faction, (short)getint(), 1);
+  const xmlChar * c = getstrtoken();
   region * r = findregion(x, y);
-  const terrain_type * terrain;
+  variant token;
+  tnode * tokens = get_translations(u->faction->locale, UT_TERRAINS);
 
   if (r==NULL || p!=rplane(r)) {
     mistake(u, ord, "Diese Region kann die Einheit nicht umwandeln.", 0);
@@ -226,11 +227,10 @@ gm_terraform(const tnode * tnext, const char * str, void * data, struct order *
     attrib * permissions = a_find(u->faction->attribs, &at_permissions);
     if (!permissions || !has_permission(permissions, atoi36("gmterf"))) return;
   }
-  for (terrain=terrains();terrain!=NULL;terrain=terrain->next) {
-    if (!strcasecmp(locale_string(u->faction->locale, terrain->_name), c)) {
-      terraform_region(r, terrain);
-      break;
-    }
+
+  if (findtoken(tokens, c, &token)!=E_TOK_NOMATCH) {
+    const terrain_type * terrain = (const terrain_type *)token.v;
+    terraform_region(r, terrain);
   }
 }
 
@@ -239,13 +239,13 @@ gm_terraform(const tnode * tnext, const char * str, void * data, struct order *
  ** requires: permission-key "gmtele"
  **/
 static void
-gm_teleport(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_teleport(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
   const struct plane * p = rplane(u->region);
-  unit * to = findunit(atoi36(igetstrtoken(str)));
-  short x = rel_to_abs(p, u->faction, (short)atoi(getstrtoken()), 0);
-  short y = rel_to_abs(p, u->faction, (short)atoi(getstrtoken()), 1);
+  unit * to = findunit(getid());
+  short x = rel_to_abs(p, u->faction, (short)getint(), 0);
+  short y = rel_to_abs(p, u->faction, (short)getint(), 1);
   region * r = findregion(x, y);
 
   if (r==NULL || p!=rplane(r)) {
@@ -269,11 +269,11 @@ gm_teleport(const tnode * tnext, const char * str, void * data, struct order * o
  ** requires: permission-key "gmmsgr"
  **/
 static void
-gm_messageplane(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_messageplane(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
   const struct plane * p = rplane(u->region);
-  const char * zmsg = igetstrtoken(str);
+  const xmlChar * zmsg = getstrtoken();
   if (p==NULL) {
     mistake(u, ord, "In diese Ebene kann keine Nachricht gesandt werden.", 0);
   } else {
@@ -304,12 +304,12 @@ gm_messageplane(const tnode * tnext, const char * str, void * data, struct order
 }
 
 static void
-gm_messagefaction(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_messagefaction(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
-  int n = atoi36(igetstrtoken(str));
+  int n = getid();
   faction * f = findfaction(n);
-  const char * msg = getstrtoken();
+  const xmlChar * msg = getstrtoken();
   plane * p = rplane(u->region);
   attrib * permissions = a_find(u->faction->attribs, &at_permissions);
   if (!permissions || !has_permission(permissions, atoi36("gmmsgr"))) {
@@ -334,13 +334,13 @@ gm_messagefaction(const tnode * tnext, const char * str, void * data, struct ord
  ** requires: permission-key "gmmsgr"
  **/
 static void
-gm_messageregion(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_messageregion(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
   const struct plane * p = rplane(u->region);
-  short x = rel_to_abs(p, u->faction, (short)atoi(igetstrtoken(str)), 0);
-  short y = rel_to_abs(p, u->faction, (short)atoi(getstrtoken()), 1);
-  const char * msg = getstrtoken();
+  short x = rel_to_abs(p, u->faction, (short)getint(), 0);
+  short y = rel_to_abs(p, u->faction, (short)getint(), 1);
+  const xmlChar * msg = getstrtoken();
   region * r = findregion(x, y);
 
   if (r==NULL || p!=rplane(r)) {
@@ -362,12 +362,12 @@ gm_messageregion(const tnode * tnext, const char * str, void * data, struct orde
  ** requires: permission-key "gmkill"
  **/
 static void
-gm_killunit(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_killunit(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
   const struct plane * p = rplane(u->region);
-  unit * target = findunit(atoi36(igetstrtoken(str)));
-  const char * msg = getstrtoken();
+  unit * target = findunit(getid());
+  const xmlChar * msg = getstrtoken();
   region * r = target->region;
 
   if (r==NULL || p!=rplane(r)) {
@@ -392,12 +392,12 @@ gm_killunit(const tnode * tnext, const char * str, void * data, struct order * o
  ** requires: permission-key "gmmsgr"
  **/
 static void
-gm_killfaction(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_killfaction(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
-  int n = atoi36(igetstrtoken(str));
+  int n = getid();
   faction * f = findfaction(n);
-  const char * msg = getstrtoken();
+  const xmlChar * msg = getstrtoken();
   plane * p = rplane(u->region);
   attrib * permissions = a_find(u->faction->attribs, &at_permissions);
   if (!permissions || !has_permission(permissions, atoi36("gmkill"))) {
@@ -426,12 +426,12 @@ gm_killfaction(const tnode * tnext, const char * str, void * data, struct order
  ** requires: permission-key "gmmsgr"
  **/
 static void
-gm_messageunit(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_messageunit(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
   const struct plane * p = rplane(u->region);
-  unit * target = findunit(atoi36(igetstrtoken(str)));
-  const char * msg = getstrtoken();
+  unit * target = findunit(getid());
+  const xmlChar * msg = getstrtoken();
   region * r;
 
   if (target == NULL) {
@@ -461,11 +461,11 @@ gm_messageunit(const tnode * tnext, const char * str, void * data, struct order
  ** requires: permission-key "gmgive"
  **/
 static void
-gm_give(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_give(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
-  unit * to = findunit(atoi36(igetstrtoken(str)));
-  int num = atoi(getstrtoken());
+  unit * to = findunit(getid());
+  int num = getint();
   const item_type * itype = finditemtype(getstrtoken(), u->faction->locale);
 
   if (to==NULL || rplane(to->region) != rplane(u->region)) {
@@ -496,11 +496,11 @@ gm_give(const tnode * tnext, const char * str, void * data, struct order * ord)
  ** requires: permission-key "gmtake"
  **/
 static void
-gm_take(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_take(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
-  unit * to = findunit(atoi36(igetstrtoken(str)));
-  int num = atoi(getstrtoken());
+  unit * to = findunit(getid());
+  int num = getint();
   const item_type * itype = finditemtype(getstrtoken(), u->faction->locale);
 
   if (to==NULL || rplane(to->region) != rplane(u->region)) {
@@ -531,12 +531,12 @@ gm_take(const tnode * tnext, const char * str, void * data, struct order * ord)
  ** requires: permission-key "gmskil"
  **/
 static void
-gm_skill(const tnode * tnext, const char * str, void * data, struct order * ord)
+gm_skill(const tnode * tnext, void * data, struct order * ord)
 {
   unit * u = (unit*)data;
-  unit * to = findunit(atoi36(igetstrtoken(str)));
+  unit * to = findunit(getid());
   skill_t skill = findskill(getstrtoken(), u->faction->locale);
-  int num = atoi(getstrtoken());
+  int num = getint();
 
   if (to==NULL || rplane(to->region) != rplane(u->region)) {
     /* unknown or in another plane */
@@ -569,22 +569,22 @@ init_gmcmd(void)
 {
   at_register(&at_gmcreate);
   at_register(&at_permissions);
-  add_command(&g_root, &g_keys, "gm", NULL);
-  add_command(&g_keys, NULL, "terraform", &gm_terraform);
-  add_command(&g_keys, NULL, "create", &gm_create);
-  add_command(&g_keys, NULL, "gate", &gm_gate);
-  add_command(&g_keys, NULL, "give", &gm_give);
-  add_command(&g_keys, NULL, "take", &gm_take);
-  add_command(&g_keys, NULL, "teleport", &gm_teleport);
-  add_command(&g_keys, NULL, "skill", &gm_skill);
-  add_command(&g_keys, &g_tell, "tell", NULL);
-  add_command(&g_tell, NULL, "region", &gm_messageregion);
-  add_command(&g_tell, NULL, "unit", &gm_messageunit);
-  add_command(&g_tell, NULL, "plane", &gm_messageplane);
-  add_command(&g_tell, NULL, "faction", &gm_messagefaction);
-  add_command(&g_keys, &g_kill, "kill", NULL);
-  add_command(&g_kill, NULL, "unit", &gm_killunit);
-  add_command(&g_kill, NULL, "faction", &gm_killfaction);
+  add_command(&g_root, &g_keys, (const xmlChar *)"gm", NULL);
+  add_command(&g_keys, NULL, (const xmlChar *)"terraform", &gm_terraform);
+  add_command(&g_keys, NULL, (const xmlChar *)"create", &gm_create);
+  add_command(&g_keys, NULL, (const xmlChar *)"gate", &gm_gate);
+  add_command(&g_keys, NULL, (const xmlChar *)"give", &gm_give);
+  add_command(&g_keys, NULL, (const xmlChar *)"take", &gm_take);
+  add_command(&g_keys, NULL, (const xmlChar *)"teleport", &gm_teleport);
+  add_command(&g_keys, NULL, (const xmlChar *)"skill", &gm_skill);
+  add_command(&g_keys, &g_tell, (const xmlChar *)"tell", NULL);
+  add_command(&g_tell, NULL, (const xmlChar *)"region", &gm_messageregion);
+  add_command(&g_tell, NULL, (const xmlChar *)"unit", &gm_messageunit);
+  add_command(&g_tell, NULL, (const xmlChar *)"plane", &gm_messageplane);
+  add_command(&g_tell, NULL, (const xmlChar *)"faction", &gm_messagefaction);
+  add_command(&g_keys, &g_kill, (const xmlChar *)"kill", NULL);
+  add_command(&g_kill, NULL, (const xmlChar *)"unit", &gm_killunit);
+  add_command(&g_kill, NULL, (const xmlChar *)"faction", &gm_killfaction);
 }
 
 /*
@@ -618,43 +618,12 @@ faction *
 gm_addquest(const char * email, const char * name, short radius, unsigned int flags)
 {
   plane * p;
-  attrib * a;
-  unit * u;
   watcher * w = calloc(sizeof(watcher), 1);
   region * center;
   boolean invalid = false;
   short minx, miny, maxx, maxy, cx, cy;
   short x;
-  int i;
-  faction * f = calloc(1, sizeof(faction));
-
-  /* GM faction */
-  a_add(&f->attribs, make_key(atoi36("quest")));
-  f->banner = strdup("Questenpartei");
-  f->passw = strdup(itoa36(rng_int()));
-  f->override = strdup(itoa36(rng_int()));
-  f->override = strdup(itoa36(rng_int()));
-  if (set_email(&f->email, email)!=0) {
-    log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email));
-  }
-  f->name = strdup("Questenpartei");
-  f->race = new_race[RC_TEMPLATE];
-  f->age = 0;
-  f->lastorders = turn;
-  f->alive = true;
-  f->locale = find_locale("de");
-  f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN);
-  {
-    faction * xist;
-    int i = atoi36("gm00")-1;
-    do {
-      xist = findfaction(++i);
-    } while (xist);
-
-    f->no = i;
-    addlist(&factions, f);
-    fhash(f);
-  }
+  faction * f;
 
   /* GM playfield */
   do {
@@ -690,35 +659,12 @@ gm_addquest(const char * email, const char * name, short radius, unsigned int fl
   }
 
   /* watcher: */
+  f = gm_addfaction(email, p, center);
   w->faction = f;
   w->mode = see_unit;
   w->next = p->watchers;
   p->watchers = w;
 
-  /* generic permissions */
-  a = a_add(&f->attribs, a_new(&at_permissions));
-
-  add_key((attrib**)&a->data.v, atoi36("gmterf"));
-  add_key((attrib**)&a->data.v, atoi36("gmtele"));
-  add_key((attrib**)&a->data.v, atoi36("gmgive"));
-  add_key((attrib**)&a->data.v, atoi36("gmskil"));
-  add_key((attrib**)&a->data.v, atoi36("gmtake"));
-  add_key((attrib**)&a->data.v, atoi36("gmmsgr"));
-  add_key((attrib**)&a->data.v, atoi36("gmmsgu"));
-  add_key((attrib**)&a->data.v, atoi36("gmgate"));
-
-  a_add((attrib**)&a->data.v, make_atgmcreate(resource2item(r_silver)));
-
-  for (i=0;i<=I_HORSE;++i) {
-    a_add((attrib**)&a->data.v, make_atgmcreate(olditemtype[i]));
-  }
-
-  /* one initial unit */
-  u = createunit(center, f, 1, new_race[RC_TEMPLATE]);
-  u->irace = new_race[RC_GNOME];
-  u->number = 1;
-  set_string(&u->name, "Questenmeister");
-
   return f;
 }
 
@@ -733,18 +679,19 @@ gm_addfaction(const char * email, plane * p, region * r)
   assert(p!=NULL);
 
   /* GM faction */
-  add_key(&f->attribs, atoi36("quest"));
-  f->banner = strdup("Questenpartei");
-  f->passw = strdup(itoa36(rng_int()));
+  a_add(&f->attribs, make_key(atoi36("quest")));
+  f->banner = (xmlChar*)strdup("quest faction");
+  f->name = (xmlChar*)strdup("quest faction");
+  f->passw = (xmlChar*)strdup(itoa36(rng_int()));
+  f->override = (xmlChar*)strdup(itoa36(rng_int()));
   if (set_email(&f->email, email)!=0) {
     log_error(("Invalid email address for faction %s: %s\n", itoa36(f->no), email));
   }
-  f->name = strdup("Questenpartei");
   f->race = new_race[RC_TEMPLATE];
   f->age = 0;
   f->lastorders = turn;
   f->alive = true;
-  f->locale = find_locale("de");
+  f->locale = default_locale;
   f->options = want(O_COMPRESS) | want(O_REPORT) | want(O_COMPUTER) | want(O_ADRESSEN);
   {
     faction * xist;
@@ -757,6 +704,7 @@ gm_addfaction(const char * email, plane * p, region * r)
     addlist(&factions, f);
     fhash(f);
   }
+
   /* generic permissions */
   a = a_add(&f->attribs, a_new(&at_permissions));
 
@@ -775,10 +723,8 @@ gm_addfaction(const char * email, plane * p, region * r)
     a_add((attrib**)&a->data.v, make_atgmcreate(olditemtype[i]));
   }
   /* one initial unit */
-  u = createunit(r, f, 1, new_race[RC_TEMPLATE]);
+  u = create_unit(r, f, 1, new_race[RC_TEMPLATE], 1, (const xmlChar*)"quest master", NULL);
   u->irace = new_race[RC_GNOME];
-  u->number = 1;
-  set_string(&u->name, "Questenmeister");
 
   return f;
 }
diff --git a/src/common/modules/museum.c b/src/common/modules/museum.c
index 326843165..cdbfed719 100644
--- a/src/common/modules/museum.c
+++ b/src/common/modules/museum.c
@@ -187,6 +187,7 @@ warden_add_give(unit *src, unit *u, const item_type *itype, int n)
 void
 create_museum(void)
 {
+#if 0 /* TODO: move this to LUA. It should be possible. */
 	unsigned int museum_id = hashstring("museum");
 	plane *museum = getplanebyid(museum_id);
 	region *r;
@@ -201,7 +202,7 @@ create_museum(void)
 			9500, 9550, PFL_MUSEUM);
 	}
 
-	if(findregion(9525, 9525) == NULL) {
+	if (findregion(9525, 9525) == NULL) {
 		/* Eingangshalle */
 		r = new_region(9525, 9525);
 		terraform_region(r, terrain_hall);
@@ -280,6 +281,7 @@ create_museum(void)
 		rsetpeasants(r, 0);
 		set_string(&r->display, "Die S�dliche Promenade f�hrt den Besucher in den kulturgeschichtlichen Teil des Museums.");
 	}
+#endif
 }
 
 static int
@@ -308,7 +310,7 @@ use_museumexitticket(unit *u, const struct item_type *itype, int amount, order *
 	unit_cookie = a->data.i;
 	a_remove(&u->attribs, a);
 
-	if(a) {
+	if (a) {
 		for(a = a_find(warden->attribs, &at_museumgiveback); a && a->type==&at_museumgiveback; a = a->next) {
 			if(((museumgiveback *)(a->data.v))->cookie == unit_cookie) break;
 		}
@@ -316,10 +318,10 @@ use_museumexitticket(unit *u, const struct item_type *itype, int amount, order *
 			museumgiveback *gb = (museumgiveback *)(a->data.v);
 			item *it;
 
-			for(it = gb->items; it; it = it->next) {
+			for (it = gb->items; it; it = it->next) {
 				i_change(&u->items, it->type, it->number);
 			}
-      ADDMSG(&u->faction->msgs, msg_message("unitmessage", "region unit sender string", r, u, warden, buf));
+      ADDMSG(&u->faction->msgs, msg_message("museumgiveback", "region unit sender items", r, u, warden, gb->items));
 			a_remove(&warden->attribs, a);
 		}
 	}
diff --git a/src/common/modules/score.c b/src/common/modules/score.c
index 80e998c63..c19a1b124 100644
--- a/src/common/modules/score.c
+++ b/src/common/modules/score.c
@@ -70,6 +70,7 @@ score(void)
   region *r;
   faction *f;
   int allscores = 0;
+  char path[MAX_PATH];
 
   for (f = factions; f; f = f->next) f->score = 0;
 
@@ -164,8 +165,8 @@ score(void)
     allscores = 1;
   }
 
-  sprintf(buf, "%s/score", basepath());
-  scoreFP = fopen(buf, "w");
+  sprintf(path, "%s/score", basepath());
+  scoreFP = fopen(path, "w");
   for (f = factions; f; f = f->next) if (f->num_total != 0) {
     fprintf(scoreFP, "%8d (%8d/%4.2f%%/%5.2f) %30.30s (%3.3s) %5s (%3d)\n",
       f->score, f->score - average_score_of_age(f->age, f->age / 24 + 1),
@@ -179,8 +180,8 @@ score(void)
     alliance *a;
     const item_type * token = it_find("conquesttoken");
 
-    sprintf(buf, "%s/score.alliances", basepath());
-    scoreFP = fopen(buf, "w");
+    sprintf(path, "%s/score.alliances", basepath());
+    scoreFP = fopen(path, "w");
     fprintf(scoreFP, "# alliance:factions:persons:score\n");
 
     for (a = alliances; a; a = a->next) {
diff --git a/src/common/modules/xecmd.c b/src/common/modules/xecmd.c
index 754251c68..5991f8c54 100644
--- a/src/common/modules/xecmd.c
+++ b/src/common/modules/xecmd.c
@@ -86,7 +86,7 @@ xe_giveballon(unit *u, struct order *ord)
 
 	sh = new_ship(st_find("balloon"), u2->faction->locale, u2->region);
 	sh->size = 5;
-	set_string(&sh->name,"Xontormia-Ballon");
+	set_string(&sh->name, (const xmlChar*)"Xontormia-Ballon");
 	leave(u2->region, u2);
 	u2->ship = sh;
 	fset(u2, UFL_OWNER);
diff --git a/src/common/spells/alp.c b/src/common/spells/alp.c
index c0669f4d3..73420b9b5 100644
--- a/src/common/spells/alp.c
+++ b/src/common/spells/alp.c
@@ -16,7 +16,10 @@
 #include "alp.h"
 
 #include <kernel/eressea.h>
+#include <kernel/faction.h>
 #include <kernel/magic.h>
+#include <kernel/message.h>
+#include <kernel/race.h>
 #include <kernel/region.h>
 #include <kernel/skill.h>
 #include <kernel/unit.h>
@@ -98,6 +101,9 @@ sp_summon_alp(struct castorder *co)
   unit *mage = co->magician.u;
   int cast_level = co->level;
   spellparameter *pa = co->par;
+  const struct race * rc = new_race[RC_ALP];
+  struct faction * f = findfaction(MONSTER_FACTION);
+  struct message * msg;
 
   opfer = pa->param[0]->data.u;
 
@@ -105,7 +111,7 @@ sp_summon_alp(struct castorder *co)
   * Regionsberichte von ihm.  Er erh�lt aber sp�ter eine Mitteilung,
   * sobald der Alp sein Opfer erreicht hat.
   */
-  alp = create_unit(r, findfaction(MONSTER_FACTION), 1, new_race[RC_ALP], 0, "Alp", NULL);
+  alp = create_unit(r, f, 1, rc, 0, NULL, NULL);
   set_level(alp, SK_STEALTH, 7);
   setstatus(alp, ST_FLEE); /* flieht */
 
@@ -119,14 +125,14 @@ sp_summon_alp(struct castorder *co)
   {
     /* Wenn der Alp stirbt, den Magier nachrichtigen */
     add_trigger(&alp->attribs, "destroy", trigger_unitmessage(mage, 
-      "Ein Alp starb, ohne sein Ziel zu erreichen.", MSG_EVENT, ML_INFO));
+      "trigger_alp_destroy", MSG_EVENT, ML_INFO));
     /* Wenn Opfer oder Magier nicht mehr existieren, dann stirbt der Alp */
     add_trigger(&mage->attribs, "destroy", trigger_killunit(alp));
     add_trigger(&opfer->attribs, "destroy", trigger_killunit(alp));
   }
-  sprintf(buf, "%s beschw�rt den Alp %s f�r %s.", unitname(mage),
-    unitname(alp), unitname(opfer));
-  addmessage(r, mage->faction, buf, MSG_MAGIC, ML_INFO);
+  msg = msg_message("summon_alp_effect", "mage alp target", mage, alp, opfer);
+  r_addmessage(r, mage->faction, msg);
+  msg_release(msg);
 
   return cast_level;
 }
@@ -141,17 +147,16 @@ alp_findet_opfer(unit *alp, region *r)
 	unit *mage = ad->mage;
 	unit *opfer = ad->target;
   variant effect;
+  message * msg;
 
 	assert(opfer);
 	assert(mage);
 
 	/* Magier und Opfer Bescheid geben */
-	strcpy(buf, "Ein Alp hat sein Opfer gefunden!");
-	addmessage(r, mage->faction, buf, MSG_MAGIC, ML_INFO);
-
-	sprintf(buf, "Ein Alp springt auf den R�cken von %s.",
-					unitname(opfer));
-	addmessage(r, opfer->faction, buf, MSG_EVENT, ML_IMPORTANT);
+  msg = msg_message("alp_success", "target", opfer);
+  add_message(&mage->faction->msgs, msg);
+  r_addmessage(opfer->region, opfer->faction, msg);
+  msg_release(msg);
 
 	/* Relations werden in destroy_unit(alp) automatisch gel�scht.
 	 * Die Aktionen, die beim Tod des Alps ausgel�st werden sollen,
diff --git a/src/common/spells/combatspells.c b/src/common/spells/combatspells.c
index 445462774..f05a0995f 100644
--- a/src/common/spells/combatspells.c
+++ b/src/common/spells/combatspells.c
@@ -716,7 +716,6 @@ sp_shadowcall(fighter * fi, int level, double power, spell * sp)
   u = create_unit(r, mage->faction, force, rc, 0, NULL, mage);
   setstatus(u, ST_FIGHT);
 
-  set_string(&u->name, racename(mage->faction->locale, u, u->race));
   set_level(u, SK_WEAPONLESS, (int)(power/2));
   set_level(u, SK_AUSDAUER, (int)(power/2));
   u->hp = u->number * unit_max_hp(u);
@@ -746,7 +745,6 @@ sp_wolfhowl(fighter * fi, int level, double power, spell * sp)
 
   setstatus(u, ST_FIGHT);
 
-  set_string(&u->name, racename(mage->faction->locale, u, u->race));
   set_level(u, SK_WEAPONLESS, (int)(power/3));
   set_level(u, SK_AUSDAUER, (int)(power/3));
   u->hp = u->number * unit_max_hp(u);
@@ -781,7 +779,6 @@ sp_shadowknights(fighter * fi, int level, double power, spell * sp)
   u = create_unit(r, mage->faction, force, new_race[RC_SHADOWKNIGHT], 0, NULL, mage);
   setstatus(u, ST_FIGHT);
 
-  set_string(&u->name, "Schattenritter");
   u->hp = u->number * unit_max_hp(u);
 
   if (fval(mage, UFL_PARTEITARNUNG))
@@ -1441,25 +1438,12 @@ sp_reanimate(fighter * fi, int level, double power, spell * sp)
   battle *b = fi->side->battle;
   unit *mage = fi->unit;
   int healable, j=0;
-  double c = 0.50;
+  double c = 0.50 + 0.02 * power;
   double k = EFFECT_HEALING_SPELL * power;
+  boolean use_item = get_item(mage, I_AMULET_OF_HEALING) > 0;
+  message * msg;
 
-  switch(sp->id) {
-    case SPL_REANIMATE:
-      sprintf(buf, "%s beginnt ein Ritual der Wiederbelebung",
-          unitname(mage));
-      c += 0.02 * power;
-      break;
-
-    default:
-      sprintf(buf, "%s zaubert %s",
-          unitname(mage),
-          spell_name(sp, default_locale));
-  }
-  if (get_item(mage, I_AMULET_OF_HEALING) > 0) {
-    scat(" und benutzt das ");
-    scat(locale_string(default_locale, resourcename(oldresourcetype[R_AMULET_OF_HEALING], 0)));
-    scat(", um den Zauber zu verst�rken");
+  if (use_item) {
     k *= 2;
     c += 0.10;
   }
@@ -1490,18 +1474,16 @@ sp_reanimate(fighter * fi, int level, double power, spell * sp)
       ++j;
     }
   }
-  if (j == 0) {
-    scat(", kann aber niemanden wiederbeleben.");
-    level = 0;
-  } else if (j == 1) {
-    scat(" und belebt einen Toten wieder.");
-    level = 1;
-  } else {
-    scat(" und belebt ");
-    icat(j);
-    scat(" Tote wieder.");
+  if (j <= 0) {
+    level = j;
   }
-  battlerecord(b, buf);
+  if (use_item) {
+    msg = msg_message("reanimate_effect_1", "mage amount item", mage, j, oldresourcetype[R_AMULET_OF_HEALING]);
+  } else {
+    msg = msg_message("reanimate_effect_0", "mage amount", mage, j);
+  }
+  message_all(b, msg);
+  msg_release(msg);
 
   return level;
 }
@@ -1566,19 +1548,15 @@ sp_healing(fighter * fi, int level, double power, spell * sp)
   battle *b = fi->side->battle;
   unit *mage = fi->unit;
   int j = 0;
-  int healhp = (int)power;
+  int healhp = (int)power * 200;
   cvector *fgs;
-
-  sprintf(buf, "%s k�mmert sich um die Verletzten", unitname(mage));
+  message * msg;
+  boolean use_item = get_item(mage, I_AMULET_OF_HEALING) > 0;
 
   /* bis zu 11 Personen pro Stufe (einen HP m�ssen sie ja noch
-  * haben, sonst w�ren sie tot) k�nnen geheilt werden */
-  healhp *= 200;
+   * haben, sonst w�ren sie tot) k�nnen geheilt werden */
 
-  if (get_item(mage, I_AMULET_OF_HEALING) > 0) {
-    scat(" und benutzt das ");
-    scat(locale_string(default_locale, resourcename(oldresourcetype[R_AMULET_OF_HEALING], 0)));
-    scat(", um die Heilzauber zu verst�rken");
+  if (use_item) {
     healhp *= 2;
   }
 
@@ -1592,18 +1570,16 @@ sp_healing(fighter * fi, int level, double power, spell * sp)
   cv_kill(fgs);
   free(fgs);
 
-  if (j == 0) {
-    scat(", doch niemand mu�te magisch geheilt werden.");
-    level = 0;
-  } else if (j == 1) {
-    scat(" und heilt einen Verwundeten.");
-    level = 1;
-  } else {
-    scat(" und heilt ");
-    icat(j);
-    scat(" Verwundete.");
+  if (j <= 0) {
+    level = j;
   }
-  battlerecord(b, buf);
+  if (use_item) {
+    msg = msg_message("healing_effect_1", "mage amount item", mage, j, oldresourcetype[R_AMULET_OF_HEALING]);
+  } else {
+    msg = msg_message("healing_effect_0", "mage amount", mage, j);
+  }
+  message_all(b, msg);
+  msg_release(msg);
 
   return level;
 }
diff --git a/src/common/spells/spells.c b/src/common/spells/spells.c
index 9c4a3fd4b..55a57c471 100644
--- a/src/common/spells/spells.c
+++ b/src/common/spells/spells.c
@@ -23,7 +23,8 @@
 #include "alp.h"
 #include "combatspells.h"
 
-#include <curse.h>
+#include <kernel/curse.h>
+#include <util/nrmessage.h>
 
 struct curse_type;
 extern void ct_register(const struct curse_type * ct);
@@ -541,6 +542,9 @@ sp_summon_familiar(castorder *co)
   skill_t sk;
   int dh, dh1;
   direction_t d;
+  message * msg;
+  xmlChar zText[NAMESIZE];
+
   if (get_familiar(mage) != NULL ) {
     cmistake(mage, co->order, 199, MSG_MAGIC);
     return 0;
@@ -573,15 +577,11 @@ sp_summon_familiar(castorder *co)
     target_region = rconnect(r,d);
   }
 
-  familiar = create_unit(target_region, mage->faction, 1, rc, 0, NULL, mage);
-  if (target_region==mage->region) {
-    familiar->building = mage->building;
-    familiar->ship = mage->ship;
-  }
+  msg = msg_message("familiar_name", "unit", mage);
+  nr_render(msg, mage->faction->locale, zText, sizeof(zText), mage->faction);
+  msg_release(msg);
+  familiar = create_unit(target_region, mage->faction, 1, rc, 0, zText, mage);
   setstatus(familiar, ST_FLEE);
-  sprintf(buf, "Vertrauter von %s", unitname(mage));
-  set_string(&familiar->name, buf);
-  if (fval(mage, UFL_PARTEITARNUNG)) fset(familiar, UFL_PARTEITARNUNG);
   fset(familiar, UFL_LOCKED);
   make_familiar(familiar, mage);
 
@@ -590,24 +590,24 @@ sp_summon_familiar(castorder *co)
   for (sk=0;sk<MAXSKILLS;sk++) {
     if (rc->bonus[sk] > -5) dh++;
   }
-  buf[0] = 0;
-  for(sk=0;sk<MAXSKILLS;sk++) {
+  zText[0] = 0;
+  for (sk=0;sk<MAXSKILLS;sk++) {
     if (rc->bonus[sk] > -5) {
       dh--;
       if (dh1 == 0) {
         dh1 = 1;
       } else {
         if (dh == 0) {
-          scat(LOC(mage->faction->locale, "list_and"));
+          strncat((char*)zText, (const char*)LOC(mage->faction->locale, "list_and"), sizeof(zText));
         } else {
-          scat(", ");
+          strncat((char*)zText, (const char*)", ", sizeof(zText));
         }
       }
-      scat(skillname(sk, mage->faction->locale));
+      strncat((char*)zText, (const char*)skillname(sk, mage->faction->locale), sizeof(zText));
     }
   }
   ADDMSG(&mage->faction->msgs, msg_message("familiar_describe",
-    "mage race skills", mage, rc, buf));
+    "mage race skills", mage, rc, zText));
   return cast_level;
 }
 
@@ -898,7 +898,7 @@ sp_summonent(castorder *co)
 
   ents = (int)min(power*power, rtrees(r,2));
 
-  u = create_unit(r, mage->faction, ents, new_race[RC_TREEMAN], 0, LOC(mage->faction->locale, rc_name(new_race[RC_TREEMAN], ents!=1)), mage);
+  u = create_unit(r, mage->faction, ents, new_race[RC_TREEMAN], 0, NULL, mage);
 
   a = a_new(&at_unitdissolve);
   a->data.ca[0] = 2;  /* An r->trees. */
@@ -941,6 +941,7 @@ sp_blessstonecircle(castorder *co)
   unit *mage = co->magician.u;
   int cast_level = co->level;
   spellparameter *p = co->par;
+  message * msg;
 
   /* wenn kein Ziel gefunden, Zauber abbrechen */
   if (p->param[0]->flag == TARGET_NOTFOUND) return 0;
@@ -961,8 +962,9 @@ sp_blessstonecircle(castorder *co)
 
   b->type = bt_find("blessedstonecircle");
 
-  sprintf(buf, "%s weiht %s.", unitname(mage), buildingname(b));
-  addmessage(r, 0, buf, MSG_MAGIC, ML_INFO);
+  msg = msg_message("blessedstonecircle_effect", "mage building", mage, b);
+  add_message(&r->msgs, msg);
+  msg_release(msg);
 
   return cast_level;
 }
@@ -1206,8 +1208,7 @@ patzer_ents(castorder *co)
   }
 
   ents = (int)(force*10);
-  u = create_unit(r, findfaction(MONSTER_FACTION), ents, new_race[RC_TREEMAN], 0,
-    LOC(default_locale, rc_name(new_race[RC_TREEMAN], ents!=1)), NULL);
+  u = create_unit(r, findfaction(MONSTER_FACTION), ents, new_race[RC_TREEMAN], 0, NULL, NULL);
 
   /* 'Erfolg' melden */
   ADDMSG(&mage->faction->msgs, msg_message(
@@ -1489,8 +1490,7 @@ sp_create_irongolem(castorder *co)
     return 0;
   }
 
-  u2 = create_unit(r, mage->faction, number, new_race[RC_IRONGOLEM], 0,
-    LOC(mage->faction->locale, rc_name(new_race[RC_IRONGOLEM], 1)), mage);
+  u2 = create_unit(r, mage->faction, number, new_race[RC_IRONGOLEM], 0, NULL, mage);
 
   set_level(u2, SK_ARMORER, 1);
   set_level(u2, SK_WEAPONSMITH, 1);
@@ -1551,8 +1551,7 @@ sp_create_stonegolem(castorder *co)
     return 0;
   }
 
-  u2 = create_unit(r, mage->faction, number, new_race[RC_STONEGOLEM], 0,
-    LOC(mage->faction->locale, rc_name(new_race[RC_STONEGOLEM], 1)), mage);
+  u2 = create_unit(r, mage->faction, number, new_race[RC_STONEGOLEM], 0, NULL, mage);
   set_level(u2, SK_ROAD_BUILDING, 1);
   set_level(u2, SK_BUILDING, 1);
 
@@ -1675,44 +1674,36 @@ sp_great_drought(castorder *co)
     }
   }
 
-  /* melden, 1x pro partei */
-  for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT);
-
-  for (u = r->units; u; u = u->next) {
-    if (!fval(u->faction, FFL_SELECT)) {
-      fset(u->faction, FFL_SELECT);
-      sprintf(buf, "%s ruft das Feuer der Sonne auf %s hinab.",
-          cansee(u->faction, r, mage, 0)? unitname(mage) : "Jemand",
-          regionname(r, u->faction));
-      if (!fval(r->terrain, SEA_REGION)) {
-        if (r->terrain == newterrain(T_SWAMP) && terraform) {
-            scat(" Eis schmilzt und verwandelt sich in Morast. Rei�ende "
-                "Str�me sp�len die mageren Felder weg und ers�ufen "
-                "Mensch und Tier. Was an Bauten nicht den Fluten zum Opfer "
-                "fiel, verschlingt der Morast. Die sengende Hitze ver�ndert "
-                "die Region f�r immer.");
-        } else {
-          scat(" Die Felder verdorren und Pferde verdursten. Die Hungersnot "
-              "kostet vielen Bauern das Leben. Vertrocknete B�ume recken "
-              "ihre kahlen Zweige in den blauen Himmel, von dem "
-              "erbarmungslos die sengende Sonne brennt.");
-          if (terraform) {
-            scat(" Die D�rre ver�nderte die Region f�r immer.");
-          }
-        }
-        addmessage(r, u->faction, buf, MSG_EVENT, ML_WARN);
-      } else { /* ist Ozean */
-        scat(" Das Eis zerbricht und eine gewaltige Flutwelle verschlingt"
-            "die Region.");
-        /* es kann gut sein, das in der Region niemand �berlebt, also
-         * besser eine Globalmeldung */
-        addmessage(0, u->faction, buf, MSG_EVENT, ML_IMPORTANT);
+  if (!fval(r->terrain, SEA_REGION)) {
+    /* not destroying the region, so it should be safe to make this a local 
+     * message */
+    message * msg;
+    const char * mtype;
+    if (r->terrain == newterrain(T_SWAMP) && terraform) {
+      mtype = "drought_effect_1";
+    } else if (!terraform) {
+      mtype = "drought_effect_2";
+    } else {
+      mtype = "drought_effect_3";
+    }
+    msg = msg_message(mtype, "mage region", mage, r);
+    add_message(&r->msgs, msg);
+    msg_release(msg);
+  } else {
+    /* possible that all units here get killed so better to inform with a global
+     * message */
+    message * msg = msg_message("drought_effect_4", "mage region", mage, r);
+    for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT);
+    for (u = r->units; u; u = u->next) {
+      if (!fval(u->faction, FFL_SELECT)) {
+        fset(u->faction, FFL_SELECT);
+        add_message(&u->faction->msgs, msg);
       }
     }
-  }
-  if (!fval(mage->faction, FFL_SELECT)) {
-    ADDMSG(&mage->faction->msgs, msg_message(
-      "drought_effect", "mage region", mage, r));
+    if (!fval(mage->faction, FFL_SELECT)) {
+      add_message(&mage->faction->msgs, msg);
+    }
+    msg_release(msg);
   }
   return cast_level;
 }
@@ -2018,7 +2009,7 @@ sp_homestone(castorder *co)
   int cast_level = co->level;
   double force = co->force;
   variant effect;
-
+  message * msg;
   if (!mage->building || mage->building->type != bt_find("castle")) {
     cmistake(mage, co->order, 197, MSG_MAGIC);
     return 0;
@@ -2041,17 +2032,16 @@ sp_homestone(castorder *co)
 
   /* melden, 1x pro Partei in der Burg */
   for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT);
+  msg = msg_message("homestone_effect", "mage building", mage, mage->building);
   for (u = r->units; u; u = u->next) {
     if (!fval(u->faction, FFL_SELECT)) {
       fset(u->faction, FFL_SELECT);
-      if (u->building ==  mage->building) {
-        sprintf(buf, "Mit einem Ritual bindet %s die magischen Kr�fte "
-            "der Erde in die Mauern von %s", unitname(mage),
-            buildingname(mage->building));
-        addmessage(r, u->faction, buf, MSG_EVENT, ML_INFO);
+      if (u->building == mage->building) {
+        r_addmessage(r, u->faction, msg);
       }
     }
   }
+  msg_release(msg);
   return cast_level;
 }
 
@@ -2075,12 +2065,12 @@ static int
 sp_drought(castorder *co)
 {
   curse *c;
-  unit *u;
   region *r = co->rt;
   unit *mage = co->magician.u;
   int cast_level = co->level;
   double power = co->force;
   int duration = (int)power+1;
+  message * msg;
 
   if (fval(r->terrain, SEA_REGION) ) {
     cmistake(mage, co->order, 189, MSG_MAGIC);
@@ -2089,20 +2079,9 @@ sp_drought(castorder *co)
   }
 
   /* melden, 1x pro Partei */
-  for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT);
-  for(u = r->units; u; u = u->next ) {
-    if (!fval(u->faction, FFL_SELECT) ) {
-      fset(u->faction, FFL_SELECT);
-      sprintf(buf, "%s verflucht das Land, und eine D�rreperiode beginnt.",
-          cansee(u->faction, r, mage, 0) ? unitname(mage) : "Jemand");
-      addmessage(r, u->faction, buf, MSG_EVENT, ML_INFO);
-    }
-  }
-  if (!fval(mage->faction, FFL_SELECT)) {
-    sprintf(buf, "%s verflucht das Land, und eine D�rreperiode beginnt.",
-        unitname(mage));
-    addmessage(0, mage->faction, buf, MSG_MAGIC, ML_INFO);
-  }
+  msg = msg_message("drought_effect", "mage", mage);
+  r_addmessage(r, NULL, msg);
+  msg_release(msg);
 
   /* Wenn schon Duerre herrscht, dann setzen wir nur den Power-Level
    * hoch (evtl dauert dann die Duerre laenger).  Ansonsten volle
@@ -2218,13 +2197,14 @@ sp_ironkeeper(castorder *co)
   region *r = co->rt;
   unit *mage = co->magician.u;
   int cast_level = co->level;
+  message * msg;
 
   if (rterrain(r) != T_MOUNTAIN && rterrain(r) != T_GLACIER) {
     report_failure(mage, co->order);
     return 0;
   }
 
-  keeper = create_unit(r, mage->faction, 1, new_race[RC_IRONKEEPER], 0, "Bergw�chter", mage);
+  keeper = create_unit(r, mage->faction, 1, new_race[RC_IRONKEEPER], 0, NULL, mage);
 
   /*keeper->age = cast_level + 2;*/
   guard(keeper, GUARD_MINING);
@@ -2237,8 +2217,9 @@ sp_ironkeeper(castorder *co)
     add_trigger(&keeper->attribs, "timer", trigger_timeout(cast_level+2, tkill));
   }
 
-  sprintf(buf, "%s beschw�rt einen Bergw�chter.", unitname(mage));
-  addmessage(r, mage->faction, buf, MSG_MAGIC, ML_INFO);
+  msg = msg_message("summon_effect", "mage amount race", mage, 1, keeper->race);
+  r_addmessage(r, NULL, msg);
+  msg_release(msg);
 
   return cast_level;
 }
@@ -2289,14 +2270,11 @@ sp_stormwinds(castorder *co)
 
     /* mit C_SHIP_NODRIFT haben wir kein Problem */
     if (is_cursed(sh->attribs, C_SHIP_FLYING, 0) ) {
-      sprintf(buf, "Es ist zu gef�hrlich, diesen Zauber auf ein "
-          "fliegendes Schiff zu legen.");
-      addmessage(r, mage->faction, buf, MSG_MAGIC, ML_MISTAKE);
+      ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, "error_spell_on_flying_ship", "ship", sh))
       continue;
     }
     if (is_cursed(sh->attribs, C_SHIP_SPEEDUP, 0) ) {
-      sprintf(buf, "Auf %s befindet sich bereits ein Zauber", shipname(sh));
-      addmessage(r, mage->faction, buf, MSG_MAGIC, ML_MISTAKE);
+      ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, "error_spell_on_ship_already", "ship", sh))
       continue;
     }
 
@@ -2355,6 +2333,7 @@ sp_earthquake(castorder *co)
   region *r = co->rt;
   unit *mage = co->magician.u;
   int cast_level = co->level;
+  message * msg;
 
   for (burg = r->buildings; burg; burg = burg->next) {
     if (burg->size == 0 )
@@ -2385,17 +2364,9 @@ sp_earthquake(castorder *co)
   }
 
   /* melden, 1x pro Partei */
-  for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT);
-  for (u = r->units; u; u = u->next ) {
-    if (!fval(u->faction, FFL_SELECT) ) {
-      fset(u->faction, FFL_SELECT);
-      sprintf(buf, "%s l��t die Erde in %s erzittern.",
-          cansee(u->faction, r, mage, 0) ? unitname(mage) : "Jemand",
-          regionname(r, u->faction));
-
-      addmessage(r, u->faction, buf, MSG_EVENT, ML_INFO);
-    }
-  }
+  msg = msg_message("earthquake_effect", "mage region", mage, r);
+  r_addmessage(r, NULL, msg);
+  msg_release(msg);
   return cast_level;
 }
 
@@ -2421,15 +2392,15 @@ patzer_peasantmob(castorder *co)
   if (r->land) {
     faction * f = findfaction(MONSTER_FACTION);
     const struct locale * lang = f->locale;
+    message * msg;
 
     anteil += rng_int() % 4;
     n = rpeasants(r) * anteil / 10;
     rsetpeasants(r, rpeasants(r) - n);
     assert(rpeasants(r) >= 0);
 
-    u = createunit(r, f, n, new_race[RC_PEASANT]);
+    u = create_unit(r, f, n, new_race[RC_PEASANT], 0, LOC(f->locale, "angry_mob"), NULL);
     fset(u, UFL_ISNEW);
-    set_string(&u->name, "Bauernmob");
     /* guard(u, GUARD_ALL);  hier zu fr�h! Befehl BEWACHE setzten */
     addlist(&u->orders, parse_order(LOC(lang, keywords[K_GUARD]), lang));
     set_order(&u->thisorder, default_order(lang));
@@ -2439,8 +2410,9 @@ patzer_peasantmob(castorder *co)
     a_add(&u->attribs, a);
     a_add(&u->attribs, make_hate(mage));
 
-    sprintf(buf, "Ein Bauernmob erhebt sich und macht Jagd auf Schwarzmagier.");
-    addmessage(r, 0, buf, MSG_MAGIC, ML_INFO);
+    msg = msg_message("mob_warning", "");
+    r_addmessage(r, NULL, msg);
+    msg_release(msg);
   }
   return;
 }
@@ -2483,6 +2455,7 @@ sp_forest_fire(castorder *co)
   int cast_level = co->level;
   double probability;
   double percentage = (rng_int() % 8 + 1) * 0.1;  /* 10 - 80% */
+  message * msg;
 
   int vernichtet_schoesslinge = (int)(rtrees(r, 1) * percentage);
   int destroyed = (int)(rtrees(r, 2) * percentage);
@@ -2498,26 +2471,12 @@ sp_forest_fire(castorder *co)
 
   /* melden, 1x pro Partei */
   for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT);
+  msg = msg_message("forestfire_effect", "mage region amount", mage, r, destroyed+vernichtet_schoesslinge);
+  r_addmessage(r, NULL, msg);
+  add_message(&mage->faction->msgs, msg);
+  msg_release(msg);
 
-  for(u = r->units; u; u = u->next ) {
-    if (!fval(u->faction, FFL_SELECT) ) {
-      fset(u->faction, FFL_SELECT);
-      sprintf(buf, "%s erzeugt eine verheerende Feuersbrunst.  %d %s "
-          "den Flammen zum Opfer.",
-          cansee(u->faction, r, mage, 0) ? unitname(mage) : "Jemand",
-          destroyed,
-          destroyed == 1 ? "Baum fiel" : "B�ume fielen");
-      addmessage(r, u->faction, buf, MSG_EVENT, ML_INFO);
-    }
-  }
-  if (!fval(mage->faction, FFL_SELECT)) {
-    sprintf(buf, "%s erzeugt eine verheerende Feuersbrunst.  %d %s "
-        "den Flammen zum Opfer.", unitname(mage), destroyed+vernichtet_schoesslinge,
-        destroyed+vernichtet_schoesslinge == 1 ? "Baum fiel" : "B�ume fielen");
-    addmessage(0, mage->faction, buf, MSG_MAGIC, ML_INFO);
-  }
-
-  for(i = 0; i < MAXDIRECTIONS; i++ ) {
+  for (i = 0; i < MAXDIRECTIONS; i++ ) {
     nr = rconnect(r, i);
     assert(nr);
     destroyed = 0;
@@ -2940,7 +2899,7 @@ sp_firewall(castorder *co)
   direction_t dir;
   region * r2;
 
-  dir = finddirection(pa->param[0]->data.s, mage->faction->locale);
+  dir = finddirection(pa->param[0]->data.xs, mage->faction->locale);
   if (dir<MAXDIRECTIONS && dir!=NODIRECTION) {
     r2 = rconnect(r, dir);
   } else {
@@ -3067,7 +3026,7 @@ sp_wisps(castorder *co)
   double force = co->force;
   spellparameter *pa = co->par;
 
-  dir = finddirection(pa->param[0]->data.s, mage->faction->locale);
+  dir = finddirection(pa->param[0]->data.xs, mage->faction->locale);
   r2 = rconnect(r, dir);
 
   if (!r2) {
@@ -3448,9 +3407,8 @@ sp_summonshadowlords(castorder *co)
   /* Bekommen Tarnung = Magie und Wahrnehmung 5. */
   set_level(u, SK_STEALTH, get_level(mage, SK_MAGIC));
   set_level(u, SK_OBSERVATION, 5);
-  sprintf(buf, "%s beschw�rt %d Schattenmeister.",
-    unitname(mage), (int)(force*force));
-  addmessage(0, mage->faction, buf, MSG_MAGIC, ML_INFO);
+
+  ADDMSG(&mage->faction->msgs, msg_message("summon_effect", "mage amount race", mage, 1, u->race));
   return cast_level;
 }
 
@@ -3469,7 +3427,6 @@ sp_summonshadowlords(castorder *co)
 static int
 sp_chaossuction(castorder *co)
 {
-  unit *u;
   region *rt;
   region *r = co->rt;
   unit *mage = co->magician.u;
@@ -3497,25 +3454,8 @@ sp_chaossuction(castorder *co)
       "Wirbel");
   new_border(&bt_chaosgate, r, rt);
 
-  freset(mage->faction, FFL_SELECT);
-  for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT);
-  for (u = r->units; u; u = u->next) {
-    if (!fval(u->faction, FFL_SELECT)) {
-      fset(u->faction, FFL_SELECT);
-      sprintf(buf, "%s �ffnete ein Chaostor.",
-          cansee(u->faction, r, mage, 0)?unitname(mage):"Jemand");
-      addmessage(r, u->faction, buf, MSG_EVENT, ML_INFO);
-    }
-  }
-  for (u = rt->units; u; u = u->next) freset(u->faction, FFL_SELECT);
-
-  for (u = rt->units; u; u = u->next) {
-    if (!fval(u->faction, FFL_SELECT)) {
-      fset(u->faction, FFL_SELECT);
-      addmessage(r, u->faction, "Ein Wirbel aus blendendem Licht erscheint.",
-        MSG_EVENT, ML_INFO);
-    }
-  }
+  add_message(&r->msgs, msg_message("chaosgate_effect_1", "mage", mage));
+  add_message(&rt->msgs, msg_message("chaosgate_effect_2", ""));
   return cast_level;
 }
 
@@ -3665,12 +3605,9 @@ sp_summonundead(castorder *co)
   int cast_level = co->level;
   int force = (int)(co->force*10);
   const race * race = new_race[RC_SKELETON];
-  message * m = NULL;
 
   if (!r->land || deathcount(r) == 0) {
-    sprintf(buf, "%s in %s: In %s sind keine Gr�ber.", unitname(mage),
-        regionname(mage->region, mage->faction), regionname(r, mage->faction));
-    addmessage(0, mage->faction, buf, MSG_MAGIC, ML_MISTAKE);
+    ADDMSG(&mage->faction->msgs, msg_feedback(mage, co->order, "error_nograves", "target", r));
     return 0;
   }
 
@@ -3687,21 +3624,8 @@ sp_summonundead(castorder *co)
   u = create_unit(r, mage->faction, undead, race, 0, NULL, mage);
   make_undead_unit(u);
 
-  sprintf(buf, "%s erweckt %d Untote aus ihren Gr�bern.",
-      unitname(mage), undead);
-  addmessage(0, mage->faction, buf, MSG_MAGIC, ML_INFO);
-
-  /* melden, 1x pro Partei */
-  for (u = r->units; u; u = u->next) freset(u->faction, FFL_SELECT);
-
-  for (u = r->units; u; u = u->next ) {
-    if (!fval(u->faction, FFL_SELECT) ) {
-      if (!m) m = msg_message("summonundead_effect", "unit", mage);
-      fset(u->faction, FFL_SELECT);
-      add_message(&u->faction->msgs, m);
-    }
-  }
-  if (m) msg_release(m);
+  ADDMSG(&mage->faction->msgs, msg_message("summonundead_effect_1", "mage amount", mage, undead));
+  ADDMSG(&r->msgs, msg_message("summonundead_effect_2", "mage", mage));
   return cast_level;
 }
 
@@ -4156,6 +4080,7 @@ sp_raisepeasantmob(castorder *co)
   int cast_level = co->level;
   double force = co->force;
   int duration = (int)force+1;
+  faction * monsters = findfaction(MONSTER_FACTION);
 
   anteil.i = 6 + (rng_int()%4);
 
@@ -4171,9 +4096,8 @@ sp_raisepeasantmob(castorder *co)
   rsetpeasants(r, rpeasants(r) - n);
   assert(rpeasants(r) >= 0);
 
-  u = createunit(r, findfaction(MONSTER_FACTION), n, new_race[RC_PEASANT]);
+  u = create_unit(r, monsters, n, new_race[RC_PEASANT], 0, LOC(monsters->locale, "furious_mob"), NULL);
   fset(u, UFL_ISNEW);
-  set_string(&u->name, "Aufgebrachte Bauern");
   guard(u, GUARD_ALL);
   a = a_new(&at_unitdissolve);
   a->data.ca[0] = 1;  /* An rpeasants(r). */
@@ -4270,26 +4194,15 @@ sp_migranten(castorder *co)
 
     for (ord = target->orders; ord; ord = ord->next) {
       if (get_keyword(ord) == K_CONTACT) {
-        const char *c;
-        /* So weit, so gut. S->s ist also ein KONTAKTIERE. Nun gilt es,
-        * herauszufinden, wer kontaktiert wird. Das ist nicht trivial.
-        * Zuerst mu� der Parameter herausoperiert werden. */
-        /* Leerzeichen finden */
+        int kontakt;
 
         init_tokens(ord);
         skip_token();
-        c = getstrtoken();
+        kontakt = getid();
 
-        /* Wenn ein Leerzeichen da ist, ist *c != 0 und zeigt auf das
-        * Leerzeichen. */
-
-        if (c!=NULL) {
-          int kontakt = atoi36(c);
-
-          if (kontakt == mage->no) {
-            kontaktiert = 1;
-            break;
-          }
+        if (kontakt == mage->no) {
+          kontaktiert = 1;
+          break;
         }
       }
     }
@@ -4445,7 +4358,7 @@ sp_recruit(castorder *co)
     rsetpeasants(r, maxp - n);
   }
 
-  u = create_unit(r, f, n, f->race, 0, (n == 1 ? "Bauer" : "Bauern"), mage);
+  u = create_unit(r, f, n, f->race, 0, LOC(f->locale,(n == 1 ? "peasant" : "peasant_p")), mage);
   set_order(&u->thisorder, default_order(f->locale));
 
   ADDMSG(&mage->faction->msgs, msg_message("recruit_effect", "mage amount", mage, n));
@@ -4472,6 +4385,7 @@ sp_bigrecruit(castorder *co)
   int cast_level = co->level;
   double force = co->force;
   faction *f = mage->faction;
+  message * msg;
 
   if (maxp <= 0) {
     report_failure(mage, co->order);
@@ -4491,12 +4405,13 @@ sp_bigrecruit(castorder *co)
     rsetpeasants(r, maxp - n);
   }
 
-  u = create_unit(r, f, n, f->race, 0, (n == 1 ? "Bauer" : "Bauern"), mage);
+  u = create_unit(r, f, n, f->race, 0, LOC(f->locale,(n == 1 ? "peasant" : "peasant_p")), mage);
   set_order(&u->thisorder, default_order(f->locale));
 
-  sprintf(buf, "%s konnte %d %s anwerben", unitname(mage), n,
-      n == 1 ? "Bauer" : "Bauern");
-  addmessage(r, mage->faction, buf, MSG_MAGIC, ML_INFO);
+  msg = msg_message("recruit_effect", "mage amount", mage, n);
+  r_addmessage(r, mage->faction, msg);
+  msg_release(msg);
+
   return cast_level;
 }
 
@@ -4561,8 +4476,7 @@ sp_pump(castorder *co)
     addmessage(r, mage->faction, buf, MSG_MAGIC, ML_INFO);
   }
 
-  u = createunit(rt, mage->faction, RS_FARVISION, new_race[RC_SPELL]);
-  set_string(&u->name, "Zauber: Aushorchen");
+  u = create_unit(rt, mage->faction, RS_FARVISION, new_race[RC_SPELL], 0, (const xmlChar*)"spell/pump", NULL);
   u->age = 2;
   set_level(u, SK_OBSERVATION, eff_skill(target, SK_OBSERVATION, u->region));
 
@@ -4999,7 +4913,7 @@ sp_icastle(castorder *co)
   spellparameter *pa = co->par;
   icastle_data * data;
 
-  if ((type=findbuildingtype(pa->param[0]->data.s, mage->faction->locale)) == NULL) {
+  if ((type=findbuildingtype(pa->param[0]->data.xs, mage->faction->locale)) == NULL) {
     type = bt_find("castle");
   }
 
@@ -5070,7 +4984,7 @@ sp_illusionary_shapeshift(castorder *co)
 
   u = pa->param[0]->data.u;
 
-  rc = findrace(pa->param[1]->data.s, mage->faction->locale);
+  rc = findrace(pa->param[1]->data.xs, mage->faction->locale);
   if (rc == NULL) {
     cmistake(mage, co->order, 202, MSG_MAGIC);
     return 0;
@@ -5641,7 +5555,7 @@ sp_resist_magic_bonus(castorder *co)
 /* "ZAUBERE [STUFE n]  \"Astraler Weg\" <Einheit-Nr> [<Einheit-Nr> ...]",
  *
  * Parameter:
- * pa->param[0]->data.s
+ * pa->param[0]->data.xs
 */
 int
 sp_enterastral(castorder *co)
@@ -6480,7 +6394,7 @@ sp_movecastle(castorder *co)
   if (pa->param[0]->flag == TARGET_NOTFOUND) return 0;
 
   b = pa->param[0]->data.b;
-  dir = finddirection(pa->param[1]->data.s, mage->faction->locale);
+  dir = finddirection(pa->param[1]->data.xs, mage->faction->locale);
 
   if (dir == NODIRECTION) {
     /* Die Richtung wurde nicht erkannt */
@@ -6988,7 +6902,7 @@ sp_break_curse(castorder *co)
 
   obj = pa->param[0]->typ;
 
-  c = findcurse(atoi36(pa->param[1]->data.s));
+  c = findcurse(atoi36(pa->param[1]->data.xs));
   if (!c) {
     /* Es wurde kein Ziel gefunden */
     ADDMSG(&mage->faction->msgs, msg_message(
@@ -7046,7 +6960,7 @@ sp_break_curse(castorder *co)
 
       ADDMSG(&mage->faction->msgs, msg_message(
         "destroy_curse_effect", "unit region command id target",
-        mage, mage->region, co->order, strdup(pa->param[1]->data.s),
+        mage, mage->region, co->order, strdup(pa->param[1]->data.xs),
         strdup(ts)));
     } else {
       ADDMSG(&mage->faction->msgs, msg_message(
diff --git a/src/common/triggers/unitmessage.c b/src/common/triggers/unitmessage.c
index d7ac44f34..b4d2190ee 100644
--- a/src/common/triggers/unitmessage.c
+++ b/src/common/triggers/unitmessage.c
@@ -18,6 +18,7 @@
 
 /* kernel includes */
 #include <kernel/unit.h>
+#include <kernel/faction.h>
 
 /* util includes */
 #include <util/attrib.h>
@@ -25,6 +26,7 @@
 #include <util/event.h>
 #include <util/base36.h>
 #include <util/goodies.h>
+#include <util/language.h>
 
 /* ansi includes */
 #include <stdio.h>
@@ -65,9 +67,11 @@ unitmessage_handle(trigger * t, void * data)
   */
   unitmessage_data * td = (unitmessage_data*)t->data.v;
   if (td->target!=NULL) {
-    addmessage(td->target->region, td->target->faction, td->string, td->type, td->level);
-  } else
+    struct faction * f = td->target->faction;
+    addmessage(td->target->region, f, LOC(f->locale, td->string), td->type, td->level);
+  } else {
     log_error(("could not perform unitmessage::handle()\n"));
+  }
   unused(data);
   return 0;
 }
diff --git a/src/common/util/Jamfile b/src/common/util/Jamfile
index adfb469b9..5f3694951 100644
--- a/src/common/util/Jamfile
+++ b/src/common/util/Jamfile
@@ -32,6 +32,7 @@ SOURCES =
  strncpy.c
  translation.c
  umlaut.c
+ unicode.c
  vmap.c
  vset.c
  windir.c
diff --git a/src/common/util/language.c b/src/common/util/language.c
index 610a1bb92..fd97221f2 100644
--- a/src/common/util/language.c
+++ b/src/common/util/language.c
@@ -76,7 +76,7 @@ debug_language(const char * log)
   s_logfile = strdup(log);
 }
 
-const char *
+const xmlChar *
 locale_getstring(const locale * lang, const char * key)
 {
   unsigned int hkey = hashstring(key);
@@ -102,7 +102,7 @@ locale_getstring(const locale * lang, const char * key)
   return NULL;
 }
 
-const char *
+const xmlChar *
 locale_string(const locale * lang, const char * key)
 {
   if (key!=NULL) {
@@ -111,7 +111,7 @@ locale_string(const locale * lang, const char * key)
     struct locale_str * find;
     
     if (key == NULL || *key==0) return NULL;
-    if (lang == NULL) return key;
+    if (lang == NULL) return BAD_CAST key;
     find = lang->strings[id];
     while (find) {
       if (find->hashkey == hkey) {
@@ -125,7 +125,7 @@ locale_string(const locale * lang, const char * key)
       find = find->nexthash;
     }
     if (!find) {
-      const char * s = key;
+      const xmlChar * s = BAD_CAST key;
       log_warning(("missing translation for \"%s\" in locale %s\n", key, lang->name));
       if (lang!=default_locale) {
         s = locale_string(default_locale, key);
@@ -146,7 +146,7 @@ locale_string(const locale * lang, const char * key)
 }
 
 void
-locale_setstring(locale * lang, const char * key, const char * value)
+locale_setstring(locale * lang, const char * key, const xmlChar * value)
 {
   unsigned int hkey = hashstring(key);
   unsigned int id = hkey & (SMAXHASH-1);
@@ -163,13 +163,13 @@ locale_setstring(locale * lang, const char * key, const char * value)
     lang->strings[id] = find;
     find->hashkey = hkey;
     find->key = strdup(key);
-    find->str = strdup(value);
+    find->str = xmlStrdup(value);
   }
   else {
-    if (strcmp(find->str, value)!=0) {
+    if (xmlStrcmp(find->str, value)!=0) {
       log_error(("Duplicate key %s for '%s' and '%s'\n", key, value, find->str));
     }
-    assert(!strcmp(find->str, value) || !"duplicate string for key");
+    assert(!xmlStrcmp(find->str, value) || !"duplicate string for key");
   }
 }
 
@@ -181,24 +181,23 @@ locale_name(const locale * lang)
 }
 
 const char *
-reverse_lookup(const locale * lang, const char * str)
+reverse_lookup(const locale * lang, const xmlChar * str)
 {
 	int i;
 	assert(lang);
-	if (strlen(str)) {
+	if (xmlStrlen(str)) {
 		if (lang!=NULL) {
 			for (i=0;i!=SMAXHASH;++i) {
 				struct locale_str * ls;
 				for (ls=lang->strings[i];ls;ls=ls->nexthash) {
-					if (strcasecmp(ls->key, str)==0) return ls->key;
-					if (strcasecmp(ls->str, str)==0) return ls->key;
+					if (xmlStrcasecmp(ls->str, str)==0) return ls->key;
 				}
 			}
 		}
 		log_error(("could not do a reverse_lookup for \"%s\" in locale %s\n", str, lang->name));
     assert(!"failed to do a reverse_lookup");
 	}
-	return str;
+	return NULL;
 }
 
 char *
diff --git a/src/common/util/language.h b/src/common/util/language.h
index 5c60e36b6..6266b42cf 100644
--- a/src/common/util/language.h
+++ b/src/common/util/language.h
@@ -18,19 +18,20 @@ extern "C" {
 #endif
 
 struct locale;
+typedef unsigned char xmlChar;
 
 /** managing multiple locales: **/
 extern struct locale * find_locale(const char * name);
 extern struct locale * make_locale(const char * key);
 
 /** operations on locales: **/
-extern void locale_setstring(struct locale * lang, const char * key, const char * value);
-extern const char * locale_getstring(const struct locale * lang, const char * key);
-extern const char * locale_string(const struct locale * lang, const char * key); /* does fallback */
+extern void locale_setstring(struct locale * lang, const char * key, const xmlChar * value);
+extern const xmlChar * locale_getstring(const struct locale * lang, const char * key);
+extern const xmlChar * locale_string(const struct locale * lang, const char * key); /* does fallback */
 extern unsigned int locale_hashkey(const struct locale * lang);
 extern const char * locale_name(const struct locale * lang);
 
-extern const char * reverse_lookup(const struct locale * lang, const char * str);
+extern const char * reverse_lookup(const struct locale * lang, const xmlChar * str);
 extern const char * mkname(const char * namespc, const char * key);
 extern char * mkname_buf(const char * namespc, const char * key, char * buffer);
 
@@ -50,6 +51,8 @@ enum {
   UT_OPTIONS,
   UT_DIRECTIONS,
   UT_ARCHETYPES,
+  UT_MAGIC,
+  UT_TERRAINS,
   UT_MAX
 };
 
diff --git a/src/common/util/language_struct.h b/src/common/util/language_struct.h
index 1f09a071b..7cb84cc16 100644
--- a/src/common/util/language_struct.h
+++ b/src/common/util/language_struct.h
@@ -10,7 +10,7 @@
 typedef struct locale_str {
   unsigned int hashkey;
   struct locale_str * nexthash;
-  char * str;
+  xmlChar * str;
   char * key;
 } locale_str;
 
diff --git a/src/common/util/nrmessage.c b/src/common/util/nrmessage.c
index 84b18c982..47097b368 100644
--- a/src/common/util/nrmessage.c
+++ b/src/common/util/nrmessage.c
@@ -131,14 +131,14 @@ nrt_register(const struct message_type * mtype, const struct locale * lang, cons
 }
 
 size_t
-nr_render(const struct message * msg, const struct locale * lang, char * buffer, size_t size, const void * userdata)
+nr_render(const struct message * msg, const struct locale * lang, xmlChar * buffer, size_t size, const void * userdata)
 {
   struct nrmessage_type * nrt = nrt_find(lang, msg->type);
 
   if (nrt) {
     const char * m = translate(nrt->string, userdata, nrt->vars, msg->parameters);
     if (m) {
-      return strlcpy(buffer, m, size);
+      return strlcpy((char*)buffer, m, size);
     } else {
       log_error(("Couldn't render message %s\n", nrt->mtype->name));
     }
diff --git a/src/common/util/nrmessage.h b/src/common/util/nrmessage.h
index d9a931570..89668998e 100644
--- a/src/common/util/nrmessage.h
+++ b/src/common/util/nrmessage.h
@@ -37,7 +37,7 @@ extern const char * nrt_string(const struct nrmessage_type *type);
 extern const char * nrt_section(const struct nrmessage_type * mt);
 
 extern size_t nr_render(const struct message * msg, const struct locale * lang,
-                     char * buffer, size_t size, const void * userdata);
+                     xmlChar * buffer, size_t size, const void * userdata);
 extern int nr_level(const struct message *msg);
 extern const char * nr_section(const struct message *msg);
 
diff --git a/src/common/util/parser.c b/src/common/util/parser.c
index 881664e90..f1bd63817 100644
--- a/src/common/util/parser.c
+++ b/src/common/util/parser.c
@@ -1,30 +1,59 @@
 #include <config.h>
 #include "parser.h"
+#include "unicode.h"
+#include "log.h"
 
 #include <assert.h>
 #include <ctype.h>
+#include <memory.h>
 
 #define SPACE_REPLACEMENT '~'
 #define ESCAPE_CHAR       '\\'
 #define MAXTOKENSIZE      8192
 
 typedef struct parser_state {
-  const unsigned char *current_token;
-  char * current_cmd;
+  const xmlChar *current_token;
+  xmlChar * current_cmd;
   struct parser_state * next;
 } parser_state;
 
 static parser_state * state;
 
+static int
+eatwhitespace_c(const xmlChar ** str)
+{
+  int ret;
+  wint_t ucs;
+  size_t len;
+
+  /* skip over potential whitespace */
+  for (;;) {
+    xmlChar utf8_character = (*str)[0];
+    if (utf8_character <= 0x7F) {
+      if (!isspace(utf8_character)) break;
+      ++*str;
+    } else {
+      ret = unicode_utf8_to_ucs4(&ucs, *str, &len);
+      if (ret!=0) {
+        log_warning(("illegal character sequence in UTF8 string: %s\n", *str));
+        return ret;
+      }
+      if (!iswspace(ucs)) break;
+      *str+=len;
+    }
+  }
+  return 0;
+}
+
 void
-init_tokens_str(const char * initstr, char * cmd)
+init_tokens_str(const xmlChar * initstr, xmlChar * cmd)
 {
   if (state==NULL) {
     state = malloc(sizeof(parser_state));
   }
   else if (state->current_cmd) free(state->current_cmd);
   state->current_cmd = cmd;
-  state->current_token = (const unsigned char *)initstr;
+  state->current_token = (const xmlChar *)initstr;
 }
 
 void
@@ -49,7 +78,7 @@ parser_popstate(void)
 boolean
 parser_end(void)
 {
-  while (isspace(*state->current_token)) ++state->current_token;
+  eatwhitespace_c(&state->current_token);
   return *state->current_token == 0;
 }
 
@@ -57,73 +86,107 @@ void
 skip_token(void)
 {
   char quotechar = 0;
+  eatwhitespace_c(&state->current_token);
 
-  while (isspace(*state->current_token)) ++state->current_token;
   while (*state->current_token) {
-    if (isspace(*state->current_token) && quotechar==0) {
+    wint_t ucs;
+    size_t len;
+
+    xmlChar utf8_character = state->current_token[0];
+    if (utf8_character <= 0x7F) {
+      ucs = utf8_character;
+      ++state->current_token;
+    } else {
+      int ret = unicode_utf8_to_ucs4(&ucs, state->current_token, &len);
+      if (ret==0) {
+        state->current_token+=len;
+      } else {
+        log_warning(("illegal character sequence in UTF8 string: %s\n", state->current_token));
+      }
+    }
+    if (iswspace(ucs) && quotechar==0) {
       return;
     } else {
-      switch(*state->current_token) {
+      switch(utf8_character) {
         case '"':
         case '\'':
-          if (*state->current_token==quotechar) return;
-          quotechar = *state->current_token;
+          if (utf8_character==quotechar) return;
+          quotechar = utf8_character;
           break;
         case ESCAPE_CHAR:
           ++state->current_token;
           break;
       }
     }
-    ++state->current_token;
   }
 }
 
-const char *
-parse_token(const char ** str)
+const xmlChar *
+parse_token(const xmlChar ** str)
 {
-  static char lbuf[MAXTOKENSIZE];
-  char * cursor = lbuf;
+  static xmlChar lbuf[MAXTOKENSIZE];
+  xmlChar * cursor = lbuf;
   char quotechar = 0;
   boolean escape = false;
-  const unsigned char * ctoken = (const unsigned char*)*str;
+  const xmlChar * ctoken = *str;
 
   assert(ctoken);
 
-  while (isspace(*ctoken)) ++ctoken;
+  eatwhitespace_c(&ctoken);
   while (*ctoken && cursor-lbuf < MAXTOKENSIZE-1) {
+    wint_t ucs;
+    size_t len;
+    boolean copy = false;
+
+    xmlChar utf8_character = *ctoken;
+    if (utf8_character <= 0x7F) {
+      ucs = utf8_character;
+      len = 1;
+    } else {
+      int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len);
+      if (ret!=0) {
+        log_warning(("illegal character sequence in UTF8 string: %s\n", ctoken));
+        break;
+      }
+    }
     if (escape) {
-      *cursor++ = *ctoken++;
-    } else if (isspace(*ctoken)) {
+      copy = true;
+    } else if (iswspace(ucs)) {
       if (quotechar==0) break;
-      *cursor++ = *ctoken++;
-    } else if (*ctoken=='"' || *ctoken=='\'') {
-      if (*ctoken==quotechar) {
+      copy = true;
+    } else if (utf8_character=='"' || utf8_character=='\'') {
+      if (utf8_character==quotechar) {
         ++ctoken;
         break;
       } else if (quotechar==0) {
-        quotechar = *ctoken;
+        quotechar = utf8_character;
         ++ctoken;
       } else {
         *cursor++ = *ctoken++;
       }
-    } else if (*ctoken==SPACE_REPLACEMENT) {
+    } else if (utf8_character==SPACE_REPLACEMENT) {
       *cursor++ = ' ';
       ++ctoken;
-    } else if (*ctoken==ESCAPE_CHAR) {
+    } else if (utf8_character==ESCAPE_CHAR) {
       escape = true;
       ++ctoken;
     } else {
-      *cursor++ = *ctoken++;
+      copy = true;
+    }
+    if (copy) {
+      memcpy(cursor, ctoken, len);
+      cursor+=len;
+      ctoken+=len;
     }
   }
 
   *cursor = '\0';
-  *str = (const char *)ctoken;
+  *str = ctoken;
   return lbuf;
 }
 
-const char *
+const xmlChar *
 getstrtoken(void)
 {
-  return parse_token((const char**)&state->current_token);
+  return parse_token((const xmlChar**)&state->current_token);
 }
diff --git a/src/common/util/parser.h b/src/common/util/parser.h
index fecb5ff9f..27330cf5e 100644
--- a/src/common/util/parser.h
+++ b/src/common/util/parser.h
@@ -14,13 +14,13 @@
 extern "C" {
 #endif
 
-extern void init_tokens_str(const char * initstr, char * cmd); /* initialize token parsing, take ownership of cmd */
+extern void init_tokens_str(const xmlChar * initstr, xmlChar * cmd); /* initialize token parsing, take ownership of cmd */
 extern void skip_token(void);
-extern const char * parse_token(const char ** str);
+extern const xmlChar * parse_token(const xmlChar ** str);
 extern void parser_pushstate(void);
 extern void parser_popstate(void);
 extern boolean parser_end(void);
-extern const char *getstrtoken(void);
+extern const xmlChar *getstrtoken(void);
 
 #ifdef __cplusplus
 }
diff --git a/src/common/util/umlaut.c b/src/common/util/umlaut.c
index d35219eff..442dcdd8c 100644
--- a/src/common/util/umlaut.c
+++ b/src/common/util/umlaut.c
@@ -1,162 +1,162 @@
 /* vi: set ts=2:
- *
- *	
- *	Eressea PB(E)M host Copyright (C) 1998-2003
- *      Christian Schlittchen (corwin@amber.kn-bremen.de)
- *      Katja Zedel (katze@felidae.kn-bremen.de)
- *      Henning Peters (faroul@beyond.kn-bremen.de)
- *      Enno Rehling (enno@eressea-pbem.de)
- *      Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
- *
- *  based on:
- *
- * Atlantis v1.0  13 September 1993 Copyright 1993 by Russell Wallace
- * Atlantis v1.7                    Copyright 1996 by Alex Schr�der
- *
- * This program may not be used, modified or distributed without
- * prior permission by the authors of Eressea.
- * This program may not be sold or used commercially without prior written
- * permission from the authors.
- */
+*
+*	
+* Eressea PB(E)M host Copyright (C) 1998-2003
+*      Christian Schlittchen (corwin@amber.kn-bremen.de)
+*      Katja Zedel (katze@felidae.kn-bremen.de)
+*      Henning Peters (faroul@beyond.kn-bremen.de)
+*      Enno Rehling (enno@eressea-pbem.de)
+*      Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
+*
+* based on:
+*
+*      Atlantis v1.0  13 September 1993 Copyright 1993 by Russell Wallace
+*      Atlantis v1.7                    Copyright 1996 by Alex Schr�der
+*
+* This program may not be used, modified or distributed without
+* prior permission by the authors of Eressea.
+* This program may not be sold or used commercially without prior written
+* permission from the authors.
+*/
 
 #include <config.h>
 #include "umlaut.h"
 
+#include "log.h"
+#include "unicode.h"
+
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 
 typedef struct tref {
-	struct tref * nexthash;
-	char c;
-	struct tnode * node;
+  struct tref * nexthash;
+  wint_t ucs;
+  struct tnode * node;
 } tref;
 
 #define LEAF 1 /* leaf node for a word. always matches */
 #define SHARED 2 /* at least two words share the node */
 
 void
-addtoken(tnode * root, const char* str, variant id)
+addtoken(tnode * root, const xmlChar * str, variant id)
 {
-	static struct replace {
-		char c;
-		const char * str;
-	} replace[] = {
-		{'�', "ae"},
-		{'�', "ae"},
-		{'�', "oe"},
-		{'�', "oe"},
-		{'�', "ue"},
-		{'�', "ue"},
-		{'�', "ss"},
-		{ 0, 0 }
-	};
-	if (!*str) {
-		root->id = id;
-		root->flags |= LEAF;
-	} else {
-		tref * next;
-		int index, i = 0;
-		register char c = *str;
-		if (c<'a' || c>'z') c = (char)tolower((unsigned char)c);
-#if NODEHASHSIZE == 8
-		index = c & 7;
-#else
-    index = ((unsigned char)c) % NODEHASHSIZE;
-#endif
-		next = root->next[index];
-		if (!(root->flags & LEAF)) root->id = id;
-		while (next && next->c != c) next = next->nexthash;
-		if (!next) {
-			tref * ref;
-			char u = (char)toupper((unsigned char)c);
-			tnode * node = calloc(1, sizeof(tnode));
+  static struct replace {
+    wint_t ucs;
+    const char str[3];
+  } replace[] = {
+    /* match lower-case (!) umlauts and others to transcriptions */
+    { 228, "AE"},
+    { 246, "OE"},
+    { 252, "UE"},
+    { 223, "SS"},
+    { 230, "AE"},
+    { 248, "OE"},
+    { 229, "AA"},
+    { 0, 0 }
+  };
+
+  if (!*str) {
+    root->id = id;
+    root->flags |= LEAF;
+  } else {
+    tref * next;
+    int ret, index, i = 0;
+    wint_t ucs, lcs;
+    size_t len;
+
+    ret = unicode_utf8_to_ucs4(&ucs, str, &len);
+    assert(ret==0 || !"invalid utf8 string");
+    lcs = ucs;
 
-			ref = malloc(sizeof(tref));
-			ref->c = c;
-			ref->node = node;
-			ref->nexthash=root->next[index];
-			root->next[index] = ref;
-			
-			if (u!=c) {
 #if NODEHASHSIZE == 8
-        index = u & 7;
+    index = ucs & 7;
 #else
-        index = ((unsigned char)u) % NODEHASHSIZE;
+    index = ucs % NODEHASHSIZE;
 #endif
-				ref = malloc(sizeof(tref));
-				ref->c = u;
-				ref->node = node;
-				ref->nexthash = root->next[index];
-				root->next[index] = ref;
-			}
-			next=ref;
-		} else {
-			next->node->flags |= SHARED;
-			if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why?*/
-		}
-		addtoken(next->node, str+1, id);
-		while (replace[i].str) {
-			if (*str==replace[i].c) {
-        char zText[1024];
-				strcat(strcpy(zText, replace[i].str), str+1);
-				addtoken(root, zText, id);
-				break;
-			}
-			++i;
-		}
-	}
+    next = root->next[index];
+    if (!(root->flags & LEAF)) root->id = id;
+    while (next && next->ucs != ucs) next = next->nexthash;
+    if (!next) {
+      tref * ref;
+      tnode * node = calloc(1, sizeof(tnode));
+
+      if (ucs<'a' || ucs>'z') {
+        lcs = towlower(ucs);
+      }
+      if (ucs==lcs) {
+        ucs = towupper(ucs);
+      }
+
+      ref = malloc(sizeof(tref));
+      ref->ucs = ucs;
+      ref->node = node;
+      ref->nexthash=root->next[index];
+      root->next[index] = ref;
+
+      /* try lower/upper casing the character, and try again */
+      if (ucs!=lcs) {
+#if NODEHASHSIZE == 8
+        index = lcs & 7;
+#else
+        index = lcs % NODEHASHSIZE;
+#endif
+        ref = malloc(sizeof(tref));
+        ref->ucs = lcs;
+        ref->node = node;
+        ref->nexthash = root->next[index];
+        root->next[index] = ref;
+      }
+      next=ref;
+    } else {
+      next->node->flags |= SHARED;
+      if ((next->node->flags & LEAF) == 0) next->node->id.v = NULL; /* why?*/
+    }
+    addtoken(next->node, str+len, id);
+    while (replace[i].str[0]) {
+      if (lcs==replace[i].ucs) {
+        xmlChar zText[1024];
+        memcpy(zText, replace[i].str, 3);
+        strcpy((char*)zText+2, (const char*)str+len);
+        addtoken(root, zText, id);
+        break;
+      }
+      ++i;
+    }
+  }
 }
 
 int
-findtoken(const tnode * tk, const char * str, variant* result)
+findtoken(const tnode * tk, const xmlChar * str, variant* result)
 {
-	if (!str || *str==0) return E_TOK_NOMATCH;
+  if (!str || *str==0) return E_TOK_NOMATCH;
 
-	do {
-		int index;
-		const tref * ref;
-		char c = *str;
+  do {
+    int index;
+    const tref * ref;
+    wint_t ucs;
+    size_t len;
+    int ret = unicode_utf8_to_ucs4(&ucs, str, &len);
 
+    if (ret!=0) {
+      /* encoding is broken. youch */
+      return E_TOK_NOMATCH;
+    }
 #if NODEHASHSIZE == 8
-    index = c & 7;
+    index = ucs & 7;
 #else
-    index = ((unsigned char)c) % NODEHASHSIZE;
+    index = ucs % NODEHASHSIZE;
 #endif
-		ref = tk->next[index];
-		while (ref && ref->c!=c) ref = ref->nexthash;
-		++str;
-		if (!ref) return E_TOK_NOMATCH;
-		tk = ref->node;
-	} while (*str);
-	if (tk) {
-		*result = tk->id;
-		return E_TOK_SUCCESS;
-	}
-	return E_TOK_NOMATCH;
+    ref = tk->next[index];
+    while (ref && ref->ucs!=ucs) ref = ref->nexthash;
+    str+=len;
+    if (!ref) return E_TOK_NOMATCH;
+    tk = ref->node;
+  } while (*str);
+  if (tk) {
+    *result = tk->id;
+    return E_TOK_SUCCESS;
+  }
+  return E_TOK_NOMATCH;
 }
-
-#ifdef TEST_UMLAUT
-#include <stdio.h>
-tnode root;
-
-int
-main(int argc, char ** argv)
-{
-	char buf[1024];
-	int i = 0;
-	for (;;) {
-		int k;
-		fgets(buf, sizeof(buf), stdin);
-		buf[strlen(buf)-1]=0;
-		if (findtoken(&root, buf, (void**)&k)==0) {
-			printf("%s returned %d\n", buf, k);
-		} else {
-			addtoken(&root, buf, (void*)++i);
-			printf("added %s=%d\n", buf, i);
-		}
-	}
-	return 0;
-}
-#endif
diff --git a/src/common/util/umlaut.h b/src/common/util/umlaut.h
index 09d4e8c04..5f3ef7746 100644
--- a/src/common/util/umlaut.h
+++ b/src/common/util/umlaut.h
@@ -32,8 +32,8 @@ typedef struct tnode {
 	variant id;
 } tnode;
 
-int findtoken(const struct tnode * tk, const char * str, variant* result);
-void addtoken(struct tnode * root, const char* str, variant id);
+int findtoken(const struct tnode * tk, const xmlChar * str, variant* result);
+void addtoken(struct tnode * root, const xmlChar* str, variant id);
 
 typedef struct local_names {
   struct local_names * next;
diff --git a/src/common/util/unicode.h b/src/common/util/unicode.h
index 1fadd0a91..aa404a25e 100644
--- a/src/common/util/unicode.h
+++ b/src/common/util/unicode.h
@@ -20,7 +20,6 @@ extern "C" {
 #endif
 
 #include <wchar.h>
-#include <libxml/xmlstring.h>
 
   extern int unicode_utf8_to_ucs4(wint_t *ucs4_character, const xmlChar *utf8_string, size_t *length);
 
diff --git a/src/common/util/util.vcproj b/src/common/util/util.vcproj
index 1bfa97bab..9522f6eab 100644
--- a/src/common/util/util.vcproj
+++ b/src/common/util/util.vcproj
@@ -283,9 +283,6 @@
 			<File
 				RelativePath=".\bsdstring.h">
 			</File>
-			<File
-				RelativePath=".\command.h">
-			</File>
 			<File
 				RelativePath=".\crmessage.h">
 			</File>
@@ -319,6 +316,9 @@
 			<File
 				RelativePath=".\nrmessage.h">
 			</File>
+			<File
+				RelativePath=".\parser.h">
+			</File>
 			<File
 				RelativePath=".\rand.h">
 			</File>
@@ -403,7 +403,7 @@
 			RelativePath=".\base36.c">
 		</File>
 		<File
-			RelativePath=".\command.c">
+			RelativePath="..\..\config.h">
 		</File>
 		<File
 			RelativePath=".\crmessage.c">
@@ -417,6 +417,9 @@
 		<File
 			RelativePath=".\event.c">
 		</File>
+		<File
+			RelativePath=".\filereader.c">
+		</File>
 		<File
 			RelativePath=".\functions.c">
 		</File>
@@ -447,6 +450,9 @@
 		<File
 			RelativePath=".\nrmessage.c">
 		</File>
+		<File
+			RelativePath=".\parser.c">
+		</File>
 		<File
 			RelativePath=".\rand.c">
 		</File>
@@ -462,6 +468,12 @@
 		<File
 			RelativePath=".\umlaut.c">
 		</File>
+		<File
+			RelativePath=".\unicode.c">
+		</File>
+		<File
+			RelativePath=".\unicode.h">
+		</File>
 		<File
 			RelativePath=".\vmap.c">
 		</File>
diff --git a/src/config.h b/src/config.h
index ecd3bd9b8..c2b542bdf 100644
--- a/src/config.h
+++ b/src/config.h
@@ -253,5 +253,7 @@ extern char * strdup(const char *s);
 # define INLINE_FUNCTION
 #endif
 
+#include <libxml/xmlstring.h>
+
 #endif
 
diff --git a/src/eressea.sln b/src/eressea.sln
index 9edd334e7..0d34374d9 100644
--- a/src/eressea.sln
+++ b/src/eressea.sln
@@ -81,12 +81,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gmtool", "eressea\gmtool.vc
 		{4C837BEC-A428-4287-84B3-8F8F9DE7FA00} = {4C837BEC-A428-4287-84B3-8F8F9DE7FA00}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcproj", "{9569C30D-742F-4F95-9C5D-BBF2B69C0727}"
+	ProjectSection(ProjectDependencies) = postProject
+		{1D80D05F-BCF5-4971-8F06-D9581FD3B1F4} = {1D80D05F-BCF5-4971-8F06-D9581FD3B1F4}
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfiguration) = preSolution
 		Debug = Debug
 		Profile = Profile
 		Release = Release
 	EndGlobalSection
+	GlobalSection(ProjectDependencies) = postSolution
+	EndGlobalSection
 	GlobalSection(ProjectConfiguration) = postSolution
 		{330712B5-8B27-4B17-B3CF-7A02CC0F93C3}.Debug.ActiveCfg = Debug|Win32
 		{330712B5-8B27-4B17-B3CF-7A02CC0F93C3}.Debug.Build.0 = Debug|Win32
@@ -160,6 +167,12 @@ Global
 		{57BA2AEE-5C65-4839-9294-C0FA2915A06C}.Profile.Build.0 = Profile|Win32
 		{57BA2AEE-5C65-4839-9294-C0FA2915A06C}.Release.ActiveCfg = Release|Win32
 		{57BA2AEE-5C65-4839-9294-C0FA2915A06C}.Release.Build.0 = Release|Win32
+		{9569C30D-742F-4F95-9C5D-BBF2B69C0727}.Debug.ActiveCfg = Debug|Win32
+		{9569C30D-742F-4F95-9C5D-BBF2B69C0727}.Debug.Build.0 = Debug|Win32
+		{9569C30D-742F-4F95-9C5D-BBF2B69C0727}.Profile.ActiveCfg = Release|Win32
+		{9569C30D-742F-4F95-9C5D-BBF2B69C0727}.Profile.Build.0 = Release|Win32
+		{9569C30D-742F-4F95-9C5D-BBF2B69C0727}.Release.ActiveCfg = Release|Win32
+		{9569C30D-742F-4F95-9C5D-BBF2B69C0727}.Release.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 	EndGlobalSection
diff --git a/src/eressea/korrektur.c b/src/eressea/korrektur.c
index 7d3048820..84966ea95 100644
--- a/src/eressea/korrektur.c
+++ b/src/eressea/korrektur.c
@@ -251,9 +251,7 @@ no_teurefremde(boolean convert)
           if (convert) {
             u->race = f->race;
             u->irace = f->race;
-            sprintf(buf, "Die G�tter segnen %s mit der richtigen Rasse",
-              unitname(u));
-            addmessage(0, u->faction, buf, MSG_MESSAGE, ML_IMPORTANT);
+            ADDMSG(&u->faction->msgs, msg_message("migrant_conversion", "unit", u));
           }
         }
       }
@@ -391,7 +389,7 @@ fix_icastles(void)
         a = a_add(&b->attribs, a_new(&at_icastle));
       }
       if (b->type!=bt_find("illusion")) {
-        /* geb�udetyp war falsch */
+        /* wrong building type */
         btype = b->type;
         b->type = bt_find("illusion");
       }
@@ -405,7 +403,7 @@ fix_icastles(void)
         data->type = btype;
       }
       if (data->building!=b) {
-        /* r�ckw�rtszeiger auf das geb�ude reparieren */
+        /* fix reverse pointer to the building */
         data->building=b;
       }
     }
@@ -715,28 +713,6 @@ fix_astralplane(void)
   return 0;
 }
 
-static int
-warn_password(void)
-{
-  faction * f = factions;
-  while (f) {
-    boolean pwok = true;
-    const char * c = f->passw;
-    while (*c) {
-      if (!isalnum((unsigned char)*c)) pwok = false;
-      c++;
-    }
-    if (pwok == false) {
-      ADDMSG(&f->msgs, msg_message("msg_errors", "string",
-        "Dein Passwort enth�lt Zeichen, die bei der Nachsendung "
-        "von Reports Probleme bereiten k�nnen. Bitte w�hle ein neues "
-        "Passwort, bevorzugt nur aus Buchstaben und Zahlen bestehend."));
-    }
-    f = f->next;
-  }
-  return 0;
-}
-
 extern border *borders[];
 
 static void
@@ -973,7 +949,6 @@ korrektur(void)
   }
   fix_allies();
   /* fix_unitrefs(); */
-  warn_password();
   fix_road_borders();
   if (turn>1000) curse_emptiness(); /*** disabled ***/
   /* seems something fishy is going on, do this just
diff --git a/src/eressea/lua/faction.cpp b/src/eressea/lua/faction.cpp
index 38aac4c33..b9ed5382b 100644
--- a/src/eressea/lua/faction.cpp
+++ b/src/eressea/lua/faction.cpp
@@ -175,8 +175,8 @@ faction_additem(faction& f, const char * iname, int number)
 static void
 faction_addnotice(faction& f, const char * str)
 {
-  str = LOC(f.locale, str);
-  ADDMSG(&f.msgs, msg_message("msg_event", "string", str));
+  const xmlChar * loc = LOC(f.locale, str);
+  ADDMSG(&f.msgs, msg_message("msg_event", "string", loc));
 }
 
 static const char *
diff --git a/src/eressea/main.c b/src/eressea/main.c
index 86204c8e6..51eb94d51 100644
--- a/src/eressea/main.c
+++ b/src/eressea/main.c
@@ -253,7 +253,7 @@ processturn(char *filename)
 #endif
 	begin = make_summary();
 	turn++;
-	if ((i=readorders(filename))!=0) return i;
+	if ((i=readorders(filename, "ISO-8859-1"))!=0) return i;
   if (!nomonsters) {
     if (turn == 0) rng_init((int)time(0));
     else rng_init(turn);
diff --git a/src/res/de/strings.xml b/src/res/de/strings.xml
index 24d298a9e..ea7e5834e 100644
--- a/src/res/de/strings.xml
+++ b/src/res/de/strings.xml
@@ -6823,4 +6823,136 @@
     <text locale="de"> und </text>
     <text locale="en"> and </text>
   </string>
+
+  <string name="villagers">
+    <text locale="de">Dorfbewohner</text>
+    <text locale="en">Villagers</text>
+  </string>
+
+  <string name="angry_mob">
+    <text locale="de">Bauernmob</text>
+    <text locale="en">Angry mob</text>
+  </string>
+
+  <string name="furious_mob">
+    <text locale="de">Aufgebrachte Bauern</text>
+    <text locale="en">Furious peasants</text>
+  </string>
+
+  <string name="random_plain_men">
+    <text locale="de">S�ldner</text>
+    <text locale="en">Mercenaries</text>
+  </string>
+
+  <string name="random_swamp_men">
+    <text locale="de">Sumpfbewohner</text>
+    <text locale="en">Swamp people</text>
+  </string>
+
+  <string name="random_forest_men">
+    <text locale="de">Waldbewohner</text>
+    <text locale="en">Woodsmen</text>
+  </string>
+
+  <string name="random_desert_men">
+    <text locale="de">Nomaden</text>
+    <text locale="en">Nomads</text>
+  </string>
+
+  <string name="random_glacier_men">
+    <text locale="de">Eisleute</text>
+    <text locale="en">Ice people</text>
+  </string>
+
+  <string name="random_mountain_men">
+    <text locale="de">Bergbewohner</text>
+    <text locale="en">Mountain people</text>
+  </string>
+
+  <string name="manual_title_magic">
+    <text locale="de">Magie der Elemente</text>
+    <text locale="en">Magic of the Elements</text>
+  </string>
+
+  <string name="manual_title_weaponsmithing">
+    <text locale="de">Schwerter, Armbr�ste, Langb�gen</text>
+    <text locale="en">Swords, Crossbows and Longbows</text>
+  </string>
+
+  <string name="manual_title_tactics">
+    <text locale="de">Gorms Almanach der Rationellen Kriegsf�hrung</text>
+    <text locale="en">Gorm's Almanach of Rational War</text>
+  </string>
+
+  <string name="manual_title_shipcraft">
+    <text locale="de">Katamarane, Koggen, Karavellen</text>
+    <text locale="en">The dragonship, the caravell and the longboat</text>
+  </string>
+
+  <string name="manual_title_sailing">
+    <text locale="de">Wege der Sterne</text>
+    <text locale="en">Ways of the Start</text>
+  </string>
+
+  <string name="manual_title_herbalism">
+    <text locale="de">Nadishahs Kleine Gift- und Kr�uterkunde</text>
+    <text locale="en">Nadishah's collected lore on poisonous and beneficial herbs</text>
+  </string>
+
+  <string name="manual_title_alchemy">
+    <text locale="de">Mandricks Kompendium der Alchemie</text>
+    <text locale="en">Mandrick's alchemistic compendium</text>
+  </string>
+
+  <string name="manual_title_building">
+    <text locale="de">Die Konstruktion der Burgen und Schl�sser von Zentralandune</text>
+  </string>
+
+  <string name="manual_title_armorer">
+    <text locale="de">Die Esse</text>
+  </string>
+
+  <string name="manual_title_mining">
+    <text locale="de">�ber die Gewinnung von Erzen</text>
+  </string>
+
+  <string name="manual_title_entertainment">
+    <text locale="de">Barinions Lieder, eine Einf�hrung f�r Unbedarfte</text>
+  </string>
+
+  <string name="manual_location_0">
+    <text locale="de">die Ruine eines alten Tempels</text>
+    <text locale="en">the ruins of an ancient temple</text>
+  </string>
+
+  <string name="manual_location_1">
+    <text locale="de">eine alte Burgruine</text>
+    <text locale="en">the ruins of a castle</text>
+  </string>
+
+  <string name="manual_location_2">
+    <text locale="de">ein zerfallenes Bauernhaus</text>
+    <text locale="en">a dilapitated farm</text>
+  </string>
+
+  <string name="manual_location_3">
+    <text locale="de">eine Leiche am Wegesrand</text>
+    <text locale="en">a corpse by the wayside</text>
+  </string>
+
+  <string name="manual_location_3">
+    <text locale="de">eine Leiche am Wegesrand</text>
+    <text locale="en">a corpse by the wayside</text>
+  </string>
+
+  <string name="firedragon">
+    <text locale="de">Feuerdrache</text>
+    <text locale="en">fire dragon</text>
+  </string>
+
+  <string name="trigger_alp_destroy">
+    <text locale="de">Ein Alp starb, ohne sein Ziel zu erreichen.</text>
+    <text locale="en">An alp died before it reached its target.</text>
+  </string>
+
 </strings>
diff --git a/src/res/messages.xml b/src/res/messages.xml
index 721a57f1e..fd925f2d9 100644
--- a/src/res/messages.xml
+++ b/src/res/messages.xml
@@ -961,6 +961,16 @@
     <text locale="de">"In $region($region) erhielt $unit($unit) eine Botschaft von $unit.dative($sender): '$string'"</text>
     <text locale="en">"In $region($region), $unit($unit) received a message by $unit($sender): '$string'"</text>
   </message>
+  <message name="museumgiveback" section="mail">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="region" type="region"/>
+      <arg name="items" type="items"/>
+      <arg name="sender" type="unit"/>
+    </type>
+    <text locale="de">"In $region($region) erhielt $unit($unit) von $unit.dative($sender) $resources($items)"</text>
+    <text locale="en">"In $region($region), $unit($unit) received $resources($items) from $unit($sender)"</text>
+  </message>
   <message name="maintenance_nowork" section="events">
     <type>
       <arg name="building" type="building"/>
@@ -1036,6 +1046,86 @@
     </type>
     <text locale="de">"$unit($unit) schwenkt sein Szepter und sorgt f�r Verwirrung und Chaos in der Region."</text>
   </message>
+
+  <message name="find_manual" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="location" type="string"/>
+      <arg name="book" type="string"/>
+    </type>
+    <text locale="de">"$unit($unit) stolpert bei der Erforschung der Region �ber $localize($location). N�here Durchsuchung f�rdert ein zerfleddertes altes Buch mit dem Titel '$localize($book)' zu Tage. Der Wissensschub ist enorm."</text>
+  </message>
+
+  <message name="alp_success" section="events">
+    <text locale="de">"Ein Alp hat sein Opfer gefunden und springt auf den R�cken von $unit($target)!"</text>
+  </message>
+
+  <message name="summon_alp_effect" section="events">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="alp" type="unit"/>
+      <arg name="target" type="unit"/>
+    </type>
+    <text locale="de">"$unit($mage) beschw�rt den Alp $unit($alp) f�r $unit($target)."</text>
+    <text locale="en">"$unit($mage) summons the alp $unit($alp) for $unit($target)."</text>
+  </message>
+
+  <message name="healing_effect_0" section="events">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="amount" type="int"/>
+    </type>
+    <text locale="de">"$unit($mage) k�mmert sich um die Verletzten und heilt $int($amount) Verwundete."</text>
+  </message>
+
+  <message name="healing_effect_1" section="events">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="amount" type="int"/>
+      <arg name="item" type="resource"/>
+    </type>
+    <text locale="de">"$unit($mage) k�mmert sich um die Verletzten und benutzt ein $resource($item,1), um den Zauber zu verst�rken. $int($amount) Verwundete werden geheilt."</text>
+  </message>
+
+  <message name="reanimate_effect_0" section="events">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="amount" type="int"/>
+    </type>
+    <text locale="de">"$unit($mage) beginnt ein Ritual der Wiederbelebung. $int($amount) Krieger stehen von den Toten auf."</text>
+  </message>
+
+  <message name="reanimate_effect_1" section="events">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="amount" type="int"/>
+      <arg name="item" type="resource"/>
+    </type>
+    <text locale="de">"$unit($mage) beginnt ein Ritual der Wiederbelebung und benutzt ein $resource($item,1), um den Zauber zu verst�rken. $int($amount) Krieger stehen von den Toten auf."</text>
+  </message>
+
+  <message name="chaosgate_effect_1" section="events">
+    <type>
+      <arg name="mage" type="unit"/>
+    </type>
+    <text locale="de">"$unit($mage) �ffnet ein Chaostor."</text>
+    <text locale="en">"$unit($mage) opens a chaos gate."</text>
+  </message>
+
+  <message name="chaosgate_effect_2" section="events">
+    <text locale="de">Ein Wirbel aus blendendem Licht erscheint."</text>
+    <text locale="en">"A vortex of blinding light appears."</text>
+  </message>
+
+  <message name="summonundead_effect_1" section="events">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="amount" type="int"/>
+    </type>
+    <text locale="de">"$unit($mage) erweckt $int($amount) Untote aus ihren Gr�bern."</text>
+    <text locale="en">"$unit($mage) calls $int($amount) undead from their graves."</text>
+  </message>
+
   <message name="viewreality_effect" section="events">
     <type>
       <arg name="unit" type="unit"/>
@@ -1043,6 +1133,7 @@
     <text locale="de">"$unit($unit) gelingt es, durch die Nebel auf die Realit�t zu blicken."</text>
     <text locale="en">"$unit($unit) manages to catch a glimpse of reality through the fog."</text>
   </message>
+
   <message name="recruit_effect" section="events">
     <type>
       <arg name="mage" type="unit"/>
@@ -1398,15 +1489,7 @@
     <text locale="de">"$unit($unit) in $region($region) wird von einem Unbekannten verflucht."</text>
     <text locale="en">"$unit($unit) in $region($region) was cursed by an unknown magician."</text>
   </message>
-  <message name="drought_effect" section="magic">
-    <type>
-      <arg name="mage" type="unit"/>
-      <arg name="region" type="region"/>
-      <arg name="extended" type="string"/>
-    </type>
-    <text locale="de">"$unit($mage) ruft das Feuer der Sonne auf $region($region) herab."</text>
-    <text locale="en">"$unit($mage) calls the fires of the sun upon $region($region)."</text>
-  </message>
+
   <message name="sparkle_effect" section="magic">
     <type>
       <arg name="mage" type="unit"/>
@@ -1759,7 +1842,7 @@
     <text locale="fr">"$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located."</text>
     <text locale="en">"$unit($unit) in $region($region): '$order($command)' - Building $int36($id) could not be located."</text>
   </message>
-  <message name="spellunitnotfound" section="magic">
+  <message name="unitnotfound_id" section="errors">
     <type>
       <arg name="unit" type="unit"/>
       <arg name="region" type="region"/>
@@ -1945,7 +2028,7 @@
     <text locale="de">"$unit($unit) in $region($region): '$order($command)' - $unit($unit) gelingt es zwar die Region zu verzaubern, aber irgendwas ging schief."</text>
     <text locale="en">"$unit($unit) in $region($region): '$order($command)' - $unit($unit) manages to put a spell on the region, but something went wrong nonetheless."</text>
   </message>
-  <message name="summonundead_effect" section="magic">
+  <message name="summonundead_effect_2" section="magic">
     <type>
       <arg name="unit" type="unit"/>
     </type>
@@ -2328,11 +2411,11 @@
       <arg name="mode" type="int"/>
       <arg name="start" type="region"/>
       <arg name="end" type="region"/>
-      <arg name="regions" type="string"/>
+      <arg name="regions" type="regions"/>
     </type>
-    <text locale="de">"$unit($unit) $if($eq($mode,1),"reitet", "wandert") von $region($start) nach $region($end).$if($strlen($regions)," Dabei wurde $regions durchquert.","")"</text>
-    <text locale="fr">"$unit($unit) $if($eq($mode,1),"chevauche", "marche") de $region($start) vers $region($end) trans $regions"</text>
-    <text locale="en">"$unit($unit) $if($eq($mode,1),"rides", "walks") from $region($start) to $region($end)$if($strlen($regions)," by way of $regions","")."</text>
+    <text locale="de">"$unit($unit) $if($eq($mode,1),"reitet", "wandert") von $region($start) nach $region($end).$if($isnull($regions),""," Dabei wurde $regions($regions,1,-2) durchquert.")"</text>
+    <text locale="fr">"$unit($unit) $if($eq($mode,1),"chevauche", "marche") de $region($start) vers $region($end) trans $regions($regions,1,-2)"</text>
+    <text locale="en">"$unit($unit) $if($eq($mode,1),"rides", "walks") from $region($start) to $region($end)$if($isnull($regions),""," by way of $regions($regions,1,-2)")."</text>
   </message>
   <message name="detectoceandir" section="movement">
     <type>
@@ -3863,6 +3946,16 @@
     <text locale="de">"$unit($unit) in $region($region): '$order($command)' - Die Einheit mu� sich an Land befinden."</text>
     <text locale="en">"$unit($unit) in $region($region): '$order($command)' - The unit must be on land."</text>
   </message>
+  <message name="error_nograves" section="errors">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="region" type="region"/>
+      <arg name="command" type="order"/>
+      <arg name="target" type="region"/>
+    </type>
+    <text locale="de">"$unit($unit) in $region($region): '$order($command)' - In $region($target) sind keine Gr�ber."</text>
+    <text locale="en">"$unit($unit) in $region($region): '$order($command)' - There are no graves in $region($target)."</text>
+  </message>
   <message name="error241" section="errors">
     <type>
       <arg name="unit" type="unit"/>
@@ -6468,9 +6561,18 @@
       <arg name="target" type="unit"/>
     </type>
     <text locale="de">"$unit($unit) �bergibt $int($amount) Person$if($eq($amount,1),"","en") an $unit($target)."</text>
-    <text locale="fr">"$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to $unit($target)."</text>
     <text locale="en">"$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to $unit($target)."</text>
   </message>
+
+  <message name="give_person_peasants" section="economy">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="amount" type="int"/>
+    </type>
+    <text locale="de">"$unit($unit) �bergibt $int($amount) Person$if($eq($amount,1),"","en") an die Bauern."</text>
+    <text locale="en">"$unit($unit) transfers $int($amount) person$if($eq($amount,1),"","s") to the local peasants."</text>
+  </message>
+
   <message name="give" section="economy">
     <type>
       <arg name="unit" type="unit"/>
@@ -6478,9 +6580,14 @@
       <arg name="resource" type="resource"/>
       <arg name="target" type="unit"/>
     </type>
-    <text locale="de">"$unit($unit) �bergibt $int($amount) $resource($resource,$amount) an $unit($target)."</text>
-    <text locale="fr">"$unit($unit) gives $int($amount) $resource($resource,$amount) to $unit($target)."</text>
-    <text locale="en">"$unit($unit) gives $int($amount) $resource($resource,$amount) to $unit($target)."</text>
+  <message name="give_peasants" section="economy">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="amount" type="int"/>
+      <arg name="resource" type="resource"/>
+    </type>
+    <text locale="de">"$unit($unit) �bergibt $int($amount) $resource($resource,$amount) an die Bauern."</text>
+    <text locale="en">"$unit($unit) gives $int($amount) $resource($resource,$amount) to the local peasants."</text>
   </message>
   <message name="maintenance" section="economy">
     <type>
@@ -6627,6 +6734,29 @@
     <text locale="en">"$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region."</text>
     <text locale="fr">"$unit($unit) in $region($region): '$order($command)' - Pyramids may be build in this region."</text>
   </message>
+  
+  <message name="error_spell_on_ship_already" section="errors">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="region" type="region"/>
+      <arg name="command" type="order"/>
+      <arg name="ship" type="ship"/>
+    </type>
+    <text locale="de">"$unit($unit) in $region($region): '$order($command)' - Auf $ship($ship) liegt beeits ein Zauber."</text>
+    <text locale="en">"$unit($unit) in $region($region): '$order($command)' - There is already a spell on $ship($ship)."</text>
+  </message>
+  
+  <message name="error_spell_on_flying_ship" section="errors">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="region" type="region"/>
+      <arg name="command" type="order"/>
+      <arg name="ship" type="ship"/>
+    </type>
+    <text locale="de">"$unit($unit) in $region($region): '$order($command)' - Es ist zu gef�hrlich, diesen Zauber auf das fliegende Schiff $ship($ship) zu legen."</text>
+    <text locale="en">"$unit($unit) in $region($region): '$order($command)' - It is far too dangerous to put this spell on the flying ship $ship($ship)."</text>
+  </message>
+  
   <message name="wdw_pyramidspell_notfound" section="events">
     <type>
       <arg name="unit" type="unit"/>
@@ -6639,6 +6769,7 @@
     <text locale="en">"$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away."</text>
     <text locale="fr">"$unit($unit) in $region($region): '$order($command)' - No pyramids may be build in this region. The closest region to build a pyramid in is between $int($mindist) and $int($maxdist) regions away."</text>
   </message>
+
   <message name="wormhole_requirements" section="events">
     <type>
       <arg name="unit" type="unit"/>
@@ -6759,10 +6890,108 @@
     <text locale="de">"$unit($mage) zaubert $spell($spell): $int($dead) $if($eq($dead,1),"Krieger wurde", "Krieger wurden") get�tet."</text>
     <text locale="en">"$unit($mage) casts $spell($spell): $int($dead) $if($eq($dead,1),"enemy was", "enemies were") killed."</text>
   </message>
+
+  <message name="earthquake_effect" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="region" type="region"/>
+    </type>
+    <text locale="de">"$unit($mage) l��t die Erde in $region($region) erzittern."</text>
+    <text locale="en">"$unit($mage) shakes the earth in $region($region)."</text>
+  </message>
+  
+  <message name="drought_effect" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+    </type>
+    <text locale="de">"$unit($mage) verflucht das Land, und eine D�rreperiode beginnt."</text>
+    <text locale="en">"$unit($mage) puts a curse on the land and a drought sets in."</text>
+  </message>
+  
+  <message name="summon_effect" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="amount" type="int"/>
+      <arg name="race" type="race"/>
+    </type>
+    <text locale="de">"$unit($mage) beschw�rt $int($amount) $race($race,$amount)."</text>
+    <text locale="en">"$unit($mage) summons  $int($amount) $race($race,$amount)."</text>
+  </message>
+  
+  <message name="forestfire_effect" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="region" type="region"/>
+      <arg name="amount" type="int"/>
+    </type>
+    <text locale="de">"$unit($mage) erschafft in $region($region) eine verheerende Feuersbrunst. $int($amount) B�ume fallen den Flammen zum Opfer."</text>
+    <text locale="de">"$unit($mage) creates a flaming inferno in $region($region). $int($amount) trees fall vistim to the flames."</text>
+</text>
+  </message>
+  
+  <message name="recruit_effect" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="amount" type="int"/>
+    </type>
+    <text locale="de">"$unit($mage) konnte $int($amount) Bauern anwerben."</text>
+    <text locale="en">"$unit($mage) recruited $int($amount) peasants."</text>
+  </message>
+
+  <message name="homestone_effect" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="building" type="building"/>
+    </type>
+    <text locale="de">"Mit einem Ritual bindet $unit($unit) die magischen Kr�fte der Erde in die Mauern von $building($building)."</text>
+  </message>
+
+  <message name="blessedstonecircle_effect" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="building" type="building"/>
+    </type>
+    <text locale="de">"$unit($mage) weight $building($building)."</text>
+    <text locale="en">"$unit($mage) blesses $building($building)."</text>
+  </message>
+
+  <message name="drought_effect_1" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="region" type="region"/>
+    </type>
+    <text locale="de">"$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Eis schmilzt und verwandelt sich in Morast. Rei�ende Str�me sp�len die mageren Felder weg und ers�ufen Mensch und Tier. Was an Bauten nicht den Fluten zum Opfer fiel, verschlingt der Morast. Die sengende Hitze ver�ndert die Region f�r immer."</text>
+  </message>
+
+  <message name="drought_effect_2" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="region" type="region"/>
+    </type>
+    <text locale="de">"$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete B�ume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt."</text>
+  </message>
+
+  <message name="drought_effect_3" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="region" type="region"/>
+    </type>
+    <text locale="de">"$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Die Felder verdorren und Pferde verdursten. Die Hungersnot kostet vielen Bauern das Leben. Vertrocknete B�ume recken ihre kahlen Zweige in den blauen Himmel, von dem erbarmungslos die sengende Sonne brennt. Die D�rre ver�ndert die Region f�r immer."</text>
+  </message>
+
+  <message name="drought_effect_4" section="magic">
+    <type>
+      <arg name="mage" type="unit"/>
+      <arg name="region" type="region"/>
+    </type>
+    <text locale="de">"$unit($mage) ruft das Feuer der Sonne auf $region($region) hinab. Das Eis zerbricht und eine gewaltige Flutwelle verschlingt die Region."</text>
+  </message>
+
   <message name="generous_effect_1" section="magic">
     <text locale="de">"Die Darbietungen eines fahrenden Gauklers begeistern die Leute. Die fr�hliche und ausgelassene Stimmung seiner Lieder �bertr�gt sich auf alle Zuh�rer."</text>
     <text locale="en">"A touring minstrel entertains the locals. The joyous and generous disposition of his songs prove infectious."</text>
   </message>
+
   <message name="generous_effect_0" section="magic">
     <type>
       <arg name="mage" type="unit"/>
@@ -7264,6 +7493,35 @@
     <text locale="en">"A message from $unit($unit): '$message'"</text>
   </message>
 
+  <message name="encounter_allies" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="name" type="string"/>
+    </type>
+    <text locale="de">"Pl�tzlich stolpert $unit($unit) �ber einige $localize($name). Nach kurzem Z�gern entschlie�en die $localize($name), sich Deiner Partei anzuschlie�en."</text>
+  </message>
+
+  <message name="encounter_villagers" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+    </type>
+    <text locale="de">"$unit($unit) entdeckt ein kleines Dorf. Die meisten H�user wurden durch einen �ber die Ufer getretenen Flu� zerst�rt. Eine Gruppe der verzweifelten Menschen schlie�t sich deiner Partei an."</text>
+    <text locale="en">"$unit($unit) discovers a small village. Most of the houses have been destroyed by flooding, and a group of the distressed villagers join your faction."</text>
+  </message>
+
+  <message name="mob_warning" section="events">
+    <text locale="de">"Ein Bauernmob erhebt sich und macht Jagd auf Schwarzmagier."</text>
+    <text locale="en">"An angry mob forms and hunts practitioners of the dark arts."</text>
+  </message>
+
+  <message name="familiar_name" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+    </type>
+    <text locale="de">"Vertrauter von $unit($unit)"</text>
+    <text locale="en">"Familiar of $unit($unit)"</text>
+  </message>
+
   <message name="recruit_archetype" section="events">
     <type>
       <arg name="unit" type="unit"/>
@@ -7274,4 +7532,71 @@
     <text locale="en">"$unit($unit) recruits $int($amount) $localize($archetype)."</text>
   </message>
 
+  <message name="illegal_password" section="events">
+    <type>
+      <arg name="newpass" type="string"/>
+    </type>
+    <text locale="de">"Dein Passwort enth�lt Zeichen, die bei der Nachsendung von Reports Probleme bereiten k�nnen. Bitte beachte, dass Passwortenur aus Buchstaben von A bis Z und Zahlen bestehen d�rfen. Dein neues Passwort ist '${newpass}'."</text>
+    <text locale="en">"Your password was changed because it contained illegal characters. Legal passwords may only contain numbers and letters from A to Z. Your new Password is '${newpass}'."</text>
+  </message>
+
+  <message name="meow" section="events">
+    <text locale="de">"Miiauuuuuu..."</text>
+    <text locale="en">"Meeoooooow..."</text>
+  </message>
+
+  <message name="migrant_conversion" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+    </type>
+    <text locale="de">"Die G�tter segnen $unit($unit) mit der richtigen Rasse."</text>
+    <text locale="en">"The gods are blessing $unit($unit) with the correct race."</text>
+  </message>
+
+  <message name="arena_leave_fail" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+    </type>
+    <text locale="de">"Der Versuch, die Greifenschwingen zu benutzen, schlug fehl. $unit($unit) konnte die Ebene der Herausforderung nicht verlassen."</text>
+  </message>
+
+  <message name="caldera_handle_0" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+    </type>
+    <text locale="de">"$unit($unit) springt in die ewigen Feuer des Kraters."</text>
+  </message>
+
+  <message name="caldera_handle_1" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+      <arg name="items" type="items"/>
+    </type>
+    <text locale="de">"$unit($unit) springt in die ewigen Feuer des Kraters."</text>
+  </message>
+
+  <message name="arena_enter_fail" section="events">
+    <type>
+      <arg name="region" type="region"/>
+      <arg name="unit" type="unit"/>
+    </type>
+    <text locale="de">"In $region($region) erklingt die Stimme des Torw�chters: 'Nur wer ohne materielle G�ter und noch lernbegierig ist, der darf die Ebene der Herausforderung betreten. Und vergi� nicht mein Trinkgeld.'. $unit($unit) erhielt keinen Einla�."</text>
+  </message>
+
+  <message name="arena_enter" section="events">
+    <type>
+      <arg name="region" type="region"/>
+      <arg name="unit" type="unit"/>
+    </type>
+    <text locale="de">"In $region($region) �ffnet sich ein Portal. Eine Stimme ert�nt, und spricht: 'Willkommen in der Ebene der Herausforderung'. $unit($unit) durchschreitet das Tor zu einer anderen Welt."</text>
+  </message>
+
+  <message name="chaos_disease" section="events">
+    <type>
+      <arg name="unit" type="unit"/>
+    </type>
+    <text locale="de">"$unit($unit) scheint von einer seltsamen Krankheit befallen."</text>
+    <text locale="en">"$unit($unit) is stricken by a strange disease."</text>
+  </message>
+
 </messages>
diff --git a/src/res/races.xml b/src/res/races.xml
index 33078c19e..4fd8d6745 100644
--- a/src/res/races.xml
+++ b/src/res/races.xml
@@ -314,6 +314,7 @@
   </race>
   <race name="wolf" magres="0.000000" maxaura="0.000000" regaura="0.000000" recruitcost="50" weight="500" capacity="540" speed="1.000000" hp="25" damage="2d6" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="3" scarepeasants="yes" walk="yes" teach="no" giveitem="yes" getitem="yes">
     <ai splitsize="5000"/>
+    <function name="name" value="namegeneric"/>
     <function name="initfamiliar" value="oldfamiliars"/>
     <skill name="alchemy" modifier="-99"/>
     <skill name="crossbow" modifier="-99"/>
@@ -572,7 +573,7 @@
   </race>
   <race name="braineater" magres="0.900000" maxaura="1.000000" regaura="1.000000" recruitcost="50000" weight="100" capacity="540" speed="1.000000" hp="20" ac="1" damage="0d0" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="10" scarepeasants="yes" fly="yes" walk="yes" teach="no" invinciblenonmagic="yes">
     <ai splitsize="500" killpeasants="yes" moverandom="yes" learn="yes"/>
-    <function name="describe" value="describe_braineater"/>
+    <function name="name" value="namegeneric"/>
     <attack type="2" damage="3d15"/>
     <attack type="3" damage="1d1"/>
     <attack type="4" damage="1d1"/>
@@ -643,15 +644,17 @@
   </race>
   <race name="alp" magres="0.950000" maxaura="1.000000" regaura="1.000000" recruitcost="50000" weight="0" capacity="0" speed="1.500000" hp="20" ac="2" damage="1d4" unarmedattack="0" unarmeddefense="0" attackmodifier="2" defensemodifier="20" fly="yes" walk="yes" canlearn="no" canteach="no">
     <ai splitsize="1"/>
+    <function name="name" value="namegeneric"/>
     <attack type="1" damage="1d4"/>
   </race>
   <race name="mountainguard" unarmedguard="yes" magres="0.500000" maxaura="1.000000" regaura="0.500000" recruitcost="50000" weight="10000" capacity="2000" speed="0.000000" hp="1000" ac="12" damage="2d40" unarmedattack="0" unarmeddefense="0" attackmodifier="6" defensemodifier="8" cannotmove="yes" canlearn="no" teach="no" noweapons="yes" giveitem="yes">
     <ai splitsize="1"/>
+    <function name="name" value="namegeneric"/>
     <attack type="4" damage="2d40"/>
   </race>
   <race name="shadowmaster" cansail="no" cansteal="no" canlearn="no" magres="0.750000" maxaura="1.000000" regaura="2.000000" recruitcost="50000" weight="500" capacity="540" speed="1.000000" hp="150" ac="4" damage="2d5" unarmedattack="0" unarmeddefense="0" attackmodifier="11" defensemodifier="13" scarepeasants="yes" walk="yes" teach="no" desert="yes" nogive="yes">
     <ai splitsize="50" killpeasants="yes" moverandom="yes" learn="yes"/>
-    <function name="name" value="nameshadow"/>
+    <function name="name" value="namegeneric"/>
     <attack type="4" damage="2d4"/>
     <attack type="2" damage="2d30"/>
     <attack type="3" damage="1d2"/>
@@ -670,6 +673,7 @@
   </race>
   <race name="irongolem" magres="0.250000" maxaura="1.000000" regaura="0.100000" recruitcost="5000" weight="10000" capacity="2000" speed="1.000000" hp="50" ac="2" damage="2d10+4" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="2" walk="yes" canlearn="no" teach="no" giveitem="yes">
     <ai splitsize="50"/>
+    <function name="name" value="namegeneric"/>
     <skill name="armorer" modifier="14"/>
     <skill name="weaponsmithing" modifier="14"/>
     <attack type="4" damage="2d8+4"/>
@@ -698,6 +702,7 @@
   </race>
   <race name="ent" magres="0.250000" maxaura="1.000000" regaura="0.500000" recruitcost="5000" weight="5000" capacity="2500" speed="1.000000" hp="50" ac="4" damage="2d4+12" unarmedattack="0" unarmeddefense="0" attackmodifier="9" defensemodifier="7" scarepeasants="yes" walk="yes" teach="no">
     <ai splitsize="1000" moverandom="yes" learn="yes"/>
+    <function name="name" value="namegeneric"/>
     <attack type="4" damage="2d12"/>
     <attack type="4" damage="2d12"/>
   </race>
@@ -1150,6 +1155,7 @@
   </race>
   <race name="shadowknight" magres="0.000000" maxaura="0.000000" regaura="0.000000" recruitcost="5" weight="1000" capacity="540" speed="1.000000" hp="1" damage="1d1" unarmedattack="0" unarmeddefense="0" attackmodifier="1" defensemodifier="1" scarepeasants="yes" nogive="yes" walk="yes" canlearn="no" teach="no" noblock="yes">
     <ai splitsize="20000" moverandom="yes"/>
+    <function name="name" value="namegeneric"/>
     <attack type="1" damage="1d1"/>
   </race>
   <race name="seaserpent" magres="0.500000" maxaura="1.000000" regaura="1.000000" recruitcost="5000" weight="20000" capacity="5000" speed="1.000000" hp="600" ac="3" damage="2d15" unarmedattack="0" unarmeddefense="0" attackmodifier="4" defensemodifier="4" scarepeasants="yes" swim="yes" teach="no" getitem="yes" resistbash="yes">
@@ -1328,11 +1334,13 @@
   </race>
   <race name="shadowbat" magres="0.800000" maxaura="0.000000" regaura="0.000000" recruitcost="500" weight="500" capacity="540" speed="1.000000" hp="1" ac="4" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes">
     <ai splitsize="5000" killpeasants="yes"/>
+    <function name="name" value="namegeneric"/>
     <attack type="4" damage="1d6"/>
     <attack type="3" damage="1d1"/>
   </race>
   <race name="nightmare" magres="0.500000" maxaura="0.000000" regaura="0.000000" recruitcost="500" weight="100" capacity="540" speed="1.000000" hp="80" ac="10" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" fly="yes" walk="yes" teach="no" getitem="yes" invinciblenonmagic="yes">
     <ai splitsize="500" killpeasants="yes"/>
+    <function name="name" value="namegeneric"/>
     <attack type="4" damage="1d4"/>
     <attack type="4" damage="1d4"/>
     <attack type="4" damage="1d4"/>
@@ -1341,6 +1349,7 @@
   </race>
   <race name="vampunicorn" magres="1.000000" maxaura="0.000000" regaura="0.000000" recruitcost="500" weight="5000" capacity="2000" speed="1.000000" hp="30" ac="4" damage="2d4" unarmedattack="0" unarmeddefense="0" attackmodifier="3" defensemodifier="3" scarepeasants="yes" walk="yes" teach="no" getitem="yes">
     <ai splitsize="5000" killpeasants="yes"/>
+    <function name="name" value="namegeneric"/>
     <attack type="4" damage="2d10"/>
     <attack type="3" damage="1d4"/>
     <attack type="3" damage="1d4"/>