Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/d/seher/haeuser/raum.c b/d/seher/haeuser/raum.c
new file mode 100644
index 0000000..7fd0c55
--- /dev/null
+++ b/d/seher/haeuser/raum.c
@@ -0,0 +1,1840 @@
+//  raum.c  -- Das Rohgeruest eines Seherhauses.
+//
+//  Grundobjekt (c) 1994 Boing@MorgenGrauen
+//  Abschliessen und Rauswerfen von Jof
+//  Fuer Aenderungen ab dem 06.10.94 verantwortlich: Wargon
+//  Ab 03.02.98 Wurzel
+//
+// $Id: raum.c,v 1.5 2003/11/15 14:03:58 mud Exp $
+#pragma strong_types,rtt_checks
+
+#include "haus.h"
+
+inherit "/std/room";
+inherit USERCMD;    // selbstdefinierte Kommandos
+inherit LOSA;       // Load() und Save()
+inherit "/mail/nedit";
+
+#include <wizlevels.h>
+#include <properties.h>
+#include <defines.h>
+#include <moving.h>
+
+static mixed detail;
+static string owner;
+static int flag, csaved;
+static int raumNr;
+static string *ausgaenge = ({ "oben", "norden", "nordosten", "osten", "suedosten",
+                  "unten", "sueden", "suedwesten", "westen", "nordwesten" });
+
+// Prototypes fuer Funktionen aus LOSA
+varargs void Save(int crunched);
+void Load();
+
+// Prototype
+// Falls noetig, mache einen Notausgang, falls nicht loesche vorhandenen
+void make_emergency_exit();
+
+// ersetzt @@ durch **
+private string normstr(string str)
+{
+  return implode(explode(str,"@@"),"**");
+}
+
+// liefert kommagetrennte Teile ohne zusaetzliche Leerzeichen
+// "Bla blubb ,  foo bar,blubber" => ({ "Bla blubb", "foo bar", "blubber" })
+private string *brk(string str)
+{
+  string *t1;
+
+  t1 = explode(str, ",");
+  map(t1, #'trim /*'*/);
+  return t1;
+}
+
+// teste Befehl
+private int befCheck(string bef)
+{
+  // Befehl enthaelt Leerzeichen => return 0
+  if (member(bef, ' ') > -1)
+    return 0;
+
+  // Befehl ist bereits Kommando (ausser Oeffnen/Schliessen)
+  // oder Richtung inclusive "raus" in die kein Ausgang fuehrt
+  // => return 0
+  if (member(m_indices(QueryProp(P_COMMANDS)) -
+                       ({"oeffne","schliess","schliesse"}), bef) > -1
+      || (member(ausgaenge+({"raus"}), bef) > -1
+          && member(m_indices(QueryProp(P_EXITS)), bef) == -1))
+    return 0;
+
+  return 1;
+}
+
+// Test auf Hausbesitzer
+int tp_owner_check()
+{
+  if(getuid(this_player()) != owner)
+  {
+    notify_fail( "Das ist nicht Dein Haus!\n" );
+    return 0;
+  }
+  return 1;
+}
+
+// Test auf Hausbesitzer oder Person mit Erlaubnis
+int allowed_check(object _test)
+{
+   string *ext;
+
+   ext = VERWALTER->HausProp(owner, HP_ALLOWED) + ({ capitalize(owner) });
+   if(member(ext, capitalize(getuid(_test))) < 0)
+   {
+     return 0;
+   }
+   else
+   {
+     return 1;
+   }
+}
+
+// Funktion ersetzt durch tp_owner_check() und allowed_check(object _test)
+// falls allowed == 0 => test ob this_player() Hausbesitzer
+// falls allowed != 0 => test ob allowed/this_player() Hausbesitzer
+//                       oder Person mit Erlaubnis
+deprecated varargs int owner_check(mixed allowed)
+{
+  object test;
+
+  if(objectp(allowed) && query_once_interactive(allowed))
+  {
+    // Parameter ist Spieler
+    test = allowed;
+  }
+  else
+  {
+    // ansonsten TP
+    test = this_player();
+  }
+  
+  if(allowed)
+  {
+    // Test auf Hausbesitzer oder Person mit Erlaubnis
+    if(!allowed_check(test))
+    {
+      notify_fail( "Das darfst Du in diesem Haus nicht!\n" );
+      return 0;
+    }
+  }
+  else if(getuid(test) != owner)
+  {
+    // Test auf Hausbesitzer
+    notify_fail( "Das ist nicht Dein Haus!\n" );
+    return 0;
+  }
+  // Erlaubnis OK
+  return 1;
+}
+
+// Gestaltet Meldung aus Texten in einem Array:
+// array leer               -> melde Text in none
+// array hat ein Element    -> melde Text in one und ersetze %s durch Element
+// array hat viele Elemente -> melde Text in many und danach
+//                             sortierte Aufzaehlung der Elemente
+// flag gesetztes Bit 2: Aufzaehlung nur mit Komma, kein 'und'
+// flag gesetztes Bit 1: Meldung wird als String returnt, sonst per write ausgegeben
+varargs string arr_out(mixed array, string none, string one, string many, int flag)
+{
+  string tmp, lastsep;
+  mixed arr;
+
+  switch(sizeof(array))
+  {
+    case 0:
+      tmp = none;
+      break;
+    case 1:
+      tmp = sprintf(one, array[0]);
+      break;
+    default:
+      tmp = many;
+      arr = sort_array(array, #'> /*'*/);
+      lastsep = (flag & 2) ? ", " : " und ";
+      tmp += CountUp(arr, ", ", lastsep)+".";
+      break;
+  }
+  if (flag & 1)
+    return(break_string(tmp, 75, 0, 1));
+  else
+    write(break_string(tmp, 75, 0, 1));
+
+  return 0;
+}
+
+protected void create()
+{
+  if (!clonep(this_object()) && object_name(this_object())==(RAUM)) {
+      set_next_reset(-1);
+      return;
+  }
+  room::create();
+  usercmd::create();
+  losa::create();
+
+  Set(P_INT_LONG, SAVE, F_MODE_AS);
+  Set(P_INT_SHORT, SAVE, F_MODE_AS);
+  Set(P_EXITS, SAVE, F_MODE_AS);
+  Set(P_DETAILS, SAVE, F_MODE_AS);
+  Set(P_READ_DETAILS, SAVE, F_MODE_AS);
+  Set(P_LIGHT, SAVE, F_MODE_AS);
+
+  SetProp(P_IDS, ({"raum","sehe\rhaus"}));
+  SetProp(P_NAME, "Haus");
+  SetProp(P_GENDER, 0);
+  SetProp(P_TRANSPARENT, 0);
+  SetProp(P_NOGET, 1);
+  SetProp(P_LIGHT, 1);
+  SetProp(P_INDOORS, 1);
+
+  AddCmd( ({ "beschreib", "beschreibe" }), "beschreiben" );
+  AddCmd("uebersicht", "uebersicht");
+  AddCmd("ausgang", "ausgang");
+  AddCmd( ({"loesche", "loesch"}), "loesch");
+  AddCmd( ({"wirf", "werf", "werfe" }), "wirf");
+  AddCmd( ({"sperr", "sperre"}), "sperren");
+  AddCmd( ({"kopier", "kopiere" }), "kopieren");
+  AddCmd("licht", "licht");
+  AddCmd( ({"aendere", "aender" }), "aendern");
+  AddCmd( ({"meldung", "meldungen"}), "report");
+}
+
+void init()
+{
+	object haus;
+  
+  room::init();
+  nedit::init_rescue();
+
+  // Magier betritt fremdes Seherhaus
+  if (query_once_interactive(PL) && IS_LEARNER(PL) && getuid(PL) != owner) {
+    if (PL->QueryProp(P_INVIS))
+      // Magier invis => im Raum melden
+      tell_room(this_object(),
+          capitalize(getuid(PL))+" betritt unsichtbar den Raum.\n",
+          ({PL}));
+
+    if ((haus = load_object(HAUSNAME(owner))) &&
+        (haus->QueryProp(H_DOORSTAT) & D_LOCKED))
+      // Tuer ist zu => Magier einen Hinweis geben
+      tell_object(PL, " ******* ACHTUNG *********************************\n *\n * "+
+        capitalize(owner)+" moechte vielleicht ungestoert bleiben!\n *\n"
+        " ******* ACHTUNG *********************************\n");
+  }
+}
+  
+int PreventInsertLiving(object ob)
+{  
+  return 0;
+}
+
+// Gegenstaende kommen in den Raum
+void NotifyInsert(object ob, object oldenv)
+{
+	object *found;
+
+	if (!objectp(ob)) return;
+	
+	if (ob->QueryProp(H_FURNITURE)!=0)
+	{ 
+    // das was reinkam ist ein autoload Moebelstueck
+    // betrachte alle schon vorhandenen autoload Moebelstuecke
+      found = filter_objects(all_inventory(this_object()),
+		        "QueryProp", H_FURNITURE);
+	  if (sizeof(found)>=MAX_FURNITURE_PER_ROOM)        
+      {
+      // Maximal-Anzahl vorhandener autoload Seherhausmoebel ist schon
+      // erreicht
+	    tell_object(this_player(), break_string(
+	      "Ein Raum kann nur "+MAX_FURNITURE_PER_ROOM+" rebootfeste "
+	      "Moebel speichern. Hier befinden sich schon "+
+	      CountUp(map_objects(found, "name"))+"."));
+	    return 0;
+      }
+      
+      queued_save(); // Speichern vorbereiten (falls mehrere Objekte 
+                     // gedroppt werden, wird so ein overflow verhindert.
+	}
+}
+
+// Gegenstaende verlassen den Raum
+void NotifyLeave(object ob, object dest)
+{
+	if (!ob &&!objectp(ob)) return 0;
+	
+  // rebootfestes Moebelstueck verlaesst den Raum
+	if (ob->QueryProp(H_FURNITURE)!=0)
+	{	
+    // Speichern vorbereiten (falls mehrere Objekte 
+    // gedroppt werden, wird so ein overflow verhindert.
+		queued_save();
+	}
+	return 0;
+}
+
+void
+reset()
+{
+  room::reset();
+  losa::reset();
+  // Wenn ein Notausgang vorhanden ist, checken, ob der noch noetig ist.
+  if (member(m_indices(QueryProp(P_EXITS)),"notausgang")!=-1)
+  {
+      make_emergency_exit();
+  }
+}
+
+int clean_up(int arg)
+{
+  mixed inv;
+
+  if (arg > 1)
+    return 1;
+
+  losa::reset();  // Evtl. gepackt speichern...
+
+  // nichts im Raum oder nur leere Seherhaustruhe => Raum kann weg
+  if ((sizeof(inv=all_inventory()) == 0) ||
+      (sizeof(inv) == 1 && inv[0]->id(TRUHE) &&
+       sizeof(all_inventory(inv[0]))==0))
+    remove(1);
+
+  return 0;
+}
+
+// Haeufungen von gleichen Objekten sind hier egal => nix tun
+protected varargs void remove_multiple(int limit) {}
+
+
+// Spieler wird im Raum Netztot
+void BecomesNetDead(object pl)
+{
+//  Nicht erlaubte Spieler werden rausgeworfen, alle anderen bleiben drin.
+  if(!allowed_check(pl))
+    pl->move(VERWALTER->HausProp(owner, HP_ENV), M_GO, 0, "schlafwandelt heraus", "schlafwandelt herein" );
+}
+
+
+/* Ist dieser Raum ein Ausgang? */
+int is_exit(string path)
+{ 
+  return (sizeof(path) > 4) && (path[<5..] == "raum0");
+}
+
+/*Pruefung, ob es einen Hausausgang gibt*/
+int room_has_exit() {
+
+    string room = object_name(this_object());
+  // sind wir schon in einem Hauptraum mit Ausgang?
+    if (is_exit(room)) return 1;
+
+    mapping r_todo = ([room]);
+    mapping r_done = ([:0]);
+    /* Die Schleife hat maximal 9 * Anzahl der verb. Haeuser Durchlaeufe */
+    while (sizeof(r_todo))
+    {
+      mapping r_exits = ([]);
+
+      // naechsten Raumpfad abarbeiten, d.h. dessen Ausgaenge betrachten
+      room = m_indices(r_todo)[0];
+      // abgearbeiteten Raumpfad von r_todo nach r_done schieben
+      r_done += ([room]);
+      m_delete(r_todo, room);
+
+      // alle Ausgaenge betrachten
+      foreach(string command, string subpath : room->QueryProp(P_EXITS))
+      {
+        // Notausgaenge nicht betrachten, da 'echte' Ausgaenge gesucht sind
+        if(command != "notausgang")
+          // alle anderen Ausgaenge sammeln
+          r_exits += ([ subpath ]);
+      }
+      // nur Raumpfade die noch nicht abgearbeitet sind testen
+      r_exits -= r_done;
+      // ist da ein Hauptraum (der dann Ausgang liefert) dabei?
+      if (sizeof(filter_indices(r_exits, #'is_exit/*'*/)))
+        return 1;
+
+      // neue Raumpfade in die TODO-Liste aufnehmen
+      r_todo += r_exits;
+    }
+    return 0;
+}
+
+// damit man Spieler nicht durch Entfernen von Ausgaengen einsperren kann
+// werden bei Bedarf Notausgaenge in den Hauptraum ergaenzt
+void make_emergency_exit()
+{
+  // Ist der Raum weder Hauptraum mit Ausgang noch fuehrt ein Weg dorthin?
+  // dann Notausgang machen
+  if(!room_has_exit())
+  {
+    // tell_room(this_object(),"DEBUG: Ein Notausgang wurde angelegt.\n");
+    room::AddExit("notausgang",
+      "durch den Notausgang#"+to_string(this_object())[0..<2]+"0");
+  }
+  else
+  {
+    // nicht mehr benoetigten Notausgang entfernen
+    room::RemoveExit("notausgang");
+  }
+}
+
+// ruft direkt das geerbte AddExit auf, ohne ggf. einen Notausgang zu
+// erzeugen. Das wird vom Haus und vom Verwalter benutzt, um Ausgaenge zu
+// erzeugen. Das ist noetig, weil der Notausgangmechanismus noch nicht
+// funktoniert, wenn der Raum gerade geladen wird (hat noch nicht den
+// endgueltigen Namen) und der Check waere ohnehin unnoetig.
+public void AddExitNoCheck(mixed cmd, mixed dest)
+{
+  room::AddExit(cmd, dest);
+}
+
+// Wird benutzt beim Laden von Raeumen, um alle Ausgaenge zu loeschen. Dabei
+// darf _kein_ Notausgang erstellt werden.
+void RemoveExitNoCheck(mixed cmd)
+{
+  room::RemoveExit(cmd);
+}
+
+// beim Ausgang setzten testen ob vorhanderner Notausgang noch benoetigt wird
+void AddExit(mixed cmd, mixed dest)
+{
+  room::AddExit(cmd, dest);
+
+  if (member(m_indices(QueryProp(P_EXITS)),"notausgang")!=-1)
+  {
+    // loescht Notausgang falls nicht mehr benoetigt
+     make_emergency_exit();
+  }
+}
+
+// beim Ausgang loeschen testen ob Notausgang benoetigt wird
+void RemoveExit(mixed cmd)
+{
+  room::RemoveExit(cmd);
+  // setzt Notausgang falls benoetigt
+  make_emergency_exit();
+}
+
+// der Langbeschreibung werden alle unsichtbaren Magier
+// (ausgenommen Seherhausbesitzer) in Klammern angefuegt
+varargs string int_long(mixed viewer, mixed viewpoint, int flags)
+{
+  string ret;
+  object *inv;
+  string *tmp;
+
+  ret = ::int_long(viewer, viewpoint, flags);
+
+  // nur was machen wenn der Betrachter im Raum ist
+  if (!ret || !objectp(viewer) || environment(viewer) != this_object())
+    return ret;
+
+  if(viewpoint == 0)
+    viewpoint = ({ viewer });
+  else if(!pointerp(viewpoint))
+    viewpoint = ({ viewpoint });
+
+  // alle Lebewesen ausser denen aus deren Sicht betrachtet wird
+  inv = filter(all_inventory(this_object()),#'interactive) - viewpoint;
+  foreach(object pl : inv)
+  {
+    // raussuchen wer ausser Seherhausbesitzer unsichtbar ist
+    if(pl && IS_LEARNER(pl) && pl->QueryProp(P_INVIS) && getuid(pl)!=owner)
+    {
+      // Name in Klammer sammeln
+      tmp += ({ "("+capitalize(getuid(pl))+")" });
+    }
+  }
+  return ret + break_string(CountUp(tmp), 78);
+}
+/*
+// TODO: Testen ob das hier nicht das Standard-Verhalten ist
+int lies(string str)
+{
+  string txt;
+
+  notify_fail("Was moechtest Du lesen?\n");
+  if (!str) return 0;
+
+  if (this_player()->CannotSee())
+    return 1;
+  if (txt = QueryProp(P_READ_DETAILS)[str]) {
+    this_player()->More(txt);
+    return 1;
+  }
+  return 0;
+}
+*/
+// Aktion Lebewesen oder Gegenstaende aus dem Haus werfen
+int wirf(string str)
+{
+  string wen, args;
+  object pl, target, *list, tp, to;
+
+  tp = this_player();
+  to = this_object();
+  args = tp->_unparsed_args(1);
+
+  // klappt nur vor Ort und mit der passenden Syntax
+  if ((environment(tp)!=to) ||
+      !args || args == "" ||
+      (sscanf(args,"%s raus",wen) != 1) )
+    return 0;
+  // Raum, in dem das Haus steht, ermitteln
+  target=find_object(VERWALTER->HausProp(owner, HP_ENV));
+  if (!target) {
+    notify_fail("Dieses Haus steht leider gerade in einem "
+                "Fehler im Raum-Zeit-Gefuege.\n");
+    return 0;
+  }
+  // Rauswerfen darf nur der Besitzer
+  if (!tp_owner_check()) {
+    notify_fail("Aber Du kannst doch niemanden aus dem Haus von "+capitalize(owner)+" werfen!\n");
+    return 0;
+  }
+  if (wen=="alle") {
+    // alle Lebewesen ausser tp (== Hausbesitzer)
+    list=filter(all_inventory(to),#'living)-({tp,0});//')
+    if (sizeof(list)==0) {
+      notify_fail("Aber Du bist doch allein in Deinem Haus!\n");
+      return 0;
+    }
+  } else if (wen == "alles") {
+    // alle Gegenstaende ausser Lebewesen und Moebel
+    // (Seherhaustruhe, Autoloader-Moebel oder Seherhaus-Moebel)
+    list = filter(all_inventory(to),
+                  function int(object ob)
+                  {
+                      return objectp(ob) &&
+                             !living(ob) &&
+                             !ob->id(TRUHE) &&
+                          // TODO Test auf nicht Seherhausmoebel von August
+                             strstr(load_name(ob),"/d/seher/haeuser/moebel/")
+                               == 0;
+                  } );
+
+    if (sizeof(list)==0) {
+      notify_fail("Aber hier ist nichts zum wegwerfen!\n");
+      return 0;
+    }
+  } else {
+    pl=present(wen,to);
+    if (!pl) {
+      notify_fail("So jemanden sehe ich hier nicht.\n");
+      return 0;
+    }
+    else if (pl->id(TRUHE) ||
+             // TODO Test auf Seherhausmoebel von August
+              strstr(load_name(pl),"/d/seher/haeuser/moebel/")==0
+             ) {
+      notify_fail("Du kannst "+pl->name(WEN)+" nicht wegwerfen!\n" );
+      return 0;
+    }
+    list=({pl});
+  }
+  string msg_wen = sprintf("%s wirft Dich aus %s Haus.\n",
+                           tp->Name(WER),
+                           tp->QueryPossPronoun(NEUTER,WEM));
+  // fuer alle rauszuwerfenden Opfer Meldungen machen und rausbewegen
+  foreach(object ob : list)
+  {
+    tell_object(ob, msg_wen);
+    tell_room(target,
+        sprintf("%s kommt in hohem Bogen aus dem Haus von %s geflogen.\n",
+                 ob->Name(WER),tp->name(WEM)));
+    ob->move(target,M_SILENT|M_GO);
+    tell_room(to,sprintf("%s wirft %s aus %s Haus.\n",
+                    tp->Name(WER),
+                    ob->name(WEN),tp->QueryPossPronoun(NEUTER,WEM)),
+              ({tp}));
+    printf("Du wirfst %s aus Deinem Haus.\n",ob->name(WEN));
+    // Verfolger abmelden, damit sie nicht gleich zurueckkommen
+    // TODO wenn man einzelne Lebewesen rauswirft kann das ja auch
+    // ein Verfolger von einem anderen Gast sein...
+    tp->RemovePursuer(ob);
+  }
+  return 1;
+}
+
+// Besitzer und Raumnummer fuer diesen Raum setzen
+varargs string SetOwner(string o, int num)
+{
+  // Default Kurz- und Langbeschreibung setzen
+  SetProp(P_INT_SHORT, "Im Haus von "+capitalize(o));
+  SetProp(P_INT_LONG, "Ein total leerer Raum.\n");
+  // Raumnummer und Besitzer merken
+  raumNr = num;
+  return owner = o;
+}
+
+// Liefert den Besitzer
+// falls withNr != 0 mit angehaengter Raumnummer
+varargs string QueryOwner(int withNr)
+{
+  return (withNr ? owner+raumNr : owner);
+}
+
+// Prototype
+static int befEingabe(string *bef);
+
+// Aktion zum Beschreiben des Raumes
+varargs int
+beschreiben(string str, int f)
+{
+  string *parts;
+  int sp, ret;
+
+  // nur der Besitzer darf
+  if(!tp_owner_check())
+    return 0;
+
+  if (!f && (!(str=UP_ARGS(this_player())) || str == "")) {
+    notify_fail("Was willst Du denn beschreiben?\n" );
+    return 0;
+  }
+
+  sp = sizeof(parts = old_explode(str, " "));
+  // je nachdem was beschrieben wird, setze detail und flag
+  // und starte damit Editor, bzw. behandle Befehle extra
+  detail = 0;
+  flag = f;
+
+  switch(parts[0][0..3]) {
+    case "raum":      // Lang- oder Kurzbeschreibung
+    case "haus":
+      if (sp == 1 || parts[1] == "lang")
+    flag |= LANG;
+      else if (parts[1] == "kurz")
+    flag |= KURZ;
+      printf("Bitte %sbeschreibung des %s eingeben.\n", (flag & LANG ? "Lang" : "Kurz"), (flag & AUSSEN ? "Hauses" : "Raumes") );
+      break;
+    case "deta":      // Details
+      if (sp==1) {
+    notify_fail("Welches Detail willst Du denn beschreiben?\n");
+    return 0;
+      }
+      flag |= DETAIL;
+      str = implode(parts[1..]," ");
+      write( "Bitte Beschreibung fuer '"+str+"' eingeben.\n");
+      break;
+    case "lesb":      // lesbare Details
+      notify_fail("Welches lesbare Detail willst Du denn beschreiben?\n");
+      if (sp == 1) return 0;
+      if (parts[1] == "details" || parts[1] == "detail") {
+    if (sp == 2) return 0;
+    str = implode(parts[2..]," ");
+      }
+      else
+    str = implode(parts[1..]," ");
+      flag |= RDETAIL;
+      write( "Bitte Beschreibung fuer '"+str+"' eingeben.\n");
+      break;
+    case "befe":      // Befehle
+      ret = 0;
+      if (sp == 1)
+    notify_fail("Welchen Befehl willst Du denn beschreiben?\n");
+      else
+    ret = befEingabe(brk(implode(parts[1..]," ")));
+      return ret;
+      break;
+    default:
+      notify_fail("Das kannst Du nicht beschreiben! Eine Liste der Dinge, die Du hier\n"
+         +"beschreiben kannst, erhaeltst Du mit 'hilfe beschreibe'.\n" );
+      return 0;
+      break;
+  }
+  detail = brk(str);
+  write( "(Beenden mit . oder **, Abbruch mit ~q)\n" );
+  nedit( "beschreibung" );
+  return 1;
+}
+
+// nedit von beschreibe xxx
+static void beschreibung(string str)
+{
+  if (!str) {
+    write("Nichts geaendert!\n");
+    return;
+  }
+
+  str = normstr(str);
+
+  if (flag & LANG)
+  {
+    // Langbeschreibung
+    if (sizeof(explode(str,"\n")) > 100
+        || sizeof(str) > 7800)
+    {
+      // ueber 100 Zeilen oder ueber 7800 Zeichen
+      write( "Das ist fuer eine Langbeschreibung zu lang!\n"
+             "Sorry, bitte denke Dir eine andere Langbeschreibung aus.\n" );
+      return;
+    }
+    if (flag & AUSSEN) {
+      // Langbeschreibung vom Haus
+      object haus;
+      haus = find_object(HAUSNAME(owner));
+      haus->SetProp(P_LONG, str);
+      haus->Save();
+    }
+    else
+      // Langbeschreibung von diesem Raum
+      SetProp(P_INT_LONG, str);
+  }
+  else if (flag & KURZ) {
+    // Kurzbeschreibung vom Raum
+    if (sizeof(old_explode(str,"\n")) > 1 || sizeof(old_explode(str,".")) > 2 || sizeof(str) > 75) {
+      write( "Das ist fuer eine Kurzbeschreibung zu lang!\nSorry, bitte denke Dir eine andere Kurzbeschreibung aus.\n" );
+      return;
+    }
+    else
+      // Vanion, 27.07.02, Bugfix
+      // Die Zeile buggte, wenn man "." oder "\n" oder "\n." oder sowas
+      // in str hat. (also z.B. bei "beschreibe raum kurz <return> .")
+      // SetProp(P_INT_SHORT, old_explode(old_explode(str,"\n")[0],".")[0]);
+      SetProp(P_INT_SHORT, explode(explode(str,"\n")[0],".")[0]);
+  }
+  else if (flag & DETAIL)
+    // Raum-Detail
+    AddDetail(detail, str);
+  else if (flag & RDETAIL)
+    // lesbares Raum-Detail
+    AddReadDetail(detail, str);
+  else {
+    write( "Huch! Unbekanntes Flag ("+flag+")... Sag mal "
+          + CountUp(MAINTAINER, ", ", " oder ")
+          + " Bescheid...\n");
+    return;
+  }
+
+  write("OK.\n");
+  Save();
+}
+
+// wird in beschreiben(str, int) 'beschreibe befehl' aufgerufen
+static int befEingabe(string *befehle)
+{
+  string* com = ({});
+
+  notify_fail("Kein Befehl zum Beschreiben uebrig... ;)\n");
+  foreach(string bef : befehle)
+  {
+    // schon vorhandener Befehl (ausser oeffnen/schlissen),
+    // Richtung ohne zugehoerigen Ausgang,
+    // oder Befehl enthaelt Leerzeichen 
+    if (!befCheck(bef))
+      write("Der Befehl '"+bef+"' kann nicht beschrieben werden!\n");
+    else
+      com += ({ bef });
+  }
+  if (!sizeof(com))
+    return 0;
+
+  arr_out(com, 0, "Zu beschreibender Befehl: %s",
+          "Zu beschreibende Befehle:\n");
+
+  write( "Bitte Parameter eingeben (evtl. durch Kommata getrennt).\n]");
+  input_to("getBefParam", 0, com);
+  return 1;
+}
+
+// input_to aus befEingabe(string) zu beschreibe befehl ...
+static void getBefParam(string param, string *bef)
+{
+  string txt = "Gib nun bitte den Text ein, der fuer diesen Befehl "
+      "ausgegeben werden soll.\n";
+
+  // Fuehrende und abschliessende Leerzeichen entfernen
+  if (param)
+    param = trim(param);
+
+  if (!param || param == "")
+    // kein Parameter, z.b. bei beschreibe befehl klopfe 
+    detail = ({ bef, "" });
+  else if (param == "@NF@" || param == "@nf@") {
+    // Parameter fuer notify fail zum Ersetzen von Wie bitte?
+    // z.B. bei beschreibe befehl druecke
+    // fuer danach Du kannst hier kein @PARA druecken, nur den Knopf!
+    detail = ({ bef, 1 });
+    txt = "Gib nun bitte den Text ein, der als Fehlermeldung "
+          "ausgegeben werden soll.\n@PARA dient dabei als Platzhalter fuer "
+          "die ungueltige Eingabe.\n";
+  }
+  else
+    // sonstige Parameter
+    // z.B. knopf, klingel bei beschreibe befehl druecke
+    detail = ({ bef }) + brk(lower_case(param));
+
+  printf(txt+"(Beenden mit . oder **, Abbruch mit ~q)\n");
+  nedit("getBefText");
+}
+
+// Prototype
+private string preparse(string str, string *invalid);
+
+// nedit fuer die Eingabe der Texte  (Fehlermeldung/Meldungen) fuer den Befehl
+static void getBefText(string text)
+{
+  string my, *txt, *warn;
+  mixed bef;
+
+  if (!text || text == "") {
+    write("** Abbruch! **\n");
+    detail = 0;
+    return;
+  }
+  // gemerktes Befehls-Array
+  bef = detail[0];
+
+  txt = old_explode(text, "@@\n");
+
+  warn = ({});
+
+  // Meldung an this_player() parsen und in warn falsche Platzhalter sammeln
+  my = preparse(txt[0], &warn);
+  string other = 0;
+  if (sizeof(txt) > 1)
+    // Meldung an andere parsen und in warn falsche Platzhalter sammeln
+    other = preparse(txt[1], &warn);
+
+  AddUserCmd(bef, (stringp(detail[1]) ? detail[1..] : ({ "@NF@" })), my, other);
+  Save();
+  arr_out(warn, "OK.", "WARNUNG! Ungueltiger Platzhalter: %s",
+               "WARNUNG! Ungueltige Platzhalter: ");
+
+  detail = 0;
+}
+
+// check, ob an Position pos in txt ein Buchstabe aus dem array choice steht
+// return 0 falls nicht, prefix + Position des Buchstabens in choice ansonsten
+// check_placeholder(({"R","S","M","N"}), 2, "WESSEN", "X"); -> X1
+string check_placeholder(string* choice, int pos, string txt, string prefix)
+{
+   int idx;
+    
+   if(sizeof(txt) < pos+1 ||
+      ((idx=member(choice, txt[pos..pos])) < 0))
+   {
+     return 0;
+   }
+   else
+   {
+     return prefix+to_string(idx);
+   }
+}
+
+// Dann drueckt @PWER den Knopf -> Dann drueckt @P0 den Knopf
+private string preparse(string str, string *invalid)
+{
+  string *txt;
+
+  txt = explode(str, "@");
+  // fuer jeden Textteil nach einem @
+  // suche Ersatz fuer den Begriff direkt nach dem @
+  // AN: wuerde es nicht theoretisch reichen, hier nur bis i>0
+  // runterzuzaehlen? Das erste Element des Arrays ist immer irrelevant, weil
+  // entweder Leerstring oder kein zu ersetzender Ausdruck.
+  for (int i=sizeof(txt)-1; i>=0; i--) {
+    int warn = 0;
+    string rpl = 0;
+    // falls Teil zu kurz nix ersetzen
+    if (sizeof(txt[i])<3)
+      continue;
+    // anhand der ersten Buchstaben, Ersatz bestimmen
+    // warn signalisiert, ob dies schiefging:
+    switch(txt[i][0..1]) {
+    case "WE":  // Name
+      // WER      -> W0
+      // WES(SEN) -> W1
+      // WEM      -> W2
+      // WEN      -> W3
+      rpl = check_placeholder(({"R","S","M","N"}), 2, txt[i], "W");  
+      warn = !rpl;
+      break;
+    case "PW":  // Personalpronomen
+      // PWER      -> P0
+      // PWES(SEN) -> P1
+      // PWEM      -> P2
+      // PWEN      -> P3
+      rpl = check_placeholder(({"R","S","M","N"}), 3, txt[i], "P");  
+      warn = !rpl;
+      break;
+    case "BN":  // Possessivpronomen
+    case "BM":
+    case "BF":
+      // BNSWER      -> B000  BMSWER      -> B010  BFSWER      -> B020
+      // BNSWES(SEN) -> B100  BMSWES(SEN) -> B110  BFSWES(SEN) -> B120
+      // BNSWEM      -> B200  BMSWEM      -> B210  BFSWEM      -> B220
+      // BNSWEN      -> B300  BMSWEN      -> B310  BFSWEN      -> B320
+      // 
+      // BNPWER      -> B001  BMPWER      -> B011  BFPWER      -> B021
+      // BNPWES(SEN) -> B101  BMPWES(SEN) -> B111  BFPWES(SEN) -> B121
+      // BNPWEM      -> B201  BMPWEM      -> B211  BFPWEM      -> B221
+      rpl = check_placeholder(({"R","S","M","N"}), 5, txt[i], "B");
+      warn = !rpl;
+      if(!warn)
+      {
+        rpl = check_placeholder(({"N","M","F"}), 1, txt[i], rpl);
+        warn = !rpl;
+        if(!warn)
+        {
+          rpl = check_placeholder(({"S","P"}), 2, txt[i], rpl);
+          warn = !rpl;
+        }
+      }
+      break;
+    case "PA":
+      // PARA -> F
+      // kein Ersatz, sondern Textteil hier direkt ersetzen:
+      if(sizeof(txt[i]) > 4)
+        txt[i] = "F"+txt[i][4..];
+      break;
+    default:
+      // kein Ersatz, nix aendern
+      warn = 0;
+      rpl = 0;
+    }
+
+    // falls Ersatz vorhanden, ersetze Pronomen durch ""+rpl und lasse den Rest t2[2] wie ist
+    if (rpl) {
+      string* t2;
+      warn = sizeof(t2 = regexplode(txt[i], "(WER|WESSEN|WEM|WEN)")) < 2;
+      if (!warn) {
+        t2[1] = rpl;
+        t2[0] = "";
+        txt[i] = implode(t2, "");
+      }
+    }
+    // falls es Probleme gab, diese merken
+    if (warn)
+      invalid += ({ "@"+old_explode(txt[i]," ")[0] });
+
+  } // for (i=sizeof(txt)-1; i>=0; i--)
+  // die eventuelle teilweise ersetzetn Teile wieder zusammenfuegen
+  return implode(txt, "@");
+}
+
+static void loesch_alles(string str)
+{
+  if (str == "ja" || str == "Ja") {
+    RemoveDetail(0);
+    RemoveReadDetail(0);
+    //SetProp(P_READ_DETAILS, ([]));
+    SetProp(H_COMMANDS, ([]));
+    write( "OK, alle Details, lesbaren Details und Befehle geloescht!\n" );
+    Save();
+  }
+  else
+    write( "Nichts geloescht!\n" );
+}
+
+static void loesch_etwas(string str, string prop)
+{
+  if (str == "ja" || str == "Ja") {
+    if ( prop == P_DETAILS )
+      RemoveDetail(0);
+    else if ( prop == P_READ_DETAILS )
+      RemoveReadDetail(0);
+    else
+      SetProp(prop, ([]));
+    write("OK.\n");
+    Save();
+  }
+  else
+    write( "Nichts geloescht!\n" );
+}
+
+int loesch(string str)
+{
+  string *s, *t, p, q;
+  int i, ret;
+  mapping com;
+
+  if (!tp_owner_check())
+    return 0;
+
+  if (!(str=UP_ARGS(this_player())) || str == "") {
+    notify_fail("Welches Detail oder welchen Befehl moechtest Du loeschen?\n");
+    return 0;
+  }
+
+  if (str == "alles") {
+    write( "Wirklich alles loeschen (ja/nein)?\n]");
+    input_to("loesch_alles");
+    return 1;
+  }
+
+  if(str=="meldungen") {
+    if(file_size(PATH+"rep/"+owner+".rep")>0) {
+      rm(PATH+"rep/"+owner+".rep");
+      write("Meldungen geloescht.\n");
+    }else{
+      write("Keine Meldungen gefunden.\n");
+    }
+    return 1;
+  }
+
+  s = brk(str);
+  s = ({ (t=old_explode(s[0], " "))[0] })+({ implode(t[1..]," ") })+s[1..];
+  ret = 1;
+  flag = 0;
+
+  switch(s[0]) {
+    case "detail":
+      s = s[1..];
+      flag |= DETAIL;
+      break;
+    case "lesbar":
+      flag |= RDETAIL;
+      s = s[1..];
+      break;
+    case "lesbares":
+    case "lesbare":
+      flag |= RDETAIL;
+      if (s[1][0..5] =="detail") {
+    s = ({ old_explode(s[1]," ")[<1] });
+    if (sizeof(s)>2)
+      s += s[2..];
+      }
+      else
+    s = s[1..];
+      break;
+    case "befehl":
+      s = s[1..];
+      break;
+    case "alle":
+      switch (s[1]) {
+      case "details":
+    q = "Details";
+    p = P_DETAILS;
+    break;
+      case "lesbaren details":
+    q = "lesbaren Details";
+    p = P_READ_DETAILS;
+    break;
+      case "befehle":
+    q = "Befehle";
+    p = H_COMMANDS;
+    break;
+      default:
+    write("Du kannst alle Befehle, alle Details und alle lesbaren Details loeschen!\n");
+    return 1;
+      }
+      printf("Wirklich alle %s loeschen (ja/nein)?\n]", q);
+      input_to("loesch_etwas", 0, p);
+      return 1;
+    default:
+      flag |= (DETAIL|RDETAIL);
+      ret = 0;  // Koennte auch ein Artikel in der Zeitung sein...
+      break;
+  }
+  for (i=sizeof(s)-1; i>=0; i--) {
+    if (!flag) {  // Befehl soll geloescht werden...
+      if (member(com=Query(H_COMMANDS), s[i])) {
+    com = m_copy_delete(com, s[i]);
+    write("Befehl '"+s[i]+"' wurde geloescht.\n");
+      }
+      else if (sizeof(t=old_explode(s[i], " ")) > 1 &&
+           member(com, t[0]) &&
+           member(com[t[0]], p=implode(t[1..], " "))) {
+    com[t[0]] = m_copy_delete(com[t[0]], p);
+    write("Befehl '"+s[i]+"' wurde geloescht.\n");
+      }
+      Set(H_COMMANDS, com);
+    }
+    else {
+      if (flag & DETAIL) {
+    if (!QueryProp(P_DETAILS)[s[i]])
+      notify_fail("Das Detail '"+s[i]+"' gibt es nicht.\n");
+    else {
+      RemoveDetail(s[i]);
+      write("Detail '"+s[i]+"' wurde geloescht.\n");
+      ret = 1;
+    }
+      }
+      if (flag & RDETAIL) {
+    if (!QueryProp(P_READ_DETAILS)[s[i]])
+      notify_fail("Das lesbare Detail '"+s[i]+"' gibt es nicht.\n");
+    else {
+      RemoveReadDetail(s[i]);
+      write("Lesbares Detail '"+s[i]+"' wurde geloescht.\n");
+      ret = 1;
+    }
+      }
+    }
+  }
+  Save();
+  return ret;
+}
+
+int ausgang(string str)
+{
+  int nr, maxNr, hin, zurueck;
+  string hier, da, ext;
+  closure hausProp;
+  mapping known_exits;
+
+  if (!tp_owner_check()) {
+    return 0;
+  }
+
+  hier = da = 0;
+  hausProp = symbol_function("HausProp",VERWALTER);
+
+  if (!(str=UP_ARGS(this_player())) ||
+      (sscanf(str, "%s %d", hier, nr) != 2 &&
+       sscanf(str, "%s %s %d",hier, ext, nr) != 3) ) {
+    notify_fail( "Syntax: ausgang <richtung> [name] <nr>\n" );
+    return 0;
+  }
+
+  if (ext) {
+    if (funcall(hausProp, ext, HP_ENV) != funcall(hausProp, owner, HP_ENV)) {
+      printf("Das Haus von %s steht nicht im gleichen Raum wie Dein Haus!\n",
+             capitalize(ext));
+      return 1;
+    }
+    else
+      da = RAUMNAME(ext, nr);
+
+    // der allowed_check() wird im Eingangsraum des Zielhauses aufgerufen,
+    // da wir von anderen Raumen noch nicht wissen, ob sie ueberhaupt
+    // existieren.
+    if (!(RAUMNAME(ext, 0)->allowed_check(this_player()))) {
+      printf("Du darfst keinen Ausgang von Deinem Haus zu dem von %s legen!\n",
+             capitalize(ext));
+      return 1;
+    }
+  }
+  else {
+    ext = owner;
+    da = RAUMNAME(ext, nr);
+  }
+
+  maxNr = funcall(hausProp, ext, HP_ROOMS);
+
+  if ( (hin = member(ausgaenge, lower_case(hier))) < 0) {
+    arr_out(ausgaenge, 0, 0, "Es sind nur folgende Ausgaenge moeglich:\n" );
+    return 1;
+  }
+  else
+    zurueck = (hin + sizeof(ausgaenge)/2) % sizeof(ausgaenge);
+
+  hier = RAUMNAME(owner, raumNr);
+
+  // Kopie des Ausgaenge-Mappings erzeugen
+  known_exits=deep_copy(QueryProp(P_EXITS));
+  // und den Notausgang entfernen. Somit bleiben nur die zu betrachtenden 
+  // Ausgaenge ueber.
+  known_exits["notausgang"]=0;
+
+  if (nr < 0 || nr > maxNr)
+    printf( "Die Nummer darf sich nur im Bereich zwischen 0 und %d bewegen!\n",
+            maxNr );
+  else if ( ext == owner && nr == raumNr)
+    printf( "Aber dies IST Raum %d!\n", raumNr );
+  else if (member(m_indices(known_exits), ausgaenge[hin]) != -1)
+    write( "Aus diesem Raum fuehrt schon ein Ausgang in diese Richtung!\n" );
+  //else if (member(m_values(QueryProp(P_EXITS)), da) != -1)
+  // Notausgang wird hier zwar geloescht, aber im AddExit
+  // gibt's eh einen neuen, so das noetig ist, V*
+  else if (member(m_values(known_exits), da) != -1)
+    printf( "Es gibt hier schon einen Ausgang zu Raum %d!\n", nr );
+  else if (member(m_indices(da->QueryProp(P_EXITS)), ausgaenge[zurueck]) != -1)
+    printf( "Es fuehrt schon irgendwo ein Ausgang in Richtung '%s'\n"
+            "nach Raum %d!\n", ausgaenge[hin], nr);
+  else {
+    AddExit( ausgaenge[hin], da );
+    Save();
+    da->AddExit(ausgaenge[zurueck], hier);
+    da->Save();
+    printf( "OK, der Ausgang '%s' zum Raum %d wurde eingerichtet.\n",
+            ausgaenge[hin], nr );
+  }
+  return 1;
+}
+
+int
+sperren(string str)
+{
+  mapping ex, cmds;
+  int hin, zurueck;
+
+  if (!tp_owner_check())
+    return 0;
+
+  if (!(str=UP_ARGS(this_player())) || str == "") {
+    notify_fail( "Syntax: sperre <ausgang>\n" );
+    return 0;
+  }
+  str = lower_case(str);
+  ex = QueryProp(P_EXITS);
+
+  if (raumNr == 0 && str == "raus") {
+    write( "Du kannst doch nicht Deine Haustuer loeschen!\n" );
+    return 1;
+  }
+  if (!member(ex,str) || (hin = member(ausgaenge,str)) < 0) {
+    printf( "Es gibt hier keinen Ausgang '%s'!\n", str);
+    return 1;
+  }
+  else
+    zurueck = (hin + sizeof(ausgaenge)/2) % sizeof(ausgaenge);
+
+  ex[str]->RemoveExit(ausgaenge[zurueck]);
+  tell_room(find_object(ex[str]), sprintf("Der Ausgang '%s' verschwindet ploetzlich...\n", ausgaenge[zurueck]));
+  cmds = ex[str]->QueryProp(H_COMMANDS);
+  cmds = m_copy_delete(cmds, ausgaenge[zurueck]);
+  ex[str]->SetProp(H_COMMANDS, cmds);
+  ex[str]->Save();
+  RemoveExit(str);
+  cmds = QueryProp(H_COMMANDS);
+  cmds = m_copy_delete(cmds, str);
+  SetProp(H_COMMANDS, cmds);
+  Save();
+  printf( "OK, der Ausgang '%s' wurde entfernt.\n", str );
+
+  Save();
+
+  return 1;
+}
+
+varargs int
+uebersicht(string dummy, string pre)
+{
+  string *xc, *xd, o, raus, str;
+  mixed *com;
+  mapping tmp;
+  int i,j,k;
+
+  if ( (getuid(this_player()) != owner) &&
+       !(PATH+"access_rights")->access_rights(geteuid(this_player()), "") )
+    return 0;
+
+  i = VERWALTER->HausProp(owner, HP_ROOMS);
+
+  if (i)
+    str = sprintf( "Dein Haus verfuegt ueber %d Raeume.\nDu stehst in Raum %d (%s).\n\n", i+1, raumNr, QueryProp(P_INT_SHORT) );
+  else
+    str = sprintf( "Dein Haus verfuegt ueber einen Raum (%s)\n\n", QueryProp(P_INT_SHORT));
+
+  str += arr_out(m_indices(QueryProp(P_DETAILS)),
+         "Du hast keine Details beschrieben.",
+         "Du hast das Detail '%s' beschrieben.",
+         "Du hast folgende Details beschrieben:\n", 1 );
+
+  str += ("\n" + arr_out(m_indices(QueryProp(P_READ_DETAILS)),
+         "Du hast keine lesbaren Details beschrieben.",
+         "Du hast das lesbare Detail '%s' beschrieben.",
+         "Du hast folgende lesbaren Details beschrieben:\n", 1 ) );
+
+  tmp = Query(H_COMMANDS);
+  xc = sort_array(m_indices(tmp),#'<);
+  if (!sizeof(xc))
+    str += ("\nDu hast keine Befehle beschrieben.\n");
+  else {
+    if (sizeof(xc) == 1 && sizeof(xd=m_indices(tmp[xc[0]])) == 1)
+      str += ("\nDu hast den Befehl '"+
+          xc[0]+((xd[0] == "") ? "" : " "+xd[0])+
+          "' beschrieben.\n");
+    else {
+      str += "\nDu hast folgende Befehle beschrieben:\n";
+
+      for (com = ({}), j=sizeof(xc)-1; j >= 0; j--) {
+    xd = sort_array(m_indices(tmp[xc[j]])-({"@NF@"}),#'>);
+    if ((sizeof(xd) > 1) && (xd[0] == "")) {
+      raus = "* "+xc[j]+", "+xc[j]+" ";
+      xd = xd[1..];
+    }
+    else
+      raus = "* "+xc[j]+" ";
+
+    str += arr_out(xd, "", raus+"%s", raus, 3);
+      }
+    }
+  }
+
+  raus = (member(QueryProp(P_EXITS),"raus") ? "raus: Nach draussen.\n" : 0 );
+  tmp = m_copy_delete(QueryProp(P_EXITS), "raus");
+  m_delete(tmp, "notausgang");
+  xc = m_indices(tmp);
+  xd = m_values(tmp);
+
+  if (!sizeof(xc) && !raus)
+    str += "\nES GIBT KEINE AUSGAENGE!\n";
+  else {
+    str +=  "\nEs gibt folgende Ausgaenge:\n";
+    for (i=sizeof(xc)-1; i>=0; i--)
+      str += sprintf( "%s: Nach Raum %d %s(%s).\n",
+             xc[i],
+             (j=to_int(xd[i][<1..])),
+             (((o=old_explode(xd[i],"/")[<1][0..<6])==owner) ?
+             "" : "von "+capitalize(o)+" "),
+             xd[i]->QueryProp(P_INT_SHORT) );
+  }
+  str += ((raus||"")+(pre||""));
+  this_player()->More(str);
+  return 1;
+}
+
+int kopieren(string str)
+{
+  string was, alt, n, *neu, *par, err;
+  mixed das;
+  mapping com;
+
+  if (!tp_owner_check())
+    return 0;
+
+  notify_fail("'kopiere detail <von> nach <nach>' oder\n"
+         +"'kopiere lesbares detail <von> nach <nach>' oder\n"
+         +"'kopiere befehl <befehl> [<parameter>] nach <befehl> [<parameter>]'!\n");
+
+  if (!(str=UP_ARGS(this_player())) || str == "")
+    return 0;
+
+  neu = old_explode(str, " ");
+  was = neu[0][0..5];
+  if (was == "detail" || was == "befehl")
+    str = implode(neu[1..], " ");
+  else if (was == "lesbar")
+    str = implode(neu[2..], " ");
+  else
+    return 0;
+
+  if (sscanf(str, "%s nach %s", alt, n) != 2)
+    return 0;
+
+  neu = brk(n);
+  switch(was) {
+    case "detail":
+      err = "Detail";
+      if (das = GetDetail(alt)) {
+    AddDetail(neu, das);
+    Save();
+      }
+      break;
+    case "lesbar":
+      err = "lesbares Detail";
+      if (das = QueryProp(P_READ_DETAILS)[alt]) {
+    AddReadDetail(neu, das);
+    Save();
+      }
+      break;
+    case "befehl":
+      err = "Befehl";
+      was = (par=old_explode(alt, " "))[0];
+      if (member(com=QueryProp(H_COMMANDS),was)) {
+    int i;
+    if (sizeof(par) == 1) { // <bef> nach <bef1,bef2,...>
+      das = com[was];
+      for (i=sizeof(neu)-1; i>=0; i--) {
+        if (befCheck(neu[i])) {
+          if (com[neu[i]])
+        com[neu[i]] += das;
+          else
+        com += ([ neu[i] : das ]);
+        }
+        else
+          write("Ungueltiger Befehl: '"+neu[i]+"'.\n");
+      }
+    }
+    else {        // <bef> <parameter> nach <bef1,bef2,...>
+      alt = implode(par[1..]-({""})," ");
+      if (das = com[was][alt]) {
+        for (i=sizeof(neu)-1; i>=0; i--) {
+          if (befCheck(neu[i])) {
+        das = ([ alt : com[was][alt];com[was][alt,1] ]);
+        if (com[neu[i]])
+          com[neu[i]] += das;
+        else
+          com += ([ neu[i] : das ]);
+          }
+          else {
+        par = old_explode(neu[i], " ");
+        n = par[0];
+        if (befCheck(n)) {
+          das = ([ implode(par[1..], " ") : com[was][alt];com[was][alt,1] ]);
+          if (com[n])
+            com[n] += das;
+          else
+            com += ([ n : das ]);
+        }
+        else
+          write("Ungueltiger Befehl: '"+neu[i]+"'.\n");
+          }
+        }
+      }
+    }
+    Save();
+      }
+      break;
+    default:
+      write( "Du kannst nur Details, lesbare Details und Befehle kopieren!\n" );
+      return 1;
+  }
+  if (!das)
+    printf( "Kann %s '%s' nicht finden!\n", err, alt);
+  else
+    write( "OK!\n" );
+
+  return 1;
+}
+
+int licht(string str)
+{
+  int ll, tl;
+
+  if (!allowed_check(this_player()))
+    return 0;
+
+  if (!str || (str != "an" && str != "aus")) {
+    notify_fail("Syntax: 'licht an' oder 'licht aus'\n");
+    return 0;
+  }
+
+  ll = QueryProp(P_LIGHT);
+  tl = PL->QueryProp(P_PLAYER_LIGHT);
+
+  switch(str) {
+  case "an":
+    if (tl > 0)
+      write("Aber es ist doch schon hell!\n");
+    else {
+      SetProp(P_LIGHT, 1);
+      tell_room(this_object(), "Es wird wieder hell.\n");
+    }
+    break;
+  case "aus":
+    if (tl <= 0)
+      write("Aber es ist doch schon dunkel!\n");
+    else {
+      SetProp(P_LIGHT, 0);
+      tell_room(this_object(), "Es wird dunkel.\n");
+    }
+    break;
+  }
+  return 1;
+}
+
+#define CASUS ({ "WER", "WESSEN", "WEM", "WEN" })
+static string rpXchg(string s)
+{
+  int c,p,g;
+
+  switch(s[0..1]) {
+    case "@W":
+      c = to_int(s[2..2]);
+      return ("@"+CASUS[c]);
+    case "@P":
+      c = to_int(s[2..2]);
+      return ("@P"+CASUS[c]);
+    case "@B":
+      c = to_int(s[2..2]);
+      g = to_int(s[3..3]);
+      p = to_int(s[4..4]);
+      return ("@B"+({"N", "M", "F"})[g]+({"S", "P"})[p]+CASUS[c]);
+    case "@F":
+      return "@PARA";
+  }
+  return s;
+}
+
+private string reParse(string s1, string s2)
+{
+  string *p;
+
+  if (s2)
+    s1 = s1+"@@\n"+s2;
+
+  p = regexplode(s1, "(@W[0-3]|@P[0-3]|@B[0-3][0-2][0-1])");
+  p = map(p, #'rpXchg);
+  return implode(p, "");
+}
+
+private string getPreText(string prop, string expr)
+{
+  mixed crunched;
+  int i;
+
+  crunched = VERWALTER->PCrunch(QueryProp(prop));
+  if (!crunched || !pointerp(crunched))
+    return 0;
+
+  if (prop == H_COMMANDS && strstr(expr, " ") < 0)
+    expr = expr+" ";
+
+  for (i=sizeof(crunched)-1; i>=0; i--)
+    if (member(crunched[i][0], expr) >= 0)
+      break;
+
+  if (i<0)
+    return 0;
+
+  detail = crunched[i][0];
+
+  if (prop == H_COMMANDS)
+    return reParse(crunched[i][1], crunched[i][2]);
+  else
+    return crunched[i][1];
+}
+
+varargs int
+aendern(string str, int f)
+{
+  string *parts, pre;
+  int sp, sr, ret;
+
+  if (!tp_owner_check())
+    return 0;
+
+  if (!f && (!(str=UP_ARGS(this_player())) || str == "")) {
+    notify_fail("Was willst Du denn aendern?\n" );
+    return 0;
+  }
+
+  sp = sizeof(parts = old_explode(str, " "));
+  sr = sizeof(brk(str));
+  detail = 0;
+  flag = f;
+
+  switch(parts[0][0..3]) {
+    case "raum":      // Lang- oder Kurzbeschreibung
+    case "haus":
+      if (sp == 1 || parts[1] == "lang")
+    flag |= LANG;
+      else if (parts[1] == "kurz") {
+    write("Nimm dazu doch bitte 'beschreibe'!\n");
+    return 1;
+      }
+      pre = ((flag & AUSSEN) ? (find_object(HAUSNAME(owner)))->QueryProp(P_LONG) : QueryProp(P_INT_LONG));
+      break;
+    case "meld":
+      if (file_size(REPFILE(owner)) > 0)
+    pre = read_file(REPFILE(owner));
+      else {
+    write("Ich finde keine Meldungen aus Deinem Haus!\n");
+    return 1;
+      }
+      flag |= REPORT;
+      break;
+    case "deta":      // Details
+      if (sp==1) {
+    notify_fail("Welches Detail willst Du denn aendern?\n");
+    return 0;
+      }
+      if (sr>1) {
+    notify_fail("Du kannst immer nur ein Detail aendern!\n");
+    return 0;
+      }
+      flag |= DETAIL;
+      pre = getPreText(P_DETAILS, implode(parts[1..], " "));
+      break;
+    case "lesb":      // lesbare Details
+      notify_fail("Welches lesbare Detail willst Du denn aendern?\n");
+      if (sp == 1) return 0;
+      if ((parts[1] == "details" || parts[1] == "detail") && (sp==2))
+    return 0;
+      if (sr>1) {
+    notify_fail("Du kannst immer nur ein lesbares Detail aendern!\n");
+    return 0;
+      }
+      flag |= RDETAIL;
+      pre = getPreText(P_READ_DETAILS, implode(parts[1..], " "));
+      break;
+    case "befe":      // Befehle
+      ret = 0;
+      if (sp == 1) {
+    notify_fail("Welchen Befehl willst Du denn aendern?\n");
+    return 0;
+      }
+      if (sr>1) {
+    notify_fail("Du kannst immer nur einen Befehl aendern!\n");
+    return 0;
+      }
+      flag |= BEFEHL;
+      pre = getPreText(H_COMMANDS, implode(parts[1..], " "));
+      break;
+    default:
+      notify_fail("Das kannst Du nicht aendern! Eine Liste der Dinge, die Du hier aendern\n"
+         +"kannst, erhaeltst Du mit 'hilfe aendere'.\n" );
+      return 0;
+      break;
+  }
+  if (!pre)
+    write("Hm, sowas ist hier noch nicht beschrieben...\n");
+  else {
+    write( "Aendere nun den Text.\n(Beenden mit . oder **, Abbruch mit ~q, Hilfe mit ~h)\n" );
+    nedit( "aenderung", pre );
+  }
+  return 1;
+}
+
+void aenderung(string str)
+{
+  string *warn;
+
+  if (!str) {
+    write("Nichts geaendert!\n");
+    return;
+  }
+
+  if (flag && !(flag & BEFEHL))
+    str = normstr(str);
+
+  warn = ({ });
+
+  if (flag & LANG) {
+    if (flag & AUSSEN) {
+      object haus;
+      haus = find_object(HAUSNAME(owner));
+      haus->SetProp(P_LONG, str);
+      haus->Save();
+    }
+    else
+      SetProp(P_INT_LONG, str);
+  }
+  else if (flag & DETAIL) {
+    if (str == "")
+      RemoveDetail(detail);
+    else
+      AddDetail(detail, str);
+  }
+  else if (flag & RDETAIL) {
+    if (str == "")
+      RemoveReadDetail(detail);
+    else
+      AddReadDetail(detail, str);
+  }
+  else if (flag & BEFEHL) {
+    if (str == "")
+      RemUserCmd(detail);
+    else {
+      string *s;
+
+      s = old_explode(preparse(str, &warn), "@@\n");
+      if (sizeof(s) > 1 && s[1] != "")
+    AddUserCmd(detail, 0, normstr(s[0]), normstr(s[1]));
+      else
+    AddUserCmd(detail, 0, normstr(s[0]), 0);
+    }
+  }
+  else if (flag & REPORT) {
+    rm(REPFILE(owner));
+    if (str != "")
+      write_file(REPFILE(owner), str);
+  }
+  else
+    write( "Huch! Unbekanntes Flag ("+flag+")... Sag mal Wargon Bescheid...\n");
+
+  arr_out(warn, "OK.", "WARNUNG! Ungueltiger Platzhalter: %s",
+               "WARNUNG! Ungueltige Platzhalter: ");
+  Save();
+}
+
+int SmartLog(string ofile, string typ, string msg, string date)
+{
+  object home;
+
+  // speichere Meldung im Rep-Log des Seherhaus-Besitzers
+  write_file(REPFILE(owner), sprintf("%s von %s in Raum %d (%s):\n%s\n",
+                     typ,
+                     capitalize(getuid(this_player())),
+                     raumNr,
+                     date,
+                     break_string(msg,78)));
+
+  if (IS_LEARNER(owner)) {
+    log_file("report/"+owner+".rep",
+         sprintf("MELDUNG von %s im Seherhaus, Raum %d (%s):\n"
+             +"Bitte zur Kenntnis nehmen! (Mit dem Befehl 'meldungen')  -Wargon\n",
+             capitalize(getuid(this_player())),
+             raumNr,
+             date));
+  }
+
+  // erhoehe im Hauptraum den Rep-Zaehler und speichere
+  home = load_object(RAUMNAME(owner,0));
+  home->Set(H_REPORT, home->Query(H_REPORT)+1);
+  home->Save();
+
+  return 1;
+}
+
+static int report(string str)
+{
+  string rep, *lines;
+  int rNum, l, s;
+
+  if (!allowed_check(this_player()))
+    return 0;
+
+  if (file_size(REPFILE(owner)) <= 0) {
+    write( "Keine Meldungen zu finden... Du bist wunschlos gluecklich.\n" );
+    return 1;
+  }
+  rep = read_file(REPFILE(owner));
+
+  if (!rep) {
+    write( "Oha! Die Datei mit den Meldungen ist zu gross! Sag doch bitte mal\n"
+      +"Wargon Bescheid!\n");
+    return 1;
+  }
+
+  if (str) {
+    string d, *new, *tmp, prev;
+    int nr, nextNr, m;
+
+    if (str == "hier")
+      rNum = raumNr;
+    else
+      rNum = to_int(str);
+
+    if (rNum > VERWALTER->HausProp(owner, HP_ROOMS)) {
+      write( "So viele Raeume hast Du gar nicht!\n");
+      return 1;
+    }
+
+    lines = old_explode(rep, "\n");
+    s = sizeof(lines);
+    for (l=0; prev == 0; l++)
+      if (sscanf(lines[l], "%s von %s in Raum %d %s:", d, d, nr, d)==4)
+    prev=lines[l];
+
+    for ( new = ({}), tmp=({}); l<s; l++) {
+      m=sscanf(lines[l], "%s von %s in Raum %d %s:", d, d, nextNr, d);
+      if (m != 4 && nr == rNum)
+    tmp += ({ lines[l] });
+
+      if (m==4) {
+    if (sizeof(tmp)) {
+      new = new + ({ prev }) + tmp;
+      tmp = ({});
+    }
+    nr = nextNr;
+    prev = lines[l];
+      }
+    }
+    if (sizeof(tmp))
+      new = new + ({prev}) + tmp;
+    rep = implode(new, "\n");
+  }
+
+  this_player()->More(rep);
+  return 1;
+}
+
+// $Log: raum.c,v $
+// Revision 1.5  2003/11/15 14:03:58  mud
+// Lichtaenderungen von Zook
+//
+// Revision 1.4  2003/02/17 20:00:00  mud
+// Im Reset wird nun getestet, ob der Raum einen Ausgang in einen Null-Raum
+// hat. Dies wurde notwengig, damit Spieler nicht in Seherhaeuser eingesperrt 
+// werden koennen. Die Funktionen AddExit(), RemoveExit() und Reset starten 
+// gegebenenfalls den Ausgangstest. Einige Funs mussten leicht angepasst 
+// werden.
+// Die Funktionen room_has_exit() und is_exit() wurden von Vardion@MG 
+// entwickelt und zur Verfuegung gestellt. - Vanion
+//
+// Revision 1.3  2001/02/04 21:21:34  mud
+// (brk,getBefParam): Vorkehrungen gegen fuehrende und schliessende
+// Leerzeichen in Befehlsparametern und anderen Listen.
+//
+// Revision 1.2  2001/01/01 18:17:47  mud
+// (ausgang): Wenn ein Ausgang zu einem anderen Seherhaus gelegt wird,
+// wird die Erlaubnis in dessen Eingangsraum abgefragt, und nicht in
+// dem angeforderten Zielraum (der Eingangsraum existiert auf jeden
+// Fall, der Zielraum vielleicht nicht).
+//
+// Revision 1.1.1.1  2000/08/20 20:22:42  mud
+// Ins CVS eingecheckt
+//
+// 04.02.98 Meldungen koennen geloescht werden.
+//
+// Revision 2.16  1997/11/15 19:33:23  Wargon
+// arr_out(), preparse(): kleine Bugfixes
+//
+// Revision 2.15  1997/10/06 15:24:38  Wargon
+// Unsichtbare Magier melden/anzeigen
+// Meldung beim Betreten abgeschlossener Haeuser fuer Magier
+//
+// Revision 2.14  1996/02/21  18:12:47  Wargon
+// SmartLog() rein, dafuer die eigenen Rueckmeldungsbefehle raus
+//
+// Revision 2.13  1995/10/31  12:56:16  Wargon
+// Rueckmeldungen fuer Objekte werden ans Spielerobjekt weitergegeben.
+//
+// Revision 2.12  1995/08/07  18:35:12  Wargon
+// Einige Bugs bei "aendere" behoben.
+//
+// Revision 2.11  1995/06/29  08:57:05  Wargon
+// Hausbesitzer, die schon Magier sind, bekommen bei Rueckmeldungen auch einen
+// Eintrag in ihr /log/report/xyz.rep-File
+// "licht an/aus" ist seit 2.9 drin ;)
+//
+// Revision 2.10  1995/06/28  08:59:57  Wargon
+// Neue Befehle aendere, meldungen fuer den Hausbesitzer.
+// typo, bug/fehler, idee werden dem Haus-.rep-File zugefuehrt.
+// Jetzt koennen die Seher ihre Typos selber fixen! ;^)
+//
+// Revision 2.9  1995/06/20  07:49:15  Wargon
+// *** empty log message ***
+//
+// Revision 2.8  1995/04/21  10:48:39  Wargon
+// Bugfix in beschreiben(), wenn die Hausaussenbeschreibung
+// verlangt wird (war schon seit Ewigkeiten buggy... ;)
+//
+// Revision 2.7  1995/04/21  08:55:32  Wargon
+// Load()/Save() und eigene Kommandos ausgelagert.
+// Kommandos koennen mit notify_fail() versehen werden.
+//
+// Revision 2.6  1995/03/07  13:55:36  Wargon
+// Add/RemUserCmd(), Beschreibungen werden bei reset()/clean_up()
+// gepackt gespeichert.
+// Bei Kommandos nur noch more(), wenn es auch noetig ist.
+//
+// Revision 2.5  1995/02/27  20:48:26  Wargon
+// Kleine Schoenheitsfehler in selbstdefinierten Befehlen beseitigt.
+//
+// Revision 2.4  1995/02/22  21:30:52  Wargon
+// Noch mehr Aenderungen an den Befehlen:
+// - Preparsing der Platzhalter
+// - Platzhalter fuer Possessivpronomen
+// - Meldung fuer Ausfuehrenden wird geMore()t
+// - Rassen- und Geschlechtespezifische Meldungen moeglich
+// - Auch fuer Ausgaenge koennen Befehle definiert werden
+//   (nur fuer existierende; wird der Ausgang gesperrt, wird auch
+//   der Befehl geloescht)
+// Im Zuge des Preparsings hat sich die Befehlauswertung etwas
+// vereinfacht.
+//
+// Revision 2.3  1995/02/20  22:15:44  Wargon
+// READ_DETAILS werden jetzt mit More() ausgegeben.
+// Selbstdefinierte Befehle: mit @PWER, ... koennen die Personalpronomina
+// eingebaut werden; Einbau jetzt auch in die Meldung fuer den Ausloeser
+// moeglich; _unparsed_args() in der Auswertung.
+//
+// Revision 2.2  1995/02/15  11:23:04  Wargon
+// NEU: Selbstdefinierbare Befehle.
+//
+// Revision 2.1  1995/02/04  15:02:36  Wargon
+// Die Truhe wird nun ueber die Property CHEST verwaltet. Der AddItem()-
+// Aufruf wurde deshalb von create() nach Load() verlegt. Geladen wird
+// sie nur, wenn das Load() von Hausverwalter erfolgte.
+// clean_up(), wenn Raum leer ist oder nur eine leere Truhe drin steht.
+//
+// Revision 2.0  1995/02/01  20:36:49  Wargon
+// Entruempelt und Massnahmen fuer _unparse_args() getroffen.
+