Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/d/seher/haeuser/tools/generator.c b/d/seher/haeuser/tools/generator.c
new file mode 100644
index 0000000..3254c2b
--- /dev/null
+++ b/d/seher/haeuser/tools/generator.c
@@ -0,0 +1,740 @@
+#include "../haus.h"
+
+inherit "/p/service/wargon/sm/statemachine";
+
+#include "/p/service/wargon/sm/statemachine.h"
+#include <properties.h>
+
+#define STATE_IDLE           0
+#define STATE_HOUSE          1
+#define STATE_ROOM           2
+#define STATE_CHEST          3
+#define STATE_DETAIL         4
+#define STATE_RDETAIL        5
+#define STATE_COMMAND        6
+#define STATE_FINALIZE       7
+#define STATE_EXITS          8
+
+#define SIG_INITIALIZE       0
+#define SIG_HOUSE            1
+#define SIG_HOUSE_DONE       2
+#define SIG_ROOM             3
+#define SIG_DO_CHEST         4
+#define SIG_DO_DETAIL        5
+#define SIG_DETAIL_DONE      6
+#define SIG_RDETAIL_DONE     7
+#define SIG_COMMAND_DONE     8
+#define SIG_DO_EXITS         9
+#define SIG_ROOM_DONE       10
+
+private nosave string file;
+private nosave int    final;
+private nosave object raum;
+private nosave int    nr;
+private nosave object hausmeister;
+private nosave mixed  hmargs;
+
+string dump(object env, int final, mixed args);
+
+private string special(string str);
+private void removeOutputFile();
+private void dumpHouse();
+private void dumpRoomHeader();
+private void dumpChest();
+private void dumpDetails();
+private void dumpReadDetails();
+private void dumpCommands();
+private void doFinalize();
+private void dumpExits();
+private void dumpRoomTrailer();
+private void doReturn();
+private void sProp(string file, string pName, string pStr);
+static void mProp(string file, string pName, mixed map_ldfied, int pos, int signal);
+static void cProp(string file, string pName, mixed cmd, int pos, int signal);
+private void prettyString(string file, string *str, int indent);
+private void prettyArray(string file, string *arr, int sep);
+private void headerRoom();
+private void trailerRoom();
+private void headerHouse();
+private void trailerHouse();
+
+create()
+{
+  ::create();
+  seteuid(getuid());
+  
+  AddState(STATE_IDLE, 0, 0);
+  AddState(STATE_HOUSE,    #'dumpHouse, 0);
+  AddState(STATE_ROOM,     #'dumpRoomHeader, 0);
+  AddState(STATE_CHEST,    #'dumpChest, 0);
+  AddState(STATE_DETAIL,   #'dumpDetails, 0);
+  AddState(STATE_RDETAIL,  #'dumpReadDetails, 0);
+  AddState(STATE_COMMAND,  #'dumpCommands, 0);
+  AddState(STATE_FINALIZE, #'doFinalize, 0);
+  AddState(STATE_EXITS,    #'dumpExits, 0);
+
+  AddTransition(SM_INVALID, SIG_INITIALIZE, STATE_IDLE, 0);
+
+  // Zustandsuebergaenge zum Schreiben des Hauses
+  AddTransition(STATE_IDLE, SIG_HOUSE, STATE_HOUSE, #'removeOutputFile);
+  AddTransition(STATE_HOUSE, SIG_HOUSE_DONE, STATE_IDLE, #'doReturn);
+
+  // Zustandsuebergaenge zum Schreiben eines Raums
+  AddTransition(STATE_IDLE,     SIG_ROOM,      STATE_ROOM, #'removeOutputFile);
+  AddTransition(STATE_ROOM,     SIG_DO_CHEST,  STATE_CHEST);
+  AddTransition(STATE_ROOM,     SIG_DO_DETAIL, STATE_DETAIL);
+  AddTransition(STATE_CHEST,    SIG_DO_DETAIL, STATE_DETAIL);
+  AddTransition(STATE_DETAIL,   SIG_DETAIL_DONE,  STATE_RDETAIL);
+  AddTransition(STATE_RDETAIL,  SIG_RDETAIL_DONE, STATE_COMMAND);
+  AddTransition(STATE_COMMAND,  SIG_COMMAND_DONE, STATE_FINALIZE);
+  AddTransition(STATE_FINALIZE, SIG_DO_EXITS,  STATE_EXITS);
+  AddTransition(STATE_FINALIZE, SIG_ROOM_DONE, STATE_IDLE, #'doReturn);
+  AddTransition(STATE_EXITS,    SIG_ROOM_DONE, STATE_IDLE, #'dumpRoomTrailer);
+  
+  StateTransition(SIG_INITIALIZE);
+}
+
+
+// Erzeuge normalen LPC-Quellcode aus einem Haus oder Raum.
+//
+// Parameter:
+//   env: Das Haus oder der Raum, aus dem Quellcode erzeugt werden soll
+//   fin: Falls gleich 0, so wird Quellcode fuer Typofixes o.ae.
+//        erzeugt; das erzeugte File heisst immer 'fixed.c'.
+//        Andernfalls wird Quellcode fuer ein eigenstaendiges Objekt
+//        erzeugt. Dieses kann z.B. zum Anschluss als "Magierhaus"
+//        verwendet werden. Die erzeugten Files heissen
+//        'rep/<name>raum<nr>.c' bzw. 'rep/<name>haus.c'. Befindet sich
+//        in dem Raum die Truhe, wird zusaetzlich die Datei
+//        'rep/<name>truhe.c' geschrieben.
+//
+// Rueckgabewert:
+//   Der Dateiname, in den die Daten geschrieben wurden.
+
+string
+dump(object env, int fin, mixed args)
+{
+  string out;
+  int num;
+
+  hausmeister = previous_object();
+  hmargs = args;
+  
+  if (QueryState() != STATE_IDLE)
+  {
+    write("Der Generator arbeitet noch...\nBitte warten!\n");
+    return "<keine Datei generiert>\n";
+  }
+  
+  // Falls ein Raum generiert wird, erhaelt <nr> die Raumnummer.
+  // Bei der Aussenansicht des Hauses wird <nr> auf -1 gesetzt.
+  if (sscanf(object_name(env), "%sraum%d", out, num) < 2)
+  {
+    num = -1;
+  }
+  
+  if (fin)
+  {
+    out = PATH+"rep/"+env->QueryOwner();
+
+    if (num >= 0)
+    {
+      out += "raum"+num+".c";
+    }
+    else
+    {
+      out += "haus.c";
+    }
+  }
+  else
+  {
+    out = PATH+"fixed.c";
+  }
+
+  // Informationen fuer die Statemachine setzen
+  file = out;
+  final = fin;
+  raum = env;
+  nr = num;
+
+  if (num >= 0)
+  {
+    StateTransition(SIG_ROOM);
+  }
+  else
+  {
+    StateTransition(SIG_HOUSE);
+  }
+  return out;
+}
+
+// Sonderzeichen \, " und TAB korrekt umwandeln
+private string special(string s)
+{
+  s = implode(explode(s, "\\"), "\\\\");
+  s = implode(explode(s, "\t"), "\\t");
+  s = implode(explode(s, "\""), "\\\"");
+
+  return s;
+}
+
+/*** Funktionen zum Generieren einer Datei aus den Properties des Hauses ***/
+
+#define EXIT_TMPL "\"/players/%s/seherhaus/%sraum%d\""
+
+private void
+removeOutputFile()
+{
+  catch(rm(file));
+}
+
+private void
+dumpHouse()
+{
+  headerHouse();
+  
+  sProp(file, "P_SHORT", raum->QueryProp(P_SHORT));
+  write_file(file, "\n");
+  sProp(file, "P_LONG", raum->QueryProp(P_LONG));
+  write_file(file, "\n");
+
+  if (final)
+  {
+    mixed n;
+
+    write_file(file, "  SetProp(P_NOGET, 1);\n");
+    write_file(file,
+               "  SetProp(P_GENDER, "+
+               ({"NEUTER","MALE","FEMALE"})[raum->QueryProp(P_GENDER)]+
+               " );\n  SetProp(P_NAME, ");
+    n = raum->QueryProp(P_NAME);
+
+    if (stringp(n))
+    {
+      write_file(file, "\""+n+"\"");
+    }
+    else
+    {
+      prettyArray(file, n, 0);
+    }
+    write_file(file, " );\n\n  AddId( ");
+    prettyArray(file,
+                raum->QueryProp(P_IDS)-({ "sehe\rhaus",
+                                          "\n"+raum->QueryOwner()+"haus" }),
+                0);
+    write_file(file, " );\n");
+  }
+  trailerHouse();
+
+  StateTransition(SIG_HOUSE_DONE);
+}
+
+private void
+dumpRoomHeader()
+{
+  headerRoom();
+  
+  sProp(file, "P_INT_SHORT", raum->QueryProp(P_INT_SHORT));
+  write_file(file, "\n");
+  sProp(file, "P_INT_LONG", raum->QueryProp(P_INT_LONG));
+  write_file(file, "\n");
+
+  if (final && raum->QueryProp(H_CHEST))
+  {
+    StateTransition(SIG_DO_CHEST);
+  }
+  else
+  {
+    StateTransition(SIG_DO_DETAIL);
+  }
+}
+
+private void
+dumpChest()
+{
+  mixed n;
+  string cfile;
+  object chest;
+
+  cfile = PATH+"rep/"+raum->QueryOwner()+"truhe.c";
+  chest = present(TRUHE, raum);
+  
+  catch(rm(cfile));
+
+  write_file(cfile,
+             "#include <properties.h>\n#include <moving.h>\n\n"
+             "inherit \"/d/wueste/durian/behaelter\";\n\n"
+             "void create()\n{\n  if(!clonep(this_object())) return;\n\n"
+             "  ::create();\n\n" );
+  sProp(cfile, "P_SHORT", chest->QueryProp(P_SHORT));
+  sProp(cfile, "P_LONG",  chest->QueryProp(P_LONG));
+
+  write_file(cfile, "  SetProp(P_NOGET, 1);\n");
+  write_file(cfile,
+             "  SetProp(P_GENDER, "+
+             ({"NEUTER","MALE","FEMALE"})[chest->QueryProp(P_GENDER)]+
+             " );\n  SetProp(P_NAME, ");
+
+  n = chest->QueryProp(P_NAME);
+  if (stringp(n))
+  {
+    write_file(cfile, "\""+n+"\"");
+  }
+  else
+  {
+    prettyArray(file, n, 0);
+  }
+  write_file(cfile, " );\n\n  AddId( ");
+  prettyArray(cfile, chest->QueryProp(P_IDS)-({ TRUHE }), 0);
+  write_file(cfile, " );\n");
+
+  if ((n=chest->QueryProp(P_ADJECTIVES)) && sizeof(n))
+  {
+    write_file(cfile, "\n  AddAdjective( ");
+    prettyArray(cfile, n, 0);
+    write_file(cfile, " );\n");
+  }
+  if ((n=chest->QueryProp(P_NAME_ADJ)) && sizeof(n))
+  {
+    write_file(cfile, "\n  SetProp(P_NAME_ADJ, ");
+    prettyArray(cfile, n, 0);
+    write_file(cfile, " );\n");
+  }
+  write_file(cfile, "}\n");
+
+  StateTransition(SIG_DO_DETAIL);
+}
+
+private void
+dumpDetails()
+{
+  mapping prop;
+  mixed det;
+  
+  prop = raum->QueryProp(P_DETAILS);
+
+  if (sizeof(prop))
+  {
+    det = VERWALTER->PCrunch(prop);
+    // next state transition happens when do_mProp is done
+    mProp(file, "AddDetail", det, sizeof(det)-1, SIG_DETAIL_DONE);
+  }
+  else
+  {
+    StateTransition(SIG_DETAIL_DONE);
+  }
+}
+
+private void
+dumpReadDetails()
+{
+  mapping prop;
+  mixed rdet;
+  
+  prop = raum->QueryProp(P_READ_DETAILS);
+
+  if (sizeof(prop))
+  {
+    rdet = VERWALTER->PCrunch(prop);
+    // next state transition happens when do_mProp is done
+    mProp(file, "AddReadDetail", rdet, sizeof(rdet)-1, SIG_RDETAIL_DONE);
+  }
+  else
+  {
+    StateTransition(SIG_RDETAIL_DONE);
+  }
+}
+
+private void
+dumpCommands()
+{
+  mapping comm;
+  mixed cmd;
+  
+  comm = raum->QueryProp(H_COMMANDS);
+
+  if (sizeof(comm))
+  {
+    cmd = VERWALTER->PCrunch(comm);
+    // next state transition happens when do_cProp is done
+    cProp(file, "AddUserCmd", cmd, sizeof(cmd)-1, SIG_COMMAND_DONE);
+  }
+  else
+  {
+    StateTransition(SIG_COMMAND_DONE);
+  }
+}
+
+private void
+doFinalize()
+{
+  if (final)
+  {
+    StateTransition(SIG_DO_EXITS);
+  }
+  else
+  {
+    StateTransition(SIG_ROOM_DONE);
+  }
+}
+
+private void
+dumpExits()
+{
+  string *k, o;
+  mapping prop;
+  int i, num;
+
+  prop = raum->QueryProp(P_EXITS);
+  k = m_indices(prop);
+  if (member(k, "raus") >= 0)
+  {
+    k -= ({ "raus" });
+    write_file(file, sprintf("  AddExit( \"raus\", \"%s\");\n", prop["raus"]));
+  }
+  
+  for (i=sizeof(k)-1; i>=0; i--)
+  {
+    if (sscanf(prop[k[i]], PATH+"%sraum%d", o, num) != 2)
+    {
+      printf("Komischer Exit (%O)\n%s -> %s\n", raum, k[i], prop[k[i]]);
+    }
+    else
+    {
+      if (o == raum->QueryOwner())
+      {
+        o = sprintf(EXIT_TMPL, o, o, num);
+        write_file(file, sprintf("  AddExit( \"%s\", %s);\n", k[i], o));
+      }
+      else
+      {
+        write_file(file,
+                   sprintf("  AddExit( \"%s\", \"%s\");\n", k[i], prop[k[i]]));
+        printf("Exit von %O nach %s!\n", raum, prop[k[i]]);
+      }
+    }
+  }
+  StateTransition(SIG_ROOM_DONE);
+}
+
+private void
+dumpRoomTrailer()
+{
+  trailerRoom();
+  doReturn();
+}
+
+private void
+doReturn()
+{
+  if (hausmeister != 0)
+  {
+    apply(#'call_other, hausmeister, "GenerationDone", hmargs);
+  }
+  destruct(this_object());
+}
+
+private void
+sProp(string f, string pName, string pStr)
+{
+  string *str;
+
+  write_file(f, "  SetProp( "+pName+",");
+
+  if (!pStr)
+  {
+    write_file(f, "0 );\n");
+    return;
+  }
+
+  pStr = special(pStr);
+
+  if (sizeof(str=old_explode(pStr,"\n")) > 1)
+  {
+    prettyString(f, str, 4);
+  }
+  else
+  {
+    if (sizeof(str)==0)
+    {
+      str = ({""});
+    }
+    write_file(f, "\n     \""+str[0]);
+
+    if (pStr[<1] == '\n')
+    {
+      write_file(f, "\\n\"");
+    }
+    else
+    {
+      write_file(f, "\"");
+    }
+  }
+  write_file(f, " );\n");
+}
+
+static void
+mProp(string file, string pName, mixed cmd, int pos, int signal)
+{
+  int i;
+  string *eq, t1;
+  
+  for (i = pos; (i >= 0) && (get_eval_cost() > 10000); --i)
+  {
+    write_file(file, "  "+pName+"(\n    ");
+    eq = cmd[i][0];
+    t1 = cmd[i][1];
+
+    prettyArray(file, eq, 0);
+    write_file(file, ", ");
+
+    prettyString(file, old_explode(special(t1), "\n"), 6);
+    write_file(file, " );\n");
+  }
+
+  // Falls wir die eval_cost ausgereizt haben, aber noch nicht
+  // alle Einträge bearbeitet wurden, wird jetzt die naechste
+  // Runde gestartet
+  if (i >= 0)
+  {
+    call_out("mProp", 1, file, pName, cmd, i, signal);
+  }
+  else
+  {
+    // Ansonsten wechseln wir jetzt in den naechsten Zustand
+    write_file(file, "\n");
+    StateTransition(signal);
+  }
+}
+
+static void
+cProp(string file, string pName, mixed cmd, int pos, int signal)
+{
+  string t1, t2;
+  mixed  eq;
+  int i;
+
+  for (i = pos; (i >= 0) && (get_eval_cost() > 10000); --i)
+  {
+    write_file(file, "  "+pName+"(\n    ");
+    eq = cmd[i][0];
+    t1 = cmd[i][1];
+    t2 = cmd[i][2];
+
+    prettyArray(file, eq, 1);
+    write_file(file, ", 0, ");
+
+    prettyString(file, old_explode(special(t1), "\n"), 4);
+    write_file(file, ", ");
+    
+    if (t2)
+    {
+      prettyString(file, old_explode(special(t2), "\n"), 4);
+    }
+    else
+    {
+      write_file(file, "0");
+    }
+    
+    write_file(file, " );\n");
+  }
+
+  // Falls wir die eval_cost ausgereizt haben, aber noch nicht
+  // alle Einträge bearbeitet wurden, wird jetzt die naechste
+  // Runde gestartet
+  if (i >= 0)
+  {
+    call_out("cProp", 1, file, pName, cmd, i, signal);
+  }
+  else
+  {
+    // Ansonsten wechseln wir jetzt in den naechsten Zustand
+    write_file(file, "\n");
+    StateTransition(signal);
+  }
+}
+
+private void
+prettyString(string f, string *str, int indent)
+{
+  string ind;
+  int i;
+
+  ind = extract("\n          ",0,indent);
+
+  if (!sizeof(str))
+  {
+    write_file(f, ind+" \"\\n\"");
+    return;
+  }
+
+  write_file(f, ind+" \""+str[0]+"\\n\"");
+
+  for (i=1; i<sizeof(str); i++)
+  {
+    write_file(f, ind+"+\""+str[i]+"\\n\"");
+  }
+}
+
+private void
+prettyArray(string f, string *arr, int sep)
+{
+  int i,j;
+  string res, t1, t2;
+
+  write_file(f, "({");
+
+  if (sizeof(arr))
+  {
+    t1 = ("\""+arr[0]+"\"");
+    res = " "+t1;
+    t2 = "";
+
+    for (i=1, j=sizeof(arr); i<j; i++)
+    {
+      t2 = "\""+arr[i]+"\"";
+      if (!sep)
+      {
+	if ((sizeof(t1) + sizeof(t2)) > 69)
+        {
+	  res += (",\n       "+t2);
+	  t1 = t2;
+	  t2 = "";
+	}
+	else {
+	  t1 += (", "+t2);
+	  res += (", "+t2);
+	}
+      }
+      else {
+	res += (",\n       "+t2);
+      }
+    }
+  }
+  write_file(f, res + " })" );
+}
+
+private void
+headerRoom()
+{
+  if (final)
+  {
+    write_file(file,
+               "#include <properties.h>\n\n"
+               "inherit \"std/room\";\n"
+               "inherit \""+PATH+"modules/usercmd\";\n\n"
+               "create()\n"
+               "{\n"
+               "  room::create();\n"
+               "  usercmd::create();\n\n"
+               "  SetProp(P_LIGHT, 1);\n"
+               "  SetProp(P_INDOORS, 1);\n\n");
+  }
+  else
+  {
+    write_file(file,
+               "#include \"haus.h\"\n"
+               "#include <properties.h>\n\n"
+               "inherit RAUM;\n"
+               "inherit \"/std/thing/moving\";\n\n"
+               "create()\n"
+               "{\n"
+               "  if (!clonep(this_object())) return;\n"
+               "  ::create();\n\n"
+               "  SetOwner(\""+raum->QueryOwner()+"\", "+nr+");\n"
+               "  Load();\n\n"
+               "  SetProp(P_DETAILS, ([]));\n"
+               "  SetProp(P_READ_DETAILS, ([]));\n\n");
+  }
+}
+
+private void
+trailerRoom()
+{
+  if (final)
+  {
+    write_file(file, "}\n");
+  }
+  else
+  {
+    write_file(file,
+               "  Save(1);\n\n"
+               "  { object raum;\n"
+               "    if (raum = find_object(RAUMNAME("
+               "\""+raum->QueryOwner()+"\", "+nr+")))\n"
+               "      raum->Load();\n"
+               "  }\n\n"
+               "  call_out(\"remove\",0);\n"
+               "}\n");
+  }
+}
+
+private void
+headerHouse()
+{
+  if (final)
+  {
+    write_file(file,
+               "#include <properties.h>\n"
+               "#include <moving.h>\n"
+               "#include \""+PATH+"haus.h\"\n\n"
+               "inherit \"std/thing\";\n"
+               "inherit HAUSTUER;\n\n"
+               "create()\n"
+               "{\n"
+               "  thing::create();\n"
+               "  haustuer::create();\n\n");
+  }
+  else
+  {
+    write_file(file,
+               "#include \"haus.h\"\n"
+               "#include <properties.h>\n\n"
+               "inherit HAUS;\n"
+               "inherit \"/std/thing/moving\";\n\n"
+               "create()\n"
+               "{\n"
+               "  if (!clonep(this_object())) return;\n"
+               "  ::create();\n\n"
+               "  SetOwner(\""+raum->QueryOwner()+"\"\n"
+               "  Load();\n\n");
+  }
+}
+
+private void
+trailerHouse()
+{
+  if (final)
+  {
+    write_file(file, read_file(PATH+"tools/haus.apx"));
+    write_file(file, "  this_player()->move(");
+    write_file(file, sprintf(EXIT_TMPL,
+                             raum->QueryOwner(), raum->QueryOwner(), 0));
+    write_file(file,
+               ",\n\t\t\tM_GO, 0, \"betritt \"+name(WEN,1), \"kommt herein\");\n"
+               "  return 1;\n}\n");
+    if (!raum->QueryProp(P_SHORT))
+    {
+      write_file(file,
+                 "\nstring short()\n"
+                 "{\n"
+                 "  string ret;\n\n"
+                 "  ret = ::short();\n"
+                 "  if (previous_object() != environment() && !ret)\n"
+                 "    ret =\"\";\n\n"
+                 "  return ret;\n"
+                 "}\n");
+    }
+  }
+  else
+  {
+    write_file(file,
+               "  Save(1);\n\n"
+               "  { object raum;\n"
+               "    if (raum = find_object(HAUSNAME("
+               "\""+raum->QueryOwner()+"\")))\n"
+               "      raum->Load();\n"
+               "  }\n\n"
+               "  call_out(\"remove\",0);\n}\n");
+  }
+}
diff --git a/d/seher/haeuser/tools/haus.apx b/d/seher/haeuser/tools/haus.apx
new file mode 100644
index 0000000..74e2877
--- /dev/null
+++ b/d/seher/haeuser/tools/haus.apx
@@ -0,0 +1,25 @@
+
+  AddCmd( ({ "betritt", "betrete" }), "betritt");
+}
+
+string long()
+{
+  string door;
+
+  door = haustuer::long();
+
+  return QueryProp(P_LONG)+door;
+}
+
+static int betritt(string str)
+{
+  notify_fail("Was moechtest Du betreten?\n");
+
+  if (!str || !id(str))
+    return 0;
+
+  if (Query(H_DOORSTAT) & D_CLOSED) {
+    printf("%s von %s ist zu.\n", capitalize(name(WER,1)), capitalize(owner));
+    return 1;
+  }
+
diff --git a/d/seher/haeuser/tools/hausmeister.c b/d/seher/haeuser/tools/hausmeister.c
new file mode 100644
index 0000000..b39de0e
--- /dev/null
+++ b/d/seher/haeuser/tools/hausmeister.c
@@ -0,0 +1,247 @@
+#include "../haus.h"
+
+inherit "std/thing";
+inherit "/p/service/wargon/sm/statemachine";
+
+#include "/p/service/wargon/sm/statemachine.h"
+#include <properties.h>
+#include <moving.h>
+
+#define STATE_IDLE       0
+#define STATE_GENERATING 1
+
+#define SIG_INIT      0
+#define SIG_GENERATE  1
+#define SIG_DONE      2
+
+private string dump(int haus, int final);
+private void enterGenerating(string ow, object env, int nr, int fin, int all);
+private void doGenerating(string ow, object env, int nr, int fin, int all);
+
+create()
+{
+  if (!clonep(this_object())) return;
+  thing::create();
+  statemachine::create();
+  
+  SetProp( P_NAME, "Hausmeister");
+  SetProp( P_SHORT, "Ein Hausmeister" );
+  SetProp( P_LONG,
+     "Dies ist der Hausmeister aller Seherhaeuser. Er hilft Wurzel bei der\n"
+    +"Verwaltung der Haeuser.\n"
+    +"Der Hausmeister hat einen blauen Kittel an und eine Abrissbirne gezueckt.\n" );
+  SetProp( P_GENDER,MALE);
+  SetProp( P_NOGET, 1);
+
+  AddId( "hausmeister" );
+
+  AddState(STATE_IDLE, 0, 0);
+  AddState(STATE_GENERATING, #'doGenerating, 0);
+
+  AddTransition(SM_INVALID, SIG_INIT, STATE_IDLE);
+  AddTransition(STATE_IDLE, SIG_GENERATE, STATE_GENERATING, #'enterGenerating);
+  AddTransition(STATE_GENERATING, SIG_GENERATE, STATE_GENERATING, #'enterGenerating);
+  AddTransition(STATE_GENERATING, SIG_DONE, STATE_IDLE);
+
+  StateTransition(SIG_INIT);
+  
+  AddCmd( "generiere", "generieren" );
+  AddCmd( ({ "reiss", "reisse" }), "abreissen" );
+  AddCmd( "verlege", "verlegen" );
+}
+
+static int
+bewege(mixed dest, int flags, string msg1, string msg2)
+{
+  int ret;
+
+  tell_room(environment(), capitalize(name(WER))+" "+msg1+".\n");
+  if ((ret = move(dest, flags)) == 1)
+    tell_room(environment(), capitalize(name(WER))+" "+msg2+".\n");
+
+  return ret;
+}
+
+static int generieren(string str)
+{
+  object env;
+  int nr, fin, all;
+  string ow, *parm;
+
+  env = environment(this_player());
+
+  notify_fail( "Syntax: generiere <name> [<nr>] [soft | ganz]\n" );
+
+  if (!str || str == "")
+    return 0;
+
+  parm = old_explode(str, " ");
+  fin = 1;
+
+  switch (sizeof(parm)) {
+    case 3:
+      if (parm[2] == "soft")
+	fin = 0;
+    case 2:
+      if (parm[1] == "soft")
+	fin = 0;
+      else if (parm[1] == "ganz") {
+	ow = parm[0];
+	nr = (VERWALTER)->HausProp(ow, HP_ROOMS);
+	str = ow+"raum"+nr;
+	all = 1;
+	break;
+      }
+      else {
+	nr = to_int(parm[1]);
+	str = parm[0]+"raum"+parm[1];
+	ow = parm[0];
+	break;
+      }
+    case 1:
+      ow = parm[0];
+      nr = -1;
+      str = ow+"haus";
+      break;
+    default:
+      return 0;
+  }
+  if (file_size(HAUSSAVEPATH+ow+".o")<0) {
+    write( "Es gibt kein '"+str+"'!\n");
+    return 1;
+  }
+  StateTransition(SIG_GENERATE, ({ow, env, nr, fin, all }) );
+  return 1;
+}
+
+static void enterGenerating(string ow, object env, int nr, int fin, int all)
+{
+  string str;
+  
+  if (nr >= 0)
+    str = ow+"raum"+nr;
+  else
+    str = ow+"haus";
+
+  bewege(PATH+str, M_NOCHECK, "geht zur Arbeit", "kommt an");
+  tell_room(environment(),
+            Name(WER)+" zueckt einen Block, sieht sich alles genau an und macht\n"
+            +"sich hin und wieder Notizen. Dann nickt er zufrieden und steckt seinen\n"
+            "Block wieder weg.\n" );
+}
+
+static void doGenerating(string ow, object env, int nr, int fin, int all)
+{
+  object gen;
+  string str, out;
+
+  gen = clone_object(PATH+"tools/generator");
+  out = gen->dump(environment(), fin, ({ ow, env, nr, fin, all }));
+  
+  if (nr >= 0)
+    str = ow+"raum"+nr;
+  else
+    str = ow+"haus";
+
+  bewege(env, M_NOCHECK, "geht zu seinem Auftraggeber zurueck", "kommt an");
+  write( "Der Hausmeister sagt: Ich habe '"+str+"' in die Datei\n"
+	+"Der Hausmeister sagt: '"+out+"' geschrieben, Chef!\n");
+}
+
+void
+GenerationDone(string ow, object env, int nr, int fin, int all)
+{
+  if (all)
+  {
+    if (nr > 0)
+    {
+      call_out("StateTransition", 1,
+               SIG_GENERATE, ({ ow, env, nr-1, fin, 1 }) );
+    }
+    else
+    {
+      call_out("StateTransition", 1,
+               SIG_GENERATE, ({ ow, env, -1, fin, 0 }) );
+    }
+  }
+  else
+  {
+    StateTransition(SIG_DONE, ({ ow, env, -1, fin, 0 }) );
+  }
+}
+
+static int abreissen(string str)
+{
+  object haus, env;
+  string ich, msg;
+
+  if (!str || str == "" || sscanf(str, "%s ab",str) != 1) {
+    notify_fail( "Syntax: reisse <name> ab\n" );
+    return 0;
+  }
+  str = lower_case(str);
+  if (!(haus = VERWALTER->FindeHaus(str))) {
+    write( capitalize(str)+" hat kein Haus!\n" );
+    return 1;
+  }
+  ich = capitalize(name(WER));
+  env = environment();
+  bewege(environment(haus), M_NOCHECK, "geht zur Arbeit", "kommt an");
+  msg = haus->Name(WER);
+
+  if (VERWALTER->LoescheHaus(str) == -1) {
+    tell_room(environment(), ich+" versucht vergeblich, ein Haus abzureissen.\n" );
+    msg = "Der Abrissversuch ist fehlgeschlagen, Chef!\n";
+  }
+  else {
+    tell_room(environment(), ich+" betaetigt eine Sirene.\n"+msg+" wird von "+name(WEM)+" eingeebnet.\n");
+    msg = msg+" ist abgerissen, Chef!\n";
+    if (haus) haus->remove();
+  }
+  bewege(env, M_NOCHECK, "geht zu seinem Auftraggeber zurueck", "kommt an");
+  write( "Der Hausmeister sagt: "+msg);
+  return 1;
+}
+
+static int verlegen(string str)
+{
+  string name, von, nach;
+  object haus;
+  int ret;
+
+  if (!str || sscanf(str, "%s nach %s", name, nach) != 2) {
+    notify_fail( "Syntax: verlege <name> nach <ziel>\n" );
+    return 0;
+  }
+  if (nach == "hier")
+    nach = object_name(environment(this_player()));
+
+  name = lower_case(name);
+
+  if (!(haus = VERWALTER->FindeHaus(name))) {
+    write( "Der Hausmeister sagt: "+capitalize(name)+" hat kein Haus!\n" );
+    return 1;
+  }
+  von = object_name(environment(haus));
+  ret = VERWALTER->VerlegeHaus(name, von, nach);
+  write( "Der Hausmeister sagt: " );
+  switch(ret) {
+    case -111:
+      write( "Das hast Du nicht zu bestimmen!\n" );
+      break;
+    case -3:
+      write( "Der Zielraum laesst sich nicht laden! Verlegen abgebrochen!\n" );
+      break;
+    case -4:
+      write( "Im Zielraum kann nicht gebaut werden!\n" );
+      break;
+    case -5:
+      write( "Im Haus von "+capitalize(name)+" gibt es noch Ausgaenge in andere Haeuser!\n");
+      break;
+    case 1:
+      write( "OK, Chef, ich habe das Haus verlegt!\n" );
+      break;
+  }
+  return 1;
+}
+
diff --git a/d/seher/haeuser/tools/hausmeister2.c b/d/seher/haeuser/tools/hausmeister2.c
new file mode 100644
index 0000000..41c5450
--- /dev/null
+++ b/d/seher/haeuser/tools/hausmeister2.c
@@ -0,0 +1,534 @@
+#include "../haus.h"
+#include <properties.h>
+#include <moving.h>
+
+inherit "std/thing";
+
+static void do_gen(string ow, object env, int nr, int fin, int all);
+private string special(string str);
+private string dump(int haus, int final);
+private void header(string f, int final, object haus, int nr);
+private void trailer(string f, int final, object haus, int nr);
+private void sProp(string f, string pName, string pStr);
+private void mProp(string f, string pName, mapping pMap);
+private void cProp(string f, string pName, mapping cMap);
+private void prettyString(string f, string *str, int indent);
+private void prettyArray(string f, string *arr, int sep);
+
+create()
+{
+  if (!clonep(this_object())) return;
+  ::create();
+
+  SetProp( P_NAME, "Hausmeister");
+  SetProp( P_SHORT, "Ein Hausmeister" );
+  SetProp( P_LONG,
+     "Dies ist der Hausmeister aller Seherhaeuser. Er hilft Wurzel bei der\n"
+    +"Verwaltung der Haeuser.\n"
+    +"Der Hausmeister hat einen blauen Kittel an und eine Abrissbirne gezueckt.\n" );
+  SetProp( P_GENDER,MALE);
+  SetProp( P_NOGET, 1);
+
+  AddId( "hausmeister" );
+
+  AddCmd( "generiere", "generieren" );
+  AddCmd( ({ "reiss", "reisse" }), "abreissen" );
+  AddCmd( "verlege", "verlegen" );
+}
+
+static int
+bewege(mixed dest, int flags, string msg1, string msg2)
+{
+  int ret;
+
+  tell_room(environment(), capitalize(name(WER))+" "+msg1+".\n");
+  if ((ret = move(dest, flags)) == 1)
+    tell_room(environment(), capitalize(name(WER))+" "+msg2+".\n");
+
+  return ret;
+}
+
+static int generieren(string str)
+{
+  object env;
+  int nr, fin, all;
+  string ow, *parm;
+
+  env = environment(this_player());
+
+  notify_fail( "Syntax: generiere <name> [<nr>] [soft | ganz]\n" );
+
+  if (!str || str == "")
+    return 0;
+
+  parm = old_explode(str, " ");
+  fin = 1;
+
+  switch (sizeof(parm)) {
+    case 3:
+      if (parm[2] == "soft")
+	fin = 0;
+    case 2:
+      if (parm[1] == "soft")
+	fin = 0;
+      else if (parm[1] == "ganz") {
+	ow = parm[0];
+	nr = (VERWALTER)->HausProp(ow, HP_ROOMS);
+	str = ow+"raum"+nr;
+	all = 1;
+	break;
+      }
+      else {
+	nr = to_int(parm[1]);
+	str = parm[0]+"raum"+parm[1];
+	ow = parm[0];
+	break;
+      }
+    case 1:
+      ow = parm[0];
+      nr = -1;
+      str = ow+"haus";
+      break;
+    default:
+      return 0;
+  }
+  if (file_size(HAUSSAVEPATH+ow+".o")<0) {
+    if (nr >= 0 && file_size(HAUSSAVEPATH+ow+nr+".o")<0) {
+      write( "Es gibt kein '"+str+"'!\n");
+      return 1;
+    }
+  }
+  do_gen(ow, env, nr, fin, all);
+  return 1;
+}
+
+static void do_gen(string ow, object env, int nr, int fin, int all)
+{
+  string str, out;
+
+  if (nr >= 0)
+    str = ow+"raum"+nr;
+  else
+    str = ow+"haus";
+
+  bewege(PATH+str, M_NOCHECK, "geht zur Arbeit", "kommt an");
+  tell_room(environment(), Name(WER)+" zueckt einen Block, sieht sich alles genau an und macht\n"
+    +"sich hin und wieder Notizen. Dann nickt er zufrieden und steckt seinen\nBlock wieder weg.\n" );
+  out = dump(nr, fin);
+  bewege(env, M_NOCHECK, "geht zu seinem Auftraggeber zurueck", "kommt an");
+  write( "Der Hausmeister sagt: Ich habe '"+str+"' in die Datei\n"
+	+"Der Hausmeister sagt: '"+out+"' geschrieben, Chef!\n");
+
+  if (all) {
+    if (nr > 0)
+      call_out("do_gen", 1, ow, env, nr-1, fin, all);
+    else
+      call_out("do_gen", 1, ow, env, -1, fin);
+  }
+}
+
+static int abreissen(string str)
+{
+  object haus, env;
+  string ich, msg;
+
+  if (!str || str == "" || sscanf(str, "%s ab",str) != 1) {
+    notify_fail( "Syntax: reisse <name> ab\n" );
+    return 0;
+  }
+  str = lower_case(str);
+  if (!(haus = VERWALTER->FindeHaus(str))) {
+    write( capitalize(str)+" hat kein Haus!\n" );
+    return 1;
+  }
+  ich = capitalize(name(WER));
+  env = environment();
+  bewege(environment(haus), M_NOCHECK, "geht zur Arbeit", "kommt an");
+  msg = haus->Name(WER);
+
+  if (VERWALTER->LoescheHaus(str) == -1) {
+    tell_room(environment(), ich+" versucht vergeblich, ein Haus abzureissen.\n" );
+    msg = "Der Abrissversuch ist fehlgeschlagen, Chef!\n";
+  }
+  else {
+    tell_room(environment(), ich+" betaetigt eine Sirene.\n"+msg+" wird von "+name(WEM)+" eingeebnet.\n");
+    msg = msg+" ist abgerissen, Chef!\n";
+    if (haus) haus->remove();
+  }
+  bewege(env, M_NOCHECK, "geht zu seinem Auftraggeber zurueck", "kommt an");
+  write( "Der Hausmeister sagt: "+msg);
+  return 1;
+}
+
+static int verlegen(string str)
+{
+  string name, von, nach;
+  object haus;
+  int ret;
+
+  if (!str || sscanf(str, "%s nach %s", name, nach) != 2) {
+    notify_fail( "Syntax: verlege <name> nach <ziel>\n" );
+    return 0;
+  }
+  if (nach == "hier")
+    nach = object_name(environment(this_player()));
+
+  name = lower_case(name);
+
+  if (!(haus = VERWALTER->FindeHaus(name))) {
+    write( "Der Hausmeister sagt: "+capitalize(name)+" hat kein Haus!\n" );
+    return 1;
+  }
+  von = object_name(environment(haus));
+  ret = VERWALTER->VerlegeHaus(name, von, nach);
+  write( "Der Hausmeister sagt: " );
+  switch(ret) {
+    case -111:
+      write( "Das hast Du nicht zu bestimmen!\n" );
+      break;
+    case -3:
+      write( "Der Zielraum laesst sich nicht laden! Verlegen abgebrochen!\n" );
+      break;
+    case -4:
+      write( "Im Zielraum kann nicht gebaut werden!\n" );
+      break;
+    case -5:
+      write( "Im Haus von "+capitalize(name)+" gibt es noch Ausgaenge in andere Haeuser!\n");
+      break;
+    case 1:
+      write( "OK, Chef, ich habe das Haus verlegt!\n" );
+      break;
+  }
+  return 1;
+}
+
+/*** Funktionen zum Generieren einer Datei aus den Properties des Hauses ***/
+
+#define EXIT_TMPL "\"/players/%s/seherhaus/%sraum%d\""
+
+private void dump_chest(string out, object chest)
+{
+  mixed n;
+
+  catch(rm(out));
+
+  write_file(out, "#include <properties.h>\n#include <moving.h>\n\n"
+		  "inherit \"/d/wueste/durian/behaelter\";\n\n"
+		  "void create()\n{\n  if(!clonep(this_object())) return;\n\n"
+		  "  ::create();\n\n" );
+  sProp(out, "P_SHORT", chest->QueryProp(P_SHORT));
+  sProp(out, "P_LONG",  chest->QueryProp(P_LONG));
+
+  write_file(out, "  SetProp(P_NOGET, 1);\n");
+  write_file(out, "  SetProp(P_GENDER, "+
+		    ({"NEUTER","MALE","FEMALE"})[chest->QueryProp(P_GENDER)]+
+		    " );\n  SetProp(P_NAME, ");
+
+  n = chest->QueryProp(P_NAME);
+  if (stringp(n))
+    write_file(out, "\""+n+"\"");
+  else
+    prettyArray(out, n, 0);
+  write_file(out, " );\n\n  AddId( ");
+  prettyArray(out, chest->QueryProp(P_IDS)-({ TRUHE }), 0);
+  write_file(out, " );\n");
+
+  if ((n=chest->QueryProp(P_ADJECTIVES)) && sizeof(n)) {
+    write_file(out, "\n  AddAdjective( ");
+    prettyArray(out, n, 0);
+    write_file(out, " );\n");
+  }
+  if ((n=chest->QueryProp(P_NAME_ADJ)) && sizeof(n)) {
+    write_file(out, "\n  SetProp(P_NAME_ADJ, ");
+    prettyArray(out, n, 0);
+    write_file(out, " );\n");
+  }
+  write_file(out, "}\n");
+}
+
+private string dump(int nr, int final)
+{
+  string out;
+  object env;
+  mapping prop;
+
+  env = environment(this_object());
+
+  if (final && env->QueryProp(H_CHEST))
+    dump_chest(PATH+"rep/"+env->QueryOwner()+"truhe.c", present(TRUHE, env));
+
+  if (final) {
+    out = PATH+"rep/"+env->QueryOwner();
+    if (nr < 0)
+      out += "haus.c";
+    else
+      out += "raum"+nr+".c";
+  }
+  else
+    out = PATH+"fixed.c";
+
+  catch(rm(out));
+
+  header(out, final, env, nr);
+  if (nr<0) {
+    sProp(out, "P_SHORT", env->QueryProp(P_SHORT));
+    write_file(out, "\n");
+    sProp(out, "P_LONG", env->QueryProp(P_LONG));
+    write_file(out, "\n");
+
+    if (final) {
+      mixed n;
+
+      write_file(out, "  SetProp(P_NOGET, 1);\n");
+      write_file(out, "  SetProp(P_GENDER, "+
+		      ({"NEUTER","MALE","FEMALE"})[env->QueryProp(P_GENDER)]+
+		      " );\n  SetProp(P_NAME, ");
+      n = env->QueryProp(P_NAME);
+      if (stringp(n))
+	write_file(out, "\""+n+"\"");
+      else
+	prettyArray(out, n, 0);
+      write_file(out, " );\n\n  AddId( ");
+      prettyArray(out, env->QueryProp(P_IDS)-({ "sehe\rhaus", "\n"+env->QueryOwner()+"haus" }), 0);
+      write_file(out, " );\n");
+    }
+  }
+  else {
+    sProp(out, "P_INT_SHORT", env->QueryProp(P_INT_SHORT));
+    write_file(out, "\n");
+    sProp(out, "P_INT_LONG", env->QueryProp(P_INT_LONG));
+    write_file(out, "\n");
+    if (sizeof(prop = env->QueryProp(P_DETAILS))) {
+      mProp(out, "AddDetail", prop);
+      write_file(out, "\n");
+    }
+    if (sizeof(prop = env->QueryProp(P_READ_DETAILS))) {
+      mProp(out, "AddReadDetail", prop);
+      write_file(out, "\n");
+    }
+    if (sizeof(prop = env->QueryProp(H_COMMANDS)))
+      cProp(out, "AddUserCmd", prop);
+
+    write_file(out, "\n");
+    if (final) {
+      string *k, o;
+      int i, num;
+
+      prop = env->QueryProp(P_EXITS);
+      k = m_indices(prop);
+      if (member(k, "raus") >= 0) {
+	k -= ({ "raus" });
+	write_file(out, sprintf("  AddExit( \"raus\", \"%s\");\n", prop["raus"]));
+      }
+      for (i=sizeof(k)-1; i>=0; i--) {
+	if (sscanf(prop[k[i]], PATH+"%sraum%d", o, num) != 2)
+	  printf("Komischer Exit (%O)\n%s -> %s\n", env, k[i], prop[k[i]]);
+	else {
+	  if (o == env->QueryOwner()) {
+	    o = sprintf(EXIT_TMPL, o, o, num);
+	    write_file(out, sprintf("  AddExit( \"%s\", %s);\n", k[i], o));
+	  }
+	  else {
+	    write_file(out, sprintf("  AddExit( \"%s\", \"%s\");\n", k[i], prop[k[i]]));
+	    printf("Exit von %O nach %s!\n", env, prop[k[i]]);
+	  }
+	}
+      }
+    }
+  }
+  trailer(out, final, env, nr);
+
+  return out;
+}
+
+private void header(string f, int final, object haus, int nr)
+{
+  if (final) {
+    write_file(f, "#include <properties.h>" );
+    if (nr >= 0) {
+      write_file(f, "\n\ninherit \"std/room\";\ninherit \""+PATH+"modules/usercmd\";");
+      write_file(f, "\n\ncreate()\n{\n  room::create();\n  usercmd::create();\n\n");
+      write_file(f, "  SetProp(P_LIGHT, 1);\n  SetProp(P_INDOORS, 1);\n\n");
+    }
+    else {
+      write_file(f, "\n#include <moving.h>\n#include \""+PATH+"haus.h\"\n\n" );
+      write_file(f, "inherit \"std/thing\";\ninherit HAUSTUER;\n\n" );
+      write_file(f, "create()\n{\n  thing::create();\n  haustuer::create();\n\n");
+    }
+  }
+  else {
+    write_file(f, "#include \"haus.h\"\n#include <properties.h>\n\ninherit ");
+    write_file(f, ((nr < 0) ? "HAUS" : "RAUM" ) );
+    write_file(f, ";\ninherit \"/std/thing/moving\";\n\n");
+    write_file(f, "create()\n{\n  if (!clonep(this_object())) return;\n  ::create();\n\n");
+    write_file(f, "  SetOwner(\""+haus->QueryOwner()+"\"");
+    if (nr >= 0)
+      write_file(f, ", "+nr);
+    write_file(f, ");\n  Load();\n\n");
+    if (nr >= 0)
+      write_file(f, "  SetProp(P_DETAILS, ([]));\n  SetProp(P_READ_DETAILS, ([]));\n\n");
+  }
+}
+
+private void trailer(string f, int final, object haus, int nr)
+{
+  if (final) {
+    if (nr >= 0)
+      write_file(f, "}\n");
+    else {
+      write_file(f, read_file(PATH+"tools/haus.apx"));
+      write_file(f, "  this_player()->move(");
+      write_file(f, sprintf(EXIT_TMPL, haus->QueryOwner(), haus->QueryOwner(), 0));
+      write_file(f, ",\n\t\t\tM_GO, 0, \"betritt \"+name(WEN,1), \"kommt herein\");\n"
+		    "  return 1;\n}\n");
+      if (!haus->QueryProp(P_SHORT))
+	write_file(f, "\nstring short()\n{\n  string ret;\n\n"
+		      "  ret = ::short();\n"
+		      "  if (previous_object() != environment() && !ret)\n"
+		      "    ret =\"\";\n\n  return ret;\n}\n");
+    }
+  }
+  else {
+    write_file(f, "  Save(1);\n\n");
+    write_file(f, "  { object raum;\n    if (raum = find_object(");
+    if (nr >= 0)
+      write_file(f, "RAUMNAME(\""+haus->QueryOwner()+"\", "+nr+")))\n");
+    else
+      write_file(f, "HAUSNAME(\""+haus->QueryOwner()+"\")))\n");
+    write_file(f, "      raum->Load();\n  }\n\n  call_out(\"remove\",0);\n}\n");
+  }
+}
+
+private string special(string s)
+{
+  s = implode(explode(s, "\\"), "\\\\");
+  s = implode(explode(s, "\t"), "\\t");
+  s = implode(explode(s, "\""), "\\\"");
+
+  return s;
+}
+
+private void sProp(string f, string pName, string pStr)
+{
+  string *str;
+  write_file(f, "  SetProp( "+pName+",");
+  if (!pStr) {
+    write_file(f, "0 );\n");
+    return;
+  }
+  pStr = special(pStr);
+  if (sizeof(str=old_explode(pStr,"\n")) > 1)
+    prettyString(f, str, 4);
+  else {
+    if (sizeof(str)==0)
+      str = ({""});
+    write_file(f, "\n     \""+str[0]);
+    if (pStr[<1] == '\n')
+      write_file(f, "\\n\"");
+    else
+      write_file(f, "\"");
+  }
+  write_file(f, " );\n");
+}
+
+private void mProp(string f, string pName, mapping pMap)
+{
+  string *eq, t1;
+  mixed cmd;
+  int i,j;
+
+  if (sizeof(pMap) == 0)
+    return;
+
+  cmd = VERWALTER->PCrunch(pMap);
+
+  for (i=sizeof(cmd)-1; i>=0; i--) {
+    write_file(f, "  "+pName+"(\n    ");
+    eq = cmd[i][0];
+    t1 = cmd[i][1];
+
+    prettyArray(f, eq, 0);
+    write_file(f, ", ");
+
+    prettyString(f, old_explode(special(t1), "\n"), 6);
+    write_file(f, " );\n");
+  }
+}
+
+private void cProp(string f, string pName, mapping cMap)
+{
+  string t1, t2;
+  mixed cmd, eq;
+  int i,j;
+
+  cmd = VERWALTER->PCrunch(cMap);
+
+  for( i=sizeof(cmd)-1; i>=0; i--) {
+    write_file(f, "  "+pName+"(\n    ");
+    eq = cmd[i][0];
+    t1 = cmd[i][1];
+    t2 = cmd[i][2];
+
+    prettyArray(f, eq, 1);
+    write_file(f, ", 0, ");
+
+    prettyString(f, old_explode(special(t1), "\n"), 4);
+    write_file(f, ", ");
+    if (t2)
+      prettyString(f, old_explode(special(t2), "\n"), 4);
+    else
+      write_file(f, "0");
+    write_file(f, " );\n");
+  }
+}
+
+private void prettyString(string f, string *str, int indent)
+{
+  string ind;
+  int i;
+
+  ind = extract("\n          ",0,indent);
+
+  if (!sizeof(str)) {
+    write_file(f, ind+" \"\\n\"");
+    return;
+  }
+  write_file(f, ind+" \""+str[0]+"\\n\"");
+  for (i=1; i<sizeof(str); i++) {
+    write_file(f, ind+"+\""+str[i]+"\\n\"");
+  }
+}
+
+private void prettyArray(string f, string *arr, int sep)
+{
+  int i,j;
+  string res, t1, t2;
+
+  write_file(f, "({");
+
+  if (sizeof(arr)) {
+    t1 = ("\""+arr[0]+"\"");
+    res = " "+t1;
+    t2 = "";
+
+    for (i=1, j=sizeof(arr); i<j; i++) {
+      t2 = "\""+arr[i]+"\"";
+      if (!sep) {
+	if ((sizeof(t1)+sizeof(t2))>69) {
+	  res += (",\n       "+t2);
+	  t1 = t2;
+	  t2 = "";
+	}
+	else {
+	  t1 += (", "+t2);
+	  res += (", "+t2);
+	}
+      }
+      else {
+	res += (",\n       "+t2);
+      }
+    }
+  }
+  write_file(f, res + " })" );
+}
+
diff --git a/d/seher/haeuser/tools/haustool.c b/d/seher/haeuser/tools/haustool.c
new file mode 100644
index 0000000..50f6e1e
--- /dev/null
+++ b/d/seher/haeuser/tools/haustool.c
@@ -0,0 +1,182 @@
+#include "../haus.h"
+#include <properties.h>
+#include <moving.h>
+#include <wizlevels.h>
+
+inherit "std/secure_thing";
+
+private int secure()
+{
+  return (this_interactive() && (IS_ARCH(this_interactive()) ||
+				 getuid(this_interactive()) == "wurzel"));
+}
+
+create()
+{
+  if (!clonep(this_object())) return;
+  ::create();
+
+  SetProp(P_SHORT, "Ein Adressverzeichnis" );
+  SetProp(P_LONG,
+     "Mit diesem Adressverzeichnis koennen die richtigen Leute Ordnung in den\n"
+    +"Wust der Seherhausangelegenheiten bringen.\n"
+    +"Die richtigen Leute?\n"
+    +"Ja: Man muss schon Erzmagier sein oder Wurzel heissen! ;)\n"
+    +"Du kannst es uebrigens lesen!\n" );
+  SetProp(P_NAME, "Adressverzeichnis");
+  SetProp(P_READ_MSG,
+     "Es stehen folgende Befehle zur Verfuegung:\n"
+    +"checked <name> [+/-] <nr>\n"
+    +"rep\n"
+    +"mkmail <name>\n"
+    );
+  SetProp(P_GENDER, NEUTER);
+  SetProp(P_WEIGHT, 100);
+  SetProp(P_AUTOLOADOBJ, 1);
+  SetProp(P_NEVERDROP, 1);
+  SetProp(P_NODROP, 1);
+
+  AddId( ({ "verzeichnis", "adressverzeichnis", "haustool" }) );
+
+  AddCmd("checked", "checked");
+  AddCmd("rep", "report");
+  AddCmd("mkmail", "mkmail");
+}
+
+#define CHECKED PATH+"log/CHECKED"
+static int
+checked(string str)
+{
+  mapping drin;
+  string name, *lines, *ind, pm;
+  int nr, i;
+  closure hp;
+
+  if (!secure())
+    return 0;
+
+  notify_fail("Syntax: checked <name> [+/-] <nr>\n" );
+  if (!str || str == "")
+    return 0;
+
+  if (file_size(CHECKED) > 0)
+    lines = explode(read_file(CHECKED), "\n") - ({""});
+  else
+    lines = ({});
+
+  for (drin = ([]), i=sizeof(lines)-1; i>=0; i--) {
+    if (sscanf(lines[i], "%s%t%d", name, nr) == 2)
+      drin += ([ name : nr-1 ]);
+  }
+  lines = ({ });
+  pm = "";
+  hp = symbol_function("HausProp", VERWALTER);
+
+  if (sscanf(str, "%s %d", name, nr)==2 || sscanf(str, "%s %s %d", name, pm, nr) == 3) {
+    if (!funcall(hp, name, HP_ENV)) {
+      write(capitalize(name)+" hat gar kein Haus!\n");
+      return 1;
+    }
+    if (nr < 0) {
+      write("Zum Abziehen nimm bitte 'checked <name> - <nr>'!\n");
+      return 1;
+    }
+    if (member(drin, name))
+      i = drin[name];
+    switch(pm) {
+      case "+":
+	if (i+nr > funcall(hp, name, HP_ROOMS)) {
+	  printf("%d Raeume? Wie soll das gehen?\n", i+nr);
+	  return 1;
+	}
+	drin[name] += nr;
+	break;
+      case "-":
+	if (i-nr < 0) {
+	  write("Soviele Raeume kannst Du "+capitalize(name)+" gar nicht abziehen...\n");
+	  return 1;
+	}
+	drin[name] -= nr;
+	break;
+      default:
+	if (nr > funcall(hp, name, HP_ROOMS)) {
+	  printf("%s nat keine %d Raeume!\n",capitalize(name),nr);
+	  return 1;
+	}
+	drin[name] = nr;
+    }
+    rm(CHECKED);
+    for (i=sizeof(ind=sort_array(m_indices(drin),#'<))-1; i>=0; i--)
+      write_file(CHECKED, sprintf("%s %d\n",ind[i], 1+drin[ind[i]]));
+    return 1;
+  }
+  else
+    return 0;
+}
+
+static int
+report()
+{
+  string *rep, *head, name;
+  int i, lp, nr;
+
+  if (file_size("/log/report/wurzel.rep")<=0) {
+    write("Kein wurzel.rep (Jippieh! ;)\n");
+    return 1;
+  }
+
+  rep = old_explode(read_file("/log/report/wurzel.rep"),"\n");
+  lp = sizeof(PATH)-1;
+
+  for (i=sizeof(rep)-2; i>=0; i-=2) {
+    head = old_explode(rep[i], " ");
+    if (head[4][0..lp] == PATH) {
+      name = old_explode(head[4],"/")[<1];
+      nr = to_int(name[<1..<1]);
+      name = name[0..<6];
+      head[2] = capitalize(head[2]);
+      write_file(PATH+"rep/"+name,
+		 sprintf("%s in Raum %d:\n%s\n",
+			 implode(head[0..2]," "),nr,rep[i+1]));
+    }
+    else
+      write_file(PATH+"rep/wurzel.rep",sprintf("%s\n%s\n", rep[i], rep[i+1]));
+  }
+  return 1;
+}
+
+static int
+mkmail(string str)
+{
+  string f,fm;
+
+  if (!str || str == "") {
+    notify_fail( "Syntax: mkmail <name>\n");
+    return 0;
+  }
+
+  if (!(f=(VERWALTER)->HausProp(str, HP_ENV))) {
+    printf("%s hat kein Haus!\n", str);
+    return 1;
+  }
+  fm = PATH+str+".mail";
+
+  write_file(fm, "\
+  Huhu!\n\
+\n\
+Da Du Magier bist, brauchst Du auch kein Seherhaus mehr. Damit Deine\n\
+Beschreibungen aber nicht verloren sind, findest Du die Files Deines\n\
+Hauses in /players/"+str+"/seherhaus/.\n\
+\n\
+Soll Dein Haus weiterhin an der jetzigen Stelle stehen bleiben\n\
+("+f+"),\n\
+so klaere das bitte mit dem dort zustaendigen Magier sowie den zustaen-\n\
+digen Regionsmagiern (weil es sich jetzt um den Anschluss von Files an\n\
+ein Gebiet handelt).\n\
+\n\
+!! Das Haus wird auf jeden Fall nach Ende der Haussperre abgerissen !!\n\
+\n\
+  Wargon.\n");
+
+  return 1;
+}
diff --git a/d/seher/haeuser/tools/liste.c b/d/seher/haeuser/tools/liste.c
new file mode 100755
index 0000000..12b39a2
--- /dev/null
+++ b/d/seher/haeuser/tools/liste.c
@@ -0,0 +1,25 @@
+#include "../haus.h"
+#include <wizlevels.h>
+
+mapping megamap;
+
+create() {
+  seteuid(getuid(this_object()));
+  restore_object(SAVEFILE);
+  do_dump();
+}
+
+do_dump()
+{
+  string *ow, typ;
+  int i, r, r2;
+  ow = m_indices(megamap);
+  ow = sort_array(ow,#'<);
+  i = sizeof(ow)-1;
+  for(r=0, r2=0; i>=0; i--) {
+    r = megamap[ow[i],HP_ROOMS];
+    if (IS_LEARNER(ow[i])) printf("%13s %d MAGIER(%d)\n", ow[i],r,query_wiz_level(ow[i]));
+    else if (!IS_SEER(ow[i])) printf("%13s %d KEIN SEHER MEHR\n", ow[i], r);
+  }
+  destruct(this_object());
+}