Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/std/player/base.c b/std/player/base.c
new file mode 100644
index 0000000..9c9a6e1
--- /dev/null
+++ b/std/player/base.c
@@ -0,0 +1,4355 @@
+// MorgenGrauen MUDlib
+//
+// player/base.c -- the basic player object
+//
+// $Id: base.c 9467 2016-02-19 19:48:24Z Zesstra $
+#pragma strong_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <sys_debug.h>
+#include <regexp.h>
+#include <input_to.h>
+#include <logging.h>
+#include <werliste.h>
+#include <time.h>
+#include <errord.h>
+#include <wizlevels.h>
+#include <money.h>
+
+inherit "/std/hook_provider";
+inherit "/std/player/restrictions";
+inherit "/std/living/attributes";
+inherit "/std/living/put_and_get";
+inherit "/std/living/clothing";
+inherit "/std/thing/properties";
+inherit "/std/player/util";
+inherit "/std/thing/language";
+inherit "/std/player/travel";
+inherit "/std/player/combat";
+inherit "/std/player/description";
+inherit "/std/player/moving";
+inherit "/std/player/life";
+inherit "/std/player/comm";
+inherit "/std/player/viewcmd";
+inherit "/std/player/moneyhandler";
+inherit "/std/player/command";
+inherit "/std/living/skill_attributes";
+inherit "/std/living/light";
+inherit "/std/player/skills";
+inherit "/std/player/quests";
+inherit "/std/player/potion";
+inherit "/std/player/soul";
+inherit "/std/more";
+inherit "/std/user_filter";
+inherit "/secure/telnetneg";
+inherit "/std/player/guide";
+inherit "/std/player/reputation";
+inherit "/std/player/protocols/gmcp";
+inherit "/std/living/helpers";
+
+#define NEED_PROTOTYPES
+#include <player/skills.h>
+#include <player/gmcp.h>
+#undef NEED_PROTOTYPES
+#include <player.h>
+#include <properties.h>
+#include <udp.h>
+#include <config.h>
+#include <ansi.h>
+#include <wizlevels.h>
+#include <living.h>
+#include <attributes.h>
+#include <language.h>
+#include <moving.h>
+#include <defines.h>
+#include <terminal.h>
+#include <new_skills.h>
+#include <pager.h>
+#include <combat.h>
+#include "/secure/questmaster.h"
+#include "/secure/lepmaster.h"
+#include <events.h>
+
+#undef NAME /* DEFINED BY UDP.H; BAD NAME CLASH :( */
+#define NAME(who) capitalize(getuid(who))
+
+mapping autoload;           /* autoload-mapping */
+int hc_play;
+
+private nosave mapping autoload_rest;
+private nosave string  *autoload_error;
+private nosave string realip; 
+
+private nosave string passw;        /* temporarily for password change */
+private nosave string passwold;     /* temporarily for password change */
+
+// HB-Zaehler. Wenn 0 erreicht wird, wird  ein Telnet TM Paket als Keep-Alive
+// an den Client gesendet und der Counter wieder auf hochgesetzt. 
+// Wenn == 0, ist das Keep-Alive abgeschaltet.
+private int telnet_tm_counter;
+
+nosave string default_home; /* Where to move us if we dont have a home set */
+
+nosave int ndead_lasttime;
+nosave mixed ndead_location;
+nosave string ndead_l_filename;
+nosave int ndead_currently;
+nosave int ndead_next_check;
+nosave object *hb_obs;
+
+private nosave string default_pray_room;
+
+nosave mixed env_ndead_info;
+
+static int _set_invis(int a);
+static string _set_tty(string str);
+static mixed _set_fraternitasdonoarchmagorum(mixed arg);
+
+
+static string al_to_title(int a);
+
+static void ndead_revive();
+
+static int wegmeldung(string player);
+
+int quit();
+void save_me(mixed value_items);
+varargs int remove(mixed arg);
+mixed RaceDefault(string arg);
+
+/** Setzt Defaultwerte vor dem Laden des Savefiles.
+    Nur die Werte bleiben spaeter uebrig, die NICHT aus dem Savefile geladen
+    werden und diese hier ersetzen.
+    Ausserdem kann man hier nicht mit den Werten aus den Savefiles arbeiten.
+    Hierzu muss man updates_after_restore() verwenden.
+*/
+protected void create()
+{
+  if(QueryProp(P_LEVEL)) 
+  {
+    return; // darf nur EINMAL gemacht werden
+  }
+  call_out("checkConsistency", 0);
+
+  ndead_next_check=NETDEAD_CHECK_TIME;
+  ndead_lasttime=0;
+  ndead_location=0;
+  ndead_l_filename=0;
+  ndead_currently=0;
+  ndead_next_check=0;
+  hc_play=0;
+  
+  command::create();
+  properties::create();
+  description::create();
+  light::create();
+  attributes::create();
+  clothing::create();
+  combat::create();
+  life::create();
+  comm::create();
+  viewcmd::create();
+  quests::create();
+  restrictions::create();
+  moving::create();
+  travel::create();
+  skills::create();
+   
+  SetProp(P_LEVEL, -1);
+  Set(P_LEVEL, SAVE|SECURED, F_MODE_AS);
+  Set(P_GHOST, SAVE, F_MODE_AS);
+  SetProp(P_SCREENSIZE, -1);
+  Set(P_SCREENSIZE, SAVE,F_MODE_AS);
+  Set(P_MORE_FLAGS, SAVE, F_MODE_AS);
+  SetProp(P_WEIGHT_PERCENT,100);
+  SetProp(P_LONG, 0);
+  SetProp(P_TITLE, "der hoffnungsvolle Anfaenger");
+  SetProp(P_ALIGN, 0);
+  SetProp(P_GENDER, NEUTER);
+  Set(P_GENDER, SAVE, F_MODE_AS);
+  SetProp(P_TTY, "vt100");
+  Set(P_TTY, SAVE, F_MODE_AS);
+  SetProp(P_WEIGHT, 75000);
+  SetProp(P_MAX_HP,50);
+  SetProp(P_MAX_SP,50);
+  SetProp(P_MAX_FOOD,100);
+  SetProp(P_MAX_DRINK,100);
+  SetProp(P_MAX_ALCOHOL,100);
+  Set( P_WIMPY, 20, F_VALUE);
+
+  SetProp(P_HANDS, ({" mit blossen Haenden", 30}));
+  Set(P_HANDS, SAVE, F_MODE_AS);
+  SetProp(P_MAX_HANDS, 2);
+
+  Set(P_MARRIED, SAVE, F_MODE_AS);
+  Set(P_EXTRA_LOOK, SAVE, F_MODE_AS);
+  Set(P_SHOW_EXITS, SAVE, F_MODE_AS);
+  Set(P_SHOW_EXITS, 1);
+  Set(P_WANTS_TO_LEARN, SAVE, F_MODE_AS);
+  Set(P_CAN_FLAGS, SAVE, F_MODE_AS);
+  Set(P_TESTPLAYER, SAVE|PROTECTED, F_MODE_AS);
+  Set(P_ALLOWED_SHADOW, SAVE|SECURED, F_MODE_AS);
+  Set(P_SECOND, SAVE, F_MODE_AS);
+  Set(P_INVIS, SAVE, F_MODE_AS);
+  Set(P_READ_NEWS, SAVE, F_MODE_AS);
+  Set(P_START_HOME, SAVE, F_MODE_AS);
+  Set(P_PRAY_ROOM, SAVE, F_MODE_AS);
+  Set(P_MAILADDR, SAVE, F_MODE_AS);
+  Set(P_HOMEPAGE, SAVE, F_MODE_AS);
+  Set(P_ICQ, SAVE, F_MODE_AS);
+  Set(P_MESSENGER, SAVE, F_MODE_AS);
+  Set(P_LOCATION, SAVE, F_MODE_AS);
+
+  Set(P_NO_ASCII_ART, SAVE, F_MODE_AS);
+
+  Set(P_VISUALBELL, SAVE, F_MODE_AS);
+  Set(P_CARRIED_VALUE, SAVE, F_MODE_AS);
+
+  Set(P_PROMPT, "> ");
+  Set(P_PROMPT, SAVE, F_MODE_AS);
+  Set(P_CALLED_FROM_IP, SAVE, F_MODE_AS);
+  Set(P_INFORMME,SAVE|PROTECTED,F_MODE_AS);
+  Set(P_WAITFOR,SAVE|PROTECTED,F_MODE_AS);
+  Set(P_WAITFOR_REASON,SAVE|PROTECTED,F_MODE_AS);
+  Set(P_DAILY_PLAYTIME,SAVE|PROTECTED,F_MODE_AS);
+  Set(P_NETDEAD_ENV, PROTECTED|NOSETMETHOD, F_MODE_AS);
+  
+  autoload = ([]);
+  autoload_rest = ([]);
+  autoload_error = ({});
+  SetProp(P_ARTICLE,0);
+  Set(P_GUILD,SAVE,F_MODE_AS);
+  Set(P_GUILD_TITLE,SAVE,F_MODE_AS);
+  Set(P_GUILD_LEVEL,SAVE,F_MODE_AS);
+  Set(P_GUILD_RATING,SAVE,F_MODE_AS);
+  Set(P_NEWSKILLS,SAVE,F_MODE_AS);
+  Set(P_NEEDED_QP,REQ_QP);
+  Set(P_DEADS,0);
+  Set(P_DEADS, NOSETMETHOD,F_SET_METHOD);
+  Set(P_DEADS,SAVE|PROTECTED|SECURED,F_MODE_AS);
+  Set(P_LAST_LOGIN,-1);
+  Set(P_LAST_LOGIN, NOSETMETHOD,F_SET_METHOD);
+  Set(P_LAST_LOGIN,SAVE|PROTECTED|SECURED,F_MODE_AS);
+  Set(P_LAST_LOGOUT,-1);
+  Set(P_LAST_LOGOUT, NOSETMETHOD,F_SET_METHOD);
+  Set(P_LAST_LOGOUT,SAVE|PROTECTED|SECURED,F_MODE_AS);
+  Set(P_CLOCKMSG,SAVE,F_MODE_AS);
+  Set(P_TIMEZONE,SAVE,F_MODE_AS);
+  Set(P_SHOWEMAIL,SAVE,F_MODE_AS);
+  Set(P_LAST_QUIT,SAVE|PROTECTED|SECURED,F_MODE_AS);
+
+  Set(P_CMSG, 0, F_MODE); // to clean out the old clone messages
+  Set(P_DMSG, 0, F_MODE);
+  Set(P_CLONE_MSG, SAVE, F_MODE);
+  SetProp(P_CLONE_MSG, "zaubert etwas hervor");
+  Set(P_DESTRUCT_MSG, SAVE, F_MODE);
+  SetProp(P_DESTRUCT_MSG, "verschwindet einfach");
+
+  Set(P_FAO, SAVE|SECURED, F_MODE_AS);
+  Set(P_FAO_PORTALS, SAVE, F_MODE_AS);
+
+  SetProp(P_NEWBIE_GUIDE,0);
+  Set(P_NEWBIE_GUIDE,SAVE,F_MODE_AS);
+
+  //TODO: Remove - Property ist not needed any more.
+  Set(P_TELNET_KEEP_ALIVE, PROTECTED|SAVE, F_MODE_AD);
+  SetProp(P_TELNET_KEEP_ALIVE, 0);
+
+  AddId("Interactive");
+
+  realip="";
+}
+
+// ACHTUNG: Falls hier mal sonst noch weitere Resets geerbt werden, muss das
+// hier ordentlich definiert werden!
+void reset() { 
+  comm::reset();
+  // momentan kann der Reset jetzt abgeschaltet werden, da er nur die
+  // TM-History loescht und ggf. von Netdead() und Disconnect() reaktiviert
+  // wird.
+  set_next_reset(-1);
+}
+
+protected void NotifyMove(object dest, object oldenv, int method)
+{
+  moving::NotifyMove(dest,oldenv,method);
+  // ggf. Daten ueber neues Env per GMCP senden.
+  if (dest != oldenv)
+    GMCP_Room();
+}
+
+string Forschung()
+{
+  return LEPMASTER->QueryForschung();
+}
+
+/** Setzt Defaultwerte fuer Rassen - wird von den Shells ueberschrieben.
+*/
+mixed RaceDefault(string arg)
+{
+  if (!arg)
+    return 0;
+  switch(arg)
+  {
+    case P_HANDS :
+      return ({" mit blossen Haenden",30,DT_BLUDGEON});
+    case P_BODY :
+      return 0;
+  }
+  return 0;
+}
+
+/** Prueft Spielerobjekt auf Konsistenz.
+  Ueberprueft das Spielerobjekt nach kompletter Initialisierung (im 
+  callout) auf korrekte Werte einiger Props.
+*/
+void checkConsistency()
+{ mixed h;
+  int   m;
+
+  if (pointerp(h=RaceDefault(P_HANDS)) && sizeof(h)>1)
+    m=(int)h[1];
+  else
+    m=30;
+  if((h=Query(P_HANDS))[1] > m && !IS_LEARNER(this_object())) {
+    log_file("inconsistent", sprintf(
+      "[%s] %O: HANDS: %d\n", dtime(time()), this_player(), h[1]));
+    h[1] = m;
+    Set(P_HANDS,h);
+  }
+
+  if (Query(P_BODY)!=(m=RaceDefault(P_BODY)))
+     Set(P_BODY,m);
+
+  if (!Query(P_SECOND_MARK,F_MODE))
+    Set(P_SECOND_MARK,SAVE|PROTECTED,F_MODE_AS);
+  if (!Query(P_TTY_SHOW,F_MODE)&SAVE)
+  {
+    Set(P_TTY_SHOW,0,F_VALUE);
+    Set(P_TTY_SHOW,SAVE,F_MODE_AS);
+  }
+  if (Query(P_TTY_COLS,F_MODE)&SAVE)
+  {
+    Set(P_TTY_COLS,SAVE,F_MODE_AD);
+    Set(P_TTY_ROWS,SAVE,F_MODE_AD);
+    Set(P_TTY_TYPE,SAVE,F_MODE_AD);
+  }
+}
+
+/** Bittet das Spielerobjekt, sich zu zerstoeren.
+  \param[in] silent Flag, ob ohne Textausgaben zerstoert werden soll
+  \return Erfolg der Selbstzerstoerung
+*/
+varargs int remove(int silent)
+{
+  return moving::remove(silent);
+}
+
+/** Schaltet in allen Objekten im Inv HBs aus.
+  Schaltet im Inv in allen Objekten (rekursiv, deep_inventory)
+  die Heartbeats aus. Falls obs uebergeben wird, werden diese Objekte
+  statt des Inventars benutzt.
+  Speichert die Objekte, die einen HB hatten, in der glob. Var. hb_obs.
+  @param[in] obs mixed - Objekte, in denen der HB abgeschaltet werden soll. 
+    Container werden rekursiv behandelt.
+  @attention Achtung! Niemals zweimal hintereinander rufen, ohne 
+    zwischendurch restart_heart_beats() gerufen zu haben!
+  @sa restart_heart_beats
+*/
+varargs static void stop_heart_beats(mixed obs)
+{
+  int i;
+
+  if (!obs)
+  {
+    hb_obs=({});
+    obs=deep_inventory(ME);
+  } 
+  foreach(mixed ob: obs) {
+    if (pointerp(ob))
+        stop_heart_beats(ob);
+    else if (set_object_heart_beat(ob,0))  
+        hb_obs+=({ob});
+  }
+}
+
+/** Schaltet HBs in Objekten im Inv wieder ein.
+  Schaltet in allen Objekten in hb_obs den Heartbeat ein.
+    In hb_obs (glob. Var.) stehen alle Objekte, die beim letzten Aufruf von
+    stop_heart_beats() einen HB hatten.
+  @sa stop_heart_beats
+*/
+static void restart_heart_beats()
+{
+  int i;
+
+  if (pointerp(hb_obs))
+  {
+    foreach(object ob: hb_obs)
+      set_object_heart_beat(ob,1);
+    hb_obs=0;
+  }
+}
+
+/** Prueft auf abgelaufene Spielzeit.
+  Prueft in Spielerobjekten, ob die taegliche Maximalspielzeit
+    abgelaufen ist.
+    Wird im heart_beat() gerufen.
+  @return int - Flag, ob Spielzeit abgelaufen und Logout erfolgen soll
+*/
+static int CheckDailyPlaytime() {
+  int *spieldauer,d;
+
+  if (!pointerp(spieldauer=Query(P_DAILY_PLAYTIME)))
+    return 0;
+  // 0:Minuten pro Tag, 1:Nr. des letzen Tages, 2:Nr. des angefangenen Tages,
+  // 3:letzte Zeitpruefung, 4:verbleibende Zeit
+  d=time()/86400;
+  if (spieldauer[1]<=d) { // Ende der zeitbeschraenkten Tage?
+    Set(P_DAILY_PLAYTIME,0);
+    return 0;
+  } else if (spieldauer[2]!=d) { // Neuer Tag?
+    spieldauer[4]=spieldauer[0];
+    spieldauer[2]=d;
+  } else {
+    spieldauer[4]-=(time()-spieldauer[3]);
+  }
+  spieldauer[3]=time();  // Letzte Zeitpruefung
+  Set(P_DAILY_PLAYTIME,spieldauer);
+  if (spieldauer[4]<0) { // Keine Zeit mehr uebrig fuer heute
+    if (!interactive(ME))
+      return 1;
+    write("Du hast lange genug gemuddet fuer heute.\n");
+    say(Name(WER)+" hat fuer heute genug gemuddet.\n");
+    remove_interactive(ME);
+    return 1;
+  }
+  return 0;
+}
+
+/** Gibt Erwartemeldung mit Grund aus.
+  @param[in] who   string - Wer ist hereingekommen?
+  @param[in] invis int - Ist der Spieler Invis?
+*/
+static void Show_WaitFor_Reason(string who, int invis)
+{
+  mixed list;
+  string reason,name;
+
+  if (invis) name="("+who+")";
+    else name=who;
+  if ((mappingp(list=QueryProp(P_WAITFOR_REASON))) && (reason=list[who]))
+    tell_object(ME,sprintf("\nDu erwartest %s wegen:\n%s\n",name,reason));
+  else
+    tell_object(ME,sprintf("Du erwartest %s aus keinem bestimmten Grund.\n",
+      name));
+}
+
+/** Gibt Liste der Erwarteten Spieler an this_player() aus.
+*/
+static void ListAwaited() //Anwesende Erwartete auflisten
+{
+    string *list;
+    mixed mlist;
+    object ob;
+    int mag;
+
+    mag=IS_LEARNER(ME);
+
+    list=({});
+    foreach(string erwartet : QueryProp(P_WAITFOR)) {
+        if (objectp(ob=find_player(lower_case(erwartet)))) {
+            if (ob->QueryProp(P_INVIS)) {
+                if (mag) list+=({ sprintf("(%s)",erwartet) });
+            }
+            else list+=({erwartet});
+        }
+    }
+    if (sizeof(list))
+        printf("Anwesende Erwartete: %s.\n",
+            CountUp(sort_array(list,#'>)));
+
+    if ((mappingp(mlist=QueryProp(P_WAITFOR_REASON))) && (sizeof(mlist)))
+        {
+          foreach(string erwartet : mlist) {
+                if (!(ob=find_player(lower_case(erwartet))) ||
+                    (!mag && ob->QueryProp(P_INVIS)));
+                else Show_WaitFor_Reason(erwartet,ob->QueryProp(P_INVIS));
+          }
+        }
+}
+/** Teilt den Gilden und anderen Spielern mit, wer reingekommen ist.
+  Ausserdem wird ggf. PlayerQuit() im Environment gerufen.
+  \param[in] rein int - wahr, wenn der Spieler einloggt.
+*/
+protected void call_notify_player_change(int rein)
+{
+  string wer = getuid(ME);
+  // erst die Gilde informieren
+  string gilde = QueryProp(P_GUILD);
+  if (stringp(gilde) && (find_object("/gilden/"+gilde)
+        || file_size("/gilden/"+gilde+".c")>0))
+    catch(("/gilden/"+gilde)->notify_player_change(ME, rein); publish);
+
+  // dann die anderen Spieler
+  int mag = IS_LEARNER(ME);
+  int invis = QueryProp(P_INVIS);
+  object *u = users() - ({ME}); // sich selber nicht melden 
+  if (mag && invis) {   // Invismagier nur Magiern melden
+    u = filter(u, function int (object o)
+        { return query_wiz_level(o) >= LEARNER_LVL; }
+        );
+  }
+  u->notify_player_change(capitalize(wer),rein,invis);
+
+  // und beim Ausloggen noch das Env informieren.
+  if (!rein) {
+    if(environment()) catch(environment()->PlayerQuit(ME);publish);
+  }
+}
+
+/** Ruft im uebergebenen Objekt ein init() auf, sofern notwendig.
+  Ruft in ob ein init() auf, falls das Objekt nach dem
+    letzten Ausloggen geschaffen wurde.
+  \param[in] ob object - Objekt, in dem init() gerufen wird.
+  \param[in] logout int - Letzter Logout
+  \return 1, falls init() gerufen wurde. 0 sonst.
+*/
+static int call_init( object ob, int logout )
+{
+    if ( objectp(ob) && object_time(ob) > logout )
+        return catch(ob->init(); publish), 1;
+    return(0);
+}
+
+/** Holt seit dem letzten Ausloggen ausgefallene Inits nach.
+  Ruft in den uebergebenen Objekten call_init(), was einen init()
+  ausloest, falls das Objekt seit dem letzten Ausloggen erstellt wurde.
+  \param[in] logout Zeitpunkt des letzten Logouts
+  \param[in] obs Array von Objekten
+  \sa call_init()
+*/
+static void inits_nachholen( int logout, object *obs )
+{
+    filter( obs, "call_init", ME, logout );
+}
+
+/** Belebt einen Netztoten wieder.
+  Wird im Login gerufen, wenn der Spieler netztot war. Aequivalent zu
+  start_player()
+  @param[in] silent Wenn Flag gesetzt, werden keine Meldung an den Raum
+  ausgegeben.
+  @param[in] ip Textuelle Repraesentation der IP-Adresse, von der der Spieler
+  kommt.
+  @see start_player()
+*/
+varargs void Reconnect( int silent )
+{
+    int num;
+    string called_from_ip;
+    object *inv;
+
+    if ( query_once_interactive(ME) )
+    {
+        // perform the telnet negotiations. (all that are available)
+        "*"::startup_telnet_negs();
+        Set( P_LAST_LOGIN, time() );
+    }
+
+    enable_commands();
+    set_living_name( getuid() );
+    _remove_netdead();
+    set_heart_beat(1);
+    // Hunttimes aktualisieren und ggf. Feinde vergessen.
+    update_hunt_times((time()-QueryProp(P_LAST_LOGOUT)) /__HEART_BEAT_INTERVAL__);
+    // Heartbeats in Objekten im Inv reaktiveren.
+    restart_heart_beats();
+    // life.c will ggf. was aufraeumen
+    life::reconnect();
+
+    log_file( "REENTER", sprintf( "%-11s %s, %-15s (%s).\n",
+                                  capitalize(getuid(ME)), ctime(time())[4..15],
+                                  query_ip_number(ME)||"Unknown",
+                                  query_ip_name(ME)||"Unknown" ),
+              200000 );
+
+    if ( ndead_currently )
+        ndead_revive();
+
+    if ( !silent && interactive(ME) )
+        call_notify_player_change(1);
+
+    command::reconnect();
+    if ( query_once_interactive(ME) )
+        modify_prompt();
+
+    // Login-event ausloesen
+    EVENTD->TriggerEvent(EVT_LIB_LOGIN, ([
+          E_OBJECT: ME,
+          E_PLNAME: getuid(ME),
+          E_ENVIRONMENT: environment() ]) );
+
+    catch( num = "secure/mailer"->FingerMail(geteuid());publish );
+
+    if ( num )
+        write( "Du hast " + num + " neue" + (num == 1 ? "n Brief" : " Briefe")
+               + " im Postamt liegen.\n" );
+
+    if ( QueryProp(P_AWAY) )
+        write( break_string( "Du bist als abwesend gekennzeichnet: " +
+                             QueryProp(P_AWAY) + ".", 78 ) );
+
+    catch( RegisterChannels(); publish );
+
+    if ( (called_from_ip = Query(P_CALLED_FROM_IP)) &&
+         query_ip_number(ME) != called_from_ip ) {
+        string tmp;
+
+        if ( stringp(tmp = query_ip_name(called_from_ip)) &&
+             tmp != called_from_ip )
+            tmp = " [" + tmp + "]";
+        else
+            tmp = "";
+
+        write( "Das letzte Mal kamst Du von " + called_from_ip + tmp + ".\n" );
+    }
+
+    Set( P_CALLED_FROM_IP, query_ip_number(ME) );
+
+    // falls Gegenstaende mit 'upd -ar' upgedated wurden, muessen die
+    // "verloren gegangenen" init()'s nachgeholt werden
+    if ( query_once_interactive(ME) && !IS_LEARNER(ME) )
+        call_out( "inits_nachholen", 0, Query(P_LAST_LOGOUT),
+                  all_inventory(ME) );
+
+    // noch nicht geclonte Autoloader "nach"clonen
+    while ( remove_call_out("load_auto_objects") != -1 )
+        /* do nothing */;
+
+    if ( sizeof(autoload_rest) )
+        call_out( "load_auto_objects", 0, autoload_rest );
+
+    if (ndead_location) {
+      catch( ndead_location->BecomesNetAlive(ME);publish );
+      inv = all_inventory(ndead_location);
+      ndead_location = 0;
+    }
+    else
+      inv = ({});
+
+    inv += deep_inventory(ME);
+
+    //ZZ foreach statt call_other(), damit nen bug in BNA nicht die anderen
+    //BNA verhindert.
+    foreach(object ob: inv) {
+        //es ist nicht auszuschliessen, dass Items durch BecomesNetAlive()
+        //eines anderen zerstoert werden.
+        if (objectp(ob))
+          catch( call_other(ob, "BecomesNetAlive", ME);publish );
+    }
+
+    // Erst an dieser Stelle, weil der Spieler u.U. durch ein BecomesNetAlive()
+    // noch bewegt wurde.
+    if ( !silent && environment() && object_name(environment()) != NETDEAD_ROOM )
+    {
+        if(query_hc_play()<=1)
+          tell_room(environment(),QueryProp(P_NAME) + " weilt wieder unter den Lebenden.\n",({ME}) );
+        else 
+          tell_room(environment(),QueryProp(P_NAME) + " weilt wieder unter den Verstorbenen.\n",({ME}) );
+    }
+
+    NewbieIntroMsg();
+
+    if ( query_once_interactive(ME) )
+        ListAwaited();
+}
+
+/** Loggt einen Spieler aus und macht ihn netztot.
+  Bewegt einen Spieler in den Netztotenraum, deaktiviert Heartbeats im
+  Inventar, ruft BecomesNetDead(), loest Erwartemeldungen aus, triggert
+  Ausloggevent.
+*/
+void NetDead()
+{
+  object *inv;
+  int num;
+
+  catch(RemoveChannels();publish);
+
+  if(query_hc_play()>1)
+    say("Ploetzlich weicht alle spirituelle Energie aus "+QueryProp(P_NAME)+".\n");
+  else
+    say("Ploetzlich weicht alles Leben aus "+QueryProp(P_NAME)+".\n");
+
+  _set_netdead();
+  remove_call_out("quit");
+  remove_living_name();
+  // Wird zwar im save_me() gemacht, aber die Zeitunterschiede beim
+  // fingern direkt nach dem Ausloggen fuehren immer wieder zu Verwirrungen
+  if(query_once_interactive(ME) && !QueryProp(P_INVIS))
+      Set(P_LAST_LOGOUT,time());
+  if (ME)
+    ndead_location = environment();
+
+  if (query_once_interactive(ME))
+    call_notify_player_change(0);
+
+  // Logout-event ausloesen
+  EVENTD->TriggerEvent(EVT_LIB_LOGOUT, ([
+          E_OBJECT: ME,
+          E_PLNAME: getuid(ME),
+          E_ENVIRONMENT: environment() ]) );
+
+  set_next_reset(900);
+  /* Bei Nicht-Magier-Shells wird comm::reset() aufgerufen, das prueft, ob
+     der Spieler immer noch netztot ist, und falls ja, die tmhist loescht.
+     Die Methode wird von /std/shells/magier.c ueberschrieben, netztote
+     Magier (die eigentlich schon anderweitig beseitigt worden sein sollten)
+     werden remove()d und destruct()ed. --Amynthor 05.05.2008 */
+
+  if (environment()) {
+    catch(environment()->BecomesNetDead(ME);publish);
+    inv = deep_inventory(ME)+all_inventory(environment());
+  }
+  else inv=deep_inventory(ME);
+  foreach(object ob: inv) {
+      if (objectp(ob)) //man weiss nie was BND() macht...
+          catch( call_other(ob, "BecomesNetDead", ME);publish );
+  }
+}
+
+
+/** Sendet ggf. Telnet Timing Marks als Keep-Alive Pakete an den Client.
+  * Wird in heart_beat() gerufen.
+  * @return 1, falls der Spieler Keep-Alive Paket wuenscht, sonst 0. 
+  * @see heart_beat()
+*/
+protected int CheckTelnetKeepAlive() {
+  if (telnet_tm_counter > 0) {
+    // Spieler hat offenbar ein Keep-Alive konfiguriert ...
+    if (!(--telnet_tm_counter)) {
+      // und das Intervall ist gerade abgelaufen.
+      // Prop offenbar gesetzt, FEature ist wirklich gewuenscht,
+      // Telnet Timing Mark senden 
+      send_telnet_timing_mark();
+      // alle 120 HBs (240s, 4min).
+      // sollte eigentlich 240 / __HEART_BEAT_INTERVAL__ sein. Aber spart
+      // eine Operation im HB. ;-)
+      telnet_tm_counter = 120;
+    }
+    return 1; // Keep-Alive ist eingeschaltet
+  }
+  return 0;
+}
+
+static void ndead_move_me();
+
+/** Heartbeat des Spielerobjektes.
+  Prueft taegliche Spielzeit, speichert regelmaessig den Spieler,
+  bewegt Netztote in den Netztodenraum, ruft die HBs aus living/combat und
+  player/life.
+*/
+protected void heart_beat() {
+  if (!ME)
+    return;
+  if (ndead_currently)
+  {
+    if (interactive(ME))
+    {
+      ndead_revive();
+      ndead_location=0;
+    }
+    else return;
+  }
+  else
+    if (!(ndead_next_check--))
+    {
+      ndead_next_check=NETDEAD_CHECK_TIME;
+      if (!interactive(ME))
+        if (ndead_lasttime)
+        {
+          save_me(1);
+          if (IS_LEARNER(ME))
+          {
+            quit();
+            if (ME)
+              remove();
+            if (ME)
+              destruct(ME);
+            return;
+          }
+          ndead_move_me();
+          // Zumindest bei Gaesten ist das Objekt jetzt zerstoert
+          if (!objectp(this_object()))
+            return;
+        }
+        else
+          ndead_lasttime=1;
+    }
+  if (ME && ndead_lasttime && interactive(ME))
+    ndead_lasttime=0;
+  if (CheckDailyPlaytime())
+    return;
+
+  CheckTelnetKeepAlive();
+
+  life::heart_beat();
+  combat::heart_beat();
+  skills::heart_beat();
+}
+
+/** ID-Funktion fuer Spielerobjekte.
+ * id() fuer Spieler. Besondere Behandlung fuer Froesche und Geister,
+ * sowie Invis-Status.
+ * Gibt immer 0 zurueck, wenn P_INVIS && lvl < P_LEVEL
+ * @param[in] str angefragter ID-String
+ * @param[in] lvl Level des Anfragenden
+ * @return 1, falls str auf den Spieler zutrifft, 0 sonst.
+ */
+varargs int id(string str, int lvl)
+{
+  if (::id(str))
+    return 1;
+  if (Query(P_INVIS) && lvl < QueryProp(P_LEVEL))
+    return 0;
+  if (QueryProp(P_GHOST)&& str == "geist von "+ lower_case(QueryProp(P_NAME)))
+    return 1;
+  if (QueryProp(P_FROG) && str == "frosch") return 1;
+  return(0);
+}
+
+/** Setzt Spielerhomepage (Spielerkommando).
+  * @param[in] str Spielereingabe
+  * @return 1 bei Erfolg, 0 sonst.
+  */
+static int set_homepage(string str)
+{
+  mixed tmp;
+  if (!(str=_unparsed_args())) {
+    if (!QueryProp(P_HOMEPAGE))
+      write("Du hast keine URL-Adresse gesetzt!\n");
+    else
+      write("Deine offizielle URL-Adresse lautet: " + QueryProp(P_HOMEPAGE)
+            +"\n");
+    return 1;
+  }
+  write("Deine offizielle URL-Adresse wurde geaendert.\n");
+  if (str=="keine") 
+    SetProp(P_HOMEPAGE, 0);
+  else {
+    tmp = filter(regexplode(str, "[<][^>]*[>]"),
+                       lambda(({'e}), ({#'!=, ({#'[, 'e, 0}), '<'})));
+    write("Sie lautet jetzt: "+(str = implode(tmp, ""))+"\n");
+    SetProp(P_HOMEPAGE, str);
+  }
+  return 1;
+}
+
+/** Setzt Spieler-Wohnort (Spielerkommando).
+  * \param[in] str Spielereingabe
+  * \return 1 bei Erfolg, 0 sonst.
+  */
+static int set_location( string str )
+{
+    mixed ort;
+
+    if ( str == "0" || str == "loeschen" ){
+        Set( P_LOCATION, 0 );
+        write( "Du loescht Deine Ortsangabe.\n" );
+        return 1;
+    }
+
+    if ( stringp(str = _unparsed_args()) && str != "" ){
+        Set( P_LOCATION, capitalize(str) );
+        printf( "Du aenderst Deine Ortsangabe auf \"%s\".\n",
+                Query(P_LOCATION) );
+    }
+    else if ( stringp(ort = Query(P_LOCATION)) )
+        printf( "Deine Ortsangabe lautet \"%s\".\n", Query(P_LOCATION) );
+    else{
+        Set( P_LOCATION, 0, F_VALUE );
+        write( "Du hast keine Ortsangabe gesetzt.\n" );
+    }
+
+    return 1;
+}
+
+/** Setzt ICQ-UIN des Spielers (Spielerkommando).
+  * \param[in] str Spielereingabe
+  * \return 1 bei Erfolg, 0 sonst.
+  */
+static int set_icq(string str) {
+  int num;
+
+  if (!str || str=="") {
+    if (!num=QueryProp(P_ICQ))
+      write("Du hast keine ICQ-Nummer gesetzt!\n");
+    else
+      printf("Deine ICQ-Nummer lautet: %d\n",num);
+    return 1;
+  }
+  if (sscanf(str,"%d",num)!=1 || !num) {
+    write("Deine ICQ-Nummer wurde geloescht.\n");
+    SetProp(P_ICQ, 0);
+  } else {
+    write("Deine ICQ-Nummer wurde geaendert.\n");
+    printf("Sie lautet jetzt: %d\n",num);
+    SetProp(P_ICQ, num);
+  }
+  return 1;
+}
+
+/** Setzt Instant Messanger vom Spieler (Spielerkommando).
+  * \param[in] str Spielereingabe
+  * \return 1 bei Erfolg, 0 sonst.
+  */
+static int set_messenger(string str) {
+  int num;
+  string s;
+
+  if (!str || str=="") {
+    if (!s=QueryProp(P_MESSENGER))
+      if (!num=QueryProp(P_ICQ)) 
+        write("Du hast keine Messenger-ID gesetzt.\n");
+      else 
+        printf("Du hast keine Messenger-ID gesetzt, aber eine ICQ-Nummer: %d\n", num);
+    else
+      printf("Deine Messenger-ID lautet: %s\n", s);
+    return 1;
+  }
+  if (str=="loeschen" || str=="keine") {
+    write("Deine Messenger-ID wurde geloescht.\n");
+    SetProp(P_MESSENGER, 0);
+  } else {
+    s = _unparsed_args();
+    printf("Deine Messenger-ID lautet nun: %s\n", s);
+    SetProp(P_MESSENGER, s);
+  }
+  return 1;
+}
+
+
+// Prueft, ob der String vermutlich eine eMail-Adresse ist.
+// dies ist nicht narrensicher, wird aber die meisten eMail-Adressen zulassen
+// und viel Schrott ablehnen.
+private string check_email(string str) {
+  if (!stringp(str)) return 0;
+  return regmatch(lower_case(str),
+      "[a-z0-9._%+-]+@(?:[a-z0-9-]+\.)+[a-z]{2,4}",RE_PCRE);
+}
+
+/** Setzt Email-Adresse des Spielers (Spielerkommando).
+  * \param[in] str Spielereingabe
+  * \return 1 bei Erfolg, 0 sonst.
+  */
+static int set_email(string str)
+{
+  if (!(str=_unparsed_args())) {
+    write("Deine offizielle Email-Adresse lautet: " + QueryProp(P_MAILADDR)
+          +"\n");
+    return 1;
+  }
+  str = check_email(str);
+  if (!str) {
+    notify_fail("Deine Eingabe scheint keine gueltige EMail-Adresse "
+        "zu sein.\n");
+    return 0;
+  }
+  write("Deine EMail-Adresse wurde geaendert zu:\n"
+      +str+"\n");
+  SetProp(P_MAILADDR, str);
+  return 1;
+}
+
+/** Spielerkommando 'selbstloeschung'.
+  * Gibt Meldung aus und fragt nach einer Bestaetigung.
+  * \return 1 bei Erfolg, 0 sonst.
+  */
+static int self_delete()
+{
+  write(
+    "     B I S T  D U  D I R  W I R K L I C H  S I C H E R ????????????\n"+
+    "Wenn Du Dich selbstloeschen willst, ist Dein Charakter UNWIDERRUFLICH\n"+
+    "verloren. Es gibt KEINE Moeglichkeit ihn wiederzuerschaffen. Solltest\n"+
+    "Du nur zeitweilig vom "MUDNAME" wegbleiben wollen, so benutze bitte\n"+
+    "den Befehl 'spielpause'.\n"+
+    "Fallst Du Dich immer noch selbstloeschen willst, gib Dein Password ein."+
+    "\n\n");
+  input_to("self_delete2",INPUT_PROMPT|INPUT_NOECHO, "Bitte das Password angeben: ");
+  return 1;
+}
+
+/** Spielerkommando 'selbstloeschung'.
+  * Empfaengt Bestaetigung des Spielers und ruft Loeschfunktion in 
+  * /secure/master auf.
+  * \param[in] str Spielereingabe
+  * \return 1 bei Erfolg, 0 sonst.
+  */
+int self_delete2(string str)
+{
+  int ret;
+  ret=(int)"secure/master"->delete_player(str, getuid(PL));
+  if (!ret)
+  {
+    write("Das hat nicht hingehauen (Gott sei Dank ....)\n");
+    return 1;
+  }
+  if (QueryProp(P_GUILD)&&file_size(GUILD_DIR+QueryProp(P_GUILD)+".c")>-1)
+    catch(call_other(GUILD_DIR+QueryProp(P_GUILD), "austreten");publish);
+
+  if (QueryProp(P_DEADS) < 5) {
+    write("Adios! Man sieht sich.\n");
+    say(name(WER,1)+" hat sich gerade selbst zerstoert.\n");
+  }
+  else {
+    write(
+      "\nTod kommt auf seinem weissen Pferd angeritten.\n"
+     +"Er steigt ab, baut sich drohend vor Dir auf und mustert Dich schadenfroh.\n"
+     +"\nTod sagt: ENDLICH! NUN KANN DIR AUCH LARS NICHT MEHR HELFEN!\n"
+     +"\nTod holt weit mit seiner Sense aus. Mit grossem Schwung laesst er sie auf\n"
+     +"Dich zusausen und dann...\n");
+    say(name(WER,1)+" schied gerade endgueltig von uns.\n");
+  }
+
+  // Event ausloesen. ;-)
+  EVENTD->TriggerEvent(EVT_LIB_PLAYER_DELETION, ([
+        E_PLNAME: getuid(ME),
+        E_ENVIRONMENT: environment(),
+        E_GUILDNAME: QueryProp(P_GUILD) ]) );
+
+  remove(1);
+  return 1;
+}
+
+/** Setzt neue taegliche Spieldauer (Spielerkommando).
+  * \param[in] str Spielereingabe
+  * \return 1 bei Erfolg, 0 sonst.
+  */
+static int spieldauer(string str) {
+  int min,day;
+  string foo;
+
+  notify_fail("  spieldauer <x> minuten fuer %d tage\noder\n"+
+              "  spieldauer <x> stunden fuer %d tage\n");
+  if (!str)
+    return 0;
+  if (sscanf(str,"%d stunde%s fuer %d tag%s",min,foo,day,foo)==4)
+    min*=60;
+  else if (sscanf(str,"%d minute%s fuer %d tag%s",min,foo,day,foo)!=4)
+    return 0;
+  if (min<5)
+    min=5;
+  if (min>=1440)
+    return notify_fail("Witzbold.\n"),0;
+
+  Set(P_DAILY_PLAYTIME,
+      ({min*60,time()/86400+day,time()/86400,time(),min*60}));
+  // 0:Minuten pro Tag, 1:Nr. des letzen Tages, 2:Nr. des angefangenen Tages,
+  // 3:letzte Zeitpruefung, 4:verbleibende Zeit
+  printf("Du darfst die naechsten %d Tag(e) nur noch\n"+
+   "%d Minuten am Tag mudden.\n",day,min);
+  return 1;
+}
+
+/** Interpretiert Angabe des Spielers fuer Spielpause.
+  * \param[in] a Zeitangabe fuer Spielpause.
+  * \return Zeitpunkt, Ende der Spielpause.
+  */
+private int InterpretTime(string a){
+  // akzeptiert folgende Formate:
+  //   dd.mm.jj     (Rueckgabe: 0:00 des entsprechenden Tages)
+
+  int *ts = allocate(9);
+  int i,j,k,nrargs;
+
+  if ((nrargs=sscanf(a,"%d.%d.%d",i,j,k))==3 ||
+      (nrargs=sscanf(a,"%d.%d.",i,j))==2) {
+    // wenn kein jahr angegeben ist, das aktuelle nehmen.
+    if (nrargs == 2)
+       ts[TM_YEAR] = localtime()[TM_YEAR];
+    else {
+       // Zwei-Ziffern-Angabe des Jahres...
+       if (k<100)
+           k += 2000;
+       ts[TM_YEAR] = k;
+    }
+    ts[TM_MDAY] = i;
+    ts[TM_MON] = j - 1;
+
+    int zeit = mktime(ts);
+
+    // negative und vergangene Zeiten pruefen.
+    if (zeit <= time()) {
+      write("Dieser Zeitpunkt liegt in der Vergangenheit.\n");
+      return 0;
+    }
+    return zeit;
+  }
+  return 0;
+}
+
+/** Setzt neue Spielpause (Spielerkommando).
+  * Fragt vorher nach Bestaetigung durch den Spieler.
+  * \param[in] str Spielereingabe
+  * \return 1 bei Erfolg, 0 sonst.
+  * \sa spielpause2()
+  */
+static int spielpause(string str)
+{
+  int days,endezeit;
+  string foo;
+
+  notify_fail("spielpause <x> tage          oder\n"+
+              "spielpause bis tt.mm[.jj]\n");
+  if (!str) return 0;
+  if(sscanf(_unparsed_args(),"bis %s",foo)==1) {
+    endezeit = InterpretTime(foo);
+    if (endezeit == 0) 
+        return 0;
+    days = ((endezeit - time()) / 86400) + 1;
+  }
+  else if(sscanf(str, "%d tag%s", days, foo) == 2) {
+    if (days < 0)
+        days = -1;
+    else
+        endezeit = (time()/86400) * 86400 + days * 86400;
+  }
+  else return 0;
+
+  if (days > 0)
+    write(strftime("Du wirst Dich erst wieder am %d.%m.%Y einloggen koennen!\n",
+          endezeit));
+  else if (days < 0)
+    write( "Du wirst Dich auf unbestimmte Zeit nicht mehr einloggen koennen.\n"
+          +"Wenn Du wieder spielen willst, musst Du Dich an einen Gott oder\n"
+          +"Erzmagier wenden (mit einem Gast oder Mail von aussen).\n" );
+  else {
+    write( "Die Spielpause ist aufgehoben.\n" );
+    master()->TBanishName(getuid(this_object()), 0);
+    return 1;
+  }
+  write( "Wenn Du das wirklich willst, gib jetzt 'ja' ein.\n" );
+  input_to( "spielpause2", INPUT_PROMPT, "]", days);
+  return 1;
+}
+
+/** Setzt neue taegliche Spieldauer, wird ueber spielpause() gerufen.
+  * \param[in] str Spielereingabe, Bestaetigung
+  * \param[in] days Dauer der Spielpause (in Tagen).
+  * \sa spielpause()
+  */
+static void spielpause2(string str, int days)
+{
+  if (str && (str == "ja" || str == "Ja" || str == "JA")) {
+    master()->TBanishName(getuid(this_object()), days);
+    write(
+      "Ok, die Spielpause wird mit dem naechsten Ausloggen wirksam.\n"
+     +"Solltest Du es Dir bis dahin noch einmal ueberlegt haben, so kannst\n"
+     +"Du den Vorgang mit 'spielpause 0 tage' wieder rueckgaengig machen.\n" );
+    return;
+  }
+  write("Vorgang wurde abgebrochen.\n" );
+}
+
+/** Setzt neues Passwort (Spielerkommando).
+  * Fragt nach altem Passwort und ruft change_password2().
+  * \return 1 bei Erfolg, 0 sonst.
+  * \sa change_password2(), change_password3(), change_password4()
+  */
+static int change_password() {
+  string verb;
+  verb=query_verb();
+  if (verb!="passwd"&&verb!="password"&&verb!="passwort")
+    return 0;
+  input_to("change_password2",INPUT_NOECHO|INPUT_PROMPT,
+      "Bitte das ALTE Passwort angeben: ");
+  return 1;
+}
+
+/** Setzt neues Passwort (Spielerkommando).
+  * Prueft altes Passwort, fragt nach neuem Passwort und ruft 
+  *   change_password3().
+  * \param[in] str Spielereingabe des alten Passwortes
+  * \return 1 bei Erfolg, 0 sonst.
+  * \sa change_password(), change_password3(), change_password4()
+  */
+static int change_password2(string str) {
+  write("\n");
+  if (!str)
+    str="";
+  if (MASTER->update_password(str,str) == 0) {
+    write("Falsches Passwort!\n");
+    return 1;
+  }
+  passwold = str;
+  input_to("change_password3",INPUT_NOECHO|INPUT_PROMPT,
+      "Bitte das NEUE Passwort eingeben: ");
+  return 1;
+}
+
+/** Setzt neues Passwort (Spielerkommando).
+  * Prueft neues Passwort, fragt nach Bestaetigung des neues
+  * Passwortes und ruft change_password4().
+  * \param[in] str Spielereingabe des neuen Passwortes
+  * \return 1 bei Erfolg, 0 sonst.
+  * \sa change_password(), change_password2(), change_password4()
+  */
+static int change_password3( string str )
+{
+    write( "\n" );
+
+    if ( !str || str == "" ){
+        write( "Abgebrochen !\n" );
+        passwold = passw = 0;
+        return 1;
+    }
+
+    if ( passwold == str ){
+        write( "Das war Dein altes Passwort.\n" );
+        input_to( "change_password3", INPUT_NOECHO|INPUT_PROMPT,
+            "Bitte das NEUE Passwort eingeben (zum Abbruch Return druecken): ");
+        return 1;
+    }
+
+    if ( !MASTER->good_password( str, getuid(ME) ) ){
+        input_to( "change_password3", INPUT_NOECHO|INPUT_PROMPT,
+            "Bitte das NEUE Passwort eingeben: ");
+        return 1;
+    }
+
+    passw = str;
+    input_to( "change_password4", INPUT_NOECHO|INPUT_PROMPT,
+        "Bitte nochmal: ");
+    return 1;
+}
+
+/** Setzt neues Passwort (Spielerkommando).
+  * Prueft neues Passwort und setzt neues Passwort.
+  * \param[in] str Spielereingabe des neuen Passwortes
+  * \return 1 bei Erfolg, 0 sonst.
+  * \sa change_password(), change_password2(), change_password3()
+  */
+static int change_password4( string str )
+{
+    write( "\n" );
+
+    if ( !str || str != passw ){
+        write( "Das war verschieden! Passwort NICHT geaendert.\n" );
+        passwold = passw = 0;
+        return 1;
+    }
+
+    if ( MASTER->update_password( passwold, passw ) )
+        write( "Passwort geaendert.\n" );
+    else
+        write( "Hat nicht geklappt!\n" );
+
+    passwold = passw = 0;
+    return 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------
+ * Rueckmeldungen von Spielern an Magier
+ *-----------------------------------------------------------------
+ */
+static int fehlerhilfe(string str) {
+  write("Welche Art von Fehler moechtest Du denn melden?\n"
+      "Fehlfunktionen    ->  bug\n"
+      "Ideen/Anregungen  ->  idee\n"
+      "Tippfehler/Typos  ->  typo\n"
+      "fehlende Details  ->  detail\n");
+
+  return 1;
+}
+
+/** Setzt eine Fehlermeldung an Magier ab (Spielerkommando).
+  * Fragt nach der Fehlermeldung und liest sie via bug2() ein, fall der
+  * Spieler kein Argument angeben hat.
+  * \param[in] str optionale Spielereingabe der Fehlerbeschreibung
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see bug2(string)
+  */
+static int bug(string str) {
+  if (!(str=_unparsed_args())) {
+    write( "Wie sieht der Fehler denn aus?\n" );
+    input_to("bug2", INPUT_PROMPT, "]");
+    return 1;
+  }
+  write("Vielen Dank fuer die Hilfe.\n");
+  smart_log("BUGS",str);
+  return 1;
+}
+
+/** Setzt eine Fehlermeldung an Magier ab (Spielerkommando).
+  * Lies Fehlerbeschreibung ein und speichert sie ab.
+  * \param[in] str Spielereingabe der Fehlerbeschreibung.
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see bug(string)
+  */
+static int bug2(string str) {
+  if (!str || str == "") {
+    write("Bug abgebrochen...\n");
+    return 1;
+  }
+  write("Vielen Dank fuer die Hilfe.\n");
+  smart_log("BUGS",str);
+  return 1;
+}
+
+/** Setzt eine Typomeldung an Magier ab (Spielerkommando).
+  * Fragt nach der Typomeldung und liest sie via typo2() ein, fall der
+  * Spieler kein Argument angeben hat.
+  * \param[in] str optionale Spielereingabe der Typobeschreibung
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see typo2(string)
+  */
+static int typo(string str) {
+  if (!(str=_unparsed_args())) {
+    write( "Wo ist denn der Tippfehler?\n" );
+    input_to("typo2", INPUT_PROMPT, "]");
+    return 1;
+  }
+  write("Vielen Dank fuer die Hilfe.\n");
+  smart_log("TYPO",str);
+  return 1;
+}
+
+/** Setzt eine Fehlermeldung an Magier ab (Spielerkommando).
+  * Liest die Typobeschreibung ein und speichert sie.
+  * \param[in] str Spielereingabe der Typobeschreibung
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see typo(string)
+  */
+static int typo2(string str) {
+  if (!str || str == "") {
+    write("Typo abgebrochen...\n");
+    return 1;
+  }
+  smart_log("TYPO",str);
+  write("Vielen Dank fuer die Hilfe.\n");
+  return 1;
+}
+
+/** Setzt eine Idee an Magier ab (Spielerkommando).
+  * Fragt nach der Idee und liest sie via idee2() ein, falls der
+  * Spieler kein Argument angeben hat.
+  * \param[in] str optionale Spielereingabe der Idee
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see idea2(string)
+  */
+static int idea(string str) {
+  if (!(str=_unparsed_args())) {
+    write( "Was fuer eine Idee hast Du denn?\n" );
+    input_to("idea2",INPUT_PROMPT, "]");
+    return 1;
+  }
+  write("Vielen Dank fuer die Hilfe.\n");
+  smart_log("IDEA",str);
+  return 1;
+}
+
+/** Setzt eine Idee an Magier ab (Spielerkommando).
+  * Liest die Idee ein und speichert sie.
+  * \param[in] str Spielereingabe der Idee
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see idea(string)
+  */
+static int idea2(string str) {
+  if (!str || str == "") {
+    write("Idee abgebrochen...\n");
+    return 1;
+  }
+  write("Vielen Dank fuer die Hilfe.\n");
+  smart_log("IDEA",str);
+  return 1;
+}
+
+/** Setzt ein fehlendes Detail an Magier ab (Spielerkommando).
+  * Fragt nach dem Detail und liest es via idee2() ein, falls der
+  * Spieler kein Argument angeben hat.
+  * \param[in] str optionale Spielereingabe des fehlenden Details
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see md2(string)
+  */
+static int md(string str) {
+  if (!(str=_unparsed_args())) {
+    write( "Fuer welches Detail fehlt denn die Beschreibung?\n" );
+    input_to("md2",INPUT_PROMPT, "]");
+    return 1;
+  }
+  write("Vielen Dank fuer die Hilfe.\n");
+  smart_log("DETAILS",str);
+  return 1;
+}
+
+/** Setzt ein fehlendes Detail an Magier ab (Spielerkommando).
+  * Liest das Detail ein und speichert es.
+  * \param[in] str Spielereingabe des fehlenden Details.
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see md(string)
+  */
+static int md2(string str) {
+  if (!str || str == "") {
+    write("Details abgebrochen...\n");
+    return 1;
+  }
+  write("Vielen Dank fuer die Hilfe.\n");
+  smart_log("DETAILS",str);
+  return 1;
+}
+
+/** Loggt eine Spielermeldung an Magier.
+  * Loggt die Spielermeldung in das passende File unter /log/report/ oder im
+  * vom Magier gewuenschten File. Hierbei werden Fehler, Ideen, MDs und Typos
+  * in getrennte Files sortiert.
+  * \param[in] str Spielermeldung
+  * \param[in] myname Art der Spielermeldung (DETAILS, BUG, TYPO, MD)
+  * @see md(string), idea(string), bug(string), typo(string)
+  */
+void smart_log(string myname, string str)
+{
+  string obnam;
+  object obj;
+
+  string *tmp = explode(str, ":");
+  if (sizeof(tmp) > 1) {
+    obnam = lower_case(trim(tmp[0]));
+    obj = present(obnam, environment()) || present(obnam);
+    if (!obj) {
+      obj = environment(this_object());
+    }
+    else // nur hier Teil vor dem : wegschneiden
+      str = trim(implode(tmp[1..],":"));
+  }
+  else {
+    obj = QueryProp(P_REFERENCE_OBJECT);
+    if (!obj || !present(obj))
+      obj = environment(this_interactive());
+  }
+
+  mapping err = ([ F_PROG: "unbekannt",
+           F_LINE: 0,
+           F_MSG: str,
+           F_OBJ: obj
+         ]);
+
+  string desc="etwas unbekanntes";
+  switch(myname) {
+    case "BUGS":
+      desc="einen Fehler";
+      err[F_TYPE]=T_REPORTED_ERR;
+      break;
+    case "DETAILS":
+      desc="ein fehlendes Detail";
+      err[F_TYPE]=T_REPORTED_MD;
+      break;
+    case "IDEA":
+      desc="eine Idee";
+      err[F_TYPE]=T_REPORTED_IDEA;
+      break;
+    case "TYPO":
+      desc="einen Typo";
+      err[F_TYPE]=T_REPORTED_TYPO;
+      break;
+  }
+
+  // Eintragung in die Fehler-DB
+  string hashkey = (string)ERRORD->LogReportedError(err);
+
+  // ggf. will das Objekte mit noch irgendwas anfangen.
+  obj->SmartLog(0, myname, str, strftime("%d. %b %Y"));
+
+  tell_object(this_object(), break_string( sprintf(
+    "Du hast an %s erfolgreich %s abgesetzt.\n"
+    "Die ID der abgesetzten Meldung lautet: %s\n",
+    (obj->IsRoom() ? "diesem Raum" : obj->name(WEM,1)),desc,
+    hashkey||"N/A"),78,BS_LEAVE_MY_LFS));
+}
+
+/** Speichert den Spieler und loggt ihn aus (Spielerkommando 'ende').
+  * Der Spieler wird vollstaendig ausgeloggt, d.h. das Spielerobjekt
+  * zerstoert.
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see disconnect()
+  */
+int quit()
+{
+  int arg;
+  SetProp(P_LAST_QUIT,time());
+  catch(RemoveChannels();publish);
+  if(!QueryGuest())
+  {
+    save_me(0);
+    tell_object(ME,"Speichere "+QueryProp(P_NAME)+".\n");
+  }
+
+  if (interactive(ME))
+    call_notify_player_change(0);
+
+  remove_living_name();
+  // EVT_LIB_LOGOUT wird in remove() getriggert.
+  if(catch(remove();publish)) destruct(ME);
+  return 1;
+}
+
+/** Wrapper im quit() herum, verhindert 'ende', falls Spieler kaempft.
+  * \return 0 oder Rueckgabewert von quit()
+  * @see quit()
+  */
+static int new_quit() {
+  notify_fail("Du bist in Gedanken noch bei Deinem letzten Kampf.\n"+
+              "Warte noch etwas bevor Du das Spiel verlaesst,\n"+
+              "damit Du so nicht in RL weitermachst...\n");
+  if (time()-Query(P_LAST_COMBAT_TIME)<120 && !IS_LEARNING(ME))
+    return 0;
+  return quit();
+}
+
+/** Gibt die Infos ueber den Char an den Spieler aus (Spielerkommando 'info').
+  * \param[in] arg Wenn arg=="short", wird eine Kurzuebersicht ausgegeben.
+  * \return 1
+  * @see short_score()
+  */
+static int score(string arg) {
+  string tmp, gender;
+  int i,sz,val;
+  mixed ind;
+  object *enem1, *enem2, *inv;
+
+  if (QueryProp(P_GHOST)) {
+    write("Im ewigen Leben gibt es keine Punkte.\n");
+    return 1;
+  }
+
+  int plev = LEPMASTER->QueryLevel();
+ 
+  switch(tmp = QueryProp(P_GENDER)) {
+  case MALE: gender = "maennlich"; break;
+  case FEMALE: gender = "weiblich"; break;
+  case NEUTER: gender = "neutral"; break;
+  default: gender = lower_case(tmp);
+  }
+
+  ind = m_indices(QueryProp(P_ATTRIBUTES));
+  tmp = "";
+  foreach(string index: ind) {
+    string aname;
+    switch (index) {
+      case "int": aname = "Intelligenz"; break;
+      case "con": aname = "Ausdauer"; break;
+      case "dex": aname = "Geschicklichkeit"; break;
+      case "str": aname = "Kraft"; break;
+      default:
+        if(stringp(index)) aname = capitalize(index);
+        else aname = "Unbekannt";
+    }
+    aname = sprintf("%-18'.'s %2.2d", aname+" ", QueryRealAttribute(index));
+    if((val = QueryAttributeOffset(index)))
+      aname += sprintf(" (%s%d)", (val>=0?"+":""), val);
+    tmp += aname + "\n";
+  }
+
+  printf("- %-'-'68s\n",
+         TeamPrefix()+capitalize(implode(explode(short()||"","\n"),""))+" ");
+  if(arg!="short") {
+    printf("Rasse ............ %-' '18s Abenteuer ........ %d %s\n",
+           QueryProp(P_RACE), QueryProp(P_QP),
+           (val = QM->QueryTotalQP()) == QueryProp(P_QP) ? "" : "("+val+")");
+    printf("Geschlecht ....... %-' '18s Groesse .......... %d cm\n",
+           gender, QueryProp(P_SIZE));
+    printf("Stufe ............ %-3.3d %-' '14s Gewicht .......... %d kg\n",
+           QueryProp(P_LEVEL), (QueryProp(P_LEVEL) < plev ? "("+plev+")" : ""),
+           QueryProp(P_WEIGHT) / 1000);
+    printf("Gilde ............ %-' '18s Gildenstufe ...... %d\n",
+         capitalize(QueryProp(P_GUILD)), QueryProp(P_GUILD_LEVEL));
+  }
+  printf("Erfahrung ........ %-' '18s Charakter ........ %-s\n\n",
+         QueryProp(P_XP)+ " Punkte", al_to_title(QueryProp(P_ALIGN)));
+  printf("%#-76.2s\n\n", tmp);
+  printf("Gesundheit ....... %-3.3d %-' '14s Gift ............. %s\n",
+         QueryProp(P_HP),
+         (QueryProp(P_HP) == (val = QueryProp(P_MAX_HP)) ? "" : "("+val+")"),
+         ((val = QueryProp(P_POISON)) ?
+          (val < 4 ? "leicht" : "gefaehrlich") : "gesund"));
+  printf("Konzentration .... %-3.3d %-' '14s Vorsicht ......... %s\n",
+         QueryProp(P_SP),
+         (QueryProp(P_SP) == (val = QueryProp(P_MAX_SP)) ? "" : "("+val+")"),
+         ((ind = QueryProp(P_WIMPY)) ? ""+ind : "mutig"));
+  printf("Todesfolgen....... %-' '18s %s\n",
+         ((val = death_suffering()) ? ""+((val+9)/10) : "kein Malus"),
+         (QueryProp(P_WIMPY) && ind=QueryProp(P_WIMPY_DIRECTION))
+         ? sprintf("Fluchtrichtung ... %O", ind) : "");
+  printf("%s",
+         (time()-Query(P_LAST_COMBAT_TIME)<120 && !IS_LEARNING(ME)) ?
+         "Spiel verlassen .. nicht moeglich\n" : ""
+         );
+
+  if(arg!="short") {
+    write(break_string(Forschung(), 70));
+    if(ind=QueryProp(P_AWAY))
+      printf("Du bist nicht ansprechbar: %O\n",ind);
+  }
+
+  if(sizeof(enem1=((mixed)QueryEnemies())[0])) {
+    enem2=({});
+    inv=all_inventory(environment(ME));
+    foreach(object en: enem1) {
+      if (member(inv,en)==-1) // Ist unser Feind und ist nicht hier
+        enem2+=({en});
+    }
+    if(sizeof(enem2))
+    {
+      write(break_string(
+            "Du verfolgst " + CountUp(map_objects(enem2, "name", WEN))+".",
+            78));
+    }
+  }
+  if(arg!="short") show_age();
+  printf("%-'-'70s\n", "");
+  return 1;
+}
+
+/** Gibt eine kuerzere Info ueber den Char aus (Spielerkommando punkte|score).
+    Ruft score("short").
+  * \param[in] arg UNUSED
+  * \return 1 bei Erfolg, 0 sonst.
+  * @see score(string), very_short_score()
+  */
+static int short_score(string arg) {
+  return score("short");
+}
+
+/** Gibt eine Miniinfo ueber LP / KP aus (Spielerkommando: kurzinfo)
+  * \return 1
+  * @see score(string), short_score(string)
+  */
+static int very_short_score(string arg) {
+  int    lp,mlp,xlp,kp,mkp,xkp;
+  string bar;
+
+  lp=QueryProp(P_HP); mlp=QueryProp(P_MAX_HP);
+  kp=QueryProp(P_SP); mkp=QueryProp(P_MAX_SP);
+  if (mlp)
+    xlp=(lp*40/mlp);
+  if (mkp)
+    xkp=(kp*40/mkp);
+  bar="  .    .    .    .    .    .    .    .  ";
+  if (QueryProp(P_NO_ASCII_ART) || arg == "-k")
+    printf("Gesundheit: %3.3d (%3.3d), Konzentration: %3.3d (%3.3d)\n",
+           lp, mlp, kp, mkp);
+  else
+    printf("Gesundheit:    0 |%'#'40.40s| %3.3d%s\n"+
+           "Konzentration: 0 |%'#'40.40s| %3.3d%s\n",
+           (xlp<0?bar:bar[xlp..]),lp,(lp==mlp?"":sprintf(" (%d)",mlp)),
+           (xkp<0?bar:bar[xkp..]),kp,(kp==mkp?"":sprintf(" (%d)",mkp))
+           );
+  return 1;
+}
+
+/** Gibt eine Manpage/Hilfeseite an den Spieler aus.
+    Beruecksichtigt hierbei die Synonymliste aus dir/.synonym, um die richtige
+    Manpage auszugeben.
+  * \param[in] dir Verzeichnis der gewuenschten Manpage
+  * \param[in] page Name der gewuenschten Manpage
+  * \return String der gewuenschten Manpage
+  */
+static string getmanpage(string dir, string page)
+{
+  string text, *syn;
+  int i;
+
+  if (dir[<1] != '/')
+    dir += "/";
+
+  if ((text=read_file(dir+page)) && sizeof(text))
+    return text;
+
+  if (text = read_file(dir+".synonym")) {
+    syn = regexplode(text, "([ \t][ \t]*|\n)");
+    if ((i=member(syn, page))!=-1)
+      return read_file(dir+syn[i+2]);
+  }
+  return 0;
+}
+
+/** Gibt eine Hilfeseite an den Spieler aus (Spielerkommando hilfe|man).
+  * Die Hilfeseite wird in div. Verzeichnissen gesucht (je nach Gilde,
+  * Magier-/Spielerstatus).
+  * \param[in] str Name der gewuenschten Hilfeseite.
+  * \return 1
+  */
+static int help(string str) {
+  string verb, rest, text, gilde;
+  mixed found;
+
+  found=0;
+  text = "";
+  if (str) {
+    str = implode( explode(str, ".." ), "");
+
+    if ( sscanf( str, "gilde %s %s", gilde, rest)==2)
+      str=rest;
+    else
+      gilde=QueryProp(P_GUILD);
+    if (!gilde) gilde="abenteurer";
+
+    if ( sscanf( str, "%s %s",verb,rest )==2 ) str = verb;
+
+    if ((IS_LEARNER(PL)) ) {
+      if (rest = getmanpage("/doc/wiz/",str)) {
+        found = 1;
+        text += rest;
+      }
+      else if (rest = getmanpage("/doc/mcmd/", str)) {
+        found = 1;
+        text += rest;
+      }
+    }
+
+    if ((IS_SEER(PL)) /*&& !found*/ ) {
+      if (rest = getmanpage("/doc/scmd/",str)) {
+        if (found)
+          text += "\n--------------------\n";
+        found = 1;
+        text += rest;
+      }
+    }
+
+    if (rest = getmanpage("/doc/g."+gilde+"/",str)) {
+      if (found)
+        text += "\n--------------------\n";
+      found = 1;
+      text += rest;
+    } else {
+      if (rest = getmanpage("/doc/help/",str)) {
+        if (found)
+          text += "\n--------------------\n";
+        found = 1;
+        text += rest;
+      }
+      else if (rest = getmanpage("/doc/pcmd/",str)) {
+        if (found)
+          text += "\n--------------------\n";
+        found = 1;
+        text += rest;
+      }
+      else if (rest = getmanpage("/doc/REGELN/",str)) {
+        if (found)
+          text += "\n--------------------\n";
+        found = 1;
+        text += rest;
+      }
+    }
+
+    if (!found)
+      text = "Dazu ist keine Hilfe verfuegbar.\n";
+
+    More(text,0);
+    return 1;
+  }
+  if (IS_LEARNER(PL))
+    text = read_file("/doc/hilfe.magier");
+  else if (IS_SEER(PL))
+    text = read_file("/doc/hilfe.seher");
+
+  More(text + read_file("/doc/hilfe.spieler"), 0);
+  return 1;
+}
+
+/** Ermittelt angebene Optionen fuer das Spielerkommando 'wer'.
+  * \param[in] str vom Spieler spezifizierter String von Filteroptionen: -k,
+  * -v, -a, -s (+ Langformen).
+  * \return Array von Spieleroptionen als veroderte Int-Flags und Rest der
+  * Spielereingabe ohne die Optionen.
+  */
+static mixed filter_who_options(string str)
+{
+  string* opt, *ans;
+  int i,len,res;
+
+  opt = explode(str," "); len=sizeof(opt);
+  ans = ({});
+  res = 0;
+  for(i=0;i<len;i++)
+    switch(opt[i]){
+      case "-k":
+      case "-kurz":
+      res |= WHO_SHORT; break;
+      case "-v":
+      case "-vertikal":
+      res |= WHO_VERTICAL; break;
+      case "-alphabetisch":
+      case "-a":
+      case "-alpha":
+      res |= WHO_ALPHA; break;
+      case "-s":
+      case "-spieler":
+      res |= WHO_PLAYER_VIEW; break;
+      default:
+      return ({ res, implode(opt[i..]," ") });
+    }
+  return ({ res, 0 });
+
+}
+
+/** Spielerkommando 'wer', fragt /obj/werliste ab.
+  * \param[in] str Spielereingabe mit Optionen fuer wer.
+  * \return 1
+  */
+static int who(string str) {
+  int i,shrt;
+  string ret;
+  mixed ans;
+
+  if ((str=_unparsed_args())&&str[0..0]!="-") {
+    ans = filter_who_options(str);
+    shrt = ans[0];
+    str = ans[1];
+    if (!shrt) {
+      if (ret=INETD->_send_udp(str,
+                              ([ REQUEST: "who", SENDER: getuid(ME) ]), 1 ))
+        write(ret);
+      else
+        write("Anfrage abgeschickt.\n");
+      return 1;
+    }
+  }
+  if (str) i=(member(str,'o')>0); else i=0;
+  if (sizeof(str)>1 && str[0] == '-') str = str[1..1];
+  More(implode( "/obj/werliste"->QueryWhoListe(
+    IS_LEARNER(ME) && QueryProp(P_WANTS_TO_LEARN),shrt,0,str,i),"\n"),0);
+  return 1;
+}
+
+/** Spielerkommando 'kwer', fragt /obj/werliste ab.
+  * \param[in] str Spielereingabe mit Optionen fuer wer.
+  * \return 1
+  */
+static int kwho(string str)
+{
+  int shrt;
+  mixed res;
+
+  if(str) {
+    res = filter_who_options(str);
+    shrt = res[0];
+    str = res[1];
+  }
+  More(implode( "/obj/werliste"->QueryWhoListe(
+      IS_LEARNER(ME) && QueryProp(P_WANTS_TO_LEARN), shrt|WHO_SHORT ,0,str),
+    "\n")+"\n\n",0);
+  return 1;
+}
+
+/** Spielerkommando 'kkwer', gibt eine einfache Liste der Anwesenden aus.
+    Filtert unsichtbare Spieler aus, falls SPielerobjekt kein Magier ist.
+  * \param[in] str Spielereingabe mit Optionen fuer wer.
+  * \return 1
+  */
+static varargs int kkwho(string str) {
+  object *obs;
+  string *namen;
+
+  obs=filter_users(str);
+  namen=({});
+  if (IS_LEARNER(this_player())) {
+    foreach(object ob: obs) {
+      if (environment(ob))
+        namen+=({capitalize(geteuid(ob))});
+    }
+  } 
+  else {
+    foreach(object ob: obs) {
+      if (!ob->QueryProp(P_INVIS) && environment(ob))
+        namen+=({capitalize(geteuid(ob))});
+    }
+  }
+  if (sizeof(namen))
+    write(break_string(CountUp(sort_array(namen,#'>),", ", ", ")+".",75));
+  else
+    write("Keine passenden Spieler gefunden.\n");
+  
+  return 1;
+}
+
+/** Spielerkommando 'toete'.
+  * Prueft auf Geist, Gast, toten HC-Spieler, Waffe/freie Hand. Versucht einen
+  * Gegner zu finden und ruft dann Kill(string).
+  * \param[in] str Spielereingabe
+  * \return 1 oder 0, falls kein potentieller Gegner bei 'toete alle' gefunden
+  * wird.
+  */
+static int kill(string str) {
+  object eob,wob;
+
+  if (QueryProp(P_GHOST))
+  {
+    write("Das kannst Du in Deinem immateriellen Zustand nicht.\n");
+    return 1;
+  }
+  
+  if(hc_play>1)
+  {
+    write("DAS HAST DU HINTER DIR.\n");
+    return 1;
+  }
+  
+  if (QueryGuest())
+  {
+    write("Du bist doch nur Gast hier.\n");
+    return 1;
+  }
+  if (!str || str == "") {
+    write("WEN willst Du toeten?\n");
+    return 1;
+  }
+  if( !QueryProp(P_WEAPON) && QueryProp(P_FREE_HANDS)==0 ) {
+    write(
+      "Dazu solltest Du eine Waffe gezueckt oder eine Hand frei haben.\n");
+    return 1;
+  }
+  str=lower_case(str);
+  if (str=="alle") {
+    object livs;
+    livs=filter(all_inventory(environment(PL)),
+        function int (object ob) {
+            if (living(ob) && !query_once_interactive(ob)
+                  && !ob->QueryProp(P_INVIS)
+                  && !ob->QueryProp(P_NO_GLOBAL_ATTACK)
+                  && !ob->QueryProp(P_FRIEND))
+            {
+                Kill(ob);
+                return 1;
+            }
+            return 0;
+        } );
+    // wenn Gegner gefunden, raus, ansonsten kommt die Fehlermeldung unten.
+    if (sizeof(livs)) return 1;
+  }
+  else {
+    int i=1;
+    while(objectp(eob = present(str,i++,environment(PL)))) {
+      if (living(eob) && !eob->QueryProp(P_INVIS))
+        break;
+      else
+        eob=0;
+    }
+  }
+  if (!objectp(eob)) {
+    // per write und return 1 ist hier mal ok, weil dies Kommando im Spieler
+    // eh zuletzt in der Kommandokette ausgefuehrt wird und per return 0 eh
+    // kein anderes mehr zum Zug kommt.
+    write("Du siehst hier kein derartiges Wesen!\n");
+    return 1;
+  }
+  else if (eob == PL) {
+    write("Selbstmord ist keine Loesung!\n");
+    return 1;
+  }
+
+  /* Kill him */
+  Kill(eob);
+  return 1;
+}
+
+/** Spielerkommando 'stop'.
+  * Loescht die Gegnerliste, sofern man nicht InFight() ist.
+  * \param[in] str Spielereingabe, wird ignoriert.
+  * \return 1
+  */
+static int stop( string str )
+{
+    if ( InFight() ){
+        write( "Das geht nicht mitten im Kampf.\n" );
+        return 1;
+    }
+
+    if ( !str ){
+        StopHuntingMode();
+        write( "Ok.\n" );
+        return 1;
+    }
+
+    if ( !StopHuntID(str) )
+        write( "So jemanden verfolgst Du nicht!\n" );
+
+    return 1;
+}
+
+/** Spielerkommando fuers emoten ':'.
+  * \param[in] str Spielereingabe
+  * \param[in] genitiv Genetivflag
+  * \return 1 oder 0, falls Spieler nicht emoten kann (kein CAN_EMOTE Flag in
+  * P_CAN_FLAGS).
+  */
+int emote(string str,int genitiv)
+{
+  string *commands,message,verb;
+  object living;
+  int i,size;
+
+  if (!(Query(P_CAN_FLAGS)&CAN_EMOTE)) return 0;
+  if (query_verb()[0]==';') genitiv=1;
+  if (query_verb()[0]==':'||query_verb()[0]==';')
+    verb=query_verb()[1..]+" ";
+  else
+    verb="";
+  str=this_player()->_unparsed_args();
+  commands=explode(verb+(str||""),"#");
+  message=break_string((IS_SEER(ME) ? "" : ">")
+                       +capitalize(genitiv ? name(WESSEN) :
+                                   name())
+                       +" "+commands[0],78);
+  size=sizeof(commands);
+  if(size>=3)
+  {
+    living=find_living(lower_case(commands[1]));
+    if(!living || environment(living)!=environment() ||
+       (living->QueryProp(P_INVIS)) && !IS_LEARNER(ME))
+    {
+      write(capitalize(commands[1])+" sehe ich hier nicht!\n");
+      return 1;
+    }
+    if(living!=this_object())
+      tell_object(living,break_string((IS_SEER(this_player()) ? "" : ">")
+                                    +capitalize(genitiv ?
+                                                this_player()->name(WESSEN) :
+                                                this_player()->name())
+                                    +" "+commands[2],78));
+  }
+  if(size>=4)
+    write(break_string(commands[3],78));
+  else
+    write(message);
+  tell_room(environment(),message,({this_object(),living}));
+  return 1;
+}
+
+/** Spielerkommando fuers remoten 'r:'.
+  * \param[in] str Spielereingabe
+  * \param[in] flag Genetivflag
+  * \return 1 oder 0, falls Spieler nicht emoten kann (kein CAN_REMOTE Flag in
+  * P_CAN_FLAGS).
+  */
+static int remote(string str, int flag)
+{
+  int m;
+  string tmp, dest;
+  string *exstr;
+  object destpl;
+
+  if ( !(Query(P_CAN_FLAGS) & CAN_REMOTE) )
+      return 0;
+
+  if ( !(str=_unparsed_args()) ||
+       sizeof( (exstr=explode(str," ")) - ({""}) ) <= 1 ){
+      write("Was willst Du zu wem `emoten`?\n");
+      return 1;
+  }
+
+  dest = lower_case(exstr[0]);
+
+  if( !(destpl=find_player( dest ) ) ||
+      (destpl->QueryProp(P_INVIS) && !IS_LEARNER(ME)) ){
+    write("Einen solchen Spieler gibt es derzeit nicht.\n");
+    return 1;
+  }
+
+  tmp = implode( exstr[1..], " " );
+
+  tmp = regreplace( tmp, "(^|[^#])#($|[^#])", "\\1aus der Ferne\\2", 1 );
+  tmp = regreplace( tmp, "(^|[^\\^])\\^($|[^\\^])", "\\1in der Ferne\\2", 1 );
+  tmp = regreplace( tmp, "##", "#", 1 );
+  tmp = regreplace( tmp, "\\^\\^", "^", 1 );
+
+  if ( strstr( tmp, "aus der Ferne" ) == -1
+       && strstr( tmp, "in der Ferne" ) == -1 )
+      tmp += " aus der Ferne";
+
+  if ( QueryProp(P_INVIS) && IS_LEARNER(destpl) ){
+      str = "(" + capitalize(getuid(ME));
+      if ( flag )
+          str += member( "sxz", str[<1] ) == -1 ? "s" : "'";
+      str += ")";
+  }
+  else
+      str = (flag ? capitalize(name(WESSEN)) : capitalize(name(WER)));
+
+  str += " " + tmp + (member( ".?!", tmp[<1] ) == -1 ? "." : "") + "\n";
+
+  m = destpl->ReceiveMsg(str, MT_COMM|MT_FAR, MA_EMOTE,0, ME);
+  switch(m)
+  {
+    case MSG_DELIVERED:
+      _recv(destpl, capitalize(destpl->name()) + "->" + str, MSGFLAG_REMOTE);
+      break;
+    case MSG_BUFFERED:
+      write( capitalize(destpl->name(WER) + " ist gerade beschaeftigt.\n") );
+      break;
+    case MSG_IGNORED:
+      write( capitalize(destpl->name(WER) + " ignoriert Dich.\n") );
+      break;
+    case MSG_VERB_IGN:
+    case MSG_MUD_IGN:
+      write( capitalize(destpl->name(WER) + " ignoriert Deine Meldung.\n") );
+      break;
+    default:
+      write( capitalize(destpl->name(WER) + " kann Dich gerade nicht "
+            "wahrnehmen.\n") );
+  }
+  return 1;
+}
+
+/** Spielerkommando fuers emoten im Genitiv ';'.
+  * Ruft emote(string,int) auf.
+  */
+static int gemote(string str)
+{
+  return emote(str, 1);
+}
+
+/** Spielerkommando fuers remoten im Genitiv 'r;'.
+  * Ruft remote(string, int) auf.
+  */
+static int gremote(string str)
+{
+  return remote(str, 1);
+}
+
+static void load_auto_objects(mapping map_ldfied);
+
+private void InitPlayer();
+private void InitPlayer2();
+private void InitPlayer3();
+
+/** Gibt eine Zufallszahl um P_AVERAGE_SIZE herum zurueck.
+  * \return Zufaellige Groesse.
+  */
+private int RandomSize()
+{
+  return (100+random(13)-random(13)+random(13)-random(13))*
+    (QueryProp(P_AVERAGE_SIZE)||170)/100;
+}
+
+/** Setzt bestimmte Props im Spieler, falls diese nicht gesetzt sind oder
+  * loescht obsolete Props. Repariert bestimmte Datenstrukturen im Spieler.
+  * Wird von start_player() nach Laden des Savefiles gerufen.
+  * Momentan wird z.B. die Groesse gesetzt, falls sie bisher 0 ist und die
+  * Skills des Spielers initialisiert bzw. repariert oder auf die aktuellste
+  * Version des Skillsystems
+  * Ruft ggf. InitSkills() und FixSkills().
+  * @param[in] newflag Gibt an, ob es ein neuerstellter Spieler ist.
+  * @sa start_player(), InitSkills(), FixSkills()
+  */
+private void updates_after_restore(int newflag) {
+ 
+  // Seher duerfen die Fluchtrichtung uebermitteln lassen.
+  // Eigentlich koennte es Merlin machen. Dummerweise gibt es ja auch alte
+  // Seher und dann kann es gleiche fuer alle hier gemacht werden. (Ob der
+  // Code jemals rauskann?)
+  //TODO: Irgendwann alle Seher korrigieren und Code nach Merlin schieben...
+  if (IS_SEER(ME))
+    SetProp(P_CAN_FLAGS,QueryProp(P_CAN_FLAGS) | CAN_REPORT_WIMPY_DIR);
+
+  // ggf. Invis-Eigenschaft aus dem Loginobjekt abrufen (Invislogin), koennte
+  // ja anders als aus Savefile sein. Gesetztes P_INVIS aus diesem aber
+  // beibehalten.
+  if (IS_LEARNER(ME) && !QueryProp(P_INVIS)
+//      && load_name(previous_object()) == "/secure/login"
+      )
+  {
+    SetProp(P_INVIS, previous_object()->query_invis());
+    if (QueryProp(P_INVIS))
+      tell_object(ME, "DU BIST UNSICHTBAR!\n" );
+  }
+  "*"::updates_after_restore(newflag);
+
+  attributes::UpdateAttributes();
+
+  int size=Query(P_SIZE);
+  if (!size) size=RandomSize();
+  while(size==QueryProp(P_AVERAGE_SIZE))
+    size=RandomSize();
+  Set(P_SIZE,size);
+
+  // Prop wird nicht mehr genutzt. TODO: irgendwann entfernen.
+  Set(P_SECOND_LIST, SAVE, F_MODE_AD);
+  Set(P_SECOND_LIST, 0, F_VALUE);
+}
+
+
+/** Setzt den HC-Modus.
+  */
+varargs nomask void set_hc_play(string str,int val)
+{
+   string str1;
+
+    str1 = explode( object_name(previous_object()), "#" )[0];
+    
+    if ( str1 != "/secure/login" &&
+         previous_object()!=this_object() &&
+         extern_call() &&
+         (!geteuid(ME) || geteuid(ME) != getuid(ME) ||
+          capitalize(geteuid(ME)) != str ||
+          geteuid(ME) != geteuid(previous_object())) ){
+        write( "DIESER VERSUCH WAR ILLEGAL !!\n" );
+        return;
+    }
+    
+    hc_play=val;
+}
+
+/** gibt den HC-Modus zurueck.
+  */
+nomask int query_hc_play()
+{
+  return hc_play;
+}
+
+/** Initialisiert und aktiviert das Spielerobjekt.
+  * Kann nur von /secure/login oder /secure/master gerufen werden.
+  * Startet Telnet Negotiation, laedt Savefile, setzt einige Props. 
+  * Ruft updates_after_restore(), um div. Daten zu aktualisieren/reparieren.
+  * Ruft create() aus /std/player/potion.c.
+  * Bei neuem Spieler wird der entsprechende Event ausgeloest die Attribute
+  * auf die Startwerte gesetzt.
+  * Prueft Zweitiemarkierungen.
+  * Ruft InitPlayer().
+  * @param[in] str Name des Charakters, der geladen werden soll.
+  * @param[in] ip textuelle Repraesentation der IP-Adresse des Spielers.
+  * @return 1 bei Erfolg, 0 sonst.
+  * @todo Div. Reparaturen/Updates nach updates_after_restore() auslagern.
+  */
+varargs nomask int start_player( string str, string ip )
+{
+    mixed second;
+    int newflag;  /* could player be restored? */
+    string str1;
+
+    call_out( "disconnect", 600 );
+
+    str1 = explode( object_name(previous_object()), "#" )[0];
+
+    if ( str1 != "/secure/login" &&
+         str1 != "/secure/master" &&
+         (!geteuid(ME) || geteuid(ME) != getuid(ME) ||
+          capitalize(geteuid(ME)) != str ||
+          geteuid(ME) != geteuid(previous_object())) ){
+        write( "DIESER VERSUCH WAR ILLEGAL !!\n" );
+        destruct(ME);
+        return 0;
+    }
+
+    /* try to restore player. If it doesn't exist, set the new flag */
+    newflag = !restore_object( "/" + SAVEPATH + lower_case(str)[0..0] + "/"
+                               +lower_case(str) );
+
+    updates_after_restore(newflag);
+
+   if ( query_once_interactive(ME) )
+    {
+      // Telnet-Negotiations durchfuehren, aber nur die grundlegenden aus
+      // telnetneg. Alle anderen sollten erst spaeter, nach vollstaendiger
+      // Initialisierung gemacht werden.
+        telnetneg::startup_telnet_negs();
+        modify_prompt();
+        Set( P_LAST_LOGIN, time() );
+    }
+
+    Set( P_WANTS_TO_LEARN, 1 ); // 1 sollte der default sein !!!
+    Set( P_WANTS_TO_LEARN, PROTECTED, F_MODE_AS );
+    // Eingefuegt 18.11.99, kann nach einem Jahr wieder raus:
+    Set( P_TESTPLAYER, PROTECTED, F_MODE_AS );
+
+    if ( IS_LEARNER(ME) )
+        SetProp( P_CAN_FLAGS, QueryProp(P_CAN_FLAGS)|CAN_REMOTE );
+
+    Set( P_NAME, str );
+    Set( P_NAME, SECURED, F_MODE_AS );
+
+    if ( !QueryProp(P_NEEDED_QP) )
+        SetProp( P_NEEDED_QP, REQ_QP );
+
+    Set( P_NEEDED_QP, NOSETMETHOD, F_SET_METHOD );
+    Set( P_NEEDED_QP, SAVE|SECURED, F_MODE_AS );
+
+    /* autosave the player after 500 heartbeats */
+    time_to_save = age + 500;
+    potion::create(); /* DO IT HERE AFTER THE RESTORE !! */
+
+    AddId( getuid() );
+    SetProp( P_AC, 0 );
+    SetProp( P_WEAPON, 0 );
+
+    /* Set some things which wont be set when all is OK */
+    SetProp( P_MAX_HP, (QueryAttribute(A_CON) * 8 + 42 ));
+    SetProp( P_MAX_SP, (QueryAttribute(A_INT) * 8 + 42 ));
+
+    catch( bb = "/secure/bbmaster"->query_bb() );
+
+    /* If this is a new character, we call the adventurers guild to get
+     * our first title !
+     */
+    if ( newflag ) {
+        if ( QueryGuest())
+            SetProp( P_TITLE, "ueberkommt das "MUDNAME" ..." );
+
+        Set( P_LEVEL, -1 );
+        SetProp( P_ATTRIBUTES, ([ A_STR:1, A_CON:1, A_INT:1, A_DEX:1 ]) );
+        SetProp( P_HP, QueryProp(P_MAX_HP) );
+
+        // Event ausloesen
+        EVENTD->TriggerEvent(EVT_LIB_PLAYER_CREATION, ([
+              E_OBJECT: ME,
+              E_PLNAME: getuid(ME) ]) );
+    }
+    
+    InitPlayer();
+
+    // Padreic 01.02.1999
+    if ( !IS_LEARNER(ME) && second = QueryProp(P_SECOND) ) {
+        if ( stringp(second) && lower_case(second)[0..3] == "von " ) {
+            second = lower_case(second[4..]);
+            SetProp( P_SECOND, second );
+        }
+
+        if ( !stringp(second ) ||
+             file_size( "/save/" + second[0..0] + "/" + second + ".o" ) <= 0 ){
+            if ( stringp(second) &&
+                 file_size( "/save/" + lower_case(second[0..0]) + "/" +
+                            lower_case(second) + ".o" ) >0 ){
+                SetProp( P_SECOND, lower_case(second) );
+                log_file( "WRONG_SECOND",
+                          sprintf( "%s: %s: P_SECOND = %O -> Automatisch "
+                                   "korrigiert,\n",
+                                   dtime(time()), object_name(), second ) );
+            }
+            else {
+                tell_object( ME,
+                             "*\n*\n* Deine Zweitiemarkierung ist ungueltig, "
+                             "bitte aendere diese und sprich im\n* Zweifel "
+                             "bitte einen Erzmagier an.\n*\n*\n" );
+
+                log_file( "WRONG_SECOND",
+                          sprintf( "%s: %s: P_SECOND = %O\n",
+                                   dtime(time()), object_name(), second ) );
+                // ein bisschen deutlicher auffordern.. Padreic 08.04.1999
+                move( "/d/gebirge/room/zwafflad", M_GO );
+            }
+        }
+    }
+    return(0);
+}
+
+/** Letzte Phase der Spielerinitialisierung beim Laden des Charakters.
+  * Ruft enable_commands(), aktiviert den Heartbeat und aktiviert die
+  * Kommandos aus den geerbten command.c, put_and_get.c, team.c, soul.c,
+  * guide.c, setzt den Living Name.
+  * Registriert UseSpell() als Catchall-Kommando.
+  * Laesst den Spieler ggf. einen Level per /std/gilde aufsteigen, ruft
+  * call_notify_player_change(), loest Login-Event aus.
+  * Gibt Willkommenstexte, News und neue Mails aus.
+  * Findet den Startraum und bewegt den Spieler dorthin.
+  * Ruft FinalSetup() (aus den Rassenshells).
+  * Begrenzt Geldmenge im Spieler (wegen Bankzweities) nach Tragkraft und
+  * erstattet Geld bei Reboot.
+  * Ruft set_is_wizard().
+  * Startet Clonen der Autoloader.
+  * @sa InitPlayer3(),InitPlayer2(), InitPlayer(), start_player().
+  */
+private void InitPlayer4()
+{
+    int num, str, ski;
+    string err, called_from_ip;
+    mixed start_place;
+    object mon;
+
+    enable_commands();
+    set_heart_beat(1);
+    command::initialize();
+    add_put_and_get_commands();
+    add_team_commands();
+    add_soul_commands();
+    add_guide_commands();
+    add_action( "UseSpell", "", 1 );
+    set_living_name( getuid() );
+    while ( remove_call_out("disconnect") != -1 )
+        ;
+
+    if ( QueryProp(P_LEVEL) == -1 )
+    {
+        catch( "/std/gilde"->try_player_advance(this_object()) ;publish );
+    }
+
+    if ( interactive(ME) )
+        call_notify_player_change(1);
+
+    if ( interactive(this_object()) ) {
+        cat( "/etc/NEWS" );
+
+        NewbieIntroMsg();
+
+        if ( QueryProp(P_INVIS) && !IS_WIZARD(ME) )
+            SetProp( P_INVIS, 0 );
+
+        catch( num = "secure/mailer"->FingerMail(getuid());publish );
+
+        if ( num )
+            write( "Du hast " + num + " neue" +
+                   (num == 1 ? "n Brief" : " Briefe")+" im Postamt liegen.\n" );
+
+        catch( RegisterChannels();publish );
+
+        if ( (called_from_ip = Query(P_CALLED_FROM_IP)) &&
+             query_ip_number(ME) != called_from_ip ){
+            string tmp;
+
+            if ( stringp(tmp = query_ip_name(called_from_ip)) &&
+                 tmp != called_from_ip )
+                tmp = " [" + tmp + "]";
+            else
+                tmp = "";
+
+            write( "Das letzte Mal kamst Du von " + called_from_ip
+                   + tmp + ".\n" );
+        }
+
+        Set( P_CALLED_FROM_IP, query_ip_number(ME) );
+    }
+
+    if ( !stringp(default_home) || default_home == "" )
+        default_home = "/gilden/abenteurer";
+
+    if ( IS_SEER(ME) && !IS_LEARNER(ME) )
+        catch( start_place = HAUSVERWALTER->FindeHaus(getuid(ME));publish );
+    // wenn der Spieler noch ganz frisch ist und noch wenig  Stufenpunkte
+    // gekriegt hat und das Tutorial noch nicht gemacht hat, startet er im
+    // Tutorial.
+    else if (QueryProp(P_LEP) <= 120
+             && QM->HasMiniQuest(this_object(),
+               "/d/anfaenger/ennox/tutorial/npcs/verkaeufer") != 1)
+        start_place = "/room/welcome/"+ getuid(this_object());
+    else
+        start_place = 0;
+
+    if ( !start_place )
+        start_place = QueryProp(P_START_HOME);
+
+    if( objectp(start_place) || (stringp(start_place) && start_place != "" ) ){
+        if ((err = catch(move( start_place, M_GO|M_SILENT|M_NO_SHOW );publish)) 
+            || !environment() )
+            err = catch(move( default_home, M_GO|M_SILENT|M_NO_SHOW );publish);
+    }
+    else
+        err = catch(move( default_home, M_GO|M_SILENT|M_NO_SHOW );publish);
+
+    if ( err )
+        catch(move( "/gilden/abenteurer", M_GO|M_SILENT|M_NO_SHOW );publish);
+
+    // Die Shell muss FinalSetup() nicht implementieren. Daher Callother
+    catch( ME->FinalSetup();publish );
+
+    // Login-event ausloesen
+    EVENTD->TriggerEvent(EVT_LIB_LOGIN, ([
+          E_OBJECT: ME,
+          E_PLNAME: getuid(ME),
+          E_ENVIRONMENT: environment() ]) );
+
+    // erst jetzt GMCP freigeben und zu verhandeln.
+    gmcp::startup_telnet_negs();
+
+    // Schonmal sichern, falls ein Bug (Evalcost...) dazwischen kommen sollte.
+    autoload_rest = autoload;
+
+    // Um Geld-Xties mit illegal viel Geld zu vermeiden, kommt ein Check:
+    if ( !IS_LEARNER(ME) && !Query(P_TESTPLAYER) &&
+         mon = present( "\ngeld", ME ) ){
+        // maximale Kraft, die der Spieler haette haben koennen
+        str = QueryAttribute(A_STR) + 4;
+        if ( Query(P_FROG) )
+            str += 30;
+        if ( str < 1 )
+            str = QueryRealAttribute(A_STR) + 4;
+        if ( str > 30 )
+            str = 30;
+
+        // Trageskill beachten
+        ski = to_int(UseSkill( SK_CARRY, ([SI_SKILLARG : str ]) ));
+        if ( !intp(ski) )
+            ski = 0;
+
+        // Wieviel konnte der Spieler insgesamt maximal tragen?
+        num = 9200 + str * 800 + ski;
+        if ( num < 3000 )
+            num = 3000;
+
+        // Verdoppeln fuer einen guten Container und nochmal 20% draufschlagen
+        // zur Sicherheit. Das Ganze danach *4, um die maximale Anzahl Muenzen
+        // zu erhalten.
+        num = (int) (num * 8.8);
+
+        // Geld, das zuviel ist, auf den Maximalwert kuerzen.
+        // Zur Sicherheit wird mitgeloggt. Falls ein Spieler sich (zu recht)
+        // beschwert, kann man immer noch wieder die Summe korrigieren ;-)
+        if ( (str = mon->QueryProp(P_AMOUNT)) > num ){
+            mon->SetProp( P_AMOUNT, num );
+            log_file( "ZUVIEL_GELD", sprintf( "%s: %s hatte %d Muenzen bei "
+                                              "sich. Korrigiert auf %d.\n ",
+                                              ctime(time())[4..],
+                                              capitalize(getuid(ME)),
+                                              str, num ) );
+        }
+    }
+    int entschaedigung = QueryProp(P_CARRIED_VALUE);
+    if ( entschaedigung > 0 )
+    {
+        write( "Du findest " + entschaedigung +
+               " Muenzen, die Du beim letzten Mal verloren hast.\n" );
+
+        if ( MayAddWeight( entschaedigung / 4 ) ){
+            write( "Weil Du nicht mehr soviel tragen kannst, spendest Du den "+
+                   "Rest der Zentralbank.\n" );
+
+            num = (QueryProp(P_MAX_WEIGHT) - query_weight_contents()) * 4;
+            entschaedigung = (num < 0) ? 0 : num;
+        }
+
+        AddMoney( entschaedigung );
+        SetProp(P_CARRIED_VALUE,0);
+    }
+
+    if ( !QueryProp(P_INVIS) )
+        say( capitalize(name(WER)) + " betritt diese Welt.\n" );
+    else
+        write( "DU BIST UNSICHTBAR!\n\n" );
+#if __EFUN_DEFINED__(set_is_wizard)
+    if ( IS_WIZARD(getuid(ME)) )
+        set_is_wizard( ME, 1 );
+    else
+        set_is_wizard( ME, 0 );
+#endif
+    if ( query_once_interactive(ME) )
+        ListAwaited();
+
+    // Autoloader werden ganz zum Schluss geclont, da das bis zum bitteren
+    // (Evalcost-)Ende geschieht und danach u.U. keine Rechenzeit fuer
+    // andere Aktionen mehr ueber ist
+    load_auto_objects( autoload );
+}
+
+/** Setzt die Spielerinitialisierung nach start_player() fort.
+  * Prueft den Wert der vom Spieler getragenen Sachen (fuer Entschaedigung
+  * nach Reboot).
+  * Setzt div. Properties des "Spielerkoerpers", die eigentlich gespeichert
+  * werden, nach einem Reboot zurueck.
+  * Fragt ggf. nach eMail-Adresse und uebergibt per input_to an
+  * InitPlayer2().
+  * @sa InitPlayer3(),InitPlayer2(), InitPlayer(), start_player().
+*/
+private void InitPlayer()
+{
+    string mailaddr;
+
+    // wenn es einen Crash gab, sollen Spieler nicht noch extra bestraft werden
+    if ( file_time( "/save/" + getuid()[0..0] + "/" + getuid() + ".o" )
+         < last_reboot_time() ){
+        SetProp( P_FOOD, 0 );
+        SetProp( P_DRINK, 0 );
+        SetProp( P_ALCOHOL, 0 );
+        SetProp( P_BLIND, 0 );
+        SetProp( P_DEAF, 0 );
+        SetProp( P_POISON, 0 );
+        SetProp( P_GHOST, 0 );
+        SetProp( P_FROG, 0 );
+        SetProp( P_HP, QueryProp(P_MAX_HP) );
+        SetProp( P_SP, QueryProp(P_MAX_SP) );
+    }
+
+    if ( QueryGuest() )
+        Set( P_MAILADDR, "none" );
+    else if ( !(mailaddr = Query(P_MAILADDR)) || mailaddr == "" ) {
+        write(break_string(
+          "Eine gueltige EMail-Adresse erleichtert es erheblich, Dir "
+          "ein neues Passwort setzen zu lassen, falls Du einmal Dein "
+          "Passwort vergisst.",78)); 
+        input_to( "getmailaddr",INPUT_PROMPT,
+            "Gib bitte Deine EMail-Adresse an: " );
+        return;
+    }
+    InitPlayer2();
+}
+
+/** liest eMail-Adresse vom Spieler ein und speichert sie.
+  * Uebergibt anschliessend an InitPlayer2()
+  * @param[in] maddr Spielereingabe der Emailadresse.
+  * @sa InitPlayer2().
+  */
+static void getmailaddr( string maddr )
+{
+    maddr = check_email(maddr);
+
+    if ( !stringp(maddr)) {
+      write("Deine Eingabe scheint keine gueltige EMail-Adresse gewesen "
+          "zu sein.\n");
+      input_to( "getmailaddr", INPUT_PROMPT,
+          "Gib bitte Deine EMail-Adresse an: " );
+      return;
+    }
+    Set( P_MAILADDR, maddr );
+    InitPlayer2();
+}
+
+
+/** Prueft Geschlecht des Spielers und fragt ggf. beim Spieler nach.
+  * Uebergibt an InitPlayer3() oder get_gender().
+  * @sa InitPlayer3(), get_gender().
+  */
+private void InitPlayer2()
+{
+    if( member(({ MALE, FEMALE }), QueryProp(P_GENDER) ) == -1 ) {
+        input_to( "getgender", INPUT_PROMPT,
+            "Bist Du maennlich oder weiblich: ");
+        return;
+    }
+
+    InitPlayer3();
+}
+
+/** Liest Spielerantwort auf die Frage nach dem Geschlecht des Chars ein.
+  * Wird gerufen von input_to().
+  * Uebergibt an InitPlayer3().
+  * @sa InitPlayer3().
+  */
+static void getgender( string gender_string )
+{
+    gender_string = lower_case( gender_string );
+
+    if ( sizeof(gender_string)==1 && gender_string[0] == 'm' ){
+        write( "Willkommen, mein Herr!\n" );
+        SetProp( P_GENDER, MALE );
+    }
+    else if ( sizeof(gender_string)==1 && gender_string[0] == 'w' ){    
+        write( "Willkommen, gnae' Frau!\n" );
+        SetProp( P_GENDER, FEMALE );    
+    }    
+    else {
+        write( "Wie? Was? Verstehe ich nicht!\n" );    
+        input_to( "getgender", INPUT_PROMPT,
+            "Bist Du maennlich oder weiblich? (tippe m oder w): ");    
+        return;
+    }
+
+    InitPlayer3();
+}
+
+
+/** Prueft Terminaltyp des Spielers und fragt ggf. beim Spieler nach.
+  * Uebergibt an InitPlayer4() oder gettty().
+  * @sa InitPlayer4(), gettty().
+  */
+private void InitPlayer3()
+{
+    if ( !QueryProp(P_TTY) || QueryProp(P_TTY) == "none" )
+    {
+        write( "Waehle einen Terminaltyp (kann spaeter mit <stty> geaendert "
+               "werden)\n");
+        input_to( "gettty", INPUT_PROMPT, "vt100, ansi, dumb (Standard: dumb): " );
+        return;
+    }
+    InitPlayer4();
+}
+
+/** Liest Spielerantwort auf die Frage nach dem Terminaltyp ein.
+  * Wird gerufen von input_to().
+  * Uebergibt an InitPlayer4().
+  * @sa InitPlayer4().
+  */
+static void gettty( string ttystr )
+{
+    if ( !ttystr || ttystr == "" )
+        ttystr = "dumb";
+
+    ttystr = lower_case(ttystr);
+
+    if ( ttystr == "vt100" ){
+        write( "Dies sollte " + ANSI_BOLD + "fett" + ANSI_NORMAL + " sein.\n" );
+        SetProp( P_TTY, ttystr );
+    }
+    else
+        if ( ttystr == "ansi" ){
+            write( "Dies sollte " + ANSI_RED + "rot" + ANSI_NORMAL +
+                   " sein.\n" );
+            SetProp( P_TTY, "ansi" );
+        }
+        else if ( ttystr == "dumb" ){
+            write( "Ohje, oede! Besorg Dir ein besseres Terminal!\n" );
+            SetProp( P_TTY, "dumb" );
+        }
+        else {
+            write( "Dieser Terminaltyp wird nicht unterstuetzt. Nimm bitte "
+                   "einen aus:\nvt100, ansi or dumb (Standard ist dumb).\n" );
+            input_to( "gettty", INPUT_PROMPT,
+                "vt100, ansi or dumb (Standard ist dumb): ");
+            return;
+        }
+
+    InitPlayer4();
+}
+
+
+/** Liefert die UID des Charakters zurueck, also den Charakternamen.
+  * @return UID des Objekts (Charaktername).
+  */
+nomask string query_real_name() {
+  /* ACHTUNG !! DIES LFUN DARF NICHT ENTFERNT WERDEN !!! */
+  /* Sie wird vom Gamedriver (zB bei F_ED) aufgerufen !! */
+  /* Ich bin da zwar nicht so ueberzeugt von, dass der Driver die heutzutage
+   * noch ruft, aber die halbe Mudlib ruft sie. ;-) (Zesstra, 27.4.08)
+   */
+  return getuid();
+}
+
+/*
+ * the wizard command review: show player moving messages
+ */
+int review() {
+  string *msg;
+  write(short());
+  write("Deine Bewegungen werden wie folgt gemeldet:\n"+
+        "mout:  "+name(WER)+" "+(msg=explode(QueryProp(P_MSGOUT),"#"))[0]
+       +" <Richtung>"+(sizeof(msg)>1 ? msg[1] : "")+".\n"+
+        "min:   "+name(WER)+" "+QueryProp(P_MSGIN)+".\n"+
+        "mmout: "+name(WER)+" "+QueryProp(P_MMSGOUT)+".\n"+
+        "mmin:  "+name(WER)+" "+QueryProp(P_MMSGIN)+".\n"+
+        (IS_LEARNER(ME) ?
+         "cmsg:  "+name(WER)+" "+QueryProp(P_CLONE_MSG)+".\n"+
+         "dmsg:  <Irgendetwas> "+QueryProp(P_DESTRUCT_MSG)+".\n"
+         : "")+
+        "Wenn Du jemanden angreifst, sieht das so aus:\n"+
+        name(WER)+" greift Dich"+QueryProp(P_HANDS)[0]+" an.\n");
+  return 1;
+}
+
+/*
+ * set player moving messages
+ */
+
+static int setmin(string str)
+{
+  SetProp(P_MSGIN, _unparsed_args()||"kommt an");
+  write("Ok.\n");
+  return 1;
+}
+
+static int setmout(string str)
+{
+  string *msg;
+
+  if(sizeof(msg=explode((_unparsed_args()||"geht"),"#"))>2)
+  {
+    write("Du darfst nur einmal '#' fuer die Richtung angeben.\n");
+    return 1;
+  }
+  if(sizeof(msg)>1)
+  {
+    if (msg[0]!="" && msg[0][<1]==' ') msg[0]=msg[0][0..<2];
+    SetProp(P_MSGOUT, msg[0]+"#"+msg[1]);
+  }
+  else
+    SetProp(P_MSGOUT, _unparsed_args()||"geht");
+  write("Ok.\n");
+  return 1;
+}
+
+static int setmmin(string str)
+{
+  SetProp(P_MMSGIN, _unparsed_args()||"erscheint");
+  write("Ok.\n");
+  return 1;
+}
+
+static int setmmout(string str)
+{
+  SetProp(P_MMSGOUT, _unparsed_args()||"verschwindet");
+  write("Ok.\n");
+  return 1;
+}
+
+static int setcmsg(string str)
+{
+  SetProp(P_CLONE_MSG, _unparsed_args()||"zaubert etwas aus "
+          + QueryPossPronoun(MALE,WEM) + " Aermel hervor");
+  write("Ok.\n");
+  return 1;
+}
+
+static int setdmsg(string str)
+{
+  SetProp(P_DESTRUCT_MSG, _unparsed_args()||"wird von " + name(WER,1)
+          + " zerstaeubt");
+  write("Ok.\n");
+  return 1;
+}
+
+static int set_title(string str)
+{
+  string bonus;
+  
+  if(!IS_SEER(this_object()) && !FAO_HAS_TITLE_GIFT(this_object()) )
+  {
+    return 0;
+  }
+  
+  bonus = "";
+  if (!(str=_unparsed_args()))
+    str = "";
+  else if( str[0..2]=="\\b," || str[0..2]=="\\b'" )
+  {
+    bonus = "\b"; // ein backspace fuer ein (hoch)komma ist ok! :-)
+    str = str[2..];
+  }
+  if(str=="0")  // damit der Gildentitel zum Vorschein kommen kann
+    SetProp(P_TITLE, 0);
+  else
+    SetProp(P_TITLE, bonus+str);
+  write("Ok.\n");
+  return 1;
+}
+
+static int extra_input(string str, string look)
+{
+  if (str=="**")
+  {
+    if (look=="")
+      SetProp(P_EXTRA_LOOK,0);
+    else
+      SetProp(P_EXTRA_LOOK,look);
+    write("Ok.\n");
+    return 1;
+  }
+  input_to("extra_input",INPUT_PROMPT, "]" ,look+str+"\n");
+  return 1;
+}
+
+static int extralook(mixed str)
+{
+  if( str=="?" )
+  {
+    write( "Dein Extralook ist : "+QueryProp(P_EXTRA_LOOK) + "\n");
+    return 1;
+  }
+  write("Bitte gib Deinen Extra-Look ein. Beenden mit **:\n");
+  input_to("extra_input",INPUT_PROMPT,"]","");
+  return 1;
+}
+
+static void calculate_value()
+{
+  int i, carried_value, value;
+
+  carried_value=0;
+  foreach(object ob: deep_inventory(ME)) {
+    if (!ob->QueryProp(P_AUTOLOADOBJ))
+      carried_value+=((value=(int)ob->QueryProp(P_VALUE)) > 1000 ? 1000 : value);
+  }
+  SetProp(P_CARRIED_VALUE, carried_value);
+}
+
+/* Called by command 'save' */
+int save_character() {
+  save_me(1);
+  write("Ok.\n");
+  return 1;
+}
+
+void save_me(mixed value_items)
+{
+  // Gaeste werden nicht gespeichert
+  if( getuid()[0..3]=="gast" )
+    return;
+ 
+  // Autoloader identifizieren und speichern
+  autoload=([]);
+  foreach(object ob: deep_inventory(ME)) {
+    int val = ob->QueryProp( P_AUTOLOADOBJ );
+    if (val && clonep(ob))
+    {
+      string obname=load_name(ob);
+      if (obname == GELD)
+        autoload[obname] += val;
+      else
+        autoload += ([obname:val]);
+    }
+  }
+  // An noch nicht geclonte Autoloader denken!
+  autoload += autoload_rest;
+  
+  // Im Bedarfsfall Wert des Inventory bestimmen
+  if (value_items)
+    calculate_value();
+  else
+    SetProp(P_CARRIED_VALUE, 0);
+
+  // Logout-Zeit speichern
+  if(query_once_interactive(ME) && !QueryProp(P_INVIS))
+    Set(P_LAST_LOGOUT,time());
+
+  // Funktion zur Bestimmung des Gildenrating aufrufen
+  string gilde=GUILD_DIR+QueryProp(P_GUILD);
+  if (find_object(gilde) || file_size(gilde+".c")>-1)
+    catch(call_other(gilde,"GuildRating",this_object());publish);
+
+  // Speichern des Spielers
+  save_object("/"+SAVEPATH+getuid()[0..0]+"/" + getuid());
+}
+
+static varargs void log_autoload( string file, string reason, mixed data, string error )
+{
+  if (member(autoload_error,file)!=-1) return;
+  log_file(SHELLLOG("NO_AUTO_FILE"),sprintf("%s: %s: %s\nreason: cannot %s file\ndata: %O\n%s\n",
+           ctime()[4..15],capitalize(getuid()),file,reason,data,
+           (error?"Fehlermeldung: "+error+"\n":"")));
+  autoload_error+=({file});
+}
+
+// tics, die fuer autoloader reichen sollten:
+#define SAFE_FOR_AUTOLOADER __MAX_EVAL_COST__/4
+
+private void load_auto_object( string file, mixed data )
+{
+    object ob;
+    string error;
+   
+    if( get_eval_cost() < SAFE_FOR_AUTOLOADER ) return;
+    m_delete( autoload_rest, file );
+    autoload_error-=({file});
+
+    if ( file == "/obj/money" )
+      file = "/items/money";
+    if ( file == "/obj/seercard" )
+      file = "/items/seercard";
+    
+    ob = find_object(file);
+    
+    if (!ob)
+    {
+        if (file_size(file+".c")<0&&
+           file_size(implode(explode(file,"/")[0..<2],"/")+
+                     "/virtual_compiler.c")<0)
+        {
+           log_autoload(file,"find",data,0);
+           return;
+        }
+        if (error = catch(load_object(file); publish))
+        {
+           log_autoload(file,"load",data,error);
+           return;
+        }
+    }
+    if ( error = catch(ob = clone_object(file); publish) )
+    {
+        log_autoload(file,"clone",data, error);
+        return;
+    }
+
+    if ( error = catch(ob->SetProp( P_AUTOLOADOBJ, data ); publish) )
+    {
+        log_autoload(file,"SetProp",data, error);
+        ob->remove(1);
+        if (ob) destruct(ob);
+        return;
+    }
+
+    if ( error = catch(ob->move( ME, M_NOCHECK );publish) ) {
+        log_autoload(file,"move",data, error);
+        ob->remove(1);
+        if(ob) destruct(ob);
+        return;
+    }
+}
+
+static void load_auto_objects( mapping map_ldfied )
+{
+    if ( (!mappingp(map_ldfied) || !sizeof(map_ldfied)) && !sizeof(autoload_rest) )
+        return;
+
+    // Mit Netztoten Spielern rechnen manche Autoloader nicht. Also
+    // das Clonen unterbrechen und in Reconnect() wieder anwerfen.
+    if ( !interactive() )
+        return;
+
+    // Kleiner Hack: autoload_rest ist eine globale Variable, die beim
+    // Clonen der einzelnen Autoloader direkt veraendert wird.
+    // So lange das Mapping noch Eintraege hat, muessen wir noch fehlende
+    // Autoloader clonen.
+    if ( !sizeof(autoload_rest) )
+        autoload_rest = map_ldfied;
+
+    // Schon hier einen call_out() zum "Nach"clonen von noch nicht geclonten
+    // Autoloadern starten, da spaeter u.U. keine Rechenzeit mehr dafuer da ist.
+    while ( remove_call_out("load_auto_objects") != -1 )
+        /* do nothing */;
+    
+    // Mit Parameter '0' aufrufen, da das globale Mapping benutzt wird.
+    // Verzoegerung 0 in rekursiven Callouts ist bloed, also 1s Delay
+    call_out( "load_auto_objects", 2, 0 );
+    
+    // Mit catch() gegen die Evalcost-Falle!
+    // Mit Absicht das walk_mapping() aus der "alten" Version erhalten und
+    // nicht durch eine (einfachere) Schleife inkl. get_eval_cost() ersetzt,
+    // da eine Schleife gegenueber der walk_mapping()-Loesung den Aufbau
+    // der previous_object()-Kette veraendern wuerde; darauf testen aber
+    // manche Objekte.
+    catch( walk_mapping( autoload_rest, #'load_auto_object/*'*/ ) );
+}
+
+/*
+ * al_to_title: Make the numeric alignment value into a string
+ */
+static string al_to_title(int a)
+{
+  if (a >= KILL_NEUTRAL_ALIGNMENT * 100)
+    return "heilig";
+  if (a > KILL_NEUTRAL_ALIGNMENT * 20)
+    return "gut";
+  if (a > KILL_NEUTRAL_ALIGNMENT * 4)
+    return "nett";
+  if (a > - KILL_NEUTRAL_ALIGNMENT * 4)
+    return "neutral";
+  if (a > - KILL_NEUTRAL_ALIGNMENT * 20)
+    return "frech";
+  if (a > - KILL_NEUTRAL_ALIGNMENT * 100)
+    return "boese";
+  return "satanisch";
+}
+
+static int toggle_whimpy_dir(string str) {
+  SetProp(P_WIMPY_DIRECTION,str=_unparsed_args()||str);
+  if (str)
+    printf("Ok, Fluchtrichtung %O.\n",str);
+  else
+    printf("Ok, bevorzugte Fluchtrichtung deaktiviert.\n");
+  return 1;
+}
+
+static int toggle_whimpy(string str)
+{
+  int i;
+
+  if(!str || str=="" || (sscanf(str,"%d",i)<0))
+  {
+    write("vorsicht <hp>, 0<=hp<"+QueryProp(P_MAX_HP)+"\n");
+    return 1;
+  }
+  if(i>=QueryProp(P_MAX_HP) || i<0)
+  {
+    write("Der Wert ist nicht erlaubt.\n");
+    return 1;
+  }
+  if(!i) write("Prinz Eisenherz-Modus.\n");
+  else write("Vorsicht-Modus ("+i+")\n");
+  SetProp(P_WIMPY,i);
+  return 1;
+}
+
+/** Bestimmt, ob das Spielerobjekt beschattet werden darf.
+  * Beschatten ist nur fuer Objekte erlaubt, die in /std/player/shadows
+  * abgelegt sind.
+  * Ausnahme: Testspieler mit gesetztem P_ALLOWED_SHADOW
+  * @param[in] obj Objekt, was beschatten moechte.
+  * @return 0, wenn Beschatten erlaubt, 1 sonst.
+  */
+varargs nomask int query_prevent_shadow(object obj)
+{
+  string what, allowed_shadow;
+  int    dummy;
+
+//  if ( Query(P_TESTPLAYER) )
+//      return 0;
+  
+  if (obj){
+    what=object_name(obj);
+    if (what && what != "" &&
+        sscanf(what,"/std/player/shadows/%s#%d",what,dummy)==2)
+      return 0;
+    
+    // Einem Testspieler kann man P_ALLOWED_SHADOW auf einen zu testenden
+    // Shadow setzen.
+    if ( Query(P_TESTPLAYER) && 
+         stringp(what) && 
+         stringp(allowed_shadow=Query(P_ALLOWED_SHADOW)) &&
+         strstr(what, allowed_shadow)==0)
+            return 0;
+  }
+  return 1;
+}
+
+static int uhrzeit()
+{
+  write(dtime(time()+QueryProp(P_TIMEZONE)*3600)+".\n");
+  return 1;
+}
+
+protected string SetDefaultHome(string str)
+{
+  return default_home=str;
+}
+
+string QueryDefaultHome()
+{
+  return default_home;
+}
+
+protected string SetDefaultPrayRoom(string str)
+{
+  if(hc_play>1)
+  {
+    default_pray_room="/room/nirvana";
+  }
+  else
+    default_pray_room=str;
+  
+  return default_pray_room;
+}
+
+string QueryPrayRoom()
+{
+  if(hc_play>1)
+  {
+    return "/room/nirvana";
+  } 
+  string room = QueryProp(P_PRAY_ROOM);
+  if (stringp(room))
+    return room;
+  else if (default_pray_room)
+    return default_pray_room;
+  // hoffentlich ist das wenigstens gesetzt. 
+  return default_home;
+}
+
+void _restart_beat()
+{
+  tell_object(ME,
+      "Der GameDriver teilt Dir mit: Dein Herzschlag hat wieder eingesetzt.\n");
+  set_heart_beat(1);
+}
+
+static int weg(string str)
+{
+  if (!(str=_unparsed_args()))
+  {
+    printf("Du bist nicht%s als abwesend gekennzeichnet.\n",
+           QueryProp(P_AWAY) ? " mehr" : "");
+    SetProp(P_AWAY, 0);
+    return 1;
+  }
+  write("Du bist jetzt als abwesend gekennzeichnet.\n");
+  SetProp(P_AWAY, str);
+  return 1;
+}
+
+/* Ein Befehl zum anschauen der Wegmeldung anderer Spieler */
+static int wegmeldung(string player)
+{
+
+  object player_ob;
+  string weg;
+
+  if ( !player || player=="" || 
+       player==lowerstring(this_player()->QueryProp(P_NAME)))
+  {
+    weg=this_player()->QueryProp(P_AWAY);
+    write ("Du bist "+(weg?"":"nicht ")+"als abwesend gekennzeichnet.\n");
+    if (weg)
+      write(break_string(weg, 78,"Grund: ",BS_INDENT_ONCE));
+    return 1;  
+  }
+
+  // Welcher Spieler ist gemeint?
+  player_ob=find_player(player);
+
+  // Spieler nicht da oder Invis und Anfrager is kein Magier
+  if (!player_ob || 
+      (player_ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player()))) 
+  {
+    write(capitalize(player)+" ist gerade nicht im Spiel.\n");
+    return 1;
+  }
+
+  weg=player_ob->QueryProp(P_AWAY);
+
+        // player_ob->Name() gibt bei invis-Magiern "Jemand" zurueck
+  write (player_ob->QueryProp(P_NAME)+" ist "+
+         (weg?"":"nicht ")+"als abwesend gekennzeichnet.\n");
+
+  if (weg)
+    write(break_string(weg, 78,"Grund: ",BS_INDENT_ONCE));
+
+  return 1;
+}
+
+static string timediff(int time)
+{
+  string ret;
+
+  ret="";
+  if(time>=86400) {
+    ret+=time/86400+"d ";
+    time%=86400;
+  }
+  if(time<36000) ret+="0";
+  ret+=time/3600+":";
+  time%=3600;
+  if(time<600) ret+="0";
+  ret+=time/60+":";
+  time%=60;
+  if(time<10) ret+="0";
+  ret+=time+"";
+  return ret;
+}
+
+
+/* Ein Befehl zum anschauen der Idlezeit anderer Spieler */
+static int idlezeit(string player)
+{
+
+  object player_ob;
+  int idle;
+
+  if ( !player || player=="" || 
+       player==lowerstring(this_player()->QueryProp(P_NAME)))
+  {
+    write ("Du bist selber natuerlich gerade nicht idle.\n");
+    return 1;  
+  }
+
+  // Welcher Spieler ist gemeint?
+  player_ob=find_player(player);
+
+  // Spieler nicht da oder Invis und Anfrager is kein Magier
+  if (!player_ob || 
+      (player_ob->QueryProp(P_INVIS) && !IS_LEARNER(this_player()))) 
+  {
+    write(capitalize(player)+" ist gerade nicht im Spiel.\n");
+    return 1;
+  }
+
+  idle=query_idle(player_ob);
+
+        // player_ob->Name() gibt bei invis-Magiern "Jemand" zurueck
+  write (player_ob->QueryProp(P_NAME)+" ist "+
+         (idle>=60?timediff(idle):"nicht")+" passiv.\n");
+
+  return 1;
+}
+
+
+/** Belebt einen netztoten Spieler wieder.
+  * Reaktiviert Heartbeats, bewegt den Spieler zurueck an den Ort, der eim
+  * Einschlafen zum Aufwachen ermittelt wurde (im einfachsten Fall der Raum,
+  * wo man eingeschlafen ist).
+  */
+static void ndead_revive()
+{
+    string fname;
+    int ret;
+
+    set_heart_beat(1);
+    ndead_next_check = NETDEAD_CHECK_TIME;
+    ndead_currently = 0;
+    ndead_lasttime = 0;
+
+    if ( !objectp(ndead_location) && 
+         stringp(ndead_l_filename) && sizeof(ndead_l_filename)) {
+        
+        if ( member( ndead_l_filename, '#' ) == -1 ){
+            catch(load_object( ndead_l_filename); publish);
+            ndead_location = find_object(ndead_l_filename);
+        }
+        else {
+            ndead_location = find_object(ndead_l_filename);
+            if ( !ndead_location && env_ndead_info ){
+                fname = explode( ndead_l_filename, "#" )[0];
+                catch(ndead_location = 
+                    (load_object(fname)->SetProp(P_NETDEAD_INFO, env_ndead_info));
+                    publish);
+                if ( !objectp(ndead_location) ){
+                    catch(load_object( ndead_location);publish);
+                    ndead_location = find_object(ndead_location);
+                }
+            }
+        }
+    }
+
+    if ( !objectp(ndead_location)
+        || catch(ret = move( ndead_location, M_GO|M_SILENT );publish) 
+        || ret != 1 ) {
+        move( "gilden/abenteurer", M_GO|M_SILENT );
+        ndead_location = environment();
+    }
+
+    //  ndead_location=0;
+    ndead_l_filename = 0;
+    env_ndead_info = 0;
+}
+
+/** Bewegt einen netztoten Spieler in den Netztotenraum
+  * Gerufen von heartbeat().
+  * Zerstoert Gaeste, verlaesst ggf. das Team, ermittelt, ob der Spieler beim
+  * Aufwachen in das alte Environment bewegt werden soll oder in einen anderen
+  * Raum, hierzu wird im Environment P_NETDEAD_INFO abgefragt.
+  * Deaktiviert die Kommandos per disable_commands().
+  */
+static void ndead_move_me() {
+  object team;
+  mixed amem;
+
+  set_heart_beat(0);
+  stop_heart_beats();
+  if (QueryGuest()) {
+    quit();
+    if (ME)
+      remove();
+    if (ME)
+      destruct(ME);
+    return;
+  }
+  ndead_next_check=NETDEAD_CHECK_TIME;
+  ndead_currently=1;
+  ndead_lasttime=0;
+  ndead_location=environment();
+  if (objectp(ndead_location))
+    ndead_l_filename=object_name(ndead_location);
+  
+  if (objectp(environment())
+      && sizeof(explode(object_name(environment()),"#")) > 1)
+    env_ndead_info=environment()->QueryProp(P_NETDEAD_INFO);
+  else
+    env_ndead_info=0;
+  
+  if ( objectp(team=Query(P_TEAM)) )
+      // Der Test auf assoziierte Teammitglieder (== FolgeNPCs)
+      // verhindert, dass Spieler nach "schlafe ein" aus dem
+      // Team ausgetragen werden. -- 29.01.2002 Tiamak
+      //      && !objectp(amem=Query(P_TEAM_ASSOC_MEMBERS))
+      //      && !(pointerp(amem) && sizeof(amem)))
+    team->RemoveMember(ME);
+  
+  disable_commands();
+  move(NETDEAD_ROOM,M_GO|M_NO_ATTACK|M_NOCHECK,"ins Reich der Netztoten");
+}
+
+/** Ist dieser Character ein Gast?
+  * @return 1, wenn Gast, 0 sonst.
+  */
+int QueryGuest()
+{
+  string dummy;
+  return sscanf(getuid(),"gast%d",dummy);
+}
+
+/** Spielerkommando 'schlafe ein'.
+  * Ruft remove_interactive() bei Spielern, bei Magiern wird quit() gerufen,
+  * um das Magierobjekt zu zerstoeren.
+  * @sa quit()
+  */
+int disconnect(string str)
+{ 
+  string verb;
+  string desc = break_string(
+      "\"schlafe ein\" beendet Deine Verbindung mit "MUDNAME". Du behaeltst "
+     "Deine Sachen.\nFalls "MUDNAME" jedoch abstuerzt oder neu gestartet "
+     "wird, waehrend Du weg bist, verlierst Du die meisten allerdings "
+     "(genauso, als wenn Du Deine Verbindung mit \"ende\" beendet haettest). "
+     "In diesem Fall bekommst Du dann eine kleine Entschaedigung."
+     ,78,0,BS_LEAVE_MY_LFS);
+
+  verb=query_verb();
+  if (!verb)
+    verb="AUTOCALL";
+  if (verb[0..5]=="schlaf" && str!="ein")
+  {
+    notify_fail(desc);
+    return 0;
+  }
+  if (IS_LEARNER(this_object()))
+    return quit();
+  
+  tell_object(this_object(), desc);
+
+  if (clonep(environment()) && !environment()->QueryProp(P_NETDEAD_INFO))
+    tell_object(this_object(),break_string(
+        "\nACHTUNG: Wenn Du hier laengere Zeit schlaefst, "
+        "kommst Du vermutlich nicht an diesen Ort zurueck!",78));
+
+  say(capitalize(name(WER))+" hat gerade die Verbindung zu "MUDNAME" gekappt.\n");
+  remove_interactive(ME);
+  call_out(#'clear_tell_history,4);
+  return 1;
+}
+
+static int finger (string str)
+{
+  string ret;
+  mixed xname;
+
+  if (!str || str==""
+      || sizeof(explode(str," ")-({"-n","-p","-s","-v","-a"}))>1)
+  {
+    write("finger <spielername> oder finger <spielername@mudname>\n"+
+      "Bitte nur den reinen Spielernamen verwenden, keine Namensvorsaetze oder Titel\n");
+    return 1;
+  }
+  xname=explode(str,"@");
+  if(sizeof(xname)==2)
+  {
+    if (xname[0]=="-n " || xname[0]=="-p " || xname[0]=="-s ")  {
+      write("finger <spielername>@<mudname> - der Spielername fehlt.\n");
+      return 1;
+    }
+    if (ret=INETD->_send_udp(xname[1],([
+                   REQUEST: "finger",
+                   SENDER: getuid(ME),
+                   DATA: (explode(xname[0]," ")-({"-n","-p","-s"}))[0]
+                   ]), 1))
+            write(ret);
+        else
+      write("Anfrage abgeschickt.\n");
+    return 1;
+  }
+  "/p/daemon/finger"->finger_single(str,1);
+  return 1;
+}
+
+string lalign(string str, int wid)
+{
+  return (str+"                                                   "+
+      "                                                   ")[0..wid-1];
+}
+
+#define MUDS_BAR "\
+-------------------------------------------------------------------------------"
+
+private void format(mixed mud, mixed hosts, string output)
+{
+  output += lalign(hosts[mud][HOST_NAME], 20) + "  " +
+        (hosts[mud][HOST_STATUS] ?
+           hosts[mud][HOST_STATUS] > 0 ?
+             "UP       " + ctime(hosts[mud][HOST_STATUS])[4..15] :
+             "DOWN     " + ctime(-hosts[mud][HOST_STATUS])[4..15]
+         : "UNKNOWN  Never accessed.") + "\n";
+}
+
+static int muds() {
+  mapping hosts;
+  int i;
+  mixed muds, output;
+
+  output = lalign("Mudname", 20) + "  Status   Last access";
+  output += "\n" + MUDS_BAR[0..sizeof(output)] + "\n";
+  muds = sort_array(m_indices(hosts = INETD->query("hosts")),#'>);
+  map(muds, #'format, hosts, &output);
+  More(output);
+  return 1;
+}
+
+// **** local property methods
+static int _set_level(int i)
+{
+  if (!intp(i)) return -1;
+  if (i<1) return -1;
+  Set(P_LEVEL, i);
+  GMCP_Char( ([P_LEVEL: i]) );
+  return i;
+}
+
+static int _set_invis(int a)
+{
+  return Set(P_INVIS, intp(a) ? a : !Query(P_INVIS));
+}
+
+/* sets the terminal type */
+/* note: support vt100 (b/w), ansi (color), dumb (none) */
+static string _set_tty(string str) {
+  if(str != "dumb" && str != "vt100" && str != "ansi")
+    return Query(P_TTY);
+  return Set(P_TTY, str);
+}
+
+static int stty(string str)
+{
+  if(str!="dumb"&&str!="vt100"&&str!="ansi"&&str!="reset")
+  {
+    write("Kommando: stty dumb|vt100|ansi oder reset\n");
+  }
+  if(str == "reset") {
+      printf("Dieser Text sollte lesbar sein!\n");
+      return 1;
+  }
+
+  write("TTY steht jetzt auf "+SetProp(P_TTY,str)+".\n");
+  if(str == "ansi" || str == "vt100") {
+      printf("Terminal Test:\n");
+      printf("VT100: fett unterstrichen "+
+             "blinkend invers\n");
+      if(str == "ansi") {
+          printf("ANSI Farben und VT100 Attribute:\n");
+          foreach(int fg: 30 .. 37) {
+              foreach(int bg: 40 .. 47) {
+                  printf("[%d;%dm@", fg, bg);
+                  printf("[%d;%dm@", fg, bg);
+                  printf("[%d;%dm@", fg, bg);
+                  printf("[%d;%dm@", fg, bg);
+              }
+              printf("\n");
+          }
+          printf("Sollte dieser Text hier nicht richtig lesbar\nsein,"+
+                 "benutze das Kommando stty reset!\n");
+      }
+
+  }
+  return 1;
+}
+
+int set_ascii_art(string str)
+{
+  if (str!="ein"&&str!="aus")
+  {
+     printf("Du moechtest 'Grafik' "+(QueryProp(P_NO_ASCII_ART)?"NICHT ":"")+
+                     "sehen.\n");
+  }
+
+  if (str=="ein") {
+    SetProp(P_NO_ASCII_ART, 0);
+    printf("Zukuenftig moechtest Du 'Grafik' sehen.\n");
+  }
+
+  if (str=="aus") {
+    SetProp(P_NO_ASCII_ART, 1);
+    printf("Zukuenftig moechtest Du KEINE 'Grafik' mehr sehen.\n");
+  }
+
+
+  return 1;
+}
+
+int _set_shell_version(int arg)
+{
+  if (!intp(arg))
+    return -1;
+  Set(P_SHELL_VERSION,({QueryProp(P_RACE),arg}));
+  return 1;
+}
+
+int _query_shell_version()
+{   mixed sv;
+
+    if (!(sv=Query(P_SHELL_VERSION)) || !pointerp(sv) || sizeof(sv)!=2 ||
+        sv[0]!=QueryProp(P_RACE) || !intp(sv[1]))
+      return 0;
+    return sv[1];
+}
+
+// XxXxXxXxXx
+
+int more(string str)
+{
+  if(!str)
+  {
+    notify_fail("Usage: more <file>\n");
+    return 0;
+  }
+  if (file_size(str) <= 0) {
+    notify_fail(str+": No such file\n");
+    return 0;
+  }
+  More(str, 1);
+  return 1;
+}
+
+static int set_visualbell(string str)
+{
+  if(!str)
+  {
+    write("Derzeitige Einstellung fuer Tonausgabe: "+
+         (QueryProp(P_VISUALBELL)?"AUS":"EIN")+".\n");
+    return 1;
+  }
+  if (str=="ein")
+  {
+    if(!QueryProp(P_VISUALBELL))
+      write("Die Tonausgabe stand schon auf EIN.\n");
+    else
+      {
+  SetProp(P_VISUALBELL,0);
+        write("OK, Tonausgabe auf EIN gestellt.\n");
+      }
+  }
+  else
+    if (str=="aus")
+    {
+      if(QueryProp(P_VISUALBELL))
+        write("Die Tonausgabe stand schon auf AUS.\n");
+      else
+        {
+          SetProp(P_VISUALBELL,1);
+    write("OK, Tonausgabe auf AUS gestellt.\n");
+  }
+    }
+    else
+      write("Syntax: ton [ein|aus]\n");
+  return 1;
+}
+
+static int set_screensize(string str)
+{
+  int size;
+
+  if (str && (str[0..2] == "abs" || str[0..2]=="rel")) {
+    size = QueryProp(P_MORE_FLAGS);
+    if (str[0..2] == "abs") {
+      size |= E_ABS;
+      write("Es wird beim Prompt die Zeilenzahl des Textes angegeben.\n");
+    }
+    else {
+      size &= ~E_ABS;
+      write("Es wird beim Prompt der prozentuale Anteil des Textes angegeben.\n");
+    }
+    SetProp(P_MORE_FLAGS, size);
+    return 1;
+  }
+
+  if ( str && (str=="auto" || sscanf( str, "auto %d", size )) ){
+      if ( size > 0 ){
+          write("Ungueltiger Wert! "
+                "In Verbindung mit 'auto' sind nur negative Werte erlaubt.\n");
+          return 1;
+      }
+
+      SetProp( P_SCREENSIZE, size-1 );
+
+      write("Ok, Deine Zeilenzahl wird nun automatisch ermittelt (derzeit "+
+            QueryProp(P_SCREENSIZE)+").\n"+
+            break_string("Bitte beachte, dass dies nur einwandfrei "
+                         "funktioniert, wenn Dein Client Telnetnegotiations "
+                         "unterstuetzt (siehe auch \"hilfe telnegs\").") );
+    return 1;
+  }
+
+  if ( !str || str=="" || !sscanf( str, "%d", size ) || size < 0 || size > 100){
+      write(break_string(
+            sprintf("Mit dem Befehl 'zeilen <groesse>' kannst Du einstellen, "
+            "wieviele Zeilen bei mehrseitigen Texten auf einmal ausgegeben "
+            "werden. Die angegebene Groesse muss zwischen 0 und 100 liegen. "
+            "Bei Groesse 0 wird einfach alles ausgegeben (ohne Pause). Mit "
+            "der Einstellung 'auto' wird die Groesse automatisch ueber "
+            "die Telnetnegotiations ermittelt (siehe auch 'hilfe telnegs'). "
+            "Um nach einer Seite Text noch etwas Platz zu haben, kann man z.B. "
+            "'zeilen auto -3' einstellen.\n"
+            "Die Voreinstellung ist 20 Zeilen.\n"
+            "Mit 'zeilen abs[olut]' und 'zeilen rel[ativ]' kannst Du fest"
+            "legen, ob im Prompt bei langen Texten die aktuelle Zeilennummer "
+            "oder eine prozentuale Angabe ausgegeben wird.\n"
+            "Deine aktuelle Einstellung ist %d%s Zeilen (%s).",
+            QueryProp(P_SCREENSIZE),
+            Query(P_SCREENSIZE) < 0 ? " 'automatische'" : "",
+            QueryProp(P_MORE_FLAGS) & E_ABS ? "absolut" : "relativ"),78,0,1));
+    return 1;
+  }
+
+  SetProp( P_SCREENSIZE, size );
+
+  printf( "Okay, Deine Zeilenzahl steht nun auf %d.\n", size );
+  return 1;
+}
+
+static int _query_screensize()
+{
+    int sz,rows;
+
+    if ( (sz=Query(P_SCREENSIZE)) >= 0 )
+        return sz;
+
+    if ( !rows=QueryProp(P_TTY_ROWS) )
+        return 0;
+
+    return (rows+=sz) >= 5 ? rows : 5;
+}
+
+static int presay(string str)
+{
+  if (!str=_unparsed_args())
+    write("Dein Presay ist jetzt geloescht.\n");
+  else
+    printf("Dein Presay lautet jetzt: \"%s\".\n",str=capitalize(str));
+  SetProp(P_PRESAY,str);
+  return 1;
+}
+
+static int sethands(string str)
+{
+  mixed *hands;
+
+  if (!(str=_unparsed_args()))
+  {
+    write("sethands <message>\n");
+    return 1;
+  }
+  if (str=="0")
+      hands=RaceDefault(P_HANDS);
+  if (!hands || !pointerp(hands))
+      hands=Query(P_HANDS);
+  hands[0]=" "+str;
+  Set(P_HANDS,hands);
+  write("Ok.\n");
+  return 1;
+}
+
+static int inform(string str)
+{
+  switch (str) {
+    case "on":
+    case "ein":
+    case "an":
+      if (Query(P_INFORMME))
+    write("Das hattest Du schon so eingestellt.\n");
+      else
+      {
+    write("Kuenftig wirst Du informiert, wenn jemand das "MUDNAME" verlaesst/betritt.\n");
+    Set(P_INFORMME,1);
+      }
+      return 1;
+    case "aus":
+    case "off":
+      if (!Query(P_INFORMME))
+    write("Das hattest Du schon so eingestellt.\n");
+      else
+      {
+    write("Ok.\n");
+    Set(P_INFORMME,0);
+      }
+      return 1;
+    case 0:
+      write("Inform-Mode ist "+(Query(P_INFORMME)?"an":"aus")+"geschaltet.\n");
+      return 1;
+    }
+  write("inform an oder inform aus, bitte.\n");
+  return 1;
+}
+
+void delayed_write(mixed *what)
+{
+  if (!pointerp(what)||!sizeof(what)||!pointerp(what[0]))
+    return;
+  tell_object(ME,what[0][0]);
+  if (sizeof(what)>1&&sizeof(what[0])>1)
+    call_out("delayed_write",what[0][1],what[1..]);
+}
+
+void notify_player_change(string who, int rein, int invis)
+{
+  string *list,name;
+  mixed mlist;
+
+  if (invis) name="("+who+")";
+    else name=who;
+
+  if (Query(P_INFORMME))
+  {
+      if (rein)
+        tell_object(ME,name+" ist gerade ins "MUDNAME" gekommen.\n");
+      else
+        tell_object(ME,name+" hat gerade das "MUDNAME" verlassen.\n");
+  }
+
+  if(Query(P_WAITFOR_FLAGS) & (0x01))return ;
+
+  if(pointerp(list=Query(P_WAITFOR)) && sizeof(list) && member(list,who)!=-1)
+  {
+    if (!QueryProp(P_VISUALBELL))
+        name+=sprintf("%c",7); // Char fuer Pieps an den String anhaengen.
+    // Moechte der Spieler keine ASCII-Grafik sehen, wird diese Meldung ohne
+    // Leerzeichen formatiert, so dass sie von Screenreadern vorgelesen wird.
+    // Anderenfalls wuerde sie einzeln buchstabiert.
+    if ( QueryProp(P_NO_ASCII_ART) )
+    {
+      delayed_write( ({ ({ sprintf("%s IST JETZT %sDA !!!\n", 
+                           name, (rein?"":"NICHT MEHR ")) }) }) );
+    }
+    else 
+    {
+      delayed_write( ({ ({ sprintf("%s   I S T   J E T Z T   %sD A !!!\n",
+                           name, (rein?"":"N I C H T   M E H R   ")) }) }) );
+    }
+  }
+
+  if (rein && (sizeof(mlist=QueryProp(P_WAITFOR_REASON))) &&
+     (mappingp(mlist)) && (mlist[who]))
+        Show_WaitFor_Reason(who,invis);
+}
+
+static int erwarte(string str)
+{
+  string *list,*str1;
+  mixed mlist;
+  int i;
+
+  if (!mappingp(mlist=QueryProp(P_WAITFOR_REASON)))
+     mlist=([]);
+  if (!pointerp(list=Query(P_WAITFOR)))
+     list=({});
+
+  if (!str || str=="-u")
+  {
+     if(Query(P_WAITFOR_FLAGS)&0x01)
+       write("Du hast 'erwarte' temporaer deaktiviert.\n");
+     write("Du erwartest jetzt");
+     if (!sizeof(list))
+        write(" niemanden mehr.\n");
+     else
+     {
+        write(":\n");
+        if (!str) list=sort_array(list,#'>);
+        More(break_string(CountUp(list),78));
+     }
+     return 1;
+  }
+  if(str=="aus"){
+    Set(P_WAITFOR_FLAGS,Query(P_WAITFOR_FLAGS)|0x01);
+    write("Erwarte ist jetzt deaktiviert.\n");
+    return 1;
+  }
+  if(str=="an" || str=="ein"){
+    Set(P_WAITFOR_FLAGS,Query(P_WAITFOR_FLAGS)&0xFE);
+    write("Erwarte ist jetzt aktiv.\n");
+    return 1;
+  }
+
+  str1=explode(_unparsed_args()||""," ");
+  if (sizeof(str1)==1)
+  {
+     if (str1[0]!="wegen")
+     {
+        str=capitalize(lower_case(str));
+        if (member(list,str)!=-1)
+        {
+           SetProp(P_WAITFOR_REASON,m_copy_delete(mlist,str));
+           list-=({str});
+           write(str+" aus der Liste entfernt.\n");
+        } else
+        {
+           if (sizeof(list)>1000)
+           {
+             write("Du erwartest schon genuegend!\n");
+             return 1;
+           }
+           list+=({str});
+           write(str+" an die Liste angehaengt.\n");
+        }
+        Set(P_WAITFOR,list);
+     }
+     else
+     {
+        if (sizeof(mlist) && sizeof(list=m_indices(mlist)))
+        {
+           write("Du erwartest aus einem bestimmten Grund:\n");
+           write(break_string(CountUp(sort_array(list,#'>))+".",78));
+        }
+        else write("Du erwartest niemanden aus einem bestimmten Grund.\n");
+     }
+     return 1;
+  }
+  notify_fail("Falsche Syntax, siehe 'hilfe erwarte'!\n");
+  if (str1[1]!="wegen") return 0;
+  if (sizeof(str1)==2)
+     Show_WaitFor_Reason(capitalize(lower_case(str1[0])),0);
+  else {
+     string s=capitalize(lower_case(str1[0]));
+     if (sizeof(str1)==3 && (str1[2]=="nichts" || str1[2]=="loeschen"))
+        if (!mlist[s])
+           write("Du hast "+s+" aus keinem bestimmten Grund erwartet!\n");
+        else
+        {
+           SetProp(P_WAITFOR_REASON,m_copy_delete(mlist,s));
+           write("Du erwartest "+s+" aus keinem bestimmten Grund mehr!\n");
+        }
+     else
+     {
+        if (IS_ARCH(ME)) i=80; else if (IS_LEARNER(ME)) i=40;
+        else if (IS_SEER(ME)) i=20; else i=10;
+        if (!mlist[s] && sizeof(mlist)>=i)
+           write("Sorry, aber Du erwartest schon genuegend Leute!\n");
+        else
+        {
+           SetProp(P_WAITFOR_REASON,mlist+([s:implode(str1[2..]," ")]));
+           Show_WaitFor_Reason(s,0);
+        }
+     }
+  }
+  return 1;
+}
+
+static int uhrmeldung(string str)
+{
+  if (!(str=_unparsed_args()))
+  {
+    str=QueryProp(P_CLOCKMSG);
+    if (!str)
+    {
+      write("Du hast die Standard-Uhrmeldung.\n");
+      return 1;
+    }
+        if( !stringp(str) ) str = sprintf("%O\n",str);
+    printf("Deine Uhrmeldung ist:\n%s\n",str[0..<2]);
+    return 1;
+  }
+  if (str=="0")
+  {
+    SetProp(P_CLOCKMSG,0);
+    write("Ok, Du hast jetzt wieder die Standard-Meldung.\n");
+    return 1;
+  }
+  if (sizeof(explode(str,"%d"))>2)
+  {
+    write("Fehler, es darf nur ein %d in der Meldung vorkommen.\n");
+    return 1;
+  }
+  /* Mehrere %-Parameter verursachen das Abschalten der Uhr zur vollen Stunde.
+   */
+  if (sizeof(explode(str,"%"))>2)
+  {
+    write("Fehler: Zuviele %-Parameter in der Meldung.\n");
+    return 1;
+  }
+  /* Nur ein %-Parameter, aber der falsche: nicht sinnvoll. */
+  else
+  {
+    int i = strstr(str,"%",0);
+    if ( i>-1 && ( i==sizeof(str)-1 || str[i+1]!='d'))
+    {
+      write("Fehler: Falscher %-Parameter in der Meldung.\n");
+      return 1;
+    }
+  }
+  str+="\n";
+  SetProp(P_CLOCKMSG,str);
+  write("Ok.\n");
+  return 1;
+}
+
+static int zeitzone(string str)
+{
+  int zt;
+  if(!str || str==""){
+    if(!(zt=QueryProp(P_TIMEZONE)))
+      write("Du hast derzeit die gleiche Zeitzone wie das "MUDNAME" "+
+            "eingestellt.\n");
+    else if(zt>0)
+      printf("Deine Zeitzone ist auf %d Stunden vor (oestlich) von Berlin "+
+             "eingestellt.\n",zt);
+    else
+      printf("Deine Zeitzone ist auf %d Stunden nach (westlich) von "+
+             "Berlin eingestellt.\n",-zt);
+    return 1;
+  }
+  if(sscanf(str,"utc %d",zt)==1)  zt=(zt-1)%24;
+  else zt=to_int(str)%24;
+
+  SetProp(P_TIMEZONE,zt);
+
+  if(!zt)
+    write("Du hast derzeit die gleiche Zeitzone wie das "MUDNAME" "+
+          "eingestellt.\n");
+  else if(zt>0)
+    printf("Deine Zeitzone ist auf %d Stunden vor (oestlich) von Berlin "+
+           "eingestellt.\n",zt);
+  else
+    printf("Deine Zeitzone ist auf %d Stunden nach (westlich) von "+
+           "Berlin eingestellt.\n",-zt);
+  return 1;
+}
+
+static int emailanzeige(string str){
+  notify_fail("Syntax: emailanzeige [alle|freunde|niemand]\n");
+  if(!str || str==""){
+    if(!(str=QueryProp(P_SHOWEMAIL)))str="Niemandem";
+    else if(str=="alle")str="allen";
+    else if(str=="freunde")str="Deinen Freunden";
+    else if(str=="niemand")str="niemandem";
+    else{
+      SetProp(P_SHOWEMAIL,0);
+      str="Niemandem";
+    }
+    write("Deine Email wird "+str+" angezeigt.\n");
+    return 1;
+  }
+  else if(member(({"alle","freunde","niemand"}),str)==-1)return 0;
+
+  SetProp(P_SHOWEMAIL,str);
+
+  if(str=="alle")str="allen";
+  else if(str=="freunde")str="Deinen Freunden";
+  else str="niemandem";
+  write("Deine Email wird "+str+" angezeigt.\n");
+  return 1;
+}
+
+static int zaubertraenke()
+{
+  More("/room/orakel"->TipListe());
+  return 1;
+}
+
+varargs static int angriffsmeldung(string arg) {
+  if (arg=="ein" || arg=="an")
+    SetProp(P_SHOW_ATTACK_MSG,1);
+  else if (arg=="aus")
+    SetProp(P_SHOW_ATTACK_MSG,0);
+  if (QueryProp(P_SHOW_ATTACK_MSG))
+    write("Du siehst saemtliche Angriffsmeldungen von Dir.\n");
+  else
+    write("Du siehst nur neue Angriffsmeldungen von Dir.\n");
+  return 1;
+}
+
+static mixed _query_localcmds()
+{
+  return ({({"zeilen","set_screensize",0,0}),
+           ({"email","set_email",0,0}),
+           ({"url","set_homepage",0,0}),
+           ({"icq","set_icq",0,0}),
+           ({"messenger", "set_messenger", 0, 0}), 
+           ({"ort","set_location",0,0}),
+           ({"punkte","short_score",0,0}),
+           ({"score","short_score",0,0}),
+           ({"info","score",0,0}),
+           ({"kurzinfo","very_short_score",0,0}),
+           ({"quit","new_quit",0,0}),
+           ({"ende","new_quit",0,0}),
+           ({"disconnect","disconnect",0,0}),
+           ({"schlaf","disconnect",1,0}),
+           ({"speichern","save_character",0,0}),
+           ({"save","save_character",0,0}),
+           ({"toete","kill",0,0}),
+           ({"angriffsmeldung","angriffsmeldung",0,0}),
+           ({"passw","change_password",1,0}),
+           ({"hilfe","help",1,0}),
+           ({"selbstloeschung","self_delete",0,0}),
+           ({"spielpause","spielpause",0,0}),
+           ({"spieldauer","spieldauer",0,0}),
+           ({"idee","idea",0,0}),
+           ({"typo","typo",0,0}),
+           ({"bug","bug",0,0}),
+           ({"fehler","fehlerhilfe",0,0}),
+           ({"md","md",0,0}),
+           ({"detail","md",0,0}),
+           ({"vorsicht","toggle_whimpy",0,0}),
+           ({"stop","stop",0,0}),
+           ({"kwho","kwho",0,0}),
+           ({"kwer","kwho",0,0}),
+           ({"kkwer","kkwho",0,0}),
+           ({"kkwho","kkwho",0,0}),
+           ({"who","who",0,0}),
+           ({"wer","who",0,0}),
+           ({"zeit","uhrzeit",0,0}),
+           ({"uhrzeit","uhrzeit",0,0}),
+           ({"weg","weg",0,0}),
+           ({"wegmeldung", "wegmeldung", 0, 0}),
+           ({"idlezeit", "idlezeit", 0, 0}),
+           ({"finger","finger",0,0}),
+           ({"muds","muds",0,0}),
+           ({"emote","emote",0,0}),
+           ({":","emote",1,0}),
+           ({";","emote",1,0}),
+           ({"remote","remote",0,SEER_LVL}),
+           ({"r:","remote",1,0}),
+           ({"r;","gremote",1,0}),
+           ({"titel","set_title",0,0}),
+           ({"review","review",0,SEER_LVL}),
+           ({"setmin","setmin",0,SEER_LVL}),
+           ({"setmout","setmout",0,SEER_LVL}),
+           ({"setmmin","setmmin",0,SEER_LVL}),
+           ({"setmmout","setmmout",0,SEER_LVL}),
+           ({"sethands","sethands",0,SEER_LVL}),
+           ({"presay","presay",0,SEER_LVL}),
+           ({"extralook","extralook",0,SEER_LVL}),
+           ({"fluchtrichtung","toggle_whimpy_dir",0,SEER_LVL}),
+           ({"inform","inform",0,0}),
+           ({"erwarte","erwarte",0,0}),
+           ({"stty","stty",0,0}),
+           ({"grafik", "set_ascii_art", 0, 0}), 
+           ({"uhrmeldung","uhrmeldung",0,0}),
+           ({"zeitzone","zeitzone",0,0}),
+           ({"behalte","behalte",0,0}),
+           ({"zweitiemarkierung","zweitiemarkierung",0,0}),
+           ({"emailanzeige","emailanzeige",0,0}),
+           ({"topliste","topliste",0,0}),
+           ({"ton","set_visualbell",0,0}),
+           ({"telnegs","show_telnegs",0,0}),
+           ({"spotte", "spotte", 0, 0}),
+           ({"reise","reise",0,0}),
+           ({"zaubertraenke","zaubertraenke",0,0}),
+           ({"telnet","telnet_cmd",0,0}),
+     })+
+     command::_query_localcmds()+
+     viewcmd::_query_localcmds()+
+     comm::_query_localcmds()+
+     skills::_query_localcmds()+
+     description::_query_localcmds();
+}
+
+static int _check_keep(object ob)
+{
+  return (ob->QueryProp(P_KEEP_ON_SELL))==geteuid(ME);
+}
+
+static mixed _set_testplayer(mixed arg) {
+  mixed res;
+  object setob;
+
+  setob=this_player();
+  if (!objectp(setob) || !query_once_interactive(setob))
+    setob=this_interactive();
+  if (!objectp(setob))
+    setob=previous_object();
+  if (setob && !IS_DEPUTY(setob)) {
+    arg=geteuid(setob);
+    if (!arg || arg=="NOBODY")
+      arg=getuid(setob);
+    arg=capitalize(arg);
+  }
+  res=Set(P_TESTPLAYER,arg);
+  Set(P_TESTPLAYER,PROTECTED,F_MODE_AS);
+  return res;
+}
+
+int zweitiemarkierung(string arg)
+{
+  if (!QueryProp(P_SECOND))
+    return _notify_fail("Aber Du bist doch gar kein Zweiti.\n"),0;
+  notify_fail("Syntax: zweitiemarkierung [unsichtbar|sichtbar|name]\n");
+  if (!arg)
+    return 0;
+  switch (arg)
+  {
+    case "unsichtbar" :
+      SetProp(P_SECOND_MARK,-1);
+      write("Jetzt sieht kein Spieler mehr, dass Du ein Zweiti bist.\n");
+      return 1;
+    case "sichtbar" :
+      SetProp(P_SECOND_MARK,0);
+      write("Jetzt sieht kein Spieler mehr, wessen Zweiti Du bist.\n");
+      return 1;
+    case "name" :
+      SetProp(P_SECOND_MARK,1);
+      write("Jetzt koennen alle sehen, wessen Zweiti Du bist.\n");
+      return 1;
+  }
+  return 0;
+}
+
+int topliste(string arg)
+{
+    if (!arg)
+    {
+        printf("Du hast Dich fuer die Topliste %s.\n",
+            (QueryProp(P_NO_TOPLIST) ? "gesperrt" : "freigegeben"));
+        return 1;
+    }
+    else if (member(({"j","ja","n","nein"}),arg)==-1)
+        return _notify_fail("Syntax: topliste [ja|nein]\n"),0;
+    if (arg[0]=='j')
+    {
+        SetProp(P_NO_TOPLIST,0);
+        write("Du kannst jetzt (theoretisch) in der Topliste auftauchen.\n");
+    }
+    else
+    {
+        SetProp(P_NO_TOPLIST,1);
+        write("Du wirst jetzt nicht in der Topliste auftauchen.\n");
+    }
+    Set(P_NO_TOPLIST,SAVE|PROTECTED,F_MODE_AS);
+    return 1;
+}
+
+int show_telnegs(string arg)
+{
+    if (!arg)
+    {
+        write("Du bekommst Aenderungen Deiner Fenstergroesse "+
+              (QueryProp(P_TTY_SHOW)?"":"nicht ")+"angezeigt.\n");
+        return 1;
+    }
+    if (member(({"ein","an","aus"}),arg)==-1)
+    {
+        write("Syntax: telnegs [ein|aus]\n");
+        return 1;
+    }
+    if (arg=="ein" || arg=="an")
+    {
+        write("Du bekommst "+(QueryProp(P_TTY_SHOW)?"":"nun ")+
+              "Aenderungen Deiner Fenstergroesse angezeigt.\n");
+        Set(P_TTY_SHOW,1);
+        return 1;
+    }
+    write("Du bekommst "+(QueryProp(P_TTY_SHOW)?"nun ":"")+
+          "Aenderungen Deiner Fenstergroesse nicht "+
+          (QueryProp(P_TTY_SHOW)?"mehr ":"")+"angezeigt.\n");
+    Set(P_TTY_SHOW,0);
+    return 1;
+}
+
+private int set_keep_alive(string str) {
+  if (str == "ein") {
+    telnet_tm_counter = 240 / __HEART_BEAT_INTERVAL__;
+    tell_object(this_object(), break_string(
+        "An Deinen Client werden jetzt alle 4 Minuten unsichtbare Daten "
+        "geschickt, um zu verhindern, dass Deine Verbindung zum "MUDNAME
+        " beendet wird.", 78));
+  }
+  else if (str == "aus") {
+    telnet_tm_counter = 0;
+    tell_object(this_object(),break_string(
+        "Du hast das Senden von unsichtbaren Daten (Keep-Alive-Pakete) an "
+        "Deinen Client ausgeschaltet.",78));
+  }
+  else {
+    if (!telnet_tm_counter)
+      tell_object(this_object(), break_string(
+        "An Deinen Client werden keine Keep-Alive-Pakete geschickt.",78));
+    else
+      tell_object(this_object(), break_string(
+        "An Deinen Client werden alle 4 Minuten " 
+        "unsichtbare Daten geschickt, damit Deine Verbindung "
+        "zum "MUDNAME" nicht beendet wird.",78));
+  }
+  return 1;
+}
+
+private int print_telnet_rttime() {
+  int rtt = QueryProp(P_TELNET_RTTIME);
+  if (rtt>0)
+    tell_object(ME, break_string(
+      "Die letzte gemessene 'round-trip' Zeit vom MG zu Deinem Client "
+      "und zurueck betrug " + rtt + " us.",78));
+  else
+    tell_object(ME, break_string(
+      "Bislang wurde die 'round-trip' Zeit vom MG zu Deinem Client "
+      "noch nicht gemessen oder Dein Client unterstuetzt dieses "
+      "nicht.",78));
+  return 1;
+}
+
+int telnet_cmd(string str) {
+  if (!str) return 0;
+  string *args = explode(str, " ");
+  string newargs;
+  if (sizeof(args) > 1)
+    newargs = implode(args[1..], " ");
+  else
+    newargs = "";
+
+  switch(args[0])
+  {
+    case "keepalive":
+      return set_keep_alive(newargs);
+    case "rttime":
+      return print_telnet_rttime();
+  }
+  return 0;
+}
+
+int spotte( string str )
+{
+    _notify_fail( "Hier ist nichts, was Du verspotten koenntest!\n" );
+    return 0;
+}
+
+int behalte(string str)
+{
+  object ob,*obs;
+  string s;
+
+  if (str)
+  {
+    if (str=="alles") {
+      filter_objects(all_inventory(), "SetProp", P_KEEP_ON_SELL, getuid());
+      write("Ok!\n");
+      return 1;
+    }
+    if (str=="nichts") {
+      filter_objects(all_inventory(), "SetProp", P_KEEP_ON_SELL, 0);
+      write("Ok!\n");
+      return 1;
+    }
+    if (!sizeof(obs=find_obs(str,PUT_GET_NONE)))
+    {
+      _notify_fail("Aber sowas hast Du nicht dabei!\n");
+      return 0;
+    }
+    else ob=obs[0];
+
+    if (ob->QueryProp(P_KEEP_ON_SELL)==geteuid(ME))
+        ob->SetProp(P_KEEP_ON_SELL,0);
+    else
+        ob->SetProp(P_KEEP_ON_SELL,geteuid(ME));
+
+    // erneut abfragen, da sich der Wert nicht geaendert haben muss
+    if (ob->QueryProp(P_KEEP_ON_SELL)==geteuid(ME))
+        write(break_string(sprintf("Ok, Du wirst %s jetzt bei 'verkaufe alles' "
+                                   "behalten.\n",ob->name(WEN)),78));
+    else
+        write(break_string(sprintf("Ok, Du wirst %s beim naechsten 'verkaufe "
+                                   "alles' mitverkaufen!\n",ob->name(WEN)),78));
+
+    return 1;
+  }
+  s=make_invlist(ME,filter(all_inventory(ME),#'_check_keep)); //'));
+  More(s);
+  return 1;
+}
+
+static int _query_lep()
+{
+  int val;
+  val = LEPMASTER->QueryLEP();
+  Set( P_LEP, val );
+  return val;
+}
+
+static mixed _set_fraternitasdonoarchmagorum(mixed arg)
+{
+  if (!intp(arg)) return -1;
+
+  if ((!previous_object(1)||object_name(previous_object(1))!=FAO_MASTER) && 
+      (!this_interactive() || !IS_ARCH(this_interactive())))
+    return -1;
+
+  if (!intp(arg)) return -1;
+
+  log_file("fao/P_FAO",sprintf("%s - %s P_FAO gesetzt auf %O\n",
+        dtime(time()),query_real_name(),arg) );
+  return Set(P_FAO,arg);
+}
+
+nomask void set_realip(string str)
+{
+  if(previous_object() && strstr(object_name(previous_object()),"/secure")==0)
+  {
+    realip=str;
+  }
+}
+
+nomask string query_realip()
+{
+  return realip ? realip : "";
+}
+
+mixed _query_netdead_env() {
+        return ndead_location || ndead_l_filename;
+}