Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/std/shells/baum.c b/std/shells/baum.c
new file mode 100644
index 0000000..522f3fe
--- /dev/null
+++ b/std/shells/baum.c
@@ -0,0 +1,113 @@
+// Autor: Rumata@gmx.de
+// ... sozusagen meine private rasse ...
+//
+// MorgenGrauen MUDlib
+//
+// shells/magier.c -- magier shell
+//
+// $Id: baum.c 8675 2014-02-18 20:39:54Z Zesstra $
+
+#pragma strong_types,save_types
+
+inherit "/std/shells/magier";
+
+//#define NEED_PROTOTYPES
+
+#include <thing/properties.h>
+#include <properties.h>
+#include <wizlevels.h>
+#include <language.h>
+#include <moving.h>
+#include <attributes.h>
+#include <combat.h>
+#include <defines.h>
+#include <ansi.h>
+#include <udp.h>
+#include <new_skills.h>
+
+static int _wurzel;
+
+void create()
+{
+  if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+      set_next_reset(-1);    
+      return;
+  }
+
+  ::create();
+	_wurzel = -1;
+}
+
+static int wurzel_an( string arg ) {
+	string num;
+	int count;
+
+	if( this_object() != this_interactive() ) return 0;
+	notify_fail( "WAS willst Du schlagen?\n" );
+	if( !arg || sscanf( arg, "wurzel%s", num ) == 0 ) return 0;
+
+	if( sscanf( num, " %d", count ) == 0 ) {
+		notify_fail( "schage wurzel <zahl>\n" );
+		return 0;
+	}
+
+	_wurzel = count;
+	say( Name(WER) + " schlaegt hier Wurzeln.\n" );
+	write( "Du schlaegst nun Wurzeln.\n" );
+	return 1;
+}
+
+static int wurzel_aus( string arg ) {
+	
+	if( this_object() != this_interactive() ) return 0;
+	notify_fail( "WAS willst du loesen?\n" );
+	if( !arg ) return 0;
+	if( member( ({"wurzel","wurzeln"}),	arg ) == -1 ) return 0;
+	
+	_wurzel = -1;
+	say( Name(WER) + " loest " + QueryPronoun(FEMALE,WEN,PLURAL)
+			 + " Wurzeln aus dem Boden.\n" );
+	write( "Du loest Deine Wurzeln aus dem Boden.\n" );
+	return 1;
+}
+
+int wurzel_info( string arg ) {
+	if( this_object() != this_interactive() ) return 0;
+	switch( _wurzel ) {
+	case -1:
+		write( "Deine Wurzeln sind lose.\n" );
+		break;
+	case 0:
+		write( "Deine Wurzeln sitzen fest.\n" );
+		break;
+	case 1:
+		write( "Noch eine Bewegung und Du sitzt fest.\n" );
+		break;
+	default:
+		printf( "Noch %d Bewegungen, und Du sitzt fest.\n", _wurzel );
+	}
+	return 1;
+}
+
+static mixed _query_localcmds() {
+	return ::_query_localcmds() + ({
+		({ "schlag"    , "wurzel_an"  ,1,ARCH_LVL }),
+		({ "loes"      , "wurzel_aus" ,1,ARCH_LVL }),
+		({ "wurzelinfo", "wurzel_info",0,ARCH_LVL })
+	});
+}
+
+varargs int move( mixed dest, int method, string dir,
+									string textout, string textin )
+{
+	if( _wurzel == 0 ) {
+		return ME_TOO_HEAVY;
+	}
+	if( _wurzel > 0 ) { _wurzel--; }
+	return ::move( dest, method, dir, textout, textin );
+}
+
+static int new_quit() {
+	_wurzel = -1;
+	return ::new_quit();
+}
diff --git a/std/shells/darkelf.c b/std/shells/darkelf.c
new file mode 100644
index 0000000..45e37fb
--- /dev/null
+++ b/std/shells/darkelf.c
@@ -0,0 +1,270 @@
+// MorgenGrauen MUDlib
+//
+// shells/darkelf.c -- Darkelf Shell
+//
+// $Id: darkelf.c 8675 2014-02-18 20:39:54Z Zesstra $
+
+#pragma strong_types,save_types
+
+inherit "/std/player/base";
+
+#include <properties.h>
+#include <attributes.h>
+#include <wizlevels.h>
+#include <health.h>
+#include <new_skills.h>
+#include <language.h>
+#include <defines.h>
+#include <combat.h>
+#include <defuel.h>
+#include <errord.h>
+
+
+protected void create()
+{
+  if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+    set_next_reset(-1);
+    return;
+  }
+  base::create();
+  SetDefaultHome("/gilden/dunkelelfen");
+  SetDefaultPrayRoom("/d/unterwelt/cadra/room/town/templemain");
+  SetProp(P_AVERAGE_SIZE,175);
+  SetProp(P_AVERAGE_WEIGHT,70000);
+  SetProp(P_ALIGN, -500);
+  SetProp(P_SKILL_ATTRIBUTE_OFFSETS,([SA_ENEMY_SAVE:110]));
+  SetProp(P_ATTRIBUTES_OFFSETS,([A_INT:4,A_DEX:2]));
+  SetProp(P_MATERIAL_KNOWLEDGE,([MATGROUP_UNHOLY: 100,
+                                 MATGROUP_MAGIC:   70,
+                                 MATGROUP_DEAD:    50,
+                                 MATGROUP_METAL:   30]) );
+  SetProp(P_RESISTANCE_STRENGTHS,
+            ([ DT_HOLY :    0.25,
+               DT_UNHOLY : -0.15,
+               DT_TERROR : -0.05 ]));
+  SetProp(P_MAX_FOOD,80);
+  SetProp(P_MAX_DRINK,150);
+  SetProp(P_MAX_ALCOHOL,70);
+
+  SetProp(P_SP_DELAY, HEAL_DELAY-2); // dafuer regeneriert man im freien
+  SetProp(P_HP_DELAY, HEAL_DELAY-1); // wirklich _nichts_
+  SetProp(P_FOOD_DELAY,FOOD_DELAY+1);
+  SetProp(P_DRINK_DELAY,DRINK_DELAY-2);
+  SetProp(P_ALCOHOL_DELAY,ALCOHOL_DELAY+1);
+
+  SetProp(P_MAGIC_RESISTANCE_OFFSET,
+        ([ MT_ILLUSION    : 200,
+           MT_ANGRIFF     : 500,
+	   MT_BEHERRSCHUNG: 500,
+	   MT_PSYCHO      : 800 ]));
+
+  /* Groesse wird nur einmal gesetzt */
+  if(!QueryProp(P_SIZE)) {
+    SetProp(P_SIZE,150+random(50));
+    Set(P_SIZE,SAVE,F_MODE_AS);
+  }
+
+  /* Dito Gewicht */
+  if(!QueryProp(P_WEIGHT) || (QueryProp(P_WEIGHT) == 75000)){
+    SetProp(P_WEIGHT,60000+random(20001));
+    if(QueryProp(P_GENDER)==FEMALE)
+      SetProp(P_WEIGHT,QueryProp(P_WEIGHT)-5000);
+    Set(P_WEIGHT,SAVE,F_MODE_AS);
+  }
+  SetProp(P_DEFUEL_LIMIT_FOOD,40);
+  SetProp(P_DEFUEL_LIMIT_DRINK,30);
+  SetProp(P_DEFUEL_TIME_FOOD,400);
+  SetProp(P_DEFUEL_TIME_DRINK,250);
+  SetProp(P_DEFUEL_AMOUNT_FOOD,0.45);
+  SetProp(P_DEFUEL_AMOUNT_DRINK,0.4);
+}
+
+static void FinalSetup()
+{
+   if (!QuerySkill(SK_NIGHTVISION))
+      ModifySkill(SK_NIGHTVISION, 5000, 0, "ANY");
+}
+
+string _query_race()
+// nicht static, da sie manchmal auch so aufgerufen wird...
+{
+  return "Dunkelelf";
+}
+
+string _query_real_race()
+{
+  return "Dunkelelf";
+}
+
+static string _query_racedescr()
+{
+	  return
+"\
+Das Volk der Dunkelelfen lebt in einer grossen Hoehlenstadt gut versteckt\n\
+hinter einem Wasserfall. Ueber kaum ein anderes Volk gibt es soviele\n\
+Vorurteile wie ueber die Dunkelelfen, und so werden sie von allen misstrauisch\n\
+beaeugt oder sogar bekaempft. In diesem Kampf, insbesondere gegen die Elfen,\n\
+sind sie voellig auf sich allein gestellt, und so hat sich eine mehr oder\n\
+minder autarke Gesellschaft entwickelt. Die Dunkelelfen haben eine eigene\n\
+Kultur und eine eigene Goettin, der sie huldigen. Wie auch die Elfen\n\
+verfuegen sie ueber ausserordenlich grosse magische Faehigkeiten, auch wenn\n\
+sie sich mehr auf die schwarze Seite der Magie spezialisiert haben.\n";
+}
+
+// int QueryAllowSelect() { return 0; }
+// Aktiviert am 28.07.03, Ark.
+int QueryAllowSelect() { return 1; }
+
+string *_query_racestring()
+{
+  if (QueryProp(P_GENDER)==2)
+    return ({"Dunkelelfe","Dunkelelfe","Dunkelelfe","Dunkelelfe"});
+  return ({"Dunkelelf","Dunkelelfen","Dunkelelf","Dunkelelf"});
+}
+
+static string _query_default_guild()
+{
+  return "dunkelelfen";
+}
+
+static int sun_in_room(object room)
+{
+  if (!room) return 0;
+  closure qp=symbol_function("QueryProp", room);
+  int lt=funcall(qp, P_LIGHT_TYPE);
+  // (lt & LT_SUN) ist hier zunaechst _testweise_ drin. Die Rasse wurde
+  // anders genehmigt. Sollte das im MG ueberhand nehmen und jeder Keller
+  // nun sonnendurchflutet sein, dann wird das wieder ausgebaut!
+  // 27.06.04 Padreic
+  return ( (funcall(qp, P_INT_LIGHT)>0) &&
+          ((lt & LT_SUN) || ((lt==LT_MISC) && !funcall(qp, P_INDOORS))));
+}
+
+protected void heart_beat()
+{
+  ::heart_beat();
+  if (sun_in_room(environment()) &&
+      QueryProp("Dunkelelfen:Outdoor")<random(100) && !QueryProp(P_GHOST)) {
+     int hp;
+     hp=QueryProp(P_HP)-1;
+     SetProp(P_HP, hp);
+     if (hp<0) {
+       tell_object(ME,
+         "Das war wohl zuviel fuer Dich. Das naechste mal solltest Du Dich "
+        +"wohl besser\ngegen die Sonne schuetzen.\n");
+       SetProp(P_KILL_NAME,"Zuviel Sonne");
+       do_damage(999,ME);
+       SetProp(P_KILL_NAME,0);
+     }
+     else tell_object(ME, /* die Info musste irgendwie in eine Zeile */
+           "Die Sonne scheint gnadenlos auf Dein Haupt und schwaecht Dich.\n");
+  }
+}
+
+static int _query_no_regeneration()
+{
+  if (sun_in_room(environment()))
+     return NO_REG;
+  return Query(P_NO_REGENERATION);
+}
+
+int StdSkill_Nightvision(object me, string sname, mixed sinfo)
+{
+  int last, light;
+
+  if (!sinfo || !environment()) return 0;
+  if (intp(sinfo)) sinfo=([SI_SKILLABILITY:sinfo]);
+  if (!mappingp(sinfo)) return 0;
+  light=(QueryProp(P_PLAYER_LIGHT)<=0 ? -1 : 1);
+  if (last=sinfo[SI_USR]) { // letztes Lichtlevel != 0
+     if (light==last) {
+       if (sinfo[SI_LASTLIGHT]<=time())
+          return sinfo[SI_SKILLABILITY]+1;
+       return -1;
+     }
+     else {
+       last=( MAX_ABILITY - sinfo[SI_SKILLABILITY] );
+       last=(last/1000) + (last%1000 > random(1001) ? 1 : 0);
+       if (light<0) last/=2; // an Dunkelkeit schneller gewoehnen...
+       if(!this_interactive() || this_interactive()==this_object())
+       {
+	       ModifySkill(sname, ([SI_USR: light, SI_LASTLIGHT: time()+last]),
+        	           0, sinfo[SI_GUILD]);
+       }
+       if (last<=0)
+          return sinfo[SI_SKILLABILITY]+1;
+       return -1;
+     }
+  }
+  else { // Startwert...
+    if(!this_interactive() || this_interactive()==this_object())
+    {
+    	ModifySkill(sname, ([SI_USR: light, SI_LASTLIGHT: 0]), 0, sinfo[SI_GUILD]);
+    }
+    return sinfo[SI_SKILLABILITY]+1;
+  }
+  return 0;
+}
+
+varargs int CannotSee(int silent)
+{
+  string is_blind;
+
+  if ( is_blind = QueryProp( P_BLIND ) ) {
+     if (!silent) {
+       if (stringp(is_blind)) write(is_blind);
+       else write("Du bist blind!\n");
+     }
+     return 1;
+  }
+  if (environment() && (!IS_LEARNER(ME) || !Query(P_WANTS_TO_LEARN))) {
+     if (QueryProp(P_GHOST)) {
+        if (StdSkill_Nightvision(ME, SK_NIGHTVISION, QuerySkill(SK_NIGHTVISION))>0)
+            return 0;
+     }
+     else if (UseSkill(SK_NIGHTVISION)>0) return 0;
+     if (!silent) {
+        if (QueryProp(P_PLAYER_LIGHT)<=0)
+          write("Du kannst nichts sehen, da sich Deine Augen noch nicht an die Dunkelheit\n"
+               +"gewoehnt haben!\n");
+        else write("Du bist von dem hellen Licht total geblendet und Du musst Dich erst langsam\n"
+                  +"daran gewoehnen.\n");
+     }
+     return 1;
+  }
+  return 0;
+}
+
+
+/*
+ * 2003-11-05, Zook:
+ *
+ *   Temporaere Funktion, die den Delfen es ermoeglicht, einen
+ *   moeglicherweise falschen Raum (Indoor/Outdoor) zu melden.
+ *
+ */
+
+static int _indoorbug(string key)
+{
+  if (!stringp(key))
+    key= "";
+
+  ERRORD->LogReportedError(
+      ([ F_PROG: "unbekannt",
+         F_LINE: 0,
+         F_MSG: "Sonnenfehler: " + key,
+         F_OBJ: environment(this_object())
+      ])
+      );
+
+  write("Du hast einen fehlerhaften Innen-/Aussen-/Sonnenlichtraum gemeldet.\n");
+
+  return 1;
+}
+
+static mixed _query_localcmds()
+{
+  return ({ ({"sonnenfehler", "_indoorbug", 0, 0 }) })
+            + base::_query_localcmds();
+}
+
diff --git a/std/shells/dwarf.c b/std/shells/dwarf.c
new file mode 100644
index 0000000..7a696dc
--- /dev/null
+++ b/std/shells/dwarf.c
@@ -0,0 +1,156 @@
+// MorgenGrauen MUDlib
+//
+// shells/dwarf.c -- Dwarven Shell
+//
+// $Id: dwarf.c,v 3.14 2004/12/13 12:54:31 Zook Exp $
+
+#pragma strong_types,save_types
+
+inherit "std/player/base";
+
+#include <properties.h>
+#include <attributes.h>
+#include <wizlevels.h>
+#include <health.h>
+#include <new_skills.h>
+#include <language.h>
+#include <combat.h>
+#include <defuel.h>
+
+
+void create(){
+  if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+      set_next_reset(-1);    
+      return;
+  }
+
+  mixed res;
+
+  base::create();
+  SetDefaultHome("/d/gebirge/room/zkapelle");
+  SetDefaultPrayRoom("/d/gebirge/room/zkapelle");
+  SetProp(P_ATTRIBUTES_OFFSETS,([A_STR:2,A_DEX:1,A_CON:3]));
+  SetProp(P_SKILL_ATTRIBUTE_OFFSETS,([SA_DURATION:110]));
+  SetProp(P_AVERAGE_SIZE,120);
+  SetProp(P_AVERAGE_WEIGHT,75000);
+  SetProp(P_MATERIAL_KNOWLEDGE,([MATGROUP_STONE:30,
+                                 MATGROUP_METAL:30, 
+                                 MATGROUP_PRECIOUS_METAL: 40, 
+                                 MAT_GOLD:100]));
+  SetProp(P_RESISTANCE_STRENGTHS,
+	  ([ DT_FIRE : -0.2,
+	   DT_WATER : 0.4 ]));
+  SetProp(P_MAX_ALCOHOL,200);
+  SetProp(P_MAX_FOOD,160);
+
+  SetProp(P_SP_DELAY,HEAL_DELAY+1);
+  SetProp(P_POISON_DELAY,POISON_DELAY+1);
+  SetProp(P_FOOD_DELAY,FOOD_DELAY-1);
+  SetProp(P_ALCOHOL_DELAY,ALCOHOL_DELAY-1);
+
+  SetProp(P_MAGIC_RESISTANCE_OFFSET,
+          ([ MT_ANGRIFF : 200,
+	   MT_ILLUSION : -500,
+           MT_BEHERRSCHUNG : 1000,
+	   MT_VERWANDLUNG : 500 ]));
+
+  if(!IS_SEER(this_object())){
+    SetProp(P_MSGIN,"stapft herein");
+    SetProp(P_MSGOUT,"stapft");
+  }
+
+  if(!(res=QueryProp(P_HANDS)) || !pointerp(res) || (sizeof(res)<3))
+    res=({" mit blossen Haenden",35,({DT_BLUDGEON}) });
+  res[1]=35;
+  SetProp(P_HANDS,res);
+  SetProp(P_BODY,10);
+
+  /* Groesse wird nur einmal gesetzt */
+  if(!QueryProp(P_SIZE)){
+    SetProp(P_SIZE,110+random(21));
+    Set(P_SIZE,SAVE,F_MODE_AS);
+  }
+
+  /* Dito Gewicht */
+  if(!QueryProp(P_WEIGHT) || (QueryProp(P_WEIGHT) == 75000)){
+    SetProp(P_WEIGHT,65000+random(20001));
+    if(QueryProp(P_GENDER)==FEMALE)
+      SetProp(P_WEIGHT,QueryProp(P_WEIGHT)-5000);
+    Set(P_WEIGHT,SAVE,F_MODE_AS);
+  }
+
+  SetProp(P_DEFUEL_LIMIT_FOOD,70);
+  SetProp(P_DEFUEL_LIMIT_DRINK,50);
+  SetProp(P_DEFUEL_TIME_FOOD,535);
+  SetProp(P_DEFUEL_TIME_DRINK,500);
+  SetProp(P_DEFUEL_AMOUNT_FOOD,0.8);
+  SetProp(P_DEFUEL_AMOUNT_DRINK,0.6);
+
+}
+
+string _query_race()
+{
+  return "Zwerg";
+}
+
+string _query_real_race()
+{
+  return "Zwerg";
+}
+
+string _query_racedescr()
+{
+  return
+  "Zwerge sind kleine aber kraeftige Gebirgsbewohner, nicht sehr gespraechig,\n"
+    +"leicht erzuernt, aber eine schlagkraeftige Unterstuetzung fuer ihre Freunde."
+    +"\n"
+    +"Ihr Mut und ihre Standfestigkeit ist weit und breit beruehmt, auch ihr\n"
+    +"Geschick im Umgang mit Zwergenwaffen verleiht ihnen zusaetzliche Kraft.\n"
+    +"Leider sind Zwerge nicht allzu schlau, sie verlassen sich lieber auf\n"
+    +"ihre Kraft als auf ihr Gehirn.\n";
+}
+
+int QueryAllowSelect() { return 1; }
+
+string *_query_racestring()
+{
+  if (QueryProp(P_GENDER)==2)
+    return ({"Zwergin","Zwergin","Zwergin","Zwergin"});
+  return ({"Zwerg","Zwerges","Zwerg","Zwerg"});
+}
+int _query_hp_delay(){
+  int re;
+  re = Query(P_HP_DELAY);
+  if (environment() && environment()->QueryProp(P_INDOORS))
+    re--;
+  else
+    re++;
+  return re;
+}
+int _query_sp_delay(){
+  int re;
+  re = Query(P_SP_DELAY);
+  if (environment() && environment()->QueryProp(P_INDOORS))
+    re--;
+  else
+    re++;
+  return re;
+}
+
+string _query_default_guild(){
+  return "abenteurer";
+}
+
+mixed RaceDefault(string arg)
+{
+  if (!arg)
+    return 0;
+  switch(arg)
+  {
+    case P_HANDS :
+      return ({" mit blossen Haenden",35,({DT_BLUDGEON}) });
+    case P_BODY :
+      return 10;
+  }
+  return 0;
+}
diff --git a/std/shells/elf.c b/std/shells/elf.c
new file mode 100644
index 0000000..dec4118
--- /dev/null
+++ b/std/shells/elf.c
@@ -0,0 +1,154 @@
+// MorgenGrauen MUDlib
+//
+// shells/elf.c -- Elven Shell
+//
+// $Id: elf.c 8928 2014-09-08 16:18:41Z Zesstra $
+
+#pragma strong_types,save_types
+
+inherit "std/player/base";
+
+#include <properties.h>
+#include <attributes.h>
+#include <wizlevels.h>
+#include <health.h>
+#include <new_skills.h>
+#include <language.h>
+#include <combat.h>
+#include <defuel.h>
+
+
+
+void create()
+{
+  if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+      set_next_reset(-1);    
+      return;
+  }
+
+  base::create();
+  SetDefaultHome("/d/wald/room/es_mitte");
+  SetDefaultPrayRoom("/d/wald/room/es_mitte");
+  SetProp(P_AVERAGE_SIZE,195);
+  SetProp(P_AVERAGE_WEIGHT,70000);
+  SetProp(P_SKILL_ATTRIBUTE_OFFSETS,([SA_ENEMY_SAVE:110]));
+  SetProp(P_ATTRIBUTES_OFFSETS,([A_INT:3,A_DEX:2,A_CON:1]));
+  SetProp(P_MATERIAL_KNOWLEDGE,([MATGROUP_WOOD:30, 
+                                 MATGROUP_HERBAL:30, 
+                                 MATGROUP_LIVING:20]));
+
+  SetProp(P_MAX_FOOD,80);
+  SetProp(P_MAX_DRINK,150);
+  SetProp(P_MAX_ALCOHOL,70);
+
+  SetProp(P_SP_DELAY,HEAL_DELAY-1);
+  SetProp(P_FOOD_DELAY,FOOD_DELAY+1);
+  SetProp(P_DRINK_DELAY,DRINK_DELAY-2);
+  SetProp(P_ALCOHOL_DELAY,ALCOHOL_DELAY+1);
+
+  SetProp(P_MAGIC_RESISTANCE_OFFSET,
+          ([ MT_ILLUSION : 800,
+           MT_ANGRIFF : 200,
+	   MT_VERWANDLUNG : 400,
+	   MT_PSYCHO : 500 ]));
+
+  // Elfen kriegen die Ebene der Wipfellaeufer per default. (Zu diesem
+  // Zeitpunkt stehen in P_CHANNELS nur die default channel drin, wird dann
+  // ueber das Einlesen des Savefiles ggf. ueberschrieben.)
+  SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({"wipfellaeufer"}));
+
+  if(!IS_SEER(this_object())){
+    SetProp(P_MSGIN,"wandelt herein");
+    SetProp(P_MSGOUT,"wandelt");
+  }
+
+  /* Groesse wird nur einmal gesetzt */
+  if(!QueryProp(P_SIZE)){
+    SetProp(P_SIZE,185+random(21));
+    Set(P_SIZE,SAVE,F_MODE_AS);
+  }
+
+  /* Dito Gewicht */
+  if(!QueryProp(P_WEIGHT) || (QueryProp(P_WEIGHT) == 75000)){
+    SetProp(P_WEIGHT,60000+random(20001));
+    if(QueryProp(P_GENDER)==FEMALE)
+      SetProp(P_WEIGHT,QueryProp(P_WEIGHT)-5000);
+    Set(P_WEIGHT,SAVE,F_MODE_AS);
+  }
+  SetProp(P_DEFUEL_LIMIT_FOOD,40);
+  SetProp(P_DEFUEL_LIMIT_DRINK,20);
+  SetProp(P_DEFUEL_TIME_FOOD,400);
+  SetProp(P_DEFUEL_TIME_DRINK,200);
+  SetProp(P_DEFUEL_AMOUNT_FOOD,0.4);
+  SetProp(P_DEFUEL_AMOUNT_DRINK,0.35);
+
+}
+
+string _query_race()
+{
+  return "Elf";
+}
+
+string _query_real_race()
+{
+  return "Elf";
+}
+
+string _query_racedescr()
+{
+  return 
+"\
+Als Elfen bezeichnet man in der Regel jene hageren Hinterwaeldler, deren\n\
+demonstratives Naturgehabe in der Regel nur durch ihre Liebe zu kitschigen\n\
+Gedichten und ausschweifendem Geschlechtsleben in den Schatten gestellt wird.\n\
+Einen Elf kann man im allgemeinen nicht nur an aeusseren Missbildungen\n\
+(spitze Ohren, spindelduerre Gestalt, blonde Haare) erkennen, sondern auch\n\
+an seiner aufdringlichen Art, ueber jeden und alles hemmungslos ins Gruene\n\
+loszuphilosophieren.\n";
+
+}
+
+int QueryAllowSelect() { return 1; }
+
+string *_query_racestring()
+{
+  if (QueryProp(P_GENDER)==2)
+    return ({"Elfe","Elfe","Elfe","Elfe"});
+  return ({"Elf","Elfen","Elf","Elf"});
+}
+int _query_hp_delay(){
+  int re;
+  re = Query(P_HP_DELAY);
+  if (environment() && environment()->QueryProp(P_INDOORS))
+    re++;
+  else
+    re--;
+  return re;
+}
+int _query_sp_delay(){
+  int re;
+  re = Query(P_SP_DELAY);
+  if (environment() && environment()->QueryProp(P_INDOORS))
+    re++;
+  else
+    re--;
+  return re;
+}
+
+string _query_default_guild(){
+  return "wipfellaeufer";
+}
+
+static void FinalSetup()
+{
+  if(QueryProp(P_GUILD) != "chaos")
+    SetProp(P_RESISTANCE_STRENGTHS,
+            ([ DT_MAGIC : -0.2,
+               DT_HOLY : 0.1,
+               DT_UNHOLY : 0.3 ]));
+  else
+    SetProp(P_RESISTANCE_STRENGTHS,
+            ([ DT_MAGIC : -0.2,
+               DT_UNHOLY : 0.1,
+               DT_HOLY : 0.3 ]));
+}
diff --git a/std/shells/feline.c b/std/shells/feline.c
new file mode 100644
index 0000000..f590fab
--- /dev/null
+++ b/std/shells/feline.c
@@ -0,0 +1,259 @@
+// MorgenGrauen MUDlib
+//
+// shells/feline.c -- Feline Shell
+//
+// $Id: feline.c 8487 2013-05-21 19:15:52Z Zesstra $
+
+#pragma strong_types,save_types
+
+inherit "/std/player/base";
+
+#include <attributes.h>
+#include <combat.h>
+#include <health.h>
+#include <new_skills.h>
+#include <properties.h>
+#include <language.h>
+#include <wizlevels.h>
+#include <defuel.h>
+
+
+void create()
+{   
+    if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+      set_next_reset(-1);    
+      return;
+    }
+
+    int   i,g;
+    mixed h;
+
+    base::create();
+
+// Startraum/Kapelle setzen
+    SetDefaultHome("/d/dschungel/paracelsus/room/fkapelle");
+    SetDefaultPrayRoom("/d/dschungel/paracelsus/room/fkapelle");
+
+// Besondere rassenspezifische Properties (bei denen es nichts macht, wenn
+// sie nach jedem Einloggen neu gesetzt werden):
+
+    SetProp(P_ATTRIBUTES_OFFSETS, // Summe 4 statt 6 wg. SA_SPEED
+    ([
+        A_STR :  1,
+        A_INT :  2,
+        A_DEX :  2,
+        A_CON : -1 
+    ]) );
+    SetProp(P_AVERAGE_SIZE,200);
+    SetProp(P_AVERAGE_WEIGHT,85000);
+    SetProp(P_BODY,15);
+    SetProp(P_SKILL_ATTRIBUTE_OFFSETS,([SA_SPEED:120]));
+    SetProp(P_MATERIAL_KNOWLEDGE,
+    ([
+        MATGROUP_WOOD    :  60,
+        MATGROUP_JEWEL   : 100,
+        MATGROUP_EATABLE :  30
+    ]) );
+
+    SetProp(P_MAGIC_RESISTANCE_OFFSET,
+    ([
+        MT_ANGRIFF     :  200,
+        MT_ILLUSION    : -500,
+        MT_VERWANDLUNG :  500,
+        MT_PSYCHO      : 1000 
+    ]) );
+
+    SetProp(P_RESISTANCE_STRENGTHS,
+    ([
+        DT_WATER : -0.1,
+        DT_ACID  :  0.1,
+        DT_COLD  :  0.1 
+    ]) );
+
+// Lebenspunkte werden langsamer als normal regeneriert
+    SetProp(P_HP_DELAY,HEAL_DELAY+1);
+
+// Magiepunkte werden schneller als normal regeneriert
+    SetProp(P_SP_DELAY,HEAL_DELAY-1);
+
+// Gift wirkt etwas langsamer als normal
+    SetProp(P_POISON_DELAY,POISON_DELAY+1);
+
+// Getraenke werden etwas schneller als normal abgebaut
+    SetProp(P_DRINK_DELAY,DRINK_DELAY-1);
+
+// Essen wird etwas schneller als normal abgebaut ...
+    SetProp(P_FOOD_DELAY,FOOD_DELAY-1);
+    SetProp(P_MAX_FOOD,140);
+
+// Es gibt einige Sachen, die sollen nur beim ersten Einloggen gesetzt werden.
+// Andere muessen nachtraeglich - aber nur einmal - gemacht werden, weil sich
+// etwas geaendert hat.
+    switch( QueryProp(P_SHELL_VERSION) )
+    {
+        case 0 :
+
+            g=QueryProp(P_GENDER);
+
+            if ( !(i=QueryProp(P_SIZE)) || (i<(g==FEMALE?165:170)) 
+                || (i>(g==FEMALE?225:230)) )
+            {
+                SetProp(P_SIZE, (g==FEMALE?195:200)
+                    + random(16) - random(16) + random(16) - random(16) );
+            }
+
+            if( !(i=QueryProp(P_WEIGHT)) || (i<(g==FEMALE?70000:77000)) 
+               || (i>(g==FEMALE?88000:95000)) || (i==75000) )
+            {
+                SetProp(P_WEIGHT, (g==FEMALE?70000:77000)
+                    + random(4501) + random(4501) + random(4501) + random(4501) );
+            }
+
+
+            SetProp(P_MATERIAL,([
+                MAT_MISC_LIVING : 90,
+                MAT_PELT        :  8,
+                MAT_HORN        :  2
+            ]) );
+
+            if ( !IS_SEER(this_object()) )
+            {
+                SetProp(P_MSGIN,"schleicht herein");
+                SetProp(P_MSGOUT,"schleicht");
+                SetProp(P_MMSGIN,"erscheint mit einem grellen Blitz");
+                SetProp(P_MMSGOUT,"verschwindet mit einem grellen Blitz");
+                SetProp(P_HANDS,({" mit scharfen Krallen",40, ({DT_RIP}) }));
+            }
+            else
+            {
+                if ( !pointerp(h=QueryProp(P_HANDS)) || (sizeof(h)<1) )
+                    h = ({" mit scharfen Krallen",40, ({DT_RIP}) });
+                else
+                    h = ({h[0],40, ({DT_RIP}) });
+                SetProp(P_HANDS, h);
+            }
+
+            if ( !pointerp(h=QueryProp(P_CHANNELS)) )
+                SetProp(P_CHANNELS,({"katzenkrieger"}));
+            else if ( member(h,"katzenkrieger")==-1 )
+                SetProp(P_CHANNELS, h + ({"katzenkrieger"}) );
+
+            Set(P_SIZE,SAVE,F_MODE_AS);
+            Set(P_MATERIAL,SAVE,F_MODE_AS);
+            Set(P_WEIGHT,SAVE,F_MODE_AS);
+
+        default :
+
+            SetProp(P_SHELL_VERSION,1);
+    }
+  SetProp(P_DEFUEL_LIMIT_FOOD,70);
+  SetProp(P_DEFUEL_LIMIT_DRINK,40);
+  SetProp(P_DEFUEL_TIME_FOOD,400);
+  SetProp(P_DEFUEL_TIME_DRINK,300);
+  SetProp(P_DEFUEL_AMOUNT_FOOD,0.55);
+  SetProp(P_DEFUEL_AMOUNT_DRINK,0.4);
+
+}
+
+// Diese Rasse kann derzeit gewaehlt werden:
+int QueryAllowSelect() { return 1; }
+
+// Rassenbezeichnung
+string _query_race()
+{
+    return "Feline";
+}
+
+string _query_real_race()
+{
+    return "Feline";
+}
+
+// Die Rassenbeschreibung, die man beim ersten Einloggen abrufen kann.
+string _query_racedescr()
+{
+    return break_string(
+        "Felinen sind aufrecht gehende Katzenwesen.\n"+
+        "Ihre Heimat ist der Dschungel. Kaum jemand duerfte sich dort "+
+        "besser zurechtfinden als sie. Bedingt durch diese Umgebung "+
+        "haben sie im Laufe der Zeit eine Vorliebe fuer elegante Hoelzer "+
+        "und funkelnde Edelsteine entwickelt. Sie sind zwar nicht so "+
+        "'raffgierig' wie Zwerge, aber dennoch sollte man besser nicht "+
+        "versuchen, einem Felinen einen Edelstein wegzunehmen. Sie "+
+        "benutzen die Edelsteine sehr gerne, um sich damit zu schmuecken. "+
+        "Felinen betreiben sogar einen regelrechten Koerperkult, "+
+        "insbesondere wenn es darum geht, das Fell oder die Krallen zu "+
+        "faerben. Edelsteine kommen da als Accessoires gerade recht.\n"+
+        "Auch im Kampf gegen einen Felinen sollte man sehr vorsichtig "+
+        "sein, da Felinen ihre geringe Ausdauer durch eine hohe "+
+        "Geschwindigkeit sowie Geschick und Intelligenz wettmachen. "+
+        "Auch die Spitzen Krallen sind da nicht zu verachten und so "+
+        "mancher Gegner musste schon als Ersatz fuer einen Kratzbaum "+
+        "herhalten.",78,0,1);
+}
+
+// Geschlechtsabhaengiges Rassenbezeichnungs-Array
+string *_query_racestring()
+{
+    if (QueryProp(P_GENDER)==2)
+        return ({"Felinin","Felinin","Felinin","Felinin"});
+    return ({"Feline","Felinen","Felinen","Felinen"});
+}
+
+// Regeneration der Lebenspunkte ist von der Umgebung abhaengig
+// Im Wald und Dschungel geht es schneller, in der Wueste und im
+// Polargebiet dagegen langsamer.
+int _query_hp_delay()
+{
+    int re;
+    string fn;
+
+    re = Query(P_HP_DELAY);
+    if (environment() && !(environment()->QueryProp(P_INDOORS)) &&
+        fn=object_name(environment()))
+    {
+        if (fn[0..12]=="/d/dschungel/" || fn[0..7]=="/d/wald/")
+            re--;
+        else if (fn[0..9]=="/d/wueste/" || fn[0..8]=="/d/polar/")
+            re++;
+    }
+    return re;
+}
+
+// Regeneration der Magiepunkte ist von der Umgebung abhaengig
+// Im Wald und Dschungel geht es schneller, in der Wueste und im
+// Polargebiet dagegen langsamer.
+int _query_sp_delay()
+{
+    int re;
+    string fn;
+
+    re = Query(P_SP_DELAY);
+    if (environment() && !(environment()->QueryProp(P_INDOORS)) &&
+        fn=object_name(environment()))
+    {
+        if (fn[0..12]=="/d/dschungel/" || fn[0..7]=="/d/wald/")
+            re--;
+        else if (fn[0..9]=="/d/wueste/" || fn[0..8]=="/d/polar/")
+            re++;
+    }
+    return re;
+}
+
+string _query_default_guild(){
+  return "katzenkrieger";
+}
+
+mixed RaceDefault(string arg)
+{
+    if (!arg)
+      return 0;
+    switch(arg)
+    {
+        case P_HANDS :
+            return ({" mit scharfen Krallen",40, ({DT_RIP}) });
+        case P_BODY :
+            return 15;
+    }
+    return base::RaceDefault(arg);
+}
diff --git a/std/shells/goblin.c b/std/shells/goblin.c
new file mode 100644
index 0000000..ed694b3
--- /dev/null
+++ b/std/shells/goblin.c
@@ -0,0 +1,213 @@
+/*
+ * Goblin-Rassenshell
+ * [/std/shells/goblin.c]
+ * (c) 2007 nibel@mg.mud.de
+ *
+ * Werte von Ark abgesegnet am 11.12.2007
+ */
+
+#pragma strong_types,save_types
+
+#include <attributes.h>
+#include <health.h>
+#include <new_skills.h>
+#include <properties.h>
+#include <wizlevels.h>
+#include <defuel.h>
+#include <moving.h>
+
+inherit "/std/player/base.c";
+
+static varargs int GoblinCmdWaaagh(string arg);
+
+public void create() {
+  mixed res;
+  base::create();
+
+  SetDefaultHome("/d/wald/kessa/waaagh/room/starthut/hut[" + 
+    getuid(this_object()) +"]");
+  SetDefaultPrayRoom("/d/wald/nibel/lichtung/room/lichtung_45");
+  
+  SetProp(P_AVERAGE_SIZE, 80);
+  SetProp(P_AVERAGE_WEIGHT, 32000);
+  SetProp(P_MATERIAL_KNOWLEDGE, ([MATGROUP_EATABLE:20, MATGROUP_DRUG:40,
+    MATGROUP_PRECIOUS_METAL:25, MATGROUP_JEWEL:25]));
+
+  SetProp(P_BODY, 15);
+  SetProp(P_ATTRIBUTES_OFFSETS, ([A_STR:0, A_INT:1, A_DEX:2, A_CON:2]));
+  SetProp(P_RESISTANCE_STRENGTHS, ([DT_FIRE:-0.15, DT_LIGHTNING:-0.15,
+    DT_SOUND:0.1, DT_HOLY:0.1, DT_AIR:0.1, DT_ACID:0.1]));
+  SetProp(P_MAGIC_RESISTANCE_OFFSET, ([MT_ANGRIFF:600, MT_ILLUSION:500,
+    MT_VERWANDLUNG:-300, MT_HELLSICHT:-750, MT_BEHERRSCHUNG:250]));
+  SetProp(P_SKILL_ATTRIBUTE_OFFSETS, ([SA_ENEMY_SAVE:103, SA_DAMAGE:107]));
+
+  SetProp(P_SP_DELAY, HEAL_DELAY + 2);
+  SetProp(P_HP_DELAY, HEAL_DELAY - 1);
+  SetProp(P_ALCOHOL_DELAY, ALCOHOL_DELAY - 1);
+
+  switch(QueryProp(P_SHELL_VERSION)) {
+    case 0:
+      if(!QueryProp(P_SIZE)) // Maennlein und Weiblein sind gleich "gross"
+        SetProp(P_SIZE, 75 + random(11));
+      if(QueryProp(P_WEIGHT) == 75000) // Dito Gewicht
+        SetProp(P_WEIGHT, (QueryProp(P_SIZE) * 390) +
+          random(QueryProp(P_SIZE) * 10));
+      SetProp(P_MATERIAL,([MAT_MISC_LIVING:100]));
+          
+      Set(P_SIZE, SAVE, F_MODE_AS);
+      Set(P_WEIGHT, SAVE, F_MODE_AS);
+      Set(P_MATERIAL, SAVE, F_MODE_AS);
+
+      if(!pointerp(res = QueryProp(P_HANDS)) || sizeof(res) < 3)
+        res = ({" mit kleinen Faeustchen", 30, ({ DT_BLUDGEON })});
+      SetProp(P_HANDS, res);
+
+      if(!IS_SEER(this_object())) {
+        SetProp(P_MSGIN, "flitzt herein");
+        SetProp(P_MSGOUT, "flitzt");
+      }
+      SetProp(P_SHELL_VERSION, 1);
+    case 1:
+      // /std/player/base setzt ja schon P_WEIGHT...
+      if(QueryProp(P_WEIGHT) == 75000) {
+        SetProp(P_WEIGHT, (QueryProp(P_SIZE) * 390) +
+          random(QueryProp(P_SIZE) * 10));
+      }
+      SetProp(P_SHELL_VERSION, 2);
+    default: break;
+  }
+  
+  SetProp(P_MAX_FOOD, 110);
+  SetProp(P_MAX_DRINK, 80);
+  SetProp(P_MAX_ALCOHOL, 125);
+  SetProp(P_DEFUEL_LIMIT_FOOD, 60);
+  SetProp(P_DEFUEL_LIMIT_DRINK, 60);
+  SetProp(P_DEFUEL_TIME_FOOD, 400);
+  SetProp(P_DEFUEL_TIME_DRINK, 360);
+  SetProp(P_DEFUEL_AMOUNT_FOOD, 0.5);
+  SetProp(P_DEFUEL_AMOUNT_DRINK, 0.4);
+}
+
+static void FinalSetup() {
+  object o;
+  if(QueryProp(P_LEVEL) > 5 || present("\nibel:waldlichtungskarte",
+    this_object())) return;
+  if(!catch(o = clone_object("/d/wald/nibel/lichtung/obj/karte")))
+    o->move(this_object(), M_NOCHECK);
+}
+
+public int QueryAllowSelect() { return 1; }
+
+public string _query_race() { return "Goblin"; }
+public string _query_real_race() { return "Goblin"; }
+
+public string _query_racedescr() {
+  return break_string("Goblins sind winzige, gruenhaeutige Wesen, sogar "
+    "noch kleiner als Hobbits. An ihren zu dick geratenen Koepfchen "
+    "befinden sich lange, selten reglose, Ohren und eine grosse, krumme "
+    "Nase. Ihre kleine Statur sollte jedoch nicht taeuschen, denn ihre "
+    "fehlende Kraft machen sie mit Geschwindigkeit, Praezision und nicht "
+    "zuletzt ihrer unbestrittenen Ruchlosigkeit alleweil wett. Obwohl "
+    "fuer sie Pluendern, lautes Herumbruellen und die gemeinsten Streiche "
+    "spielen zum Alltag gehoert, wuerde sie niemand als boesartig "
+    "bezeichnen. Denn Goblins sind vieles, aber sicherlich nicht die "
+    "intelligentesten Kreaturen. Durch ihren zaehen Willen und die dicke, "
+    "lederne Haut sind sie aussergewoehnlich widerstandsfaehig, und, "
+    "sofern funkelnde Beute winkt, fuer jedes Abenteuer zu haben.", 78);
+}
+
+public string *_query_racestring() {
+  if(QueryProp(P_GENDER) == FEMALE)
+    return ({"Goblinfrau", "Goblinfrau", "Goblinfrau", "Goblinfrau"});
+  return ({"Goblin", "Goblins", "Goblin", "Goblin"});
+}
+
+public string _query_default_guild() {return "abenteurer";}
+
+public string _query_visible_guild() {
+  switch(lower_case(QueryProp(P_GUILD))) {
+    case "abenteurer": return "abentoira";
+    case "wipfellaeufer": return "wiffelloifa";
+    case "chaos": return "kaos";
+    case "zauberer": return "zaubara";
+    case "bierschuettler": return "biaschuettla";
+    case "katzenkrieger": return "kaznkriega";
+	  case "tanjian": return "tanschan";
+	  case "klerus": return "klerikae";	  	
+	  case "dunkelelfen": return "dunklelfn";
+	  case "kaempfer": return "kaempfa";
+	  case "karate": return "karatae";
+	  case "werwoelfe": return "weawoelf";
+	  case "magus": return "magia";
+    case "urukhai": return "urugai";
+  }
+  return QueryProp(P_GUILD);
+}
+
+public mixed RaceDefault(string arg) {
+  if(!arg) return 0;
+  switch(arg) {
+    case P_HANDS:
+      return ({" mit kleinen Faeustchen", 30, ({  DT_BLUDGEON })});
+    case P_BODY:
+      return 15;
+  }
+  return base::RaceDefault(arg);
+}
+
+static mixed _query_localcmds() {
+  return ({({"waaagh", "GoblinCmdWaaagh", 0, 0})}) +
+    base::_query_localcmds();
+}
+
+// "knuddel alle" ist deutlich teurer also who cares :-)
+static varargs int GoblinCmdWaaagh(string arg) {
+  object *obs;
+  string s, w;
+  
+  if(!objectp(environment())) return 0;
+  obs = filter(all_inventory(environment()) - ({this_object()}), #'living);
+  obs = obs - filter_objects(obs, "QueryProp", P_INVIS);
+  // levelabhaengige Anzahl aaaaaaa's
+  w = "W"+ sprintf("%'a'"+ (QueryProp(P_LEVEL) / 10 + 3) +"s", "aaa") +"gh!";
+
+  foreach(object o : obs)
+  {
+    string str=(break_string(Name(WER) +" ballt die Faeustchen und "
+      "kreischt laut: "+ w +"\n"
+      + capitalize(o->QueryDu(WER)) + " zuckst erschrocken zusammen.",
+      78, 0, BS_LEAVE_MY_LFS));
+
+    int res=o->ReceiveMsg(str,MT_LISTEN,MA_EMOTE,0,this_object());
+    if (res<0)
+    {
+      obs-=({o}); // unten nicht mehr mit anzeigen.
+      if (res==MSG_SENSE_BLOCK)
+        ReceiveMsg(o->Name(WER) +" kann Dich nicht hoeren.",
+                   MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE,
+                   MA_EMOTE,0,this_object());
+      else
+        ReceiveMsg(o->Name(WER) +" ignoriert Dich oder diesen Befehl.",
+                   MT_NOTIFICATION|MSG_DONT_IGNORE|MSG_DONT_STORE,
+                   MA_EMOTE,0,this_object());
+    }
+  }
+  int anzahl=sizeof(obs);
+  if(!anzahl)
+  {
+    ReceiveMsg("Du ballst die Faeustchen und kreischst laut: "
+               + w, MT_NOTIFICATION|MSG_DONT_IGNORE,MA_EMOTE,0,this_object());
+  }
+  else
+  {
+    s = CountUp(map_objects(obs, "name", WER));
+    ReceiveMsg(break_string("Du ballst die Faeustchen und kreischst laut: "
+               + w +"\n"+ capitalize(s) +" zuck"
+               +(anzahl > 1 ? "en" : "t") +" erschrocken zusammen.",
+               78, 0, BS_LEAVE_MY_LFS),
+               MT_NOTIFICATION|MSG_DONT_STORE|MSG_DONT_IGNORE,
+               MA_EMOTE,0,this_object());
+  }
+  return 1;
+}
+
diff --git a/std/shells/hobbit.c b/std/shells/hobbit.c
new file mode 100644
index 0000000..b626b06
--- /dev/null
+++ b/std/shells/hobbit.c
@@ -0,0 +1,139 @@
+// MorgenGrauen MUDlib
+//
+// shells/hobbit.c -- Hobbit Shell
+//
+//   9.April 1995  V1.0 Gundur
+//
+//   15.Juni prayroom und defHome auf Hobbitdorf gesetzt von Gundur
+//
+// $Id: hobbit.c 8920 2014-09-02 20:18:38Z Zesstra $
+
+#pragma strong_types,save_types
+
+inherit "std/player/base";
+
+#include <properties.h>
+#include <attributes.h>
+#include <wizlevels.h>
+#include <health.h>
+#include <new_skills.h>
+#include <language.h>
+#include <combat.h>
+#include <moving.h>
+#include <defuel.h>
+
+
+
+void create(){
+  if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+      set_next_reset(-1);    
+      return;
+  }
+
+  mixed res;
+
+  base::create();
+  SetDefaultHome("/d/wald/gundur/hobbitdorf/schrein");
+  SetDefaultPrayRoom("/d/wald/gundur/hobbitdorf/schrein");
+  SetProp(P_ATTRIBUTES_OFFSETS,([A_DEX:4,A_CON:2]));
+  SetProp(P_AVERAGE_SIZE, 105);
+  SetProp(P_AVERAGE_WEIGHT, 60000);
+  SetProp(P_MATERIAL_KNOWLEDGE,([MATGROUP_EATABLE:30, 
+                                 MATGROUP_DRUG:30, 
+                                 MATGROUP_POISONOUS:10]));
+  SetProp(P_RESISTANCE_STRENGTHS,
+	  ([ DT_TERROR : -0.1,
+	   DT_MAGIC : -0.1,
+	   DT_SOUND : 0.2,
+	   DT_LIGHTNING : 0.1,
+	   DT_POISON : 0.1 ]));
+  SetProp(P_MAX_FOOD,250);
+  SetProp(P_MAX_DRINK,100);
+  SetProp(P_MAX_ALCOHOL,150);
+
+  SetProp(P_SP_DELAY,HEAL_DELAY+1);
+  SetProp(P_POISON_DELAY,POISON_DELAY-1);
+  SetProp(P_FOOD_DELAY,FOOD_DELAY-2);
+  SetProp(P_ALCOHOL_DELAY,ALCOHOL_DELAY+1);
+
+  SetProp(P_MAGIC_RESISTANCE_OFFSET,
+          ([ MT_ANGRIFF : 500,
+	   MT_HELLSICHT : -500,
+	   MT_PSYCHO : -500 ]));
+
+  if(!(res=QueryProp(P_HANDS)) || !pointerp(res) || (sizeof(res)<3))
+    res=({" mit pelzigen Haenden",25,({DT_BLUDGEON})});
+  res[1]=25;
+  SetProp(P_HANDS,res);
+  SetProp(P_BODY,15);
+
+  /* Groesse wird nur einmal gesetzt */
+  if(!QueryProp(P_SIZE)){
+    SetProp(P_SIZE,95+random(21));
+    Set(P_SIZE,SAVE,F_MODE_AS);
+  }
+
+  /* Dito Gewicht */
+  if(!QueryProp(P_WEIGHT) || (QueryProp(P_WEIGHT) == 75000)){
+    SetProp(P_WEIGHT,50000+random(20001));
+    if(QueryProp(P_GENDER)==FEMALE)
+      SetProp(P_WEIGHT,QueryProp(P_WEIGHT)-5000);
+    Set(P_WEIGHT,SAVE,F_MODE_AS);
+  }
+  SetProp(P_DEFUEL_LIMIT_FOOD,140);
+  SetProp(P_DEFUEL_LIMIT_DRINK,50);
+  SetProp(P_DEFUEL_TIME_FOOD,850);
+  SetProp(P_DEFUEL_TIME_DRINK,450);
+  SetProp(P_DEFUEL_AMOUNT_FOOD,0.8);
+  SetProp(P_DEFUEL_AMOUNT_DRINK,0.6);
+
+}
+
+string _query_race()
+{
+  return "Hobbit";
+}
+
+string _query_real_race()
+{
+  return "Hobbit";
+}
+
+string _query_racedescr()
+{
+  return "Hobbits sind kleine Wesen, die am ehesten den Menschen aehneln.\n"+
+    "Sie zeichnen sich trotz Ihrer Groesse durch ihren Mut und Standfestigkeit "+
+	"aus.\nObwohl sie viel lieber zuhause vorm warmen Kamin sitzen, sind sie "+
+	"immer\nfuer ein Abenteuer zu haben.\n";
+}
+
+int QueryAllowSelect() { return 1; }
+
+string *_query_racestring(){
+  if (QueryProp(P_GENDER) == FEMALE)
+    return ({"Hobbitfrau","Hobbitfrau","Hobbitfrau","Hobbitfrau"});
+  return ({"Hobbit","Hobbits","Hobbit","Hobbit"});
+}
+
+string _query_default_guild(){
+  return "abenteurer";
+}
+
+void FinalSetup() {
+  if(!present("pfeifchen",this_object()))
+    clone_object("/items/pfeifchen")->move(this_object(),M_NOCHECK);
+}
+
+mixed RaceDefault(string arg)
+{
+  if (!arg)
+    return 0;
+  switch(arg)
+  {
+    case P_HANDS :
+      return ({" mit pelzigen Haenden",25,({DT_BLUDGEON}) });
+    case P_BODY :
+      return 15;
+  }
+  return base::RaceDefault(arg);
+}
diff --git a/std/shells/human.c b/std/shells/human.c
new file mode 100644
index 0000000..c18df2d
--- /dev/null
+++ b/std/shells/human.c
@@ -0,0 +1,113 @@
+// MorgenGrauen MUDlib
+//
+// shells/human.c -- Human Shell
+//
+// $Id: human.c 9022 2015-01-10 21:50:50Z Zesstra $
+
+#pragma strong_types,save_types
+
+inherit "/std/player/base";
+
+#include <properties.h>
+#include <attributes.h>
+#include <moving.h>
+#include <wizlevels.h>
+#include <health.h>
+#include <new_skills.h>
+#include <language.h>
+#include <defuel.h>
+
+
+
+void create() {
+  if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+      set_next_reset(-1);    
+      return;
+  }
+
+  base::create();
+  SetDefaultHome("/gilden/abenteurer");
+  SetDefaultPrayRoom("/d/ebene/room/PortVain/pray_room");
+  SetProp(P_ATTRIBUTES_OFFSETS,([A_INT:1,A_STR:1,A_CON:1,A_DEX:3]));
+  SetProp(P_AVERAGE_SIZE,170);
+  SetProp(P_AVERAGE_WEIGHT,75000);
+  SetProp(P_MATERIAL_KNOWLEDGE,([MATGROUP_WOOD:20, 
+                                 MATGROUP_METAL:20, 
+                                 MATGROUP_ELEMENTAL:20, 
+                                 MATGROUP_CLOTH:20]));
+
+  SetProp(P_MAX_FOOD,120);
+  SetProp(P_MAX_DRINK,120);
+  SetProp(P_MAX_ALCOHOL,120);
+
+  SetProp(P_MAGIC_RESISTANCE_OFFSET,
+          ([ MT_ANGRIFF : 500,
+	   MT_ILLUSION : 700,
+           MT_BEHERRSCHUNG : 500,
+	   MT_HELLSICHT : 1000,
+	   MT_VERWANDLUNG : -500,
+	   MT_PSYCHO : -500 ]));
+
+  // Zukuenftig 0, nicht mehr -5. Ark, 04.01.08.
+  SetProp(P_BODY,0);
+
+  /* Groesse wird nur einmal gesetzt */
+  if(!QueryProp(P_SIZE)){
+    SetProp(P_SIZE,160+random(21));
+    Set(P_SIZE,SAVE,F_MODE_AS);
+  }
+
+  /* Dito Gewicht */
+  if(!QueryProp(P_WEIGHT) || (QueryProp(P_WEIGHT) == 75000)){
+    SetProp(P_WEIGHT,65000+random(20001));
+    if(QueryProp(P_GENDER)==FEMALE)
+      SetProp(P_WEIGHT,QueryProp(P_WEIGHT)-5000);
+    Set(P_WEIGHT,SAVE,F_MODE_AS);
+  }
+  SetProp(P_DEFUEL_LIMIT_FOOD,60);
+  SetProp(P_DEFUEL_LIMIT_DRINK,50);
+  SetProp(P_DEFUEL_TIME_FOOD,500);
+  SetProp(P_DEFUEL_TIME_DRINK,245);
+  SetProp(P_DEFUEL_AMOUNT_FOOD,0.75);
+  SetProp(P_DEFUEL_AMOUNT_DRINK,0.5);
+
+}
+
+string _query_race()
+{
+  return "Mensch";
+}
+
+string _query_real_race()
+{
+  return "Mensch";
+}
+
+string *_query_racestring()
+{
+  if (QueryProp(P_GENDER)==2)
+    return ({"Menschenfrau","Menschenfrau","Menschenfrau","Menschenfrau"});
+  return ({"Mensch","Menschen","Mensch","Menschen"});
+}
+
+string _query_racedescr()
+{
+  return "Die Staerke des Menschen ist seine Vielseitigkeit.\n"+
+    "Der Mensch kann zwar nichts besonders gut - dafuer aber eigentlich alles.\n";
+}
+
+int QueryAllowSelect() { return 1; }
+
+void FinalSetup()
+{
+  // Im MG gibt fuer kleine Spieler eine Karte von Port Vain. Die gibt es
+  // woanders meist nicht.
+#if MUDNAME == "MorgenGrauen"
+  if (QueryProp(P_LEVEL)<=3 && !present("portvainkarte",this_object()))
+    clone_object("/d/ebene/obj/pv")->move(this_object(),M_NOCHECK);
+#endif
+}
+
+string _query_default_guild(){
+  return "abenteurer";
+}
diff --git a/std/shells/magier.c b/std/shells/magier.c
new file mode 100644
index 0000000..dc2a150
--- /dev/null
+++ b/std/shells/magier.c
@@ -0,0 +1,326 @@
+// MorgenGrauen MUDlib
+//
+// shells/magier.c -- magier shell
+//
+// $Id: magier.c 9231 2015-05-27 21:53:32Z Zesstra $
+
+//
+// Magiershell Basisfile
+//
+// Ueberarbeitung abgeschlossen am 18.12.2002
+//
+// Dank an Zwirch@PK, Rikus@MG, Zoran@PK, Vanion@MG
+// und viele andere, die ich vergessen habe.
+//
+// Fragen und Bughinweise an Mandragon@MG oder einen
+// Erzmagier Deiner Wahl.
+//
+// Zur Shell gehoeren ausser dieser Datei:
+// admin.c:      Administrative Befehle
+// comm.c:       Kommunikationsbefehle
+// fileedit.c:   Befehle zum Veraendern von Dateien
+// fileview.c:   Befehle zum Lesen von Dateien
+// magier_ext.c: Generelle Magierbefehle
+// moving.c:     Bewegungsbefehle
+// objects.c:    Erzeugen und zerstoeren von Objekten
+// parsing.c     Auswertung von Pfadangaben und Wildcards
+// players.c:    Befehle zur Beeinflussung von Spielern
+// todo.c:       Implementation der Todoliste
+// upd.c:        Der Befehl upd
+// magier.h      Generelle Header-Datei
+//
+
+#pragma strict_types,save_types
+
+inherit "/std/player/base";
+inherit "/std/shells/magier/magier_ext";
+
+#include <wizlevels.h>
+#include <moving.h>
+#include <properties.h>
+#include <new_skills.h>
+#include <config.h>
+
+protected void create()
+{
+  if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+      set_next_reset(-1);
+      return;
+  }
+
+  base::create();
+
+  Set(P_RACE, SAVE, F_MODE);
+  Set(P_ZAP_MSG, SAVE, F_MODE);
+  Set(P_TRANK_FINDEN, SAVE, F_MODE);
+  Set(P_HANDS, SAVE, F_MODE);
+  Set(P_RACESTRING, SAVE, F_MODE);
+  SetDefaultHome("/gilden/abenteurer");
+  SetProp(P_ENEMY_DEATH_SEQUENCE,
+    ([17:"Der Tod schuettelt verstaendnislos den Kopf.\n\n",
+      18:"Der Tod sagt: WIESO MUSSTEST DU DICH AUCH UNBEDINGT "
+      "MIT EINEM MAGIER ANLEGEN?\n\n"]));
+  SetProp(P_ATTRIBUTES_OFFSETS,([]));
+  SetProp(P_AVERAGE_SIZE,185);
+  if(!QueryProp(P_DEFAULT_GUILD)) SetProp(P_DEFAULT_GUILD,"abenteurer");
+}
+
+protected void create_super() {
+  set_next_reset(-1);
+}
+
+
+protected void heart_beat()
+{
+  mixed *en;
+
+  if (!QueryProp(P_WANTS_TO_LEARN)||((en=QueryEnemies())&&sizeof(en[0])))
+    base::heart_beat();
+  else if (!CheckTelnetKeepAlive()) {
+    // Wenn der Magier kein Telnet Keep-Alive wuenscht, kann der HB ganz
+    // abgeschaltet werden. Sonst muss er aber weiterlaufen, damit
+    // CheckTelnetKeepAlive() regelmaessig gerufen wird.
+    set_heart_beat(0);
+  }
+}
+
+
+public varargs int remove(int silent)
+{
+  string workroom;
+
+  if (IS_WIZARD(this_object()))
+    workroom = "/players/"+getuid()+"/workroom";
+  else
+    workroom = "/secure/merlin";
+  if( !environment() || object_name(environment()) != workroom )
+    catch(move(workroom, M_GO, "nach Hause"));
+  return base::remove(silent);
+}
+
+public string NotifyDestruct(object caller) {
+
+  if (previous_object() != master()
+      || object_name(this_object()) == __FILE__[..<3])
+    return 0;
+  
+  // Nicht-EMs sollen keine EMs zerstoeren koennen, woraufhin auch evtl.
+  // EM-Tools rumliegen koennten.
+  if ( IS_ARCH(this_object()) && caller != this_object() 
+      && getuid(caller) != ROOTID
+      && (process_call() || !ARCH_SECURITY) )
+    return "Das Zerstoeren von EMs ist ein Fehler. ;-)\n";
+
+  return ::NotifyDestruct(caller);
+}
+
+void reset()
+{
+  if (!interactive(this_object()))
+  {
+    quit();
+    if (this_object())
+      remove();
+    if (this_object())
+        destruct(this_object());
+    return;
+  }
+}
+
+//                ####################
+//################# Query-Funktionen ##################
+//                ####################
+
+varargs int id (string str) {
+  if (QueryProp(P_INVIS) &&
+      (!this_interactive() ||!IS_LEARNER(this_interactive())))
+    return 0;
+  return ::id(str);
+}
+
+
+static string *_query_racestring()
+{
+  if (pointerp(Query(P_RACESTRING)))
+    return Query(P_RACESTRING);
+  else
+    return
+    ({QueryProp(P_RACE),QueryProp(P_RACE),
+      QueryProp(P_RACE),QueryProp(P_RACE)});
+}
+
+
+static string _query_default_guild()
+{
+    return (Query(P_DEFAULT_GUILD)||"abenteurer");
+}
+
+
+static string _query_racedescr()
+{
+  return "Magier koennen einfach alles. Aber manche Magier koennen mehr.\n";
+}
+
+
+static string _query_race()
+{
+  if (previous_object() && previous_object()->query_login_object())
+    return 0;
+
+  return Query(P_RACE) ? Query(P_RACE) : Set(P_RACE, "Magier");
+}
+
+
+static mixed _query_localcmds()
+{
+  return
+    base::_query_localcmds()
+    +magier_ext::_query_localcmds();
+}
+
+
+static void upd_my_age()
+{
+  age=_age+absolute_hb_count()-_hbstop;
+  _age=age;
+  _hbstop=absolute_hb_count();
+  return;
+}
+
+
+static int _query_age()
+{
+  upd_my_age();
+  return age;
+}
+
+static int _set_earmuffs(int level)
+{
+  int maxl=1+query_wiz_level(this_object());
+  maxl = max(maxl,99);
+  return Set(P_EARMUFFS,min(maxl,level));
+}
+
+
+//                   ############################
+//#################### Interne Shell-Funktionen ####################
+//                   ############################
+
+int MayAddWeight(int w) { return 0;}
+int MayAddObject(object ob) { return 1; }
+
+
+static void initialize()
+{
+  magier_ext::initialize();
+  return;
+}
+
+
+static void FinalSetup()
+{
+  SetProp(P_CURRENTDIR,"/players/"+getuid());
+  initialize();
+  if (IS_LEARNER(this_player())) cat("/etc/WIZNEWS");
+  _age=age;
+  _hbstop=absolute_hb_count();
+  return;
+}
+
+
+void save_me(int i)
+{
+  upd_my_age();
+  base::save_me(i);
+  return;
+}
+
+
+varargs void Reconnect(int silent,string my_ip)
+{
+  base::Reconnect(silent,my_ip);
+  magier_ext::reconnect();
+  return;
+}
+
+
+void notify_player_change(string who, int rein, int invis)
+{
+  string *list,name;
+  mixed mlist;
+  int vis_change;
+
+  if (invis) name="("+who+")";
+    else name=who;
+
+  if(query_verb() && (query_verb()=="vis" || query_verb()=="invis"))
+    vis_change=1;
+
+  if (Query(P_INFORMME) && !vis_change)
+  {
+    if (rein) 
+      tell_object(this_object(),
+                  sprintf("%s ist gerade ins "MUDNAME" gekommen.\n",name));
+    else
+      tell_object(this_object(),
+                  sprintf("%s hat gerade das "MUDNAME" verlassen.\n",name));
+  }
+
+  if(Query(P_WAITFOR_FLAGS) & (0x01))return ;
+
+  if (pointerp(list=Query(P_WAITFOR))&&sizeof(list))
+    if (member(list,who)!=-1)
+      delayed_write(
+         ({
+           ({sprintf("%s%s   I S T   J E T Z T   %s !!!\n",
+                     (QueryProp(P_VISUALBELL) ? "" : sprintf("%c",7)),
+                     name,
+                     (vis_change?
+                       (rein?"S I C H T B A R":"U N S I C H T B A R"):
+                       (rein?"D A":"N I C H T   M E H R   D A"))),
+           0})
+         }));
+
+  if (rein && (sizeof(mlist=QueryProp(P_WAITFOR_REASON))) &&
+     (mappingp(mlist)) && (mlist[who]))
+        Show_WaitFor_Reason(who,invis);
+  return;
+}
+
+mixed modify_command(string str) {
+  if (previous_object() &&
+      (previous_object()!=this_object() || process_call()) )
+  {
+    if (IS_ARCH(this_object()))
+      tell_object(this_object(),
+        sprintf("Illegal modify_command(%s) from %O\n",
+        str, previous_object()));
+    return 0;
+  }
+  //////////////////////////////////////////////////////////////////////
+  // Magier-Escape-Kommandos werden behandelt 
+  if (str=="\\ESCAPE" && IS_LORD(this_object()))
+  {
+    __set_environment(this_object(),"/room/void");
+    environment()->init();
+    printf("You escaped.\n");
+    return "";
+  }
+  if (str[0..2]=="\\\\\\" && IS_LORD(this_object()))
+  {
+    str = _return_args(str);
+    string* input = explode(str[3..]," ");
+    string verb = input[0];
+    if (verb && verb!="")
+    {
+      string cmd = implode(input[1..]," ");
+      if (!__auswerten(cmd,verb))
+        SoulComm(cmd,verb);
+    }
+    return 1;
+  }
+  //////////////////////////////////////////////////////////////////////
+
+  return ::modify_command(str);
+}
+
diff --git a/std/shells/magier/admin.c b/std/shells/magier/admin.c
new file mode 100644
index 0000000..a41d1b7
--- /dev/null
+++ b/std/shells/magier/admin.c
@@ -0,0 +1,428 @@
+// MorgenGrauen MUDlib
+//
+// admin.c
+//
+// $Id: admin.c 8755 2014-04-26 13:13:40Z Zesstra $
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <udp.h>
+#include <wizlevels.h>
+#include <input_to.h>
+
+#define NEED_PROTOTYPES
+#include <magier.h>
+#include <player.h>
+
+inherit "/std/util/cidr";
+
+mixed _query_localcmds()
+{
+  return ({({"udpq","_udpq",0,LEARNER_LVL}),
+           ({"shutdown","shut_down_game",0,ARCH_LVL}),
+           ({"addmaster","_addmaster",0,GOD_LVL}),
+           ({"removemaster","_removemaster",0,GOD_LVL}),
+           ({"addguildmaster", "_addguildmaster", 0, GOD_LVL}),
+           ({"removeguildmaster", "_removeguildmaster", 0, GOD_LVL}),
+           ({"suender","sinners",0,WIZARD_LVL}),
+           ({"banish","banish", 0, WIZARD_LVL}),
+           ({"mbanish","mbanish", 0, WIZARD_LVL}),
+           ({"tbanish","tbanish", 0, WIZARD_LVL}),
+           ({"sbanish","sbanish", 0, WIZARD_LVL})});
+}
+
+static int _udpq(string str)
+{
+  string ret, mud, type;
+
+  if (!(str=_unparsed_args()) || str=="" || sscanf(str,"%s %s",mud,type)<2)
+  {
+    write("Syntax: udpq mud type\n");
+    return 1;
+  }
+  if (member(({"commands","email","hosts","inetd","list","mud_port","time",
+         "version"}),type)==-1)
+    write("TYPEs: commands, email, hosts, inetd, list, mud_port, time, version\n");
+  if (ret=(string)INETD->_send_udp(mud,([SENDER:getuid(), REQUEST:QUERY, DATA:type]),1))
+    write(ret);
+  else
+    write("Anfrage abgeschickt.\n");
+  return 1;
+}
+
+static int shut_down_game(string str)
+{
+  if (!IS_ARCH(this_object()) || this_object()!=this_interactive())
+    return 0;
+  _notify_fail("Du musst einen Grund dafuer angeben.\n");
+  if (!str) return 0;
+  write( "Direkter shutdown mit Grund \""+str+"\"?\n" );
+  input_to("shut_down_game_2",INPUT_PROMPT, "(ja/nein) :", str);
+  return 1;
+}
+
+static int shut_down_game_2(string arg,string str)
+{
+  if (!IS_ARCH(this_object()) || this_object()!=this_interactive())
+    return 0;
+  if( arg!="ja" ) {
+    write( "Shutdown abgebrochen.\n" );
+  } else {
+    shutdown(str);
+  }
+  return 1;
+}
+
+
+static int _addmaster(string str)
+{
+  string master, domain;
+
+  if (!GOD_SECURITY)
+  {
+    write("Das darfst Du nicht!\n");
+    return 1;
+  }
+  _notify_fail("Syntax: addmaster <user> <domain>\n");
+  if (!str) return 0;
+  if (sscanf(str,"%s %s",master,domain)!=2) return 0;
+  if (!master || !domain) return 0;
+  if (!"/secure/master"->add_domain_master(master,domain))
+    write("Hat nicht funktioniert.\n");
+  else
+    write("Ok.\n");
+  return 1;
+}
+
+static int _removemaster(string str)
+{
+  string master, domain;
+
+  if (!GOD_SECURITY)
+  {
+    write("Das darfst Du nicht!\n");
+    return 1;
+  }
+  _notify_fail("Syntax: removemaster <user> <domain>\n");
+  if (!str) return 0;
+  if (sscanf(str,"%s %s",master,domain)!=2) return 0;
+  if (!master || !domain) return 0;
+  if (!"/secure/master"->remove_domain_master(master,domain))
+    write("Hat nicht funktioniert.\n");
+  else
+    write("Ok.\n");
+  return 1;
+}
+
+static int _addguildmaster(string str)
+{
+  string master, guild;
+  
+  if (!GOD_SECURITY)
+  {
+    write ("Das darfst Du nicht!\n");
+    return 1;
+  }
+
+  _notify_fail("Synatx: addguildmaster <user> <guild>\n");
+  if (!str) return 0;
+  if (sscanf(str, "%s %s", master, guild)!=2) return 0;
+  if (!master || !guild) return 0;
+  if (!"/secure/master"->add_guild_master(master,guild))
+    write("Hat nicht funktioniert.\n");
+  else
+    write ("Ok.\n");
+  return 1;
+}
+
+static int _removeguildmaster(string str)
+{
+  string master, guild;
+  
+  if (!GOD_SECURITY)
+  {
+    write ("Das darfst Du nicht!\n");
+    return 1;
+  }
+  _notify_fail("Syntax: removeguildmaster <user> <guild>\n");
+  if (!str) return 0;
+  if (sscanf(str, "%s %s", master, guild)!=2) return 0;
+  if (!master || !guild) return 0;
+  if (!"/secure/master"->remove_guild_master(master,guild))
+    write("Hat nicht funktioniert.\n");
+  else
+    write("Ok.\n");
+  return 1;
+}
+
+static int sinners(string arg)
+{   string *parts;
+    int    i;
+
+    if ( !IS_DEPUTY(this_object()) )
+      return 0;
+
+    arg=_unparsed_args()||arg;
+
+    notify_fail(
+        "Syntax: suender ?              => Liste aller Eingetragenen\n"+
+        "        suender <name>         => Eintraege lesen\n"+
+        "        suender +<name> <text> => Eintrag hinzufuegen\n"+
+        "        suender -<name> <nr>   => Eintrag loeschen\n"+
+        "        suender !              => Alle Eintraege dumpen\n"+
+        "        suender *              => Alle Eintraege anzeigen\n");
+
+    if ( !stringp(arg) || (sizeof(arg)<1) )
+      return 0;
+
+    if ( arg=="?" )
+    {
+        write(call_other("/secure/sinmaster","ListSinners"));
+        return 1;
+    }
+    if ( arg=="!" )
+    {
+        write(call_other("/secure/sinmaster","Dump"));
+        return 1;
+    }
+    if ( arg=="*" )
+    {
+        More((string)call_other("/secure/sinmaster","Dump",1));
+        return 1;
+    }
+
+    if ( (i=sizeof(parts=explode(arg," ")))<1 )
+      return 0;
+
+    if ( parts[0][0..0]=="-" )
+    {
+      if ( i<2 )
+        return 0;
+      write(call_other("/secure/sinmaster","RemoveSin",
+            lowerstring(parts[0][1..]),
+            to_int(parts[1])));
+    }
+    else if ( parts[0][0..0]=="+" )
+    {
+      if ( i<2 )
+        return 0;
+      write(call_other("/secure/sinmaster","AddSin",
+            lowerstring(parts[0][1..]),
+            implode(parts[1..]," ")));
+    }
+    else
+    {
+      if ( i>1 )
+        return 0;
+      write(call_other("/secure/sinmaster","ListSins",
+            lowerstring(parts[0])));
+    }
+    return 1;
+}
+
+static int banish(string str)
+{
+  string grund, name;
+  int force;
+
+  if ( !LORD_SECURITY && !IS_DEPUTY(secure_euid()) )
+      return 0;
+
+  if ( !str || !stringp(str) || !sizeof(str) ) {
+      write("Syntax: banish [-f] <name> [<grund>]\n");
+      return 1;
+  }
+
+  str = _unparsed_args();
+
+  if ( explode(str, " ")[0] == "-f" ){
+      str = implode( explode(str, " ")[1..], " " );
+      force = 1;
+  }
+
+  if ( sscanf( str, "%s %s", name, grund ) != 2 )
+      name=str;
+
+  if ( !name || !sizeof(name) ){
+    write("Syntax: banish [-f] <name> [<grund>]\n");
+    return 1;
+  }
+
+  name=lower_case(name);
+  "/secure/master"->BanishName( name, grund, force );
+  return 1;
+}
+
+static int mbanish(string str)
+{
+    string grund, name, *namen, txt, *dummy;
+    mapping list;
+    int i;
+
+    if ( !IS_DEPUTY(secure_euid()) )
+        return 0;
+
+    _notify_fail( "Syntax: mbanish <name> [<grund>]\n" );
+
+    if ( !str || !stringp(str) || !sizeof(str) ){
+        if ( !mappingp(list = (mapping)"/secure/merlin"->MBanishList()) ||
+             !(i = sizeof(list)) ){
+            write( "Momentan ist kein Spieler auf der mbanish-Liste.\n" );
+            return 1;
+        }
+
+        txt = "      Name     | gebanisht von |                    Grund\n" +
+            "=============================================================" +
+            "==================\n";
+
+        namen = sort_array( m_indices(list), #'</*'*/ );
+
+        for ( ; i--; ){
+            dummy = explode( break_string( list[namen[i],0] ||
+                                                 "-- keine Begruendung --", 45 ),
+                                   "\n" ) - ({""});
+
+            txt += sprintf( "  %-11s  |  %-11s  |  %s\n",
+                            capitalize( namen[i] ),
+                            capitalize( list[namen[i],1] || "" ),
+                            capitalize( implode( dummy, "\n               |"
+                                                 "               |  " ) ) );
+        }
+
+        More(txt);
+
+        return 1;
+    }
+
+    if ( sscanf( str, "%s %s", name, grund ) !=2 )
+        name = str;
+
+    if ( !name || !sizeof(name) )
+        return 0;
+
+    name = lower_case(name);
+
+    if ( !grund || !stringp(grund) || lower_case(grund) != "loeschen" ){
+        "/secure/merlin"->MBanishInsert( name, grund, this_interactive() );
+        write( "Du setzt "+capitalize(name)+" auf die MBanish-Liste.\n" );
+    }
+    else{
+        if ( !ARCH_SECURITY ){
+            write( "Das duerfen nur Erzmagier.\n" );
+            return 1;
+        }
+        "/secure/merlin"->MBanishDelete( name );
+        write( "Du loescht "+capitalize(name)+" von der MBanish-Liste.\n" );
+    }
+
+    return 1;
+}
+
+
+static int tbanish( string str )
+{
+  string name;
+  int days;
+
+  if ( !IS_DEPUTY(secure_euid()) )
+      return 0;
+
+  _notify_fail("Syntax: tbanish <name> <tage>\n");
+
+  if ( !str || !stringp(str) || !sizeof(str) )
+    return 0;
+
+  if ( sscanf(str,"%s %d",name,days) != 2 )
+      return 0;
+
+  if ( !name || !sizeof(name) )
+    return 0;
+
+  name = lower_case(name);
+
+  if ( !"/secure/master"->TBanishName( name, days ) )
+      return 1;
+
+  if ( !days )
+      write( "Okay, keine Spielpause fuer "+capitalize(name)+" mehr.\n" );
+  else
+      write( "Du verpasst "+capitalize(name)+" eine Spielpause fuer "+
+             (days>0 ? days+" Tage" : "laaaange Zeit")+".\n" );
+  return 1;
+}
+
+static int sbanish( string str )
+{
+    string ip;
+    int days;
+    mapping sites;
+
+    // Mindestens L26 fuer diesen Befehl
+    if ( secure_level() <= DOMAINMEMBER_LVL )
+        return 0;
+
+    if ( !str || !stringp(str) || !sizeof(str) ){
+        if ( !sizeof(sites = (mapping)MASTER->SiteBanish( 0, 0 )) ){
+            write( "Es sind zur Zeit keine Adressen gesperrt!\n" );
+            return 1;
+        }
+
+        ip = "      Adresse      |  gesperrt bis                 |  gesperrt "
+            + "durch\n========================================================"
+            + "==============\n";
+
+        int *keys = sort_array( m_indices(sites), #'</*'*/ );
+
+        foreach(int key : keys) {
+            ip += sprintf( "  %:15-s  |  %:27-s  |  %-s\n",
+                           IPv4_int2addr(key),
+                           sites[key] > 0 ? dtime(sites[key]) :
+                           "St. Nimmerleinstag", 
+                           capitalize(sites[key, 1]) );
+        }
+        write( ip + "\n" );
+        return 1;
+    }
+
+    _notify_fail("Syntax: sbanish <numerische ip> <tage>\n");
+
+    if ( sscanf( this_player()->_unparsed_args(), "%s %d", ip, days ) != 2 )
+        return 0;
+
+    if ( !ip || !sizeof(ip) )
+        return 0;
+
+//    _notify_fail( "Ungueltiges Adress-Format!\n" );
+
+    if ( !days ){
+        int res=(int)MASTER->SiteBanish(ip, 0);
+        if ( res == 1 )
+             printf( "Die Adresse '%s' ist jetzt nicht mehr gesperrt.\n",
+                     ip );
+        else if ( res == 0 )
+             printf( "Die Adresse '%s' war gar nicht gesperrt!\n",
+                     ip );
+        else
+            printf( "Du darfst nur eigene Sperrungen wieder aufheben!\n" );
+    }
+    else {
+        int res;
+        if ( days != 1 && !IS_DEPUTY(secure_euid()) )
+            write( "Du darfst Adressen nur fuer einen Tag sperren!\n" );
+        else if ( (res = (int)MASTER->SiteBanish(ip, days)) == 1 )
+             printf( "Die Adresse '%s' ist jetzt fuer %s gesperrt.\n",
+                     ip, (days > 1 ? sprintf( "%d Tage", days ) :
+                      (days > 0 ? "einen Tag" : "immer")) );
+        else if ( res == -1 )
+            write( "Du darfst " + (LORD_SECURITY ? "255 IP-Adressen"
+                                   : "nur einzelne IP-Adressen") + " sperren!\n" );
+        else if ( res == -2 )
+            write( "Du hast schon genug Adressen gesperrt!\n" );
+    }
+
+    return 1;
+}
+
diff --git a/std/shells/magier/comm.c b/std/shells/magier/comm.c
new file mode 100644
index 0000000..0cbd266
--- /dev/null
+++ b/std/shells/magier/comm.c
@@ -0,0 +1,149 @@
+// MorgenGrauen MUDlib
+//
+// comm.c
+//
+// $Id: comm.c 8755 2014-04-26 13:13:40Z Zesstra $
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <wizlevels.h>
+#include <magier.h>
+#define NEED_PROTOTYPES
+#include <thing/properties.h>
+#include <thing/description.h>
+#include <player.h>
+#include <properties.h>
+
+
+//                           ###########
+//############################ ECHOALL ################################
+//                           ###########
+
+static int _echoall(string str)
+{
+  if (!(str=_unparsed_args()))
+    return USAGE("echoall <text>\n");
+  str=break_string(str);
+  shout(str);
+  printf(str);
+  return 1;
+}
+
+//                           ##########
+//############################ ECHOTO #################################
+//                           ##########
+
+static int _echoto(string str)
+{
+  object ob;
+  string who;
+  string msg;
+
+  if (!(str=_unparsed_args())||sscanf(str, "%s %s", who, msg) != 2)
+    return USAGE("echoto <spieler> <text>\n");
+  ob = find_player(lower_case(who));
+  if (!ob)
+  {
+    printf("echoto: Es ist kein Spieler '%s' eingeloggt.\n",who);
+    return 1;
+  }
+  msg=break_string(msg,78);
+  tell_object(ob,msg);
+  printf("%s->%s",ob->Name(WEN),msg);
+  return 1;
+}
+
+//                           #########
+//############################ MECHO ##################################
+//                           #########
+
+static int _mecho(string str)  {
+  object *who;
+  int i;
+
+  if (!sizeof(str=_unparsed_args()))
+    return USAGE("mecho <text>\n");
+  who=users();
+  i=sizeof(who);
+  while(i--)if (IS_LEARNER(who[i]))
+      tell_object(who[i], break_string(str,78));
+  return 1;
+}
+
+//                            ########
+//############################# PING ##################################
+//                            ########
+
+static int _ping(string str)
+{
+  object pl;
+
+  if (!sizeof(str))
+    return USAGE("ping <spielername>\n");
+  if (!(pl=find_player(lower_case(str))))
+    return
+      _notify_fail(sprintf("ping: Spieler %s nicht gefunden.\n",
+                           capitalize(str))),0;
+  tell_object(pl,sprintf("%s pingt Dich an.\a\n",capitalize(getuid())));
+  return printf("PINGGGGGGG! DAS sollte %s auf Dich aufmerksam "
+                "gemacht haben.\n",capitalize(getuid(pl))),1;
+}
+
+//                           ##########
+//############################ OROPAX #################################
+//                           ##########
+
+int _oropax(string cmdline)
+{
+  int level,old,new;
+
+  cmdline=_unparsed_args();
+  old=QueryProp(P_EARMUFFS);
+  if (!sizeof(cmdline)||cmdline=="0")
+  {
+    if (old)
+    {
+      printf("Du nimmst das Oropax aus Deinen Ohren und hoerst "
+             "wieder allen anderen zu.\n");
+      SetProp(P_EARMUFFS, 0);
+    }
+    else
+      printf("Du hast doch gar kein Oropax in den Ohren.\n");
+    return 1;
+  }
+  if (sscanf(cmdline, "%d", level) == 0 || level < 1)
+    return USAGE("oropax [<magierlevel>]\n");
+  if ((new=SetProp(P_EARMUFFS, level))==level)
+  {
+    if (new==old)
+      return printf("Du hattest Deine Oropaxmenge schon auf Magierlevel "
+                    "%d angepasst.\n",level),1;
+    if (new>old)
+      return printf("Du stopfst Dir soviel Oropax in die Ohren, dass "
+                    "Du nur noch %s ab\nLevel %d hoerst.\n",
+                    level>=LEARNER_LVL?"Magier":"Seher",level),1;
+    return printf("Du nimmst soviel Oropax aus den Ohren, dass Du ab "
+                  "sofort wieder %s ab\nLevel %d verstehst.\n",
+                  level>=LEARNER_LVL?"Magier":"Seher",level),1;
+  }
+  return printf("Du stopfst und stopfst, bis Dir das Oropax wieder zur "
+                "Nase herauskommt.\nLeider musst Du damit Magier ab Level "
+                "%d weiterhin hoeren.\n",new),1;
+}
+
+//                         ###################
+//########################## INITIALISIERUNG #############################
+//                         ###################
+
+static mixed _query_localcmds()
+{
+  return
+    ({({"oropax","_oropax",0,LEARNER_LVL}),
+      ({"echoto","_echoto",0,LEARNER_LVL}),
+      ({"echoall","_echoall",0,LEARNER_LVL}),
+      ({"mecho","_mecho",0,LEARNER_LVL}),
+      ({"ping","_ping",0,LEARNER_LVL})});
+}
diff --git a/std/shells/magier/fileedit.c b/std/shells/magier/fileedit.c
new file mode 100644
index 0000000..f4df0a5
--- /dev/null
+++ b/std/shells/magier/fileedit.c
@@ -0,0 +1,718 @@
+// MorgenGrauen MUDlib
+//
+//fileedit.c
+//
+// $Id: fileedit.c 9142 2015-02-04 22:17:29Z Zesstra $
+#pragma strict_types
+#pragma save_types
+//#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <wizlevels.h>
+#include <input_to.h>
+
+#define NEED_PROTOTYPES
+#include <magier.h>
+#include <player.h>
+#include <files.h>
+
+//                        ###################
+//######################### INITIALISIERUNG #############################
+//                        ###################
+
+mixed _query_localcmds()
+{
+  return ({ ({"cp","_cp",0,WIZARD_LVL}),
+            ({"mv","_cp",0,WIZARD_LVL}),
+            ({"rm","_rm",0,WIZARD_LVL}),
+            ({"rmdir","_rmdir",0,WIZARD_LVL}),
+            ({"mkdir","_mkdir",0,WIZARD_LVL}),
+            ({"ed","_ed",0,WIZARD_LVL})});
+}
+
+//                               ######
+//################################ ED ###################################
+//                               ######
+
+
+//
+// _ed_file: Mehrere Files hintereinander editieren
+//
+
+private nosave string *_ed_cache;
+
+private void _ed_file()
+{
+  if (!sizeof(_ed_cache)) return;
+  printf("ed: Naechste Datei: %s\n",_ed_cache[0]);
+  ed(_ed_cache[0],"_ed_file");
+  _ed_cache=_ed_cache[1..];
+  return;
+}
+
+#if __VERSION__ < "3.2.9"
+private mixed _ed_size_filter(mixed *arg)
+{
+  if (arg[FILESIZE]>=-1) return arg[FULLNAME];
+  printf("%s ist ein Verzeichnis.\n",arg[FULLNAME]);
+  return 0;
+}
+#endif
+
+//
+// _more: Dateien anzeigen
+// cmdline: Kommandozeile
+//
+
+static int _ed(string cmdline)
+{
+  mixed *args,*args2;
+  int flags,i,arg_size;
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,"",1);
+  if (flags==-1||!(arg_size=sizeof(args)))
+    return USAGE("ed <datei> [<datei2>..]");
+  while(arg_size--)
+  {
+    if (sizeof(args2=file_list(args[arg_size..arg_size],MODE_ED,0,"/")))
+      args[arg_size..arg_size]=args2;
+    else
+      args[arg_size]=({ "" , -1, 0 , (string)
+              call_other(master(),"_get_path",args[arg_size],
+                  getuid())});
+  }
+#if __VERSION__ < "3.2.9"
+  args=map(args,#'_ed_size_filter)-({0});
+#else
+  args=map(args,(:
+          if ($1[FILESIZE]>=-1) return $1[FULLNAME];
+          printf("%s ist ein Verzeichnis.\n",$1[FULLNAME]);
+          return 0; :))-({0});
+#endif
+  if (flags==-1||!sizeof(args)) return USAGE("ed <datei> [<datei2>..]");
+  _ed_cache=args;
+  _ed_file();
+  return 1;
+}
+
+
+//                             ###########
+//############################## CP & MV ################################
+//                             ###########
+
+static void _cp_ask_copy(mixed *filedata,int dummy, int flags);
+static void _cp_ask_overwrite(mixed *filedata, int mode, int flags);
+static void _mv_ask_overwrite(mixed *filedata, int mode, int flags);
+
+static mixed cp_file(mixed filedata,int move,int flags, mixed *do_delete)
+{
+  string source,dest;
+  source=(string)filedata[FULLNAME];
+  dest=(string)filedata[DESTNAME];
+  if (source==dest) return ERROR(SAME_FILE,source,RET_FAIL);
+  if (!MAY_READ(source)) return ERROR(NO_READ,source,RET_JUMP);
+  if (!MAY_WRITE(dest)) return ERROR(NO_WRITE,dest,RET_JUMP);
+  if (filedata[FILESIZE]==-1) return ERROR(DOESNT_EXIST,source,RET_JUMP);
+  if (filedata[FILESIZE]==-2) // Quelle ist Verzeichnis
+  {
+    switch(file_size(dest))
+    {
+      case -1:
+        if (move)
+        {
+          if (rename(source,dest)) return ERROR(NO_CREATE_DIR,dest,RET_JUMP);
+          if (flags&CP_V) printf(FILE_MOVED,source);
+          return RET_JUMP;
+        }
+        if (!mkdir(dest)) return ERROR(NO_CREATE_DIR,dest,RET_JUMP);
+        if (flags&CP_V) printf(DIR_CREATED,dest);
+      case -2:
+        if (!move) return RET_OK;
+        if (filedata[SUBDIRSIZE]>0) return RET_DELETE;
+        if (!rmdir(source)) return ERROR(NO_DELETE,source,RET_FAIL);
+        if (flags&MV_V) printf("mv: %s: Quellverzeichnis wurde "
+                               "geloescht.\n",source);
+        return RET_OK;    
+      default:  return ERROR(NO_DIRS,dest,RET_JUMP);
+    }
+  }
+  switch(file_size(dest))
+  {
+    case -2: return ERROR(DEST_IS_DIR,dest,RET_FAIL);
+    default:
+      if (flags&CP_F)
+      {
+        if (!rm(dest)) return ERROR(DEST_NO_DELETE,dest,RET_FAIL);
+        if (flags&CP_V) printf(FILE_DELETED,dest);
+      }
+      else
+      {
+        if (move) return #'_mv_ask_overwrite;
+        else return #'_cp_ask_overwrite;
+      }
+    case -1:
+      if (move)
+      {
+        if (rename(source,dest)) return ERROR(NO_MOVE,source,RET_FAIL);
+        if (flags&CP_V) printf(FILE_MOVED,source);
+        return RET_OK;
+      }
+      if (copy_file(source,dest)) return ERROR(NO_COPY,source,RET_FAIL);
+      if (flags&CP_V) printf(FILE_COPIED,source);
+      return RET_OK;
+  }
+  return 0; // not-reached
+}
+
+static void _cp_ask_overwrite2(string input, mixed *filedata,
+                               int interactive,int flags,int move)
+{
+  if (!sizeof(input)) input=" ";
+  input=lower_case(input);
+  switch(input[0])
+  {
+    case 'q':
+      printf("%s abgebrochen!\n",move?"Bewegen":"Kopieren");
+      return;
+    case 'a':
+      flags|=CP_F;
+      if (!(flags&CP_I))
+      {
+        asynchron(filedata,#'cp_file,move,flags,0);
+        return;
+      }
+    case 'y':
+    case 'j':
+      if (!rm(filedata[0][DESTNAME]))
+        printf(DEST_NO_DELETE "Uebergehe Datei...\n",filedata[0][DESTNAME]);
+      else
+      {
+        if (flags&CP_V) printf(FILE_DELETED,filedata[0][DESTNAME]);
+        if (move)
+        {
+          if (rename(filedata[0][FULLNAME],filedata[0][DESTNAME]))
+            printf(NO_MOVE "Uebergehe Datei...\n",filedata[0][FULLNAME]);
+        }
+        else
+        {
+          if (copy_file(filedata[0][FULLNAME],filedata[0][DESTNAME]))
+            printf(NO_COPY "Uebergehe Datei...\n",filedata[0][FULLNAME]);
+        }
+      }
+    case 'n':
+      if (flags&CP_I)
+        _cp_ask_copy(filedata[1+filedata[0][SUBDIRSIZE]..],move,flags);
+      else
+        asynchron(filedata[1+filedata[0][SUBDIRSIZE]..],
+                                     #'cp_file,move,flags,0);
+      return;
+    default:
+      printf("Kommando nicht verstanden.\n");
+      _cp_ask_overwrite(filedata,interactive,flags);
+      return;
+  }
+
+}
+
+static void _cp_ask_overwrite(mixed *filedata, int interactive, int flags)
+{
+  printf("Die Datei '%s' existiert schon.\n",
+         filedata[0][DESTNAME]);
+  input_to("_cp_ask_overwrite2",INPUT_PROMPT,"Ueberschreiben? (j,n,a,q): ",
+      filedata,interactive,flags,0);
+  return;
+}
+
+static void _mv_ask_overwrite(mixed *filedata, int interactive, int flags)
+{
+  printf("Die Datei '%s' existiert schon.",
+         filedata[0][DESTNAME]);
+  input_to("_cp_ask_overwrite2",INPUT_PROMPT,"Ueberschreiben? (j,n,a,q): ",
+      filedata,interactive,flags,1);
+  return;
+}
+
+static void _cp_ask_copy2(string input,mixed *filedata,int mode,
+                           int flags,int move)
+{
+  if (!sizeof(input)) input=" ";
+  input=lower_case(input);
+  switch(input[0])
+  {
+    case 'y':
+    case 'j':
+      if (mode==1)
+      {
+        if (!(flags&CP_F))
+        {
+          if (move) _mv_ask_overwrite(filedata,1,flags);
+          else      _cp_ask_overwrite(filedata,1,flags);
+          return;
+        }
+        if (!rm(filedata[0][DESTNAME]))
+        {
+          printf(DEST_NO_DELETE "Uebergehe Datei...\n",
+                 filedata[0][DESTNAME]);
+          _cp_ask_copy(filedata[1..],move,flags);
+          return;
+        }
+        if (flags&CP_V) printf(FILE_DELETED,filedata[0][DESTNAME]);
+      }
+      if (mode<2)
+      {
+        if (move) rename(filedata[0][FULLNAME],filedata[0][DESTNAME]);
+        else copy_file(filedata[0][FULLNAME],filedata[0][DESTNAME]);
+        _cp_ask_copy(filedata[1..],move,flags);
+        return;
+      }
+      if (mode==2)
+      {
+        if (move)
+        {
+          if (rename(filedata[0][FULLNAME],filedata[0][DESTNAME]))
+            printf(NO_MOVE "Uebergehe Verzeichnis...\n",
+                   filedata[0][FULLNAME]);
+          _cp_ask_copy(filedata[1+filedata[0][SUBDIRSIZE]..],move,flags);
+          return;
+        }
+        if (mkdir(filedata[0][DESTNAME]))
+        {
+          _cp_ask_copy(filedata[1..],0,flags);
+          return;
+        }
+        printf(NO_CREATE_DIR "Uebergehe Verzeichnis...\n",
+               filedata[0][DESTNAME]);
+      }
+    case 'n':
+      _cp_ask_copy(filedata[(1+filedata[0][SUBDIRSIZE])..],0,flags);
+      return;
+    case 'q':
+      printf("Kopieren abgebrochen!\n");
+      return;
+    case 'a':
+      flags&=~CP_I;
+      asynchron(filedata,#'cp_file,move,flags,0);
+      return;
+    default:
+      printf("Kommando nicht verstanden.\n");
+      _cp_ask_copy(filedata,0,flags);
+      return;
+  }
+}
+
+static void _cp_ask_copy(mixed *filedata,int move, int flags)
+{
+  mixed data;
+  string dest,source;
+  int delete_subs,jump;
+
+  if(!sizeof(filedata))
+  {
+    printf("%s: abgeschlossen.\n",move?"mv":"cp");
+    return; 
+  }
+  dest=filedata[0][DESTNAME];
+  source=filedata[0][FULLNAME];
+  switch(0)   // break wirkt damit wie ein goto end_of_switch
+  {
+    default:
+    case 0: // Sinnlos, aber er compiliert sonst nicht :(
+      jump=filedata[0][SUBDIRSIZE];
+      if (source==dest)
+      {
+        printf(SAME_FILE,source);
+        break;
+      }
+      if (!MAY_READ(source))
+      {
+        printf(NO_READ,source);
+        break;
+      }
+      if (!MAY_WRITE(dest))
+      {
+        printf(NO_WRITE,dest);
+        jump=0;
+        break;
+      }
+      if (filedata[0][FILESIZE]==-1)
+      {
+        printf(DOESNT_EXIST,source);
+        break;
+      }
+      if (filedata[0][FILESIZE]==-2) // Quelle ist Verzeichnis
+      {
+        if (file_size(dest)>-1)
+        {
+          printf(NO_DIRS,dest);
+          break;
+        }
+        if (file_size(dest)==-2)
+        {
+          jump=0;
+          break;
+        }
+        printf("Verzeichnis '%s' %s?\n",source,
+               move?"bewegen":"kopieren");
+        input_to("_cp_ask_copy2",INPUT_PROMPT, "(j,n,a,q) ",
+            filedata,2,flags,move);
+        return;
+      }
+      if (file_size(dest)==-2)
+      {
+        printf(DEST_IS_DIR,dest);
+        break;
+      }
+      printf("'%s' %s?\n",source,move?"bewegen":"kopieren");
+      input_to("_cp_ask_copy2",INPUT_PROMPT, "(j,n,a,q) ",
+          filedata,(file_size(dest)!=-1),flags,move);
+      return;
+  }
+  _cp_ask_copy(filedata[1+jump..],move,flags);
+  return;
+}
+
+
+static int _cp(string cmdline)
+{
+  mixed *args;
+  int flags;
+  string mask;
+  string dest,*dest2;
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,CP_OPTS,0);
+  if (flags==-1||!sizeof(args))
+    return USAGE(query_verb()+" [-" CP_OPTS
+                 "] <datei/verz> [<datei2/verz2> ... ] <ziel> [<maske>]");
+  if (flags&CP_M)
+  {
+    mask=args[<1];
+    args=args[0..<2];
+  }
+  if (!dest=to_filename(args[<1]))
+     return USAGE(query_verb()+" [-" CP_OPTS
+          "] <datei/verz> [<datei2/verz2> ... ] <ziel> [<maske>]");
+  if (file_size(dest)==-1)
+  {
+    dest2=explode(dest,"/");
+    if (file_size(implode(dest2[0..<2],"/"))==-2)
+    {
+      if (dest2[<1]=="*")
+        dest=implode(dest2[0..<2],"/");
+      else
+        if (member(dest2[<1],'*')>-1||
+            member(dest2[<1],'?')>-1)
+         return notify_fail(
+          sprintf("%s: Keine * und ? im Zielnamen erlaubt.\n",query_verb())),0;
+    }
+    else
+      return notify_fail(
+        sprintf("%s: Der angegebene Zielpfad existiert nicht.\n",
+                query_verb())),0;
+  }
+  args=args[0..<2];
+  if (file_size(dest)!=-2&&sizeof(args)>1)
+    return notify_fail(
+        sprintf("%s: Bei mehreren Quellen muss das Ziel ein Verzeichnis "
+                "sein.\n",query_verb())),0;
+  if (!sizeof(args=map(args,#'to_filename)-({0})))
+    return USAGE(query_verb()+" [-" CP_OPTS
+          "] <datei/verz> [<datei2/verz2> ... ] <ziel> [<maske>]");
+  // DEBUG("DEST: " + dest + " : FLAGS: " + flags);
+  args=file_list(args,MODE_CP,(flags&CP_R),dest+"/",mask);
+  if (!sizeof(args))
+    return notify_fail(sprintf("%s: Keine passenden Dateien gefunden.\n",
+                               query_verb())),0;
+
+  if (sizeof(args)>1&&(args[0][FILESIZE]>=0)&&file_size(dest)!=-2)
+      return notify_fail(
+        sprintf("%s: Bei mehreren Quellen muss das Ziel ein Verzeichnis "
+                "sein.\n",query_verb())),0;
+  if (sizeof(args)==1&&file_size(dest)!=-2)
+    args[0][DESTNAME]=dest;
+  if (!(flags&CP_I))
+  {
+    asynchron(args,#'cp_file,(query_verb()=="mv"),flags,0);
+    return 1;
+  }
+  if (query_verb()=="cp")
+    _cp_ask_copy(args,0,flags);
+  else
+    _cp_ask_copy(args,1,flags);
+  return 1;
+}
+
+//                              #########
+//############################### RMDIR #################################
+//                              #########
+
+
+//
+// _rmdir: Verzeichnis loeschen
+// cmdline: Kommandozeilenargumente
+//
+
+
+#if __VERSION__ < "3.2.9"
+
+private int _dir_filter(mixed arg)
+{
+  return (arg[FILESIZE]==-2);
+}
+
+#endif
+
+static int _rmdir(string cmdline)
+{
+  string dest,tmp;
+  int flags;
+  mixed *args;
+  
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,RMDIR_OPTS,1);
+  if (flags==-1||!sizeof(args))
+    return USAGE("rmdir [-" RMDIR_OPTS "] <Verzeichnis>");
+  if (sizeof(args)>1)
+    return
+    notify_fail("Mit 'rmdir' kann nur jeweils EIN Verzeichnis geloescht "
+         "werden.\nDer Befehl 'rm' bietet erweiterte Moeglichkeiten.\n"),0;
+  dest=args[0];
+  if (dest!="/")
+  {
+    args=file_list(({dest}),MODE_RMDIR,0,"/");
+#if __VERSION__ < "3.2.9"
+    args=filter(args,#'_dir_filter);
+#else
+    args=filter(args,(: ($1[FILESIZE]==-2) :));
+#endif
+    if (!sizeof(args))
+      return notify_fail(
+        sprintf("rmdir: %s: Kein solches Verzeichnis gefunden.\n",dest)),0;
+    if (sizeof(args)>1)
+      return notify_fail(
+                sprintf("rmdir: %s: Maske ist nicht eindeutig.\n",dest)),0;
+    dest=args[0][FULLNAME];
+    if (!MAY_WRITE(dest)) return ERROR(NO_WRITE,dest,1);
+    if (!rmdir(dest))
+    {
+      if (sizeof((get_dir(dest+"/*")||({}))-({".",".."})))
+        printf("rmdir: %s: Verzeichnis ist nicht leer.\n",dest);
+    }
+    else
+    {
+      if (flags&&RMDIR_V) printf(FILE_DELETED,dest);
+    }
+    return 1;
+  }
+  return ERROR(NO_DELETE,dest,1);
+}
+
+//                              #########
+//############################### MKDIR #################################
+//                              #########
+
+
+//
+// _mkdir: Verzeichnis erstellen
+// cmdline: Kommandozeilenargumente
+//
+
+static int _mkdir(string cmdline)
+{
+  string dest,tmp;
+  int flags,i;
+  string *args;
+  
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,MKDIR_OPTS,1);
+  if (flags==-1) return 0;
+  if (!sizeof(args))
+    return USAGE("mkdir [-" MKDIR_OPTS "] <Verzeichnis>");
+  if (sizeof(args)>1)
+    return notify_fail("Mit 'mkdir' kann nur jeweils EIN Verzeichnis "
+                       "erstellt werden.\n"),0;
+  dest=args[0];
+  
+  if ((i=file_size(implode((args=explode(dest,"/"))[0..<2],"/")))==FSIZE_DIR)
+  {
+    if (!mkdir(dest)) return ERROR(NO_CREATE_DIR,dest,1);
+    if (flags&MKDIR_V) printf(DIR_CREATED,dest,1);
+    printf("mkdir: abgeschlossen.\n");
+    return 1;
+  }
+  
+  if (i==FSIZE_NOFILE)
+  {
+    if (flags&MKDIR_R)
+    {
+      if (mkdirp(dest) != 1)
+        return ERROR(NO_CREATE_DIR,dest,1);
+      if (flags&MKDIR_V)
+        printf(DIR_CREATED,implode(args[0..i],"/"));
+      printf("mkdir: abgeschlossen.\n");
+      return 1;
+    }
+    return ERROR(DOESNT_EXIST,implode(args[0..<2],"/"),1);
+  }
+  return ERROR(ALREADY_EXISTS,dest,1);
+}
+
+//                               ######
+//################################ RM ###################################
+//                               ######
+
+private void _rm_ask_delete(mixed *filedata, int flags);
+
+static void _rm_ask_delete2(string input,mixed *filedata,int flags)
+{
+  int i;
+  if (!sizeof(input)) input=" ";
+  input=lower_case(input);
+  switch(input[0])
+  {
+    case 'q':
+      printf("Loeschen abgebrochen!\n");
+      return;
+    case 'y':
+    case 'j':
+      if (filedata[0][FILESIZE]==-2)
+      {
+        if (i=filedata[0][SUBDIRSIZE]) // Dir-Eintrag nach hinten schieben
+        {
+          mixed temp;
+          int j;
+          temp=filedata[0];
+          temp[SUBDIRSIZE]=0;
+          for(j=0;j<i;j++) filedata[j]=filedata[j+1];
+          filedata[j]=temp;
+          _rm_ask_delete(filedata,flags);
+          return;
+        }
+        if (!rmdir(filedata[0][FULLNAME]))
+          printf(NO_DELETE,filedata[0][FULLNAME]);
+        else if (flags&RM_V) printf(FILE_DELETED,filedata[0][FULLNAME]);
+      }
+      else // Datei existiert
+      {
+        if (!rm(filedata[0][FULLNAME]))
+          printf(DEST_NO_DELETE "Uebergehe Datei...\n",
+                 filedata[0][FULLNAME]);
+        else if (flags&RM_V) printf(FILE_DELETED,filedata[0][FULLNAME]);
+        
+      }
+    case 'n':
+      _rm_ask_delete(filedata[1+filedata[0][SUBDIRSIZE]..],flags);
+      return;
+    default:
+      printf("Kommando nicht verstanden.\n");
+      _rm_ask_delete(filedata,flags);
+      return;
+  }
+  return;
+}
+
+private void _rm_ask_delete(mixed *filedata, int flags)
+{
+  int i;
+  mixed temp;
+  if (!sizeof(filedata))
+  {
+    printf("rm: abgeschlossen.\n");
+    return;
+  }
+  switch(filedata[0][FILESIZE])
+  {
+    case -1:
+      if (flags&RM_V) printf(DOESNT_EXIST,filedata[0][FULLNAME]);
+      _rm_ask_delete(filedata[1..],flags);
+      return;
+    case -2:
+      if (i=filedata[0][SUBDIRSIZE])
+        printf("Ins Verzeichnis '%s' hinabsteigen?\n",
+          filedata[0][FULLNAME]);
+      else
+        printf("Verzeichnis '%s' loeschen?\n",
+               filedata[0][FULLNAME]);
+      input_to("_rm_ask_delete2",INPUT_PROMPT, "(j,n,q) ",
+          filedata,flags);
+      return;
+    default:
+      printf("'%s' loeschen? (j,n,q)\n",
+         filedata[0][FULLNAME]);
+      input_to("_rm_ask_delete2",INPUT_PROMPT, "(j,n,q) ",
+          filedata,flags);
+      return;
+  }
+}
+
+
+private void rm_file(mixed filedata, mixed notused, int flags)
+{
+  string dest;
+  dest=filedata[FULLNAME];
+  if (!MAY_WRITE(dest))
+  {
+    printf(NO_WRITE,dest);
+    return;
+  }
+  switch(filedata[FILESIZE])
+  {
+    case -1:
+      if (flags&RM_V) printf(DOESNT_EXIST,dest);
+      return;
+    case -2:
+      if (!rmdir(dest)) printf(DEST_NO_DELETE,dest);
+      else
+      {
+        if (flags&RM_V) printf(FILE_DELETED,dest);
+      }
+      return;
+    default:
+      if (!rm(dest)) printf(DEST_NO_DELETE,dest);
+      else
+      {
+        if (flags&RM_V) printf(FILE_DELETED,dest);
+      }
+      return;
+  }
+}
+
+static int _rm(string cmdline)
+{
+  mixed *args,*args2;
+  int flags,i;
+  string mask;
+  
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,RM_OPTS,0);
+  if (flags==-1||!sizeof(args))
+    return USAGE("rm [-" RM_OPTS
+                 "] <datei/verz> [<datei2/verz2> ... ] [<maske>]");
+  if (flags&RM_M)
+  {
+    mask=args[<1];
+    args=args[0..<2];
+  }
+  args=map(args,#'to_filename)-({0});
+  args=file_list(args,MODE_RM,(flags&RM_R),"/",mask);
+  if (!(i=sizeof(args)))
+    return printf("Keine passende Datei gefunden.\n"),1;
+  if (!(flags&RM_I))
+  {
+    if (i>1) // Umdrehen
+    {
+      mixed temp;
+      i>>=1;
+      while(i)
+      {
+        temp=args[<(i--)];
+        args[<(i+1)]=args[i];
+        args[i]=temp;
+      }
+    }
+    asynchron(args,#'rm_file,args,flags,0);
+    return 1;
+  }
+  _rm_ask_delete(args,flags);
+  return 1;
+}
diff --git a/std/shells/magier/fileview.c b/std/shells/magier/fileview.c
new file mode 100644
index 0000000..731de5a
--- /dev/null
+++ b/std/shells/magier/fileview.c
@@ -0,0 +1,728 @@
+// MorgenGrauen MUDlib
+//
+// fileview.c
+//
+// $Id: fileview.c 9142 2015-02-04 22:17:29Z Zesstra $
+#pragma strict_types
+#pragma save_types
+//#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <ansi.h>
+#include <player/base.h>
+#include <wizlevels.h>
+#include <shells.h>
+#include <daemon/mand.h>
+#include <udp.h>
+#define NEED_PROTOTYPES
+#include <magier.h>
+#include <thing/properties.h>
+#include <player.h>
+
+private nosave mapping colorstrings;
+private nosave mapping oldman_result;
+
+//                        ###################
+//######################### INITIALISIERUNG #############################
+//                        ###################
+
+mixed _query_localcmds()
+{
+  return ({({"ls","_ls",0,LEARNER_LVL}),
+           ({"more","_more",0,LEARNER_LVL}),
+           ({"cat","_cat",0,LEARNER_LVL}),
+           ({"head","_cat",0,LEARNER_LVL}),
+           ({"tail","_cat",0,LEARNER_LVL}),
+           ({"man","_man",0,LEARNER_LVL}),
+           ({"rman","_rman",0,LEARNER_LVL}),
+           ({"showprops","_showprops",0,WIZARD_LVL}),
+           ({"grep","_grep",0,LEARNER_LVL})});
+}
+
+
+//                               ######
+//################################ LS ###################################
+//                               ######
+
+//
+// _ls: Der ls-Befehl: Verzeichnisse und Dateien anzeigen
+// cmdline: Kommandozeile
+//
+
+//
+// Funktionen zum Sortieren und fuer filter_ldfied/map_ldfied
+//
+
+
+private string _get_color(string color)
+{
+  return COLORS[lower_case(color)];
+}
+
+
+private void SetColorstrings()
+{
+  string tmp,term;
+  mapping vars;
+  vars=QueryProp(P_VARIABLES);
+  colorstrings=m_allocate(0,2);
+  switch(term=QueryProp(P_TTY))
+  {
+    case "vt100":
+    case "ansi":
+      if(stringp(vars["LS_DIR"]))
+        tmp=implode(map(explode(vars["LS_DIR"],"+"),#'_get_color),
+                    "");
+      else
+        tmp = (term == "ansi") ? ANSI_BLUE+ANSI_BOLD: ANSI_BOLD;
+      colorstrings[DIR] = tmp+"%s"+(term == "vt100"?"/":"")+ANSI_NORMAL;
+      if(term == "vt100") colorstrings[DIR, 1] = 1;
+      if(stringp(vars["LS_OBJ"]))
+        tmp=implode(map(explode(vars["LS_OBJ"],"+"),#'_get_color),
+                    "");
+      else
+        tmp = (term == "ansi") ? ANSI_RED : ANSI_INVERS;
+      colorstrings[OBJ] = tmp+"%s"+ANSI_NORMAL;
+      if(stringp(vars["LS_VC"]))
+        tmp=implode(map(explode(vars["LS_VC"],"+"),#'_get_color),
+                    "");
+      else
+        tmp = (term == "ansi") ? ANSI_PURPLE : ANSI_INVERS;
+      colorstrings[VC] = tmp+"%s"+ANSI_NORMAL;
+      break;
+    case "dumb":
+      colorstrings[DIR] = "%s/"; colorstrings[DIR, 1] = 1;
+      colorstrings[OBJ] = "%s*"; colorstrings[OBJ, 1] = 1;
+      colorstrings[VC]  = "%s*"; colorstrings[VC , 1] = 1;
+      break;
+    default:
+      colorstrings[DIR] = "%s";
+      colorstrings[OBJ] = "%s";
+      colorstrings[VC]  = "%s";
+  }
+  return;
+}
+
+
+private string _ls_output_short(mixed filedata,
+                                int maxlen,int counter,int maxcount)
+{
+  string tmp;
+  tmp=filedata[BASENAME];
+  maxlen-=sizeof(tmp);
+  switch(filedata[FILESIZE])
+  {
+    case -2: tmp=sprintf(colorstrings[DIR],tmp);
+             maxlen-=colorstrings[DIR,1]; break;
+    case -1: tmp=sprintf(colorstrings[VC],tmp);
+             maxlen-=colorstrings[VC,1]; break;
+    default: if (find_object(filedata[FULLNAME]))
+             {
+               maxlen-=colorstrings[OBJ,1];
+               tmp=sprintf(colorstrings[OBJ],tmp); break;
+             }
+  }
+  if (!maxcount) return tmp+"\n";
+  return sprintf("%-*s%s",(maxlen+sizeof(tmp)),tmp,
+	((counter++)==maxcount?(counter=0,"\n"):"  "));
+}
+
+private int _ls_maxlen(mixed filedata,int flags,int maxlen)
+{
+  string base;
+  int size;
+  base=filedata[BASENAME];
+  if (!(flags&LS_A)&&(base[0]=='.')) return 0;
+#if __VERSION__ < "3.2.9"
+  if (sizeof(base)>maxlen) maxlen=sizeof(base);
+#else
+  maxlen=max(maxlen,sizeof(base));
+#endif
+  return 1;
+}
+
+private string _ls_output_long(mixed filedata, int flags,closure valid_read,
+                               closure valid_write,closure creator_file)
+{
+  string *tmp,full,base,path,date,creator,group;
+  int size,dir,ftime;
+  object ob;
+  
+  base=filedata[BASENAME];
+  if (!(sizeof(base))||((!(flags&LS_A))&&(base[0]=='.')))
+    return 0;
+  size=filedata[FILESIZE];
+  path=filedata[PATHNAME];
+  tmp=(string *)call_other(master(),"full_path_array",
+                 filedata[FULLNAME],getuid());
+  full=sprintf("/%s",implode(tmp,"/"));
+  dir=(size==-2);
+  ob=find_object(full);
+  ftime=filedata[FILEDATE];
+  date=dtime(ftime);
+  date=sprintf("%s %s %s",date[9..11],date[5..6],
+               ((time()-ftime)<31536000?date[19..23]:(" "+date[13..16])));
+  creator="";
+  group="";
+  if (flags&LS_U)
+  {
+    creator=(string)call_other(master(),"creator_file",full);
+    switch(creator)
+    {
+      case ROOTID: creator="root"; break;
+      case BACKBONEID: creator="daemon"; break;
+      default: if(!creator) creator="none"; break;
+    }
+  }
+  if (flags&LS_G)
+  {
+    if (sizeof(tmp))
+    {
+      switch(tmp[0])
+      {
+      case WIZARDDIR: group="magier"; break;
+      case "news": group="news"; break;
+      case "mail": group="mail"; break;
+      case "open": group="public"; break;
+      case "p": group="project"; break;
+      case DOMAINDIR: if (sizeof(tmp)>1) { group=tmp[1]; break; }
+      default: group="mud"; break;
+      }
+    }
+    else group="mud";
+  }
+  if (dir) base=sprintf(colorstrings[DIR],base);
+  else
+  {
+    if (ob)
+    {
+      if (size==-1)
+        base=sprintf(colorstrings[VC],base);
+      else
+        base=sprintf(colorstrings[OBJ],base);
+    }
+  }
+  return sprintf(("%c%c%c%c %3d"+((flags&LS_U)?" %-24.24s":"%-0.1s")+
+                 ((flags&LS_G)?" %-8.8s":"%0.1s")+" %8s %s %s\n"),
+                 (dir?'d':'-'),
+                 (!funcall(valid_read,full,getuid(),
+                           "read_file",this_object())?'-':'r'),
+                 (!funcall(valid_write,full,getuid(),
+                           "write_file",this_object())?'-':'w'),
+                 (ob?'x':'-'),
+                 (dir?(sizeof((get_dir(full+"/*")||({}))-({".",".."}))):0),
+                 creator,group,(dir?"-":size==-1?"<vc>":to_string(size)),
+                                    date,base);
+}
+
+
+static int _ls(string cmdline)
+{
+  int flags,cmp,i,arg_size,size;
+  int maxlen,counter,maxcount;
+  string *args,output;
+  mixed *tmp;
+  closure output_fun,v_read,v_write,creator,sort_fun;
+  
+  cmdline=_unparsed_args()||"";
+  args=parseargs(cmdline,&flags,LS_OPTS,1);
+  if (flags==-1)
+    return USAGE("ls [-" LS_OPTS "] [<Verzeichnis>] [<Verzeichnis2> ..]");
+  SetColorstrings();
+  output="";
+  if (!sizeof(args)) args=({ QueryProp(P_CURRENTDIR) });
+  if (!sizeof(args=file_list(args,MODE_LSA,0,"/")))
+    return notify_fail("ls: Keine passenden Verzeichnisse gefunden.\n"), 0;
+// Files sortieren die erste
+  if (flags&LS_T) cmp=FILEDATE;
+  else if (flags&LS_S) cmp=FILESIZE;
+  else cmp=BASENAME; // =0 :-)
+  sort_fun=lambda(({ 'a,'b }),({
+    ((!cmp&&!(flags&LS_R))||(cmp&&(flags&LS_R))?#'>:#'<),
+    ({#'[,'a,cmp}),({#'[,'b,cmp})}));
+  args=sort_array(args,sort_fun);
+// Ausgabeformat bestimmen
+  if (flags&LS_L)
+  {
+    v_read=VALID_READ_CL;
+    v_write=VALID_WRITE_CL;
+    creator=CREATOR_CL;
+  }
+  arg_size=sizeof(args);
+  if (arg_size>1||(arg_size&&args[0][FILESIZE]>=0))
+  {
+    if (flags&LS_L)
+      tmp=map(args,#'_ls_output_long,flags,v_read,
+                    v_write,creator)-({0});
+    else
+    {
+      counter=0;maxlen=0;
+      tmp=filter(args,#'_ls_maxlen,flags,&maxlen);
+      if (maxlen>76) maxlen=76;
+      maxcount=(78/(maxlen+2))-1;
+      tmp=map(tmp,#'_ls_output_short,maxlen,&counter,maxcount);
+    }
+    output=sprintf("\n%d Dateien/Unterverzeichnisse:\n%s\n",
+                   sizeof(tmp),implode(tmp,""));
+  }
+  for(i=0;i<arg_size;i++)
+  {
+    tmp=({});
+    size=args[i][FILESIZE];
+    if (size==-2)
+    {
+      tmp=file_list(({args[i][FULLNAME]+"/*"}),MODE_LSB,0,"/");
+      tmp=sort_array(tmp,sort_fun);
+      if (flags&LS_L)
+        tmp=map(tmp,#'_ls_output_long,flags,v_read,
+                      v_write,creator)-({0});
+      else
+      {
+        counter=0;maxlen=0;
+        tmp=filter(tmp,#'_ls_maxlen,flags,&maxlen);
+        maxcount=(78/(maxlen+2));
+        if (maxcount) maxcount--;
+        tmp=map(tmp,#'_ls_output_short,maxlen,&counter,maxcount);
+      }
+      if (sizeof(tmp))
+      {
+        output+=sprintf("\n%s: Verzeichnis, %d Dateien/Unterverzeichnisse:\n",
+                      args[i][FULLNAME],sizeof(tmp));
+        output+=(implode(tmp,"")+((string)(tmp[<1][<1..<1])=="\n"?"":"\n"));
+      }
+      else
+      {
+        output+=sprintf("\n%s: Leeres Verzeichnis.\n",args[i][FULLNAME]);
+      }
+    }
+  }
+  More(output);
+  return 1;
+}
+
+//                              ########
+//############################### MORE ###################################
+//                              ########
+//
+// _more_file: Mehrere Files hintereinander ausgeben
+//
+
+private void _more_file(string *arg)
+{
+  if (!sizeof(arg)) return;
+  printf("more: Naechste Datei: %s\n",arg[0]);
+  More(arg[0],1,#'_more_file,({ arg[1..]}));
+  return;
+}
+
+
+private mixed _size_filter(mixed *arg)
+{
+  if (arg[FILESIZE]>0) return arg[FULLNAME];
+  if (arg[FILESIZE]==0)
+  {
+    printf("%s: %s: Leere Datei.\n",query_verb()||"more",arg[FULLNAME]);
+    return 0;
+  }
+  if (arg[FILESIZE]==-2)
+    printf("%s: %s ist ein Verzeichnis.\n",query_verb()||"more",arg[FULLNAME]);
+  else
+    printf("%s: %s: Datei existiert nicht.\n", query_verb()||"more",
+           arg[FULLNAME]);
+  return 0;
+}
+
+
+//
+// _more: Dateien anzeigen
+// cmdline: Kommandozeile
+//
+
+static int _more(string cmdline)
+{
+  mixed *args;
+  int flags;
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,"",1);
+  if (flags==-1||!sizeof(args)) return USAGE("more <datei> [<datei2>..]");
+  args=file_list(args,MODE_MORE,0,"/");
+  if (!sizeof(args))
+    return printf("more: %s: Keine passende Datei gefunden.\n",cmdline),1;
+  args=map(args,#'_size_filter)-({0});
+  if (sizeof(args)) _more_file(args);
+  return 1;
+}
+
+//                         ###################
+//########################## HEAD, TAIL, CAT #############################
+//                         ###################
+
+static int _cat(string cmdline)
+{
+  mixed *args;
+  int flags;
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,"",1);
+  if(flags==-1||!sizeof(args))
+    return USAGE(query_verb()+" <dateiname> [<datei2>..]");
+  args=file_list(args,MODE_CAT,0,"/");
+  if (!sizeof(args))
+    return printf("%s: %s: Keine passende Datei gefunden.\n",query_verb(),
+                cmdline),1;
+  args=map(args,#'_size_filter)-({0});
+  if (!sizeof(args)) return 1;
+  while(sizeof(args))
+  {
+    switch(query_verb())
+    {
+      case "cat":
+        if (!cat(args[0]))
+          printf("cat: %s konnte nicht angezeigt werden.\n",args[0]);
+        break;
+      case "head":
+        if (!cat(args[0],0,10))
+          printf("head: %s konnte nicht angezeigt werden.\n",args[0]);
+        break;
+      case "tail": tail(args[0]); break;
+    }
+    args=args[1..];
+  }
+  return 1;
+}
+
+//                              #######
+//############################### MAN ###################################
+//                              #######
+
+static int _man(string cmdline)
+{
+  mixed *args;
+  int i, flags;
+  string *tmp, *tmp2;
+
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,MAN_OPTS,0);
+  
+  if (flags==-1 ||
+      (sizeof(args)!=1 &&
+       (sizeof(args)<2 || sizeof(args[1])>1 || !(i=to_int(args[1])))))
+    return USAGE("man [-" MAN_OPTS "] <hilfeseite>");
+  tmp=explode(args[0],"/");
+
+  if (oldman_result && sizeof(tmp)==1 && sizeof(args)==1 &&
+      sizeof(tmp[0])==1 && (i=to_int(tmp[0])) && member(oldman_result,i)) {
+   tmp=({oldman_result[i,0],oldman_result[i,1]});
+   i=0;
+  }
+  else if (!(flags&(MAN_M|MAN_R))&&sizeof(tmp)>1)
+  {
+    if (file_size(MAND_DOCDIR+args[0])>=0)
+      tmp=({tmp[<1],args[0]});
+    else
+      tmp=({});
+  }
+  else
+  {
+    if (flags&MAN_R)
+    {
+      flags&=(~MAN_M);
+      if (catch(regexp(({""}),args[0]))||
+          !regexp(({""}),args[0]))
+        return printf("man: Ungueltiger Ausdruck in Maske.\n"),1;
+    }
+    tmp=(string *)call_other(MAND,"locate",args[0],flags&(MAN_M|MAN_R));
+  }
+
+  oldman_result=(mapping)0;
+  if(i && sizeof(tmp)>2 && sizeof(tmp)>=(i<<1))
+    tmp=tmp[((i<<1)-2)..((i<<1)-1)];
+  switch(sizeof(tmp))
+  {
+    case 0:
+      printf("Keine Hilfeseite gefunden fuer '%s'.\n",args[0]);
+      break;
+    case 2:
+       /*
+         if (flags&MAN_I)
+         {
+         // BRANCH TO MANUALD
+         return 1;
+         }
+       */
+      printf("Folgende Hilfeseite wurde gefunden: %s\n",tmp[1]);
+      More(MAND_DOCDIR+tmp[1],1);
+      return 1;
+    default:
+      i=sizeof(tmp)>>1;
+      tmp2=allocate(i);
+      oldman_result=m_allocate(i,2);
+      while(i)
+      {
+        tmp2[(i-1)]=sprintf("%d: ",i)+tmp[(i<<1)-2];
+	oldman_result[i,0]=tmp[(i<<1)-2];
+	oldman_result[i,1]=tmp[(i<<1)-1];
+        i--;
+      }
+      printf("Es wurden folgende potentiell passenden Seiten gefunden:\n"
+             "%'-'78.78s\n%s%'-'78.78s\n","",
+             break_string(implode(tmp2," "),78),"");
+      break;
+  }
+  return 1;
+}
+
+//                              ########
+//############################### RMAN ##################################
+//                              ########
+
+static int _rman(string str)
+{
+  int flags;
+  string *args;
+  
+  str=_unparsed_args();
+  args=parseargs(str,&flags,"",0);
+  if (flags==-1||sizeof(args)!=2)
+    return USAGE("rman <hilfeseite> <mudname>");
+  write("man: " +
+        (string)call_other(UDP_CMD_DIR+"man","send_request",args[1],args[0]));
+  return 1;
+}
+
+
+//                            #############
+//############################# SHOWPROPS ###############################
+//                            #############
+
+//
+// _showprops: Zeigt Properties zu einem Objekt an
+//
+
+static int _showprops(string str)
+{
+   int i;
+   string *list, ausgabe;
+
+   if (str) {
+      if (str[0]!='/') str="/"+str;
+      if (str[0..4]!="/std/")
+      {
+         printf("showprops: Es koennen nur Properties von Objekten "
+                "aus /std/ angezeigt werden.\n");
+         return 1;
+      }
+      if (str[<1]=='.') str+="c";
+      if (str[<2..<1]!=".c") str+=".c";
+      if (file_size(str)<0)
+      {
+        printf("showprops: %s: Es gibt kein Objekt diesen Namens.\n",str[0..<3]);
+        return 1;
+      }
+      if (catch(call_other(str[0..<3], "???")))
+      {
+        printf("showprops: %s: Datei konnte nicht geladen werden.\n",str);
+        return 1;
+      }
+   }
+   if (!str || !find_object(str)) {
+      notify_fail("Welche Properties moechtest Du sehen?"
+                  " Bsp.: <showprops /std/npc>\n");
+      return 0;
+   }
+   list=inherit_list(find_object(str));
+#if __VERSION__ < "3.2.9"
+   list=map(list,lambda(({'x}),({#'extract,'x,4,-2})));
+   list+=map(list,lambda(({'x}),({#'[<,({#'old_explode,'x,"/"}),1})));
+   list=map(m_indices(mkmapping(list)),lambda(({'x}),({#'+,({#'+,"/sys/",'x}),"h"})));
+   list=filter(list,lambda(({'x}),({#'>,({#'file_size,'x}),0})) );
+#else
+   list=map(list,(: return $1[5..<2]+"h"; :));
+   list+=map(list,(: return explode($1,"/")[<1]; :));
+   list=map(m_indices(mkmapping(list)),(: return "/sys/"+$1; :));
+   list=filter(list,(: return file_size($1)>0; :));
+#endif
+   list=sort_array(list, #'<);
+   ausgabe="";
+   for (i=sizeof(list);i--;)
+   {
+#if __VERSION__ < "3.2.9"
+     str=implode(filter(old_explode(read_file(list[i]), "\n"),
+        lambda( ({ 'x }), ({#'==, ({#'extract, 'x, 0, 9}), "#define P_"}) ))
+                 , "\n");
+#else
+     str=implode(filter(explode(read_file(list[i]),"\n"),
+                              (: return $1[0..9]=="#define P_";:)),"\n");
+#endif
+     if (str!="") ausgabe+=sprintf("%s\n%s\n\n", list[i], str);
+   }
+   if (ausgabe!="")
+     More(ausgabe);
+   else
+     printf("Keine Property-Definitionen zu diesem Objekt gefunden!\n");
+   return 1;
+}
+
+//                              ########
+//############################### GREP ###################################
+//                              ########
+
+#if __VERSION__ < "3.2.9"
+
+private int _grep_filter(string filename)
+{
+  return (call_other("valid_write",filename,getuid(this_object()),
+                      "write_file",this_object())!=0);
+}
+
+#endif
+
+//
+// grep_file: Datei greppen
+// rexpr: Regular Expression
+// flags: Flags
+//
+
+private int grep_file(mixed filedata, string rexpr, int flags)
+{
+  string fullname,data,carry,*lines,*lines_orig,*tmp,*result;
+  int ptr,count,i,nol,match,index;
+  fullname=filedata[FULLNAME];
+  if ((flags&GREP_F)&&fullname=="/players/"+getuid()+"/grep.out")
+  {	 
+	write_file("/players/"+getuid()+"/grep.out",
+                   "Uebergehe grep.out ...\n");
+	return RET_FAIL;
+  }
+  switch(filedata[FILESIZE])
+  {
+    case -2: return RET_FAIL;
+    case -1: return ERROR(DOESNT_EXIST,fullname,RET_FAIL);
+    case 0:  return RET_FAIL;
+    default: break;
+  }
+  if (!MAY_READ(fullname)) return ERROR(NO_READ,fullname,RET_FAIL);
+  carry=""; result=({});
+  if (flags&GREP_I)
+    rexpr=lower_case(rexpr);
+  do
+  {
+    data=read_bytes(fullname,ptr,MAXLEN)||"";
+    ptr+=MAXLEN;
+    lines=explode(carry+data,"\n");
+    switch(sizeof(lines))
+    {
+      case 0: continue;
+      case 1:
+        carry="";
+        break;
+      default:
+        carry=lines[<1];
+        lines=lines[0..<2];
+        break;
+    }
+    lines_orig=lines;
+    if (flags&GREP_I)
+      lines=map(lines,#'lower_case);
+    nol=sizeof(lines);
+    for (i=0;i<nol;i++)
+    {
+      match=sizeof(regexp(lines[i..i],rexpr));
+      if (flags&GREP_V) match=!match;
+      if (match)
+      {
+        if (!(flags&GREP_C))
+        {
+          if (flags&GREP_N)
+            result+=({ sprintf("%4d %s",index+i+1,lines_orig[i])});
+          else
+            result+=lines_orig[i..i];
+        }
+        count++;
+      }
+    }
+    index+=nol;
+  }
+  while(sizeof(data)==MAXLEN);
+  if (carry!="")
+  {
+    if (flags&GREP_I) carry=lower_case(carry);
+    match=sizeof(regexp(({ carry }),rexpr));
+    if (flags&GREP_V) match=!match;
+    if (match)
+    {
+      if(!(flags&GREP_C))
+      {
+        if(flags&GREP_N)
+           result+=({ sprintf("%4d %s",index+1,carry) });
+        else
+           result+=({carry});
+      }
+      count++;
+    }
+  }
+  carry="";
+  if (count)
+  {
+    if (flags&GREP_L) carry=sprintf("%s\n",fullname);
+    else if (flags&GREP_H) data="";
+    else data=sprintf(" %s:",fullname);
+    if (flags&GREP_C) carry=sprintf("%s %d passende Zeile%s.\n",data,count,
+                             (count==1?"":"n"));
+    else
+      carry=(data+"\n"+implode(result,"\n")+"\n");
+  }
+  if (flags&GREP_F)
+    return write_file("/players/"+getuid()+"/grep.out",carry);
+  write(carry);
+  return RET_OK;
+}
+
+static int _grep(string cmdline)
+{
+  string rexpr,mask;
+  mixed *args;
+  int flags;
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,GREP_OPTS,0);
+  if ((flags==-1)||!sizeof(args))
+    return USAGE("grep [-" GREP_OPTS
+          "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
+  rexpr=args[0];
+  if (catch(regexp(({""}),rexpr))||!regexp(({""}),rexpr))
+    return printf("grep: Ungueltiger Suchausdruck: %s\n",rexpr) ,1;
+  args=args[1..];
+  if (flags&GREP_M)
+  {
+    mask=args[<1];
+    args=args[0..<2];
+  }
+  if (!sizeof(args))
+      return USAGE("grep [-" GREP_OPTS
+          "] <regexp> <datei/verz> [<datei2> ... ] [<maske>]");
+  args=map(args,#'to_filename)-({0});
+  /*
+#if __VERSION__ < "3.2.9"
+  args=filter(args,#'_grep_filter);
+#else
+  args=filter(args,(: return (valid_write($1,
+            getuid(this_object()),"write_file",this_object())!=0):));
+#endif
+  */
+  args=file_list(args,MODE_GREP,(flags&GREP_R?1:0),"/",mask);
+  if (!sizeof(args))
+    return printf("Keine passenden Dateien gefunden.\n"),1;
+  if (flags&GREP_I) rexpr=lower_case(rexpr);
+  if (flags&GREP_F)
+  {
+    if (file_size("/players/"+getuid()+"/grep.out")==-2||
+	  !MAY_WRITE("/players/"+getuid()+"/grep.out"))
+      return printf("grep: Datei /players/%s/grep.out kann nicht "
+		      "geschrieben werden.\n",getuid()),1;
+    else
+      write_file("/players/"+getuid()+"/grep.out",
+                 "Ausgabe von \"grep " + _unparsed_args() + "\":\n"); 
+  }
+  asynchron(args,#'grep_file,rexpr,flags,0);
+  return 1;
+}
diff --git a/std/shells/magier/magier_ext.c b/std/shells/magier/magier_ext.c
new file mode 100644
index 0000000..a5d30b2
--- /dev/null
+++ b/std/shells/magier/magier_ext.c
@@ -0,0 +1,733 @@
+// $Id: magier_ext.c 9555 2016-05-03 20:42:46Z Zesstra $
+#pragma strict_types
+#pragma save_types
+//#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <wizlevels.h>
+#include <logging.h>
+#include <magier.h>
+#include <snooping.h>
+#include <driver_info.h>
+#define NEED_PROTOTYPES
+#include <player/telnetneg.h>
+#include <player/base.h>
+#undef NEED_PROTOTYPES
+#include <properties.h>
+#include <files.h>
+#include <events.h>
+#include <player/comm.h>
+
+inherit "/std/shells/magier/parsing";
+inherit "/std/shells/magier/upd";
+inherit "/std/shells/magier/fileview";
+inherit "/std/shells/magier/objects";
+inherit "/std/shells/magier/fileedit";
+//inherit "/std/shells/magier/todo";
+inherit "/std/shells/magier/players";
+inherit "/std/shells/magier/admin";
+inherit "/std/shells/magier/moving";
+inherit "/std/shells/magier/comm";
+
+
+//                              #######
+//############################### SET #################################
+//                              #######
+
+
+//
+// _set(): Shell-Befehl 'set'
+// args:   Kommandozeilenargumente
+//
+
+static int _set(mixed args)
+{
+  int pos;
+  string var;
+  mixed val;
+  mapping vars;
+
+  if(!args=_unparsed_args())
+  {
+    if(!sizeof(vars=QueryProp(P_VARIABLES))) 
+      printf("Du hast noch keine Variablen definiert!\n");
+    else
+    {
+      printf("Du hast die folgenden Variablen definiert:\n");
+      walk_mapping(vars,((: printf(" %-20s = %s\n",$1,
+                                 pointerp($2)?implode($2,":"):$2) :)));
+
+    }
+    return 1;
+  }
+  pos = member(args,' ');
+  if(pos == -1)
+    if(sizeof(args))
+      {
+        m_delete(QueryProp(P_VARIABLES), args);
+        printf("Variable %s wurde geloescht.\n",args);
+        return 1;
+      }
+    else return USAGE("set <variable> <wert>");
+  var = args[0..pos-1];
+  val = (member(args[pos+1..],':')>-1?
+         explode(args[pos+1..], ":") :
+         args[pos+1..]);
+  vars=QueryProp(P_VARIABLES);
+  vars+= ([var : val]);
+  printf("Variable gesetzt: %s = %s\n",var,args[pos+1..]);
+  return 1;
+}
+
+//                            ############
+//############################# CD + PWD ###################################
+//                            ############
+
+static int _pwd()
+{
+  printf("Aktuelles Verzeichnis: %s\n",QueryProp(P_CURRENTDIR));
+  return 1;
+}
+
+static int _cd2(string cmdline)
+{
+  string dest,tmp;
+  int flags;
+  mixed *args;
+  
+  args=parseargs(cmdline,&flags,CD_OPTS,1);
+  if (flags==-1) return 0;
+  if(flags&CD_B)
+  {
+    dest=QueryProp(P_LASTDIR);
+  }
+  if (sizeof(args)>1)
+    return notify_fail("Man kann sich (leider) nur in einem "
+                       "Verzeichnis gleichzeitig befinden.\n"),0;
+  if(!dest)
+  {
+    if (!sizeof(args))
+    {
+      if (IS_WIZARD(this_object()))
+        dest="/players/"+getuid(this_object());
+      else
+        dest="/doc";
+    }
+    else
+    {
+      dest=args[0];
+    }
+  }
+  
+  if (dest!="/")
+  {
+    args=file_list(({dest}),MODE_CD,0,"/");
+    args = filter(args, function int (mixed arr)
+        { return arr[FILESIZE] == FSIZE_DIR; } );
+
+    if (!sizeof(args))
+      return notify_fail("cd: "+dest+
+                       ": Kein solches Verzeichnis gefunden.\n"),0;
+    if (sizeof(args)>1)
+      return notify_fail("cd: "+dest+": Maske ist nicht eindeutig.\n"),0;
+    dest=args[0][FULLNAME];
+  }
+  if (!IS_WIZARD(this_object())&&dest[0..3]!="/doc") dest="/doc";
+  SetProp(P_LASTDIR,QueryProp(P_CURRENTDIR));
+  printf("Aktuelles Verzeichnis ist jetzt: %s\n",SetProp(P_CURRENTDIR,dest));
+  tmp="";
+  if (((flags&CD_L)||
+       ((!m_contains(&tmp,QueryProp(P_VARIABLES),"CD_SHORT")||
+         tmp!="1")&&(!(flags&CD_S)))))
+    tell_object(this_object(),
+                read_file(dest+(dest[<1]=='/'?".readme":"/.readme"))||"");
+  return 1;
+}
+
+static int _cd(string cmdline)
+{
+  return _cd2(_unparsed_args());
+}
+
+static string _set_currentdir(string path)
+{
+  Set(P_CURRENTDIR, path);
+  this_object()->modify_prompt();  // Prompt mit neuem Pfad setzen, telnetneg
+  return path;
+}
+
+private string _query_currentdir()
+{
+  string c;
+  if(!c=Query(P_CURRENTDIR))
+    return Set(P_CURRENTDIR, "/players/"+getuid(this_object()),F_VALUE);
+  return c;
+}
+
+//                           ##########
+//############################ PROMPT #################################
+//                           ##########
+
+//
+// _prompt_subst: Mudnamen, Usernamen, Zeilenvorschub in Eingabeauf-
+//                forderung einbauen
+// str:           Uebergebener Kommandozeilenabschnitt
+//
+
+private string _prompt_subst(string str)
+{
+  switch(str)
+  {
+    case "\\h": return sizeof(MUDNAME)?MUDNAME:"Mud ohne Namen";
+    case "\\u": return capitalize(getuid(this_object()));
+    case "\\n": return "\n";
+    case "\\t": return "\t";
+    case "\\w": return "\w";
+  }
+  return str;
+}
+
+
+//
+// _prompt: Eingabeaufforderung setzen
+// arg:     Kommandozeile
+//
+
+static int _prompt(string args)
+{
+  string *pargs;
+
+  args=(extern_call()?_unparsed_args():args);
+  if (!sizeof(args)) args="> ";
+  if (args[0]=='"') args=args[1..<2];     //");
+  if(!sizeof(pargs = regexplode(args, "\\\\[thuwn]")))
+    return USAGE("prompt \"<Eingabeaufforderungsdefinition>\"");
+  pargs=map(pargs,#'_prompt_subst);
+
+  SetProp(P_PROMPT,implode(pargs,""));
+  return 1;
+}
+
+static string _set_prompt(string prompt) {
+  Set(P_PROMPT, prompt, F_VALUE);
+  this_object()->modify_prompt(); // neuen Prompt setzen (telnetneg.c)
+  return prompt;
+}
+
+
+//                           ##############
+//############################ SHOWPRESAY ###############################
+//                           ##############
+
+static int _showpresay(string cmdline)
+{
+  int presay;
+  presay=QueryProp(P_CAN_FLAGS)&CAN_PRESAY;
+  cmdline=_unparsed_args(0);
+  if (!sizeof(cmdline))
+  {
+    printf("Dein Presay wird im Moment %sangezeigt.\n"
+           "%sschalten mit \'showpresay %s\'.\n",
+           presay?"":"nicht ",presay?"Aus":"Ein",
+           presay?"aus":"ein");
+    return 1;
+  }
+  if (cmdline=="ein"||cmdline=="an")
+  {
+    printf("Dein Presay wird jetzt angezeigt.\n");
+    SetProp(P_CAN_FLAGS,QueryProp(P_CAN_FLAGS)|CAN_PRESAY);
+    return 1;
+  }
+  if (cmdline=="aus")
+  {
+    printf("Dein Presay wird jetzt nicht mehr angezeigt.\n");
+    SetProp(P_CAN_FLAGS,QueryProp(P_CAN_FLAGS)&~CAN_PRESAY);
+    return 1;
+  }
+  return USAGE("showpresay [ein|an|aus]");
+}
+
+//                              ########
+//############################### EXEC ###############################
+//                              ########
+
+static int _exec(string filename)
+{
+  object ob;
+  if (!IS_LORD(this_object())) return 0;
+  if (this_player()!=this_interactive()) return 0;
+  if (this_player()!=this_object()) return 0;
+  if (!(filename=_unparsed_args())) return USAGE("exec <objektname>");
+  filename=(string)"secure/master"->_get_path(filename,getuid());
+  if (file_size(filename)<0&&(!to_filename(filename+".c"))||
+      file_size(to_filename(filename+".c"))<0)
+  {
+    printf("exec: %s: Datei nicht vorhanden oder ein Verzeichnis.\n",filename);
+    return 1;
+  }
+  if (catch(call_other(filename,"????"))) 
+  {
+    printf("exec: Fehler beim Laden von %s.\n",filename);
+    return 1;
+  }
+  if (!(ob=clone_object(filename))) return 0;
+  if (getuid(ob) != getuid(this_object()))
+  {
+    printf("exec: UID-Konflikt: %s <-> %s.\n",getuid(ob),
+           getuid(this_object()));
+    destruct(ob);
+    return 1;
+  }
+  log_file(SHELLLOG("EXEC"),
+         sprintf("%12.12s %40.40s %25.25s\n",
+                 capitalize(getuid(this_object())),filename,dtime(time())[4..]));
+  disable_commands();
+  exec(ob,this_object());
+  if (interactive(this_object())||!interactive(ob))
+  {
+    enable_commands();
+    printf("Fehler bei EXEC: Uebertragung der Shell "
+           "nicht moeglich.\n");
+    return 1;
+  }
+  ob->start_player(capitalize(getuid(this_object())));
+  remove();
+  return 1;
+}
+//                            ############
+//############################# SNOOPING ###############################
+//                            ############
+
+private nosave string snoop_allowed;
+private nosave object snoopee;
+
+nomask int QueryAllowSnoop(object who)
+{
+  return (getuid(who) == snoop_allowed);
+}
+
+static int _sallow(string str)
+{
+  object ob;
+
+  if (!sizeof(str))
+  {
+    if (!snoop_allowed) return USAGE("sallow [<name>]\n");
+    str=snoop_allowed;
+    snoop_allowed=0;
+    printf("Du entziehst %s die Erlaubnis zum Snoopen.\n",capitalize(str));
+    ob=query_snoop(this_player());
+    if (!ob||(getuid(ob)!=str)) return 1;
+    tell_object(ob,break_string(sprintf("%s entzieht Dir die "
+            "Erlaubnis zum snoopen und zwingt Dich so dazu, mit "
+            "dem Snoopen aufzuhoeren.\n",capitalize(getuid()))));
+    snoop(ob);
+    return 1;
+  }
+  if (snoop_allowed) _sallow(""); // Erstmal abschalten
+  ob=find_player(lower_case(str));
+  str=capitalize(str);
+  if (!ob) return
+      printf("sallow: Spieler %s konnte nicht gefunden werden.\n",str),1;
+  if (query_wiz_grp(ob)>query_wiz_grp(this_player()))
+    return printf("sallow: %s hat einen hoeheren Rang als Du und kann "
+                  "Dich daher ohnehin snoopen.\n",str),1;
+  snoop_allowed=getuid(ob);
+  return printf("sallow: Du erlaubst %s, Dich zu snoopen.\n",str),1;
+}
+
+static int _snoop(string cmdline)
+{
+  object ob;
+  int flags;
+  string *args;
+
+  if (!sizeof(cmdline=_unparsed_args())||
+      sizeof(args=parseargs(cmdline,&flags,SNOOP_OPTS,0))!=1||flags==-1)
+  {
+    if (!snoop(this_object())) return USAGE("snoop [-" SNOOP_OPTS
+                                            "] [<spieler>]\n");
+    if (snoopee)
+      printf("Du snoopst %s jetzt nicht mehr.\n",capitalize(getuid(snoopee)));
+    else
+    {
+      printf("Du hoerst auf zu snoopen.\n");
+    // evtl. irgendetwas loggen ... sollte eigentlich nicht passieren.
+    }
+    snoopee=(object)0;
+    return 1;
+  }
+  SetProp(P_SNOOPFLAGS,flags); // FUNKTIONIERT NUR, WENN magier.h und
+                               // snooping.h abgeglichen sind
+  if (!(ob = find_player(args[0])))
+    return printf("snoop: Konnte keinen Spieler '%s' finden.\n",
+                  capitalize(args[0])),1;
+  if (!snoop(this_player(),ob))
+    return printf("snoop: Der Versuch, %s zu snoopen, ist "
+                  "fehlgeschlagen.\n%s",capitalize(args[0]),
+                  ((~flags)&SNOOP_F)?"Eventuell funktioniert es mit dem "
+                  "Flag '-f'.\n":""),1;
+  snoopee=ob;
+  return printf("Du snoopst jetzt %s.\n",capitalize(getuid(ob))),1;
+}
+
+
+//                           ##########
+//############################ MSCHAU #################################
+//                           ##########
+
+static int _mschau(string str)
+{
+  if (this_interactive()!=this_object()) return 0;
+  if (str=="ja"||str=="an"||str=="ein")
+  {
+    if ( QueryProp(P_WANTS_TO_LEARN) )
+      printf("Du hast den Magier-Modus doch schon eingeschaltet!\n");
+    else
+    {
+      printf("Du hast jetzt den Magier-Modus eingeschaltet.\n" );
+      SetProp(P_WANTS_TO_LEARN, 1);
+    }
+    return 1;
+  }
+  if (str=="nein"||str=="aus")
+  {
+    if (QueryProp(P_WANTS_TO_LEARN))
+    {
+      printf( "Du schaltest den Magier-Modus aus.\n");
+      set_heart_beat(1);
+      SetProp(P_WANTS_TO_LEARN,0);
+    }
+    else
+      printf("Du hast den Magier-Modus doch schon ausgeschaltet.\n");
+    return 1;
+  }
+  if (str=="+debug")
+  {
+    printf("Du nimmst jetzt Debugausgaben wahr.\n");
+    SetProp(P_WIZ_DEBUG,1);
+    return 1;
+  }
+  if (str=="-debug")
+  {
+    printf("Du nimmst jetzt keine Debugausgaben mehr wahr.\n");
+    SetProp(P_WIZ_DEBUG,0);
+    return 1;
+  }
+  return USAGE("mschau [an|ein|ja|aus|nein|+debug|-debug]\n");
+}
+
+//                           ###########
+//############################ PROTECT ################################
+//                           ###########
+
+static int _protect(string str)
+{
+ 
+  if (this_object()!=this_interactive()) return 0;
+  if (!sizeof(str))
+    return USAGE("protect <propertyname>\n");
+  Set(str, PROTECTED, F_MODE);
+  return printf("Deine Property %s ist jetzt %sgeschuetzt.\n",
+                str,(Query(str,F_MODE) & PROTECTED?"":"nicht mehr ")),1;
+}
+
+
+//                         ###############
+//########################## VIS + INVIS ##############################
+//                         ###############
+
+static int _hbstop;
+static int _age;
+
+static int _invis(string inform)
+{
+
+  if (QueryProp(P_INVIS))
+    return printf("Du bist doch schon unsichtbar!\n"),1;
+  tell_room(environment(),sprintf("%s %s.\n",capitalize(Name()),
+            QueryProp(P_MMSGOUT)),({ this_object() }));
+  if (inform=="e") {
+    // Logout-event ausloesen
+    EVENTD->TriggerEvent(EVT_LIB_LOGOUT, ([
+            E_OBJECT: this_object(),
+            E_PLNAME: getuid(this_object()),
+            E_ENVIRONMENT: environment() ]) );
+
+    call_notify_player_change(0);
+  }
+
+  SetProp(P_INVIS, QueryProp(P_AGE));
+  printf("Du bist jetzt unsichtbar.\n");
+  return 1;
+}
+
+static int _vis(string inform)
+{
+  if (!QueryProp(P_INVIS))
+    return printf("Du bist doch schon sichtbar.\n"),1;
+   tell_room(environment(),sprintf("%s %s.\n",capitalize(Name()),
+            QueryProp(P_MMSGIN)),({ this_object() }));
+  SetProp(P_INVIS, 0);
+  if (inform=="e") {
+    // Login-event ausloesen
+    EVENTD->TriggerEvent(EVT_LIB_LOGIN, ([
+          E_OBJECT: this_object(),
+          E_PLNAME: getuid(this_object()),
+          E_ENVIRONMENT: environment() ]) );
+
+    call_notify_player_change(1);
+  }
+  printf("Du bist jetzt sichtbar.\n");
+  return 1;
+}
+
+//                          ############
+//########################### LOCALCMD ###############################
+//                          ############
+
+
+static int _localcmd()
+{
+  int size,more;
+  string *verbs,result;
+
+  // Per Umweg ueber Mapping doppelte Werte einstampfen
+  size=sizeof(verbs=m_indices(mkmapping(query_actions(this_object()))));
+  verbs-=({""});
+  more=(size>sizeof(verbs));
+  if (!sizeof(verbs))
+  {
+    if (more)
+      printf("Die vorhandenen Befehle koennen nicht angezeigt werden, "
+             "da sie per 'add_action(\"funktion\",\"\",1)' definiert "
+             "wurden.\n");
+    else
+      printf("Dir stehen keine Befehle zur Verfuegung ... eigenartig!\n");
+    return 1;
+  }
+  verbs=sort_array(verbs,#'>);
+  result=break_string(sprintf("\'%s\'",implode(verbs,"' '")),78);
+  return printf("\n%'-'78.78s\nDie fuer Dich aktuell verfuegbaren "
+                "Befehle sind:\n\n%s\n%s%'-'78.78s\n","",result,
+                more?"Zudem wurden Befehle per 'add_action("
+                "\"funktion\",\"\",1)' definiert.\n":"",""),1;
+}
+
+//                           ###########
+//############################ TRAENKE ################################
+//                           ###########
+
+static int _traenke(string str)
+{
+  if(SetProp(P_TRANK_FINDEN, !QueryProp(P_TRANK_FINDEN)))
+    write("Du kannst jetzt Zaubertraenke finden.\n");
+  else
+    write("Du findest jetzt keine Zaubertraenke mehr.\n");
+  return 1;
+}
+
+static int norm_rusage() {
+	mixed* r;
+  r = rusage();
+  return r[0]/100 + r[1]/100;
+}
+
+//                           #############
+//############################ ASYNCHRON #################################
+//                           #############
+
+//
+// asynchron(): Asynchrone Abarbeitung eines Arrays
+// array:     Zu bearbeitendes Array
+// cmd:       Auszufuehrende Closure
+// data:      Extraargumente
+// flags:     Zusatzdaten (normalerweise Flags)
+// c:         schon asynchron?
+//
+
+static varargs void asynchron(mixed* array, closure cmd, mixed data, mixed flags,int c)
+{
+  int i, j, k;
+  mixed ret_val;
+  string cmd_string;
+
+  k = norm_rusage()+5;
+  j = sizeof(array);
+  i=0;
+  
+  switch (cmd_string=explode(sprintf("%O",cmd),"->")[1])
+  {
+    case "_make":     cmd_string=(data&UPD_LOAD?"load":"upd");break;
+    case "cp_file":   cmd_string =(data?"mv":"cp"); break;
+    case "grep_file": cmd_string = "grep"; break;
+    case "rm_file":   cmd_string = "rm"; break;
+    default: break;
+  }
+  
+  while(i < j && get_eval_cost() > 200000 && norm_rusage()<k)
+    // Sowohl Too-Long-Eval als auch Lag verhindern
+  {
+    ret_val=apply(cmd,array[i],data, flags);
+    if (closurep(ret_val))
+    {
+      if(c) tell_object(this_object(),
+               sprintf("%s: Verlasse Asynchronen Modus.\n",cmd_string));
+      funcall(ret_val,array[i..],data,flags);
+      return;
+    }
+    if (ret_val==RET_DELETE)
+    {
+      array[i+array[i][SUBDIRSIZE]+1..i+array[i][SUBDIRSIZE]]=
+        ({ (array[i][0..5]+({0})) });
+    }
+    if (ret_val==RET_JUMP) i+=array[i][SUBDIRSIZE];
+    i++;
+  }
+  if(sizeof(array = array[i..])) 
+  {  
+    if(!c) tell_object(this_object(),
+              sprintf("%s: Asynchroner Modus aktiviert!\n", cmd_string));
+    call_out(#'asynchron, 1, array, cmd, data,flags, 1);
+  }
+  else
+  {
+    if(c) tell_object(this_object(),
+                      sprintf("%s: abgeschlossen.\n",cmd_string));
+      else if (query_verb()) tell_object(this_object(),
+            sprintf("%s: abgeschlossen.\n",query_verb()));
+  }
+  return;                                                    
+}
+
+//
+// ######################## Driver Status Infos ##########################
+//
+static int _driver_malloc(string str)
+{
+    if(!sizeof(str))
+    {
+        write(efun::driver_info(DI_STATUS_TEXT_MALLOC));
+        return 1;
+    }
+    if(str == "extstats")
+    {
+        write(efun::driver_info(DI_STATUS_TEXT_MALLOC_EXTENDED));
+        return 1;
+    }
+    return 0;
+}
+
+static int _driver_dumpallobj(string str)
+{
+    write("Dumping to /OBJ_DUMP ... ");
+    efun::dump_driver_info(DDI_OBJECTS);
+    efun::dump_driver_info(DDI_OBJECTS_DESTRUCTED);
+    write("done\n");
+    return 1;
+}
+
+static int _driver_opcdump(string str)
+{
+    efun::dump_driver_info(DDI_OPCODES);
+    return 1;
+}
+
+static int _driver_status(string str)
+{
+    int opt;
+
+    switch(str || "")
+    {
+        case "":
+            opt = DI_STATUS_TEXT_MEMORY;
+            break;
+
+        case "tables":
+        case " tables":
+            opt = DI_STATUS_TEXT_TABLES;
+            break;
+
+        case "swap":
+        case " swap":
+            opt = DI_STATUS_TEXT_SWAP;
+            break;
+
+        case "malloc":
+        case " malloc":
+            opt = DI_STATUS_TEXT_MALLOC;
+            break;
+
+        case "malloc extstats":
+        case " malloc extstats":
+            opt = DI_STATUS_TEXT_MALLOC_EXTENDED;
+            break;
+
+        default:
+            return 0;
+    }
+    write(efun::driver_info(opt));
+    return 1;
+}
+
+//                         ###################
+//########################## INITIALISIERUNG #############################
+//                         ###################
+
+//
+// _query_localcmds: Welche Kommandos werden in dieser Datei implementiert?
+//
+
+static mixed _query_localcmds()
+{
+  return ({
+    ({"set","_set",0,LEARNER_LVL}),
+    ({"pwd","_pwd",0,LEARNER_LVL}),
+    ({"cd","_cd",0,LEARNER_LVL}),
+    ({"prompt","_prompt",0,LEARNER_LVL}),
+    ({"showpresay","_showpresay",0,LEARNER_LVL}),
+    ({"exec","_exec",0,ARCH_LVL}),
+    ({"sallow","_sallow",0,LEARNER_LVL}),
+    ({"snoop","_snoop",0,WIZARD_LVL}),
+    ({"mschau","_mschau",0,LEARNER_LVL}),
+    ({"protect","_protect",0,WIZARD_LVL}),
+    ({"invis","_invis",0,LEARNER_LVL}),
+    ({"vis","_vis",0,LEARNER_LVL}),
+    ({"localcmd","_localcmd",0,LEARNER_LVL}),
+    ({"traenke","_traenke",0,DOMAINMEMBER_LVL}),
+    ({"malloc","_driver_malloc",0,LEARNER_LVL}),
+    ({"dumpallobj","_driver_dumpallobj",0,ARCH_LVL}),
+    ({"opcdump","_driver_opcdump",0,ARCH_LVL}),
+    ({"status","_driver_status",0,LEARNER_LVL}),
+  })
+    +fileview::_query_localcmds()
+    +upd::_query_localcmds()
+    +objects::_query_localcmds()
+    +fileedit::_query_localcmds()
+//    +todo::_query_localcmds()
+    +players::_query_localcmds()
+    +admin::_query_localcmds()
+    +moving::_query_localcmds()
+    +comm::_query_localcmds();
+}
+
+//
+// initialize: Initialisierung der Shell
+//
+
+static void initialize()
+{
+  Set(P_PROMPT, SAVE, F_MODE_AS);
+  Set(P_VARIABLES,SAVE,F_MODE_AS);
+  Set("filesys",SAVE,F_MODE_AD);   // P_FILESYS ist obsolet
+  Set("short_cwd",SAVE,F_MODE_AD); // P_SHORT_CWD auch
+  if(!mappingp(QueryProp(P_VARIABLES)))
+    SetProp(P_VARIABLES, ([]));
+  _prompt(QueryProp(P_PROMPT));
+//  todo::initialize();
+  _cd2("");
+  return;
+}
+
+static void reconnect() { _cd(QueryProp(P_CURRENTDIR)); }
diff --git a/std/shells/magier/moving.c b/std/shells/magier/moving.c
new file mode 100644
index 0000000..3095a3f
--- /dev/null
+++ b/std/shells/magier/moving.c
@@ -0,0 +1,232 @@
+// MorgenGrauen MUDlib
+//
+// moving.c
+//
+// $Id: moving.c 9142 2015-02-04 22:17:29Z Zesstra $
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <magier.h>
+#include <thing/properties.h>
+#include <living/moving.h>
+#include <player.h>
+#undef NEED_PROTOTYPES
+#include <wizlevels.h>
+#include <moving.h>
+#include <properties.h>
+
+private mixed verfolger()
+{
+  mixed *pur;
+
+  if (!pointerp(pur=QueryProp(P_PURSUERS))) return 0;
+  else return pur[0];
+}
+
+//                         #########
+//########################## IN+AT ############################
+//                         #########
+
+static int _move_base(object target, object old_room, string cmd)
+{
+  if (environment()!=target)
+    if (IS_ARCH(this_object()))
+    {
+      __set_environment(this_object(),target);
+      printf("%s: Bewegung hat nicht geklappt. Versuche es mit "
+             "set_environment... %s.\n.",query_verb(),
+             environment()==target?"hat geklappt":"erfolglos");
+    }
+  else
+    printf("%s: Bewegung hat nicht geklappt.\n",query_verb());
+  if (environment()!=target) return 1;
+  command(cmd);
+  if (old_room) move_object(old_room);
+  else
+    return printf("%s: Ursprungsraum wurde zerstoert.\n",query_verb()),1;  
+  if (environment()!=old_room)
+  {
+    if (IS_ARCH(this_object()))
+    {
+      __set_environment(this_object(),old_room);
+      printf("%s: Zurueckbewegen hat nicht geklappt. Versuche es mit "
+             "set_environment ... %s.\n",query_verb(),
+             environment()==old_room?"hat geklappt":"erfolglos");
+    }
+    else
+      printf("at: Zurueckbewegen hat nicht geklappt.\n");
+  }
+  return 1;
+}
+
+static int _in_room(string str)
+{
+  string room;int size;
+  object old_room;
+  string cmd,err;
+
+  if (!sizeof(str=_unparsed_args()) ||
+      !sizeof(str=regreplace(str,"^ *","",1)) ||
+      sscanf(str, "%s %s", room, cmd) != 2)
+    return USAGE("in <raum> <befehl>\n");
+  old_room = environment();
+  room=(string)call_other(master(),"_get_path",room,getuid());
+  if (err=catch(move_object(room)))
+  {
+    if (catch(size=file_size(room+".c"))||size<1)
+      printf("%s: %s.c: Datei nicht vorhanden.\n",query_verb(),room);
+    else
+      printf("%s: Bewegung nach %s hat nicht funktioniert: %s\n",
+             query_verb(),room,err);
+    return 1;
+  }
+  return _move_base(find_object(room),old_room,cmd);
+}
+
+static int _at_player(string dest)
+{
+  object ob,old_room;
+  mixed tmp;
+  string cmd;
+
+  if (!sizeof(dest=_unparsed_args()) ||
+      !sizeof(dest=regreplace(dest,"^ *","",1)) ||
+      sscanf(dest, "%s %s", dest, cmd) != 2)
+    return USAGE("at <lebewesen> <befehl>\n");
+  if (!(ob=find_living(dest)))
+  {
+    tmp=match_living(dest,1);
+    if (stringp(tmp)) ob = find_living(tmp);
+  }
+  if (!ob||!(ob=environment(ob)))
+    return _notify_fail(sprintf("at: Lebewesen \'%s\' nicht gefunden.\n",
+                                dest)),0;
+  old_room=environment();
+  move_object(ob);
+  return _move_base(ob,old_room,cmd);
+}
+
+//                           ########
+//############################ GOTO ############################
+//                           ########
+
+static object find_living_nr(string str)
+{ string name,check;
+  int nr;
+  object*livings;
+  if(sscanf(str,"%s %d%s",name,nr,check)<2||sizeof(check))
+    return find_living(str);
+  if(!sizeof(livings=filter((find_livings(name)||({})),#'environment))
+     ||nr<1||sizeof(livings)<nr)
+    return 0;
+  return livings[nr-1];
+}
+
+static int _goto(string dest){
+  mixed target;
+  string target2,err;
+
+  if (!sizeof(dest=_unparsed_args()))
+    return USAGE("goto [lebewesen|filename]\n");
+  if (!((target=find_living_nr(dest)) && (target=environment(target))))
+  {
+     target2=target=(mixed)call_other(master(),"_get_path",dest,getuid());
+     if (!find_object(target))
+     {
+       if (target2[<1]=='.') target2+="c";
+       if (target2[<2..<1]!=".c") target2+=".c";
+       notify_fail(sprintf("goto: Datei %O nicht vorhanden.\n",target));
+       if (!(file_size(target2)>-1||
+           file_size(implode(explode(target,"/")[0..<2],"/")+
+               "/virtual_compiler.c")>-1)||(err=catch(call_other(target,"?"))))
+       {
+         if (err)
+              notify_fail(sprintf("goto: Fehler beim Teleport nach %O:\n%s\n",
+                      dest,implode(explode(err,"\n")," ")));
+         target=match_living(dest,1);
+         if (!(stringp(target)&&(target=find_living(target))&&
+               (target=environment(target))))
+           return 0;
+       }
+     }
+  }
+  if (verfolger()) _verfolge("");
+  if (move(target,M_TPORT|M_NOCHECK)<0)
+    printf("Bewegung fehlgeschlagen!\n");
+  return 1;
+}
+
+//                           ########
+//############################ HOME ############################
+//                           ########
+
+static int _home()
+{
+  string dest;
+  if (verfolger()) _verfolge("");
+  dest="/players/" + getuid() + "/workroom";
+  if (file_size(dest+".c")<1||catch(call_other(dest,"???")))
+  {
+    printf("Fehler beim Laden Deines Workrooms.\n"
+           "Gehe zum Magiertreff.\n");
+    dest="/secure/merlin";
+  }
+  
+  if (move(dest,M_TPORT|M_NOCHECK)<0)
+    printf("Bewegung fehlgeschlagen!\n");
+  return 1;
+}
+
+//                        ###############
+//######################### +MAGIERNAME ##########################
+//                        ###############
+
+static int _go_wiz_home(string str)
+{
+  _notify_fail("Syntax: '+magiername'\n");
+  if(sizeof(query_verb())>1) str=query_verb()[1..];
+  if(!sizeof(str)) return 0;
+  if(query_verb()[0]!='+') return 0;
+  str=(old_explode(str," ")-({0}))[0];
+  if(!sizeof(str)) return 0;
+  str=lower_case(str);
+  if (str=="merlin")
+  {
+    move("/secure/merlin",M_TPORT|M_NOCHECK);
+    return 1;
+  }
+  if ((!call_other(master(),"get_userinfo",str))||
+      !IS_LEARNER(str))
+  {
+    printf("Es gibt keinen Magier namens %s.\n",
+           capitalize(str));
+    return 1;
+  }
+  if (file_size("/players/"+str+"/workroom.c")<1)
+  {
+    printf("%s hat keinen Workroom.\n",capitalize(str));
+    return 1;
+  }
+  if (catch(call_other("/players/"+str+"/workroom","???")))
+  {
+    printf("Der Workroom von %s hat Fehler.\n",capitalize(str));
+    return 1;
+  }
+  move("/players/"+str+"/workroom",M_TPORT|M_NOCHECK);
+  return 1;
+}
+
+
+static mixed _query_localcmds()
+{
+  return
+    ({({"goto","_goto",0,LEARNER_LVL}),
+      ({"in","_in_room",0,LEARNER_LVL}),
+      ({"at","_at_player",0,LEARNER_LVL}),
+      ({"home","_home",0,WIZARD_LVL}),
+      ({"+","_go_wiz_home",1,LEARNER_LVL})});
+}
diff --git a/std/shells/magier/objects.c b/std/shells/magier/objects.c
new file mode 100644
index 0000000..ed74f56
--- /dev/null
+++ b/std/shells/magier/objects.c
@@ -0,0 +1,168 @@
+// $Id: objects.c 8848 2014-06-11 22:05:04Z Zesstra $
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <wizlevels.h>
+#include <moving.h>
+#define NEED_PROTOTYPES
+#include <thing/language.h>
+#include <thing/properties.h>
+#include <thing/description.h>
+#include <living/put_and_get.h>
+#include <player.h>
+#include <magier.h>
+
+//                        ###################
+//######################### INITIALISIERUNG #############################
+//                        ###################
+
+
+static mixed _query_localcmds()
+{
+  return ({({"clone","_clone",0,WIZARD_LVL}),
+           ({"setcmsg","_setcmsg",0,WIZARD_LVL}),
+           ({"setdmsg","_setdmsg",0,WIZARD_LVL}),
+           ({"destruct","_destruct",0,WIZARD_LVL}),
+          });
+}
+
+//                              #########
+//############################### CLONE ##############################
+//                              #########
+
+static int _clone(string cmdline)
+{
+  mixed *tmp;
+  int flags;
+  object ob;
+  string *args,*args2,err;
+  
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,CLONE_OPTS,1);
+  if (flags==-1||sizeof(args)!=1)
+    return USAGE("clone [-" CLONE_OPTS "] <objektname>");
+  if (flags&CLONE_F)
+    cmdline=args[0];
+  else
+  {
+    // etwas umstaendlich, aber so kann man auch Dateien clonen,
+    // wenn man keine Leserechte hat. Man muss aber im Verzeichnis
+    // lesen koennen
+    args2=explode(args[0],"/");
+    if (args2[<1][<1]=='.') args2[<1]+="c";
+    else if (args2[<1][<2..<1]!=".c") args2[<1]+=".c";
+    tmp=file_list(({implode(args2[0..<2],"/")+"/*"}),MODE_CLONE,0,"",
+                  args2[<1]);
+    if (!sizeof(tmp)||tmp[0][FILESIZE]<0)
+      return printf("clone: %s: Datei existiert nicht.\n",args[0]),1;
+    cmdline=tmp[0][FULLNAME];
+  }
+
+  if (err=catch(ob=clone_object(cmdline))||!ob)
+    return printf("clone: %s: Objekt konnte nicht erzeugt werden.\n"
+                  "Grund: %O",
+                  args[0],err||"unbekannt"),1;
+  if (!objectp(ob))
+    return printf("clone: %s: Objekt beim Erzeugen zerstoert.\n",
+                  args[0]),1;
+  if ((ob->move(this_object(),M_GET)>0) || 
+      (!objectp(ob)||ob->move(environment(),M_NOCHECK)>0)||!objectp(ob))
+  {
+    if (!objectp(ob))
+      return printf("clone: %s: Objekt beim Erzeugen zerstoert.\n",
+                  args[0]),1;
+    printf("Clone: %s erzeugt.\n",object_name(ob));
+    tell_room(environment(this_object()),
+              sprintf("%s %s.\n",Name(WER,1),QueryProp(P_CLONE_MSG)),
+                      ({ this_object()}));
+    return 1;
+  }
+  tell_room(environment(this_object()),
+            sprintf("%s malt wilde Zeichen in die Luft und "
+                    "murmelt vor sich hin, aber nichts "
+                    "passiert...\n",Name(WER,1)),
+            ({ this_object()}));
+  destruct(ob);
+  printf("Clone: %s: Objekt konnte nicht bewegt werden.",args[0]);
+  return 1;
+}
+
+
+//                            ############
+//############################# DESTRUCT ##############################
+//                            ############
+
+//
+// _destruct: Objekte zerstoeren
+//
+
+static int _destruct(string cmdline)
+{
+  int flags;
+  mixed *args;
+  object ob;
+
+  if (!sizeof(cmdline=_unparsed_args()))
+    return USAGE(query_verb()+" <objektname>");
+  args=find_obs(lower_case(cmdline),PUT_GET_NONE);
+  if (!args||!sizeof(args))
+  {
+    if (!(ob=find_object(cmdline)))
+    {
+      notify_fail(query_verb()+": Objekt \"" +cmdline+
+                  "\" nicht gefunden.\n");
+      return 0;
+    }
+  }
+  else
+    ob=args[0];
+  cmdline=capitalize(to_string(ob->name(WER)));
+  flags=(int)ob->QueryProp(P_PLURAL); // Missbrauch von flags :o)
+  if (query_verb()=="destruct")
+  {
+    if (!ob->remove())
+    {
+      notify_fail(cmdline+" will nicht zerstoert werden!\n");
+      return 0;
+    }
+  }
+  else destruct(ob);
+  if (!ob)
+  {
+    if (!QueryProp(P_INVIS))
+    {
+      tell_room(environment(this_object()),
+                sprintf("%s %s.\n",cmdline,QueryProp(P_DESTRUCT_MSG)),
+                ({ this_object() }));
+    }
+    printf("%s w%s von Dir zerstaeubt.\n",cmdline,(flags?"erden":"ird"));
+  }
+  else
+    printf("%s kann nicht zerstoert werden.\n",cmdline);
+  return 1;
+}
+
+//                        ####################
+//######################### SetCMsg, SetDMsg ############################
+//                        ####################
+
+static int _setcmsg(string str)
+{
+  printf("Beim Clonen von Objekten sehen die Anderen nun:\n"
+         "<Dein Name> %s.\n",
+         (SetProp(P_CLONE_MSG, _unparsed_args()||"zaubert etwas aus "
+          + QueryPossPronoun(MALE,WEM) + " Aermel hervor")));
+  return 1;
+}
+
+static int _setdmsg(string str)
+{
+  printf("Beim Zerstoeren von Objekten sehen die Anderen nun:\n"
+         "<Objekt> %s.\n",
+         SetProp(P_DESTRUCT_MSG, _unparsed_args()||"wird von " + name(WER,1)
+          + " zerstaeubt"));
+  return 1;
+}
diff --git a/std/shells/magier/parsing.c b/std/shells/magier/parsing.c
new file mode 100644
index 0000000..555332d
--- /dev/null
+++ b/std/shells/magier/parsing.c
@@ -0,0 +1,370 @@
+// $Id: parsing.c 9142 2015-02-04 22:17:29Z Zesstra $
+#pragma strict_types
+#pragma save_types
+//#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <files.h>
+#include <wizlevels.h>
+#include <logging.h>
+#include <regexp.h>
+#define NEED_PROTOTYPES
+#include <magier.h>
+#include <thing/properties.h>
+#include <player.h>
+
+//
+// glob2regexp: Argument von glob in Regexp umwandeln
+// str: Argument (als Referenz)
+//
+
+static string glob2regexp(string str)
+{
+  str=regreplace(str,"([\\.\\^\\$\\[\\]\\(\\)])","\\\\\\1",RE_TRADITIONAL|1);
+  str=regreplace(str,"\\*",".*",RE_TRADITIONAL|1);
+  return sprintf("^%s$",regreplace(str,"?",".",RE_TRADITIONAL|1));
+}
+
+//
+// to_filename: Argument in Dateinamen umwandeln
+// str:  Argument
+// Rueckgabe: Dateiname
+//
+
+static mixed to_filename(string str)
+{
+  string *tmp,p,newfn;
+  int i;
+// Testen ob .. in einem Filenamenabschnitt, falls Version <3.2.5
+  tmp=explode(str,"/");
+// Testen auf Pfadvariable
+  if (sizeof(tmp[0]) && tmp[0][0]=='$' 
+      && m_contains(&p,QueryProp(P_VARIABLES),tmp[0][1..]))
+    tmp[0]=p;
+// Pfad absolut machen (Hat danach noch Wildcards drinnen) oder auch nicht
+  return master()->make_path_absolute(implode(tmp,"/"));
+}
+
+
+//
+// _parseargs(): Kommandozeilenabschnitt parsen
+// str:         Kommandozeilenabschnitt
+// line:        Array von geparsten Kommandozeilenabschnitten (Referenz)
+// flags:       Als Referenz uebergebener Flag-Wert
+// opts:        Erlaubte Flags
+// build_fn:    Filenamen aendern
+//
+
+private void _parseargs(string str, string *line,int flags,string opts,
+                     int build_fn )
+{
+
+// Strings in "" erhalten
+  if(str[0] == "\""[0])  
+  { 
+    line += ({ str[1..<2] });
+    return; 
+  }  
+//  Flags parsen
+  if(str[0] == '-')  
+  { 
+    int i,j;
+    i=sizeof(str);
+    while(i--)
+      if (str[i]!='-')
+      {
+        if((j = member(opts, str[i])) != -1)
+          flags |= (1 << j);
+        else
+        {
+          flags=-1;
+          printf("Das Flag '-%c' wird von dem Befehl '%s' nicht "
+                 "unterstuetzt.\n",str[i],query_verb()||"");
+        }
+      }
+    return;
+  }
+  if (build_fn)
+  {
+    if (str=(string)to_filename(str)) line+=({ str });
+  } 
+  else
+    line+= ({ str });
+}
+
+
+//
+// parseargs() - zerlegt Kommandozeile in ein Array:
+// cmdline:     Kommandozeile
+// flags:       Als Referenz uebergebener leerer Integerwert. Enthaelt danach
+//              die Flags
+// opts:        String mit erlaubten Optionen
+// build_fn:    Filenamen umbauen?
+// Rueckgabe: Array der Kommandozeilenargumente (ausser Flags)
+//
+
+static string *parseargs(string cmdline,int flags, string opts,int build_fn)
+{
+  int i;
+  string *line;
+  line=({});
+  if (!sizeof(cmdline)) return ({});
+  map(regexplode(cmdline,"[\"][^\"]*[\"]| ", RE_TRADITIONAL)-({" ", ""}),
+            #'_parseargs, &line, &flags,opts, build_fn);
+  return line - ({""});
+}
+
+//
+// _vc_map: VC-Objektnamen zu Arrays umwandeln ({ name, -1, program_time() })
+//
+
+private int *_vc_map(object ob,mixed *list)
+{
+  list+=({ explode(object_name(ob),"/")[<1],-1,program_time(ob) });
+  return 0;
+}
+
+
+//
+// _get_files: Filedaten beim Rekursiven kopieren erstellen
+// dirname:    Bearbeitetes Verzeichnis
+// mask:       Maske, der Dateinamen genuegen muessen
+// mode:       Welche Daten werden benoetigt? (siehe magier.h)
+// dest:       In welches Verzeichnis soll kopiert werden?
+// Rueckgabe:  Alist mit den Dateiinformationen
+//
+
+private varargs mixed *_get_files(string dirname,string mask,int mode,string dest)
+{
+  mixed *files,*tmp,*data;
+  string fullname,base;
+
+  //DEBUG("_GF: DIRNAME " + dirname);
+  data=get_dir(dirname+"*",7);
+  if(!sizeof(data)) return ({});
+  files=({});
+ 
+  while(sizeof(data))
+  {
+    tmp=({});
+    base=data[BASENAME];
+    fullname=dirname+base;
+    if (base!="."&&base!=".."&&(!(mode==MODE_GREP&&base=="RCS"))&&
+        ((data[FILESIZE]==-2&&
+       sizeof(tmp=_get_files(fullname+"/",mask,mode,
+      dest+base+"/"))&&mode!=MODE_RM)||!mask||sizeof(regexp(({ base }),mask, RE_TRADITIONAL))))
+    {
+      //DEBUG("_GF: ADDING FILE " + fullname);
+      files+= ({ data[0..2]+({ fullname,dirname,dest+base,
+                               sizeof(tmp) }) });
+    }
+    if (sizeof(files)+sizeof(tmp)>MAX_ARRAY_SIZE)
+       raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
+    files+=tmp;
+    data=data[3..];
+  }
+  
+  if(sizeof(files)>300&&!IS_ARCH(this_object()))
+    // Tod allen Laggern :o)
+    raise_error("Zu viele Files (>300)!! Abgebrochen!\n");
+  return files;
+}
+ 
+
+//
+// _get_matching: Rekursive Funktion zum ermitteln der Files, wenn mit Maske
+//                gearbeitet wird (z.B. cp -m /bla/*/* /ziel *.c)
+// pathmask: Array, das die einzelnen Elemente der Maske (Arg1) enthaelt
+//                   (per efun:old_explode(arg1,"/"))
+// depth:     Aktuelles Element von pathmask
+// path:      implode(pathmask[0..depth],"/");
+// mode:      Welche Daten werden benoetigt? (siehe magier.h)
+// flags:     Welche Flags wurden gesetzt?
+// dest:      Zielverzeichnis (beim kopieren/moven)
+// filemask:  Maske, der die Files genuegen muessen
+// Rueckgabe: Alist mit den Dateiinformationen
+//
+
+private mixed *_get_matching(string *pathmask, int depth, string path, 
+                    int mode, int recursive, string dest,string filemask)
+{
+  mixed *data,*tmp,*files;
+  string base,full;
+
+  //DEBUG("_GM: PM: " + pathmask[depth]);
+  //DEBUG("_GM: FM: " + filemask);
+  data=get_dir(path+pathmask[depth++],GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES)||({});
+  if (!sizeof(data)) return ({});
+  files=({});
+  while(sizeof(data))
+  {
+    if ((base=data[BASENAME])=="."||base=="..")
+    {
+      data=data[3..];
+      continue;
+    }
+    full=path+base;
+    //DEBUG("_GM: FULL: " + full);
+    if ((data[FILESIZE]==-2)&&(sizeof(pathmask)>depth)&&
+        (!(mode==MODE_GREP&&base=="RCS")))
+    {
+      //DEBUG("DESCEND INTO " + full);
+      tmp=_get_matching(pathmask,depth,full+"/",mode,recursive,
+                        (recursive?dest+base+"/":dest),filemask);
+    }
+    else tmp=({});
+    //DEBUG("DEPTH: " + depth + " : " + sizeof(pathmask));
+    if((!filemask&&(depth==sizeof(pathmask)))||
+        (filemask&&(depth+2>sizeof(pathmask))&&
+        sizeof(regexp(({ base }),filemask,RE_TRADITIONAL)))||
+       ((mode==MODE_CP||mode==MODE_MV||(filemask&&
+        (mode==MODE_RM)&&sizeof(regexp(({ base}),filemask,RE_TRADITIONAL))))&&
+        sizeof(tmp)))
+    {
+      //DEBUG("ADDING: " + base+ " : "+ full );
+      files+=({ data[0..2]+({ full, path, dest+base,sizeof(tmp)}) });
+    }
+    if (sizeof(files)+sizeof(tmp)>MAX_ARRAY_SIZE)
+       raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
+    files+=tmp;
+    data=data[3..];
+  }
+  if(sizeof(files)>300&&!IS_ARCH(this_object()))
+    // Tod allen Laggern!
+    raise_error("Zu viele Files (>300)!! Abgebrochen!\n");
+  return files;
+}
+
+
+//
+// get_files: Basisroutine zum Ermitteln der zu bearbeitenden Dateien
+// filename:  Pfadmaske, Verzeichnisname, Dateiname, der bearbeitet werden
+//            soll
+// mode:      Welche Daten werden benoetigt? (siehe magier.h)
+// recursive: Auch Unterverzeichnisse bearbeiten?
+// dest:      Wenn kopiert werden soll: wohin?
+// filemask:  Maske, der die Dateinamen genuegen muessen
+// Rueckgabe: Alist mit den Dateiinformationen
+//
+
+static varargs mixed *get_files(string filename, int mode, int recursive, string dest, string filemask)
+{ 
+  string full,path,base,*patharray,*vrooms,dest2;
+  object vcompiler;
+  mixed *files,*data;
+
+  // DEBUG("GF: " + filename);
+  // DEBUG("REC: " + recursive + " MODE: " + mode);
+  // if (dest[<1..<1]!="/") DEBUG("DEST: " + dest);
+  if (filename=="/")
+    {
+      switch (mode)
+      {
+        case MODE_LSA: return ({({ "", -2, 0,"","","",0 })});
+        default: if (!recursive) return ({});
+                 break;
+      }
+    }
+  patharray=explode(filename,"/");
+  if(!sizeof(data=get_dir(filename,7)||({}))&&
+     (mode==MODE_UPD||mode==MODE_MORE||mode==MODE_ED))
+    data=get_dir(filename+".c",7)||({});
+  if ((mode==MODE_LSA||mode==MODE_LSB)&&
+      (vcompiler = find_object(implode(patharray[0..<2],"/")+"/virtual_compiler")) &&
+      pointerp(vrooms=(mixed *)vcompiler->QueryObjects()))
+    map(vrooms,#'_vc_map,&data);
+  files=({});
+  if (sizeof(data)) // passende files
+  {
+    mixed *subfiles;
+    subfiles=({});
+    path=implode(patharray[0..<2],"/")+"/";
+    while (sizeof(data))
+    {
+      subfiles=({});
+      base=data[BASENAME];
+      if (mode==MODE_LSB||(base!="."&&base!=".."))
+      {
+        //DEBUG("PATH: " + path+" BASE: " + base + " MODE: " + mode);
+        full=path+base;
+        dest2=((dest=="/"||file_size(dest[0..<2])==-2)?
+               (dest+base):(dest=="/"?"/":dest[0..<2]));
+        //DEBUG("DEST: " + dest);
+        if (recursive&&data[FILESIZE]==-2) // Verzeichnis, Rekursiv
+          subfiles=_get_files(full+"/",filemask,mode,dest2+"/");
+        if (!(filemask&&!sizeof(subfiles)&&!sizeof(regexp(({ base }),filemask,RE_TRADITIONAL))))
+        {
+          if (!filemask||mode!=MODE_RM)
+            files+=({ data[0..2]+({ full, path, dest2,sizeof(subfiles)}) });
+          if (sizeof(files)+sizeof(subfiles)>MAX_ARRAY_SIZE)
+            raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
+          files+=subfiles;
+        }
+      }
+      data=data[3..];
+    }
+    return files;
+  }
+// File existiert nicht -> Wildcard oder tatsaechlich nicht existent
+// Behandeln je nach mode
+  switch(mode)
+  {
+    case MODE_CP:
+    case MODE_MV:
+    case MODE_CD:
+    case MODE_LSA:
+      files=_get_matching(patharray+(filemask?({ "*" }):({})),1,"/",mode,
+                           recursive,dest,filemask);
+      break;
+    default: break; 
+  }
+  return files;
+}
+
+
+//
+// file_list(): Liste der Fileinformationen
+// files:     Array der Filenamen MIT Wildcards
+// mode:      Welche Daten werden benoetigt
+// recursive: Rekursiv listen?
+// dest:      Zielverzeichnis
+// mask:      Maske (regexp, wenn definiert)
+// Rueckgabe: Liste der betroffenen Files
+//
+
+static varargs mixed *file_list(string *files, int mode, int recursive, string dest, string mask)
+{
+  string *list,err,*result;
+  int i,j;
+  list=({});
+  if (mask) mask=glob2regexp(mask);
+  j=sizeof(files);
+  for(i=0;i<j;i++)
+  {
+    // Abschliessenden / von Pfadnamen abschneiden, weil in diesem Fall 
+    // die Inhalte der ersten Unterverzeichnisebene mit ausgegeben
+    // wurden. Ursache hierfuer ist ein Fix an full_path_array() im 
+    // Masterobjekt, der dazu fuehrte, dass get_dir() den abschliessenden /
+    // des uebergebenen Pfades jetzt korrekt behandelt. \o/
+    if ( sizeof(files[i]) > 1 && files[i][<1] == '/' )
+    {
+      files[i] = files[i][0..<2];
+      if ( !sizeof(files[i]) )
+        continue;
+    }
+    if (err=catch(list+=get_files(files[i],mode,recursive,dest,mask)))
+    {
+      printf("Fehler aufgetreten: %s\n",err);
+      log_file(SHELLLOG("FILE_LIST"),
+               sprintf("%s fuehrte folgendes Kommando aus: (Zeit: %s)\n"
+                       "  >>%s %s<<\n"
+                       "  Folgender Fehler trat dabei auf:\n"
+                       "  %s\n\n",
+                       capitalize(getuid())||"<Unbekannt>",dtime(time()),
+                       query_verb()||"*",_unparsed_args()||"*",err||"*"));
+      return ({});
+    }
+  }
+   return list;
+}
diff --git a/std/shells/magier/players.c b/std/shells/magier/players.c
new file mode 100644
index 0000000..c563d9d
--- /dev/null
+++ b/std/shells/magier/players.c
@@ -0,0 +1,529 @@
+// MorgenGrauen MUDlib
+//
+// players.c
+//
+// $Id: players.c 9551 2016-04-20 22:54:58Z Arathorn $
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <wizlevels.h>
+#include <ansi.h>
+#include <logging.h>
+#define NEED_PROTOTYPES
+#include <magier.h>
+#include <thing/properties.h>
+#include <thing/description.h>
+#include <living/comm.h>
+#include <player.h>
+#undef NEED_PROTOTYPES
+#include <properties.h>
+#include <moving.h>
+
+static mixed _query_localcmds()
+{
+  return ({({"zap","_zap",0,WIZARD_LVL}),
+           ({"verfolge","_verfolge",0,LEARNER_LVL}),
+           ({"trans","_trans",0,LEARNER_LVL}),
+           ({"peace","_frieden",0,LEARNER_LVL}),
+           ({"frieden","_frieden",0,LEARNER_LVL}),
+           ({"pwho","_pwho",0,WIZARD_LVL}),
+           ({"zwinge","_zwinge",0,WIZARD_LVL}),
+           ({"heal","_heile",0,WIZARD_LVL}),
+           ({"heil","_heile",1,WIZARD_LVL}),
+           ({"people","_people",0,LEARNER_LVL}),
+           ({"spieler","_spieler",0,WIZARD_LVL})});
+}
+
+//                               #######
+//################################ ZAP ##################################
+//                               #######
+
+private string _zap_message(string str, object obj)
+{
+  str=regreplace(str,"@@wer@@",(string)obj->name(WER,2),1);
+  str=regreplace(str,"@@wessen@@",(string)obj->name(WESSEN,2),1);
+  str=regreplace(str,"@@wem@@",(string)obj->name(WEM,2),1);
+  str=regreplace(str,"@@wen@@",(string)obj->name(WEN,2),1);
+  str=regreplace(str,"@@ich@@",name(WER,2),1);
+  return capitalize(str);
+}
+
+static int _zap(string str)
+{
+    object opfer;
+    string *message, dummy;
+    int spieler;
+
+    if (!str) return USAGE("zap <name>");
+    if (sscanf( str, "spieler %s", dummy ))
+    {
+      str = dummy;
+      spieler = 1;
+    }
+    if (opfer=present(str,environment()))
+    {
+      if ( !living(opfer) )
+      {
+        printf("%s ist doch gar kein Lebewesen!\n",capitalize(str) );
+        return 1;
+      }
+      if (query_once_interactive(opfer)&&!spieler )
+      {
+        printf( "Spieler kannst Du nur mit der Syntax 'zap spieler <name>' "
+                "toeten!\n" );
+        return 1;
+      }
+      else
+        if ( !query_once_interactive(opfer) && spieler )
+        {
+          printf( "Aber %s ist doch gar kein Spieler!\n",capitalize(str));
+          return 1;
+        }
+
+      message = QueryProp(P_ZAP_MSG);
+
+      if ( !pointerp(message) || sizeof(message) != 3 ){
+          tell_room(environment(),sprintf("%s beschwoert einen Blitz "
+                "vom Himmel.\n",capitalize(getuid())),({ this_object() }));
+          printf("Du toetest %s.\n",opfer->name( WEN,2));
+      }
+      else
+      {
+        printf(_zap_message(message[0],opfer));
+        tell_room(environment(),_zap_message(message[1],opfer),
+             ({this_player(),opfer}));
+        tell_object(opfer,_zap_message(message[2],opfer));
+      }
+
+      opfer->die();
+      return 1;
+  }
+  else{
+      printf("Sowas siehst Du hier nicht.\n");
+      return 1;
+  }
+}
+
+
+//                             ############
+//############################## VERFOLGE ################################
+//                             ############
+
+static int _verfolge(string str)
+{
+  // Wenn nichts eingegeben wurde, wird ver Verfolgungsmodus beendet, sofern
+  // er zuvor eingeschaltet war. Ansonsten wird eine Fehlermeldung 
+  // ausgegeben.
+  if (!sizeof(str))
+  {
+    mixed *pur = Query(P_PURSUERS);
+    if ( pointerp(pur) && sizeof(pur) && objectp(pur[0]) )
+    {
+      pur[0]->RemovePursuer(this_object());
+      ReceiveMsg("Verfolgungsmodus abgeschaltet.", MT_NOTIFICATION);
+    }
+    else
+    {
+      ReceiveMsg("Du verfolgst doch ueberhaupt niemanden.", MT_NOTIFICATION);
+    }
+    return 1;
+  }
+  str=lower_case(str);
+  
+  // match_living() erlaubt die Pruefung, ob die Angabe eindeutig war.
+  int|string lv = match_living(str);
+  if ( intp(lv) )
+  {
+    if ( lv == -2 )
+      ReceiveMsg("Kein solches Wesen gefunden.", MT_NOTIFICATION);
+    else
+      ReceiveMsg(sprintf("verfolge: '%s' ist nicht eindeutig.\n", str),
+        MT_NOTIFICATION);
+    return 1;
+  }
+  
+  // Spieler zuerst auswaehlen, danach im Raum anwesende Lebewesen.
+  object ziel = find_player(lv) || present(lv, environment(this_player()));
+  
+  // Wurde kein Lebewesen gefunden, wird das erste Element aus der Liste der
+  // Lebewesen dieses Namens gewaehlt, falls vorhanden. Nur Lebewesen mit
+  // Environment kommen in Frage, denn sonst gibt es keinen Raum, in den der
+  // neue Verfolger bewegt werden koennte.
+  if ( !objectp(ziel) ) {
+    object* eligible_livings = filter(find_livings(lv), #'environment);
+    if (sizeof(eligible_livings))
+      ziel = eligible_livings[0];
+  }
+  
+  // Endlich etwas gefunden? Dann Verfolger eintragen und zum Ziel bewegen.
+  if ( objectp(ziel) )
+  {
+    if ( ziel == this_player() ) 
+    {
+      ReceiveMsg("Du kannst Dich nicht selbst verfolgen.", MT_NOTIFICATION);
+    }
+    else
+    {
+      ReceiveMsg(sprintf(
+        "Du verfolgst jetzt %s. [%s]", ziel->name(WEN), object_name(ziel)),
+        MT_NOTIFICATION, MA_MOVE);
+      ziel->AddPursuer(this_object());
+      ziel->TakeFollowers();
+    }
+  }
+  else
+  {
+    ReceiveMsg("Kein Wesen mit dem Namen '"+lv+"' gefunden, oder nur "
+      "solche ohne Environment.", MT_NOTIFICATION, 0, "verfolge: ");
+  }
+  return 1;
+}
+
+
+//                              #########
+//############################### TRANS #################################
+//                              #########
+
+static int _trans(string str)
+{
+  object living;
+
+  if (!sizeof(str))
+    return _notify_fail("Syntax: trans <spielername>\n"),0;
+  str=match_living(str,0);
+  if (intp(str))
+    switch (str)
+    {
+      case -1: write("Das war nicht eindeutig.\n"); return 1;
+      case -2: write("So ein Wesen gibt es nicht.\n"); return 1;
+    }
+  if(living=find_living(str))
+  {
+    if (living->move(object_name(environment()),
+                     M_TPORT|M_NOCHECK)<=0)
+    {
+      printf("Teleportieren von %s fehlgeschlagen.\n",living->Name(WEM));
+      if (IS_LEARNER(living))
+        tell_object(living,sprintf("%s wollte Dich teleportieren, "
+             "hat aber versagt!\n",capitalize(getuid())));
+      return 1;
+    }
+    tell_object(living,sprintf(
+    "Ein seltsames Gefuehl ueberkommt Dich ...\n"
+    "Du verlierst die Orientierung ...\n"
+    +(QueryProp(P_INVIS)?"":"%s holt Dich zu sich.\n"),
+    capitalize(getuid())));
+    printf("%s wurde herbeizitiert.\n",living->Name(WER));
+    return 1;
+  }
+  printf("Das Lebewesen '%s' konnte nicht gefunden werden.\n",
+         capitalize(str));
+  return 1;
+}
+
+//                             ###########
+//############################## FRIEDEN #################################
+//                             ###########
+
+static int _frieden(string sname)
+{
+  object *enem,obj;
+  int i;
+  string him;
+  
+  if (!sname)
+  {
+    enem=all_inventory(environment());
+    map_objects(enem,"StopHuntingMode");
+    tell_room(environment(),sprintf("%s stiftet Frieden.\n",capitalize(getuid())),
+              ({ this_object()}));
+    printf("Du stiftest Frieden.\n");
+    return 1;
+  }
+  else
+  {
+    if (!obj=find_living(sname))
+      return printf("Kein solches Lebewesen im Spiel.\n"),1;
+    him=(string)obj->name(WEM);
+    i=sizeof(enem=(object *)(((mixed *)obj->StopHuntingMode())[0]));
+    // Mistdriver ... object** waere richtig gewesen ... *seufz*
+    while(i--)
+    {
+      enem[i]->StopHuntFor(obj);
+      tell_object(obj,sprintf("%s beendet Deinen Kampf mit %s.\n",
+                              capitalize(getuid()),enem[i]->Name(WEM)));
+      tell_object(enem[0],sprintf("%s beendet Deinen Kampf mit %s.\n",
+                                  capitalize(getuid()),him));
+    }
+  }
+  printf("%s und alle Gegner wurden befriedet.\n",obj->Name(WER));
+  return 1;
+}
+
+//                              ########
+//############################### PWHO ##################################
+//                              ########
+
+#if __VERSION__ < "3.2.9"
+private int _pwho_learner_test(object ob)
+{
+  return !IS_LEARNER(ob);
+}
+#endif
+
+static int _pwho()
+{
+  mixed* spieler, res, *hands;
+  int i;
+#if __VERSION__ < "3.2.9"
+  spieler = filter(users(),#'_pwho_learner_test);
+#else
+  spieler = filter(users(),(: return !IS_LEARNER($1); :));
+#endif
+  spieler = sort_array(spieler, function int (object a, object b)
+      { return a->QueryProp(P_LEVEL) > b->QueryProp(P_LEVEL); } );
+  
+  res = "Lvl Name         Erfahrung   QP  Int Str Dex Con WC   "
+    "AC   HANDS HP  (max)\n"
+    "--------------------------------------------------------------"
+    "-----------------\n";
+  for (i=sizeof(spieler)-1; i>=0; i--)
+    res += sprintf("%3d %-12s %9d %5d %3d %3d %3d %3d %4d %4d  %5d "
+                   "%4d (%4d)\n",
+     spieler[i]->QueryProp(P_LEVEL),
+     capitalize(getuid(spieler[i])),
+     spieler[i]->QueryProp(P_XP),
+     spieler[i]->QueryProp(P_QP),
+     spieler[i]->QueryAttribute(A_INT),
+     spieler[i]->QueryAttribute(A_STR),
+     spieler[i]->QueryAttribute(A_DEX),
+     spieler[i]->QueryAttribute(A_CON),
+     spieler[i]->QueryProp(P_TOTAL_WC),
+     spieler[i]->QueryProp(P_TOTAL_AC),
+     (sizeof(hands=((int *)spieler[i]->QueryProp(P_HANDS)))?hands[1]:0),
+     spieler[i]->QueryProp(P_HP),
+     spieler[i]->QueryProp(P_MAX_HP));
+  More(res);
+  return 1;
+}
+
+//                             ##########
+//############################## ZWINGE #################################
+//                             ##########
+
+static int _zwinge(string str)
+{
+  object living;
+  string what, rest;
+  string living_name;
+
+  str = _unparsed_args();
+  if(!str|| sscanf( str, "%s %s", living_name, what ) != 2 )
+    return _notify_fail("Zwinge WEN zu WAS?\n"),0;
+  if( sscanf( what, "zu %s", rest ) == 1 ) what = rest;
+  if (!(living = find_living(living_name)))
+    return printf ("Ein Lebewesen namens '%s' konnte nicht gefunden werden!\n",
+                   capitalize(living_name)),1;
+  if (living->command_me(what))
+  {
+    printf("Du zwingst %s zu \"%s\".\n",capitalize(living_name),what);
+    if (!IS_ARCH(this_object())&&getuid()!=(string)living->QueryProp(P_TESTPLAYER))
+      log_file(SHELLLOG("ZWINGE"),
+               sprintf("%s zwingt %s (%s) zu %s [%s]\n",
+                       capitalize(getuid()),living->Name(),capitalize(getuid(living)),
+                       what,dtime(time())));
+  }
+  else
+    write("Hat leider nicht geklappt!\n");
+  return 1;
+}
+
+//                              #########
+//############################### HEILE #################################
+//                              #########
+
+static int _heile(string name)
+{
+  object ob;
+  int lpv, mpv;
+
+  if (!name) return USAGE("heile <name>");
+  name = lower_case(name);
+  if ((!(ob = present(name,environment())))
+      ||!living(ob))
+    ob = find_living(name);
+  if (!ob)
+  {
+    printf("'%s' ist momentan nicht da.\n",capitalize(name));
+    return 1;
+  }
+  lpv = (int)ob->QueryProp(P_HP);
+  mpv = (int)ob->QueryProp(P_SP);
+  ob->heal_self(1000000);
+  if (!IS_LEARNER(ob) && (!ob->QueryProp(P_TESTPLAYER)||
+          (((string)ob->QueryProp(P_TESTPLAYER))[<5..<1]=="Gilde")))
+    log_file(SHELLLOG("HEAL"),
+       sprintf("%s heilt %s (%s) %s (LP: %d -> %d, MP: %d -> %d)\n",
+         capitalize(geteuid(this_player())),
+         call_other(ob,"name"), capitalize(geteuid(ob)),
+         dtime(time()), lpv, (int)ob->QueryProp(P_HP),
+               mpv,(int)ob->QueryProp(P_SP)));
+  tell_object(ob, QueryProp(P_NAME) + " heilt Dich.\n");
+  printf("Du heilst %s.\n",capitalize(name));
+  return 1;
+}
+
+//                             ##########
+//############################## PEOPLE #################################
+//                             ##########
+
+private string _people_filename(object obj)
+{
+  string str;
+  str=object_name(environment(obj));
+  if (!str) return 0;
+  if (str[0..2] == "/d/") return sprintf("+%s",str[3..<1]);
+  if (str[0..8] == "/players/") return sprintf("~%s",str[9..<1]);
+  return str;
+}
+
+static int _people()
+{
+  mixed *list, res;
+  int i,j, a;
+  string a_age,a_ipnum,a_name,a_level,a_idle,a_room,a_end, a_title;
+
+  switch(QueryProp("tty"))
+  {
+    case "vt100":
+      a_ipnum = ""; a_name = ANSI_BOLD;
+      a_level = ANSI_NORMAL; a_idle = ANSI_BLINK;
+      a_room = ANSI_NORMAL; a_end = ANSI_NORMAL;
+      a_title = ANSI_INVERS; a_age = ANSI_NORMAL;
+      break;
+    case "ansi":
+      a_ipnum = ANSI_BLUE; a_name = ANSI_BOLD;
+      a_level = ANSI_RED; a_idle = ANSI_BLACK+ANSI_BOLD;
+      a_room = ANSI_BOLD+ANSI_BLUE; a_end = ANSI_NORMAL;
+      a_title = ANSI_INVERS; a_age = ANSI_PURPLE;
+      break;
+    default:
+      a_title = a_ipnum = a_name = a_level = a_idle = a_room = a_end = "";
+      a_age = "";
+  }
+  list = sort_array(users(), function int (object a, object b) {
+      return query_ip_number(a)>query_ip_number(b);} ); 
+
+  j=sizeof(list);
+  a=0;res="";
+  for(i=0; i<sizeof(list); i++) {
+    string name_; 
+    name_ = capitalize(list[i]->query_real_name()||"<logon>");
+    res += sprintf( "%s%-15s%s %s%-13s%s %s%3d%s %s %s %s%s%s%s %s%s\n",
+                    a_ipnum, query_ip_number(list[i]),a_end,a_name,
+                    (list[i]->QueryProp(P_INVIS)?"("+name_+")":name_),
+                    a_end,a_level, MASTER->get_wiz_level(getuid(list[i])),
+                    a_end,a_age,
+                    time2string("%4x %0X",((int)list[i]->QueryProp(P_AGE))*2),
+                    query_idle(list[i])>=300?(a++,(a_idle+"I")):" ",
+                    a_end,
+                    query_editing(list[i])?a_idle+"E"+a_end:" ",
+                    query_input_pending(list[i])?a_idle+"M"+a_end:" ",
+                    environment(list[i])?a_room+_people_filename(list[i]):"",
+                    a_end);
+  }
+  if (a)
+    res = sprintf("%s%d Spieler anwesend (%d aktiv). %s%s\n",a_title,j,
+                  (j-a),query_load_average(),a_end)+res;
+  else
+    res = sprintf("%s%d Spieler anwesend. %s%s\n",a_title,j,
+                  query_load_average(),a_end)+res;
+  More(res);
+
+  return 1;
+}
+
+
+//                             ###########
+//############################## SPIELER #################################
+//                             ###########
+
+private string _spieler_time2string(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;
+}
+
+
+static int _spieler(string arg)
+{
+  string dummy,ip;
+  object *spieler,pl;
+  int i;
+  
+  arg=_unparsed_args();
+  if(!sizeof(arg) || sscanf(arg,"aus ip %s",dummy)!=1)
+    return USAGE("spieler aus ip [von <spieler>|<ip>]");
+  arg=dummy;
+  if (sscanf(arg,"von %s",dummy)==1)
+  {
+    dummy=lower_case(dummy);
+    if (!(pl=find_player(dummy)))
+      return notify_fail(sprintf("Spieler '%s' konnte nicht gefunden "
+                                 "werden.\n",capitalize(dummy))),0;
+    ip=query_ip_number(pl);
+  }
+  else ip=arg;
+  ip=implode((explode(ip,".")-({""})+({"*","*","*","*"}))[0..3],".");
+if (catch(
+  spieler=filter(users(),
+    (: return sizeof(regexp(({query_ip_number($1)}),$2)); :),"^"+glob2regexp(ip)+"$")
+
+                                      ))
+  return printf("In der IP duerfen nur Zahlen(0-255), Punkte (.) und "
+                "Sterne (*) vorkommen.\n"),1;
+  if (!sizeof(spieler))
+    return printf("Es konnte kein Spieler mit der IP '%s' gefunden "
+                  "werden.\n",ip),1;
+  arg=sprintf("\nFolgende Spieler haben die IP %s:\n"
+       "================================================================"
+              "===========\n"
+       "Name:       Zweitie von:      Eingeloggt:                  "
+              "Idle seit:\n"
+       "----------------------------------------------------------------"
+              "-----------\n",ip);
+  i=sizeof(spieler);
+  while(i--)
+  {
+    arg+=sprintf("%-11s %-17s %26s  %-15s\n",
+                 capitalize(getuid(spieler[i])),
+                 ((dummy=(string)spieler[i]->QueryProp(P_SECOND))?
+                  (sizeof((mixed *)call_other(master(),
+                                              "get_userinfo",dummy))?
+                   capitalize(dummy):"*ungueltig*"):""),
+                 dtime(spieler[i]->QueryProp(P_LAST_LOGIN)),
+                 _spieler_time2string(query_idle(spieler[i])));
+  }
+  arg+="==============================================================="
+    "============\n\n";
+  More(arg);
+  return 1;
+}
diff --git a/std/shells/magier/todo.c b/std/shells/magier/todo.c
new file mode 100644
index 0000000..f4120e7
--- /dev/null
+++ b/std/shells/magier/todo.c
@@ -0,0 +1,222 @@
+// $Id: todo.c 9142 2015-02-04 22:17:29Z Zesstra $
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#include <wizlevels.h>
+#include <defines.h>
+#define NEED_PROTOTYPES
+#include <magier.h>
+#include <player.h>
+
+#define SAVEFILENAME sprintf("/players/%s/.todoliste",getuid())
+
+private nosave status todo_initialized;
+private nosave mixed *todo_data;
+mixed *todo_data_public;
+static mixed _query_localcmds()
+{
+  return ({
+    ({"todo","_todo",0,WIZARD_LVL})});
+}
+
+private void todo_save()
+{
+
+  int i,j;
+  string a,b;
+  a=SAVEFILENAME+".o";
+  rm(a);
+  if (j=sizeof(todo_data))
+  {
+#if !__EFUN_DEFINED__(save_value)   
+    write_file(a,"#0:0\ntodo_data_public ({");
+    for (i=0;i<j;i++)
+    {
+      b=regreplace(todo_data[i][1],"\"","\\\"",1);
+      b=regreplace(b,"\n","\\n",1);
+      write_file(a,sprintf("({%d,\"%s\",}),",
+                           todo_data[i][0],b));
+    }
+    write_file(a,"})\n");
+#else
+    todo_data_public=todo_data;
+    write_file(a,save_value(todo_data_public));
+    todo_data_public=0;
+#endif
+  }
+  return;
+
+}
+
+static void initialize()
+{
+  if(!IS_WIZARD(this_object())) return;
+  if (!restore_object(SAVEFILENAME)) todo_data=({});
+  else
+    {
+      todo_data=todo_data_public;
+      todo_data_public=0;
+    }
+  return;
+}
+
+static void _todo_neu2(string input,string carry)
+{
+  if (input=="q"||(input=="."&&!sizeof(carry)))
+  {
+    printf("Abbruch!");
+    return;
+  }
+  if (input!=".")
+  {
+    printf("]");
+    input_to("_todo_neu2",0,carry+input+"\n");
+    return;
+  }
+  todo_data+=({ ({ time(), carry }) });
+  todo_save();
+  printf("Eintrag angelegt. Laufende Nummer ist %d.\n",sizeof(todo_data));
+  return;
+}
+
+private int _todo_neu(string cmdline)
+{
+  if (cmdline!="neu") return 0;
+  printf("Was musst Du noch machen? (Abbruch mit 'q', "
+         "Ende mit '.')\n]");
+  input_to("_todo_neu2",0,"");
+  return 1;
+}
+
+private int _todo_loeschen(string cmdline)
+{
+  int nr;
+  if (!sscanf(cmdline,"loeschen %d",nr))
+    return notify_fail("Welchen Eintrag moechtest Du loeschen?\n"),0;
+  if (!sizeof(todo_data))
+    return notify_fail("Deine Todo-Liste hat ja ueberhaupt keinen "
+                       "Eintrag!\n"),0;
+  if (nr>sizeof(todo_data))
+  {
+    printf("Deine Todo-Liste hat nur %d Eintra%s.\n",sizeof(todo_data),
+           (sizeof(todo_data)==1?"g":"ege"));
+    return 1;
+  }
+  todo_data[nr-1]=0;
+  todo_data-=({0});
+  todo_save();
+  printf("Eintrag Nummer %d wurde geloescht. Da hast Du ja ordentlich "
+         "was geschafft...\noder geschickt delegiert ;-)\n",nr);
+  return 1;
+}
+
+private int _todo_anzeigen(string cmdline)
+{
+  int nr1,nr2;
+  string output;
+  if (!sizeof(todo_data))
+    return notify_fail("Deine Todo-Liste hat keine Eintraege.\n"),0;
+  switch(sscanf(cmdline,"anzeigen %d bis %d",nr1,nr2)) 
+  {
+  case 0: nr1=1; nr2=sizeof(todo_data); break;
+  case 1: nr2=nr1; break;
+  case 2: break;
+  }
+  if (nr1<0) nr1=sizeof(todo_data)+nr1+1;
+  if (nr2<0) nr2=sizeof(todo_data)+nr2+1;
+  if (nr1<1||nr2<1||nr1>sizeof(todo_data)||nr2>sizeof(todo_data))
+    return notify_fail(sprintf("Deine Todo-Liste hat (gluecklicherweise) "
+                               "nur %d Eintra%s.\n",sizeof(todo_data),
+                               (sizeof(todo_data)>1?"ege":"g"))),0;
+  output="\n-----------------------------------------------------------------------------\n";
+  if (nr1>nr2) // Rueckwaerts
+  {
+    while(nr1>=nr2)
+      output+=sprintf("Eintrag Nr. %d von %s:\n%s\n\n",nr1--,
+           dtime(todo_data[nr1][0]),break_string(todo_data[nr1][1],78,5,
+                                       BS_LEAVE_MY_LFS));
+  }
+  else
+  {
+    nr1--;
+    while (nr1<nr2)
+      output+=sprintf("\nEintrag Nr. %d von %s:\n%s\n",(nr1+1),
+           dtime(todo_data[nr1][0]),break_string(todo_data[nr1++][1],78,5,
+                                       BS_LEAVE_MY_LFS));
+  }
+  More(output+"-----------------------------------------------------------------------------\n");
+  return 1;
+}
+
+private int _todo_verschieben(string cmdline)
+{
+  int from;
+  mixed to,dummy;
+  if (!(sscanf(cmdline,"verschieben %d nach %d",from,to)==2||
+        sscanf(cmdline,"verschieben %d nach %s",from,to)==2))
+    return 0;
+  from--;
+  if (stringp(to))
+  {
+    switch(to)
+    {
+      case "oben": to=from-1; break;
+      case "unten": to=from+1; break;
+      default: return 0;
+    }
+  }
+  else to--;
+  if (to==from) return notify_fail("Da ist der Eintrag ja schon!\n"),0;
+  if (from<0||from>=sizeof(todo_data)) return notify_fail(
+        "Wie willst Du einen nicht existenten Eintrag verschieben?\n"),0;
+  if (to<0||to>=sizeof(todo_data)) return notify_fail(
+        "Dahin kannst Du den Eintrag nicht verschieben.\n"),0;
+  dummy=todo_data[from];
+  if (to>from)
+    while (from++<to) todo_data[from-1]=todo_data[from];
+  else
+    while(from-->to) todo_data[from+1]=todo_data[from];
+  todo_data[to]=dummy;
+  printf("Eintrag wurde verschoben.\n");
+  return 1;
+}
+
+private int _todo_hilfe()
+{
+  printf(
+  "-------------------------------------------------------------------------------\n\n"
+  " Die Todo-Liste laesst sich mit den folgenden Befehlen steuern:\n\n"
+  " todo neu                                - Legt einen neuen Eintrag an.\n"
+  " todo loeschen <nummer>                  - Loescht einen Eintrag.\n"
+  " todo anzeigen [<nummer> [bis <nummer>]] - Zeigt die Todo-Liste an.\n"
+  " todo verschieben <nummer> nach <ziel>   - Verschiebt einen Eintrag.\n\n"
+  " <ziel> kann eine Zahl oder die Worte 'oben' oder 'unten' sein.\n"
+  "-------------------------------------------------------------------------------\n");
+  return 1;
+}
+
+
+static int _todo(string cmdline)
+{
+  string *args;
+  
+  cmdline=_unparsed_args(1);
+  notify_fail("Falsche Syntax. 'todo hilfe' zeigt eine Hilfe an.\n");
+  if (sizeof(cmdline))
+  {
+    args=explode(cmdline," ");
+    switch(args[0])
+    {
+      case "neu":         return _todo_neu(cmdline);
+      case "loeschen":    return _todo_loeschen(cmdline);
+      case "anzeigen":    return _todo_anzeigen(cmdline);
+      case "verschieben": return _todo_verschieben(cmdline);
+      case "hilfe":       return _todo_hilfe();
+     default:            return 0;
+    }
+  }
+  return 0;
+}
diff --git a/std/shells/magier/upd.c b/std/shells/magier/upd.c
new file mode 100644
index 0000000..f09ea9a
--- /dev/null
+++ b/std/shells/magier/upd.c
@@ -0,0 +1,563 @@
+// MorgenGrauen MUDlib
+//
+// upd.c
+//
+// $Id: upd.c 8850 2014-06-13 21:34:44Z Zesstra $
+#pragma strict_types
+#pragma save_types
+#pragma range_check
+#pragma no_clone
+#pragma pedantic
+
+#define NEED_PROTOTYPES
+#include <magier.h>
+#include <player.h>
+#undef NEED_PROTOTYPES
+#include <debug_info.h>
+#include <wizlevels.h>
+#include <moving.h>
+#include <properties.h>
+#include <logging.h>
+#include <thing/properties.h>
+
+varargs static int _make(string file, int flags, int recursive);
+
+static mixed _query_localcmds()
+{
+  return ({({"upd","_upd",0,LEARNER_LVL}),
+           ({"load","_load",0,LEARNER_LVL})});
+}
+
+//
+// _save(): Spieler in Rettungsraum retten
+// obj:      Spielerobjekt(?)
+// inv_save: Rettungsraumname 
+// Rueckgabe: 0 wenn kein Spielerobjekt
+//            Spielerobjekt, falls doch
+//
+
+static mixed _save( object obj, object inv_saver )
+{ 
+    if ( query_once_interactive(obj) )
+      { 
+        obj->move( inv_saver, NO_CHECK );
+        return obj;
+      }
+    return 0;
+}
+
+
+//
+// _reload(): Objekt laden
+// file:  Filename. Muss in der Form /xx/xx/xx.c vorliegen
+// clone:  > 0 -> Es soll geclont werden, enthaelt Objektnummer des
+//                Vorgaengerobjektes
+// flags: Kommandozeilenoptionen
+// err:   Leerstring als Referenz uebergeben. Enthaelt nach dem
+//        Aufruf vom _reload() die Fehlermeldungen als String.
+// Rueckgabe: Das neu erzeugte Objekt bzw. das schon vorhandene Objekt
+//            bzw. 0, wenn Fehler auftrat.
+//
+
+private object _reload(string file, int clone, int flags, string err)
+{
+  object obj;
+  
+  if (!obj=find_object(file[0..<3]+(clone?("#"+clone):"")))
+  {
+    int pos,pos2;
+    string bt;
+
+    if(file_size(file)<0)
+    {
+      if (file_size(file)==-1)
+        err = sprintf("upd: %s: Datei existiert nicht.\n", file);
+      else // directory
+        err = sprintf("upd: %s: Verzeichnisse koennen nicht geladen "
+                      "werden.\n",file);
+      return obj; // 0
+    }
+    pos = max(file_size(__DEBUG_LOG__),0);
+
+    if ((err = (clone?catch(obj = clone_object(file)):
+                catch(load_object(file)) )) && (flags & UPD_B))        
+    {     
+      if (( pos2=file_size(__DEBUG_LOG__)) > pos )
+        err+=sprintf("\nBacktrace:\n%s",
+                     read_bytes(__DEBUG_LOG__,pos, pos2-pos ));
+      else
+        err+=sprintf("\nKEIN BACKTRACE VERFUEGBAR!\n");
+    }
+    if (!err&&!obj&&(!obj = find_object(file[0..<3])))
+      err += sprintf( "upd: %s: Blueprint nach dem Laden zerstoert.\n",file );
+  }
+  else
+    err=sprintf("upd: Objekt existiert schon: %O\n",obj);
+  return obj;
+}
+
+
+//
+// _update(): File updaten -> Blueprint destructen
+// file:  Filename
+// dummy: simulieren? (1->wird nicht aktualisiert)
+// flags: Kommandozeilenoptionen
+// Rueckgabe: -1: Keine Vollzugriff
+//             0: Objekt ist nicht geladen
+//             1: Operation wird durchgefuehrt
+//
+
+private varargs int _update(string file, int dummy, int flags)
+{
+  object obj;
+  string err;
+  if (!dummy && !objectp(obj = find_object(file))) return 0;
+  if (!IS_ARCH(this_object()))
+  {
+    // Schreibrechte nur pruefen, wenn echt aktualisiert werden soll.
+    if(!dummy && !MAY_WRITE(file))
+      return (printf("upd: %s: Keine Schreibrechte!\n",file), -1);
+    if(!MAY_READ(file)) 
+      return (printf("upd: %s: Keine Leserechte!\n", file), -1);
+  }
+  if (dummy) return 1;
+  
+  if ( flags & UPD_D )
+  {
+    object *inv;
+    if (sizeof(inv = deep_inventory(obj)))
+    {
+      printf("upd: %s: Entferne Objekte im Inventar\n", file );
+      if (!(flags&UPD_H))
+      {
+        if(err=catch(filter_objects( inv, "remove", 1 )))
+          printf("upd: %s: Fehlgeschlagen. Grund:\n%s\n",
+                 file,err);
+      }
+      if (sizeof(inv = deep_inventory(obj)))
+        filter(inv, function void (object ob)
+            {destruct(ob);});
+    }
+  }
+  if (!(flags&UPD_H))
+  {
+    if(err = catch(obj->remove()))
+      printf("upd: %s: remove() fehlgeschlagen. Aufruf von " +
+             "destruct().\n",file);
+  }
+  if(objectp(obj)) destruct(obj);
+  return 1;
+}
+
+
+//
+// _instance_upd(): Alle Objekte nach Clones des Objekts durchsuchen
+// file:  Filename des Objektes
+// flags: Kommandozeilenargumente
+// obj:   Aktuelles Objekt
+// instances: Zahl der gefundenen Instanzen
+//
+
+private void _instance_upd(string file, int flags, mixed obj, int instances,
+                           int firstcall)
+{
+ int i;
+ if (firstcall)
+    printf("upd: %s: %s Instanzen.\n",file,flags&UPD_A?"Aktualisiere":"Suche");
+  
+  while (get_eval_cost()>220000 && i < sizeof(obj))
+  {
+    if (!objectp(obj[i]))
+      instances--;
+    else
+    {
+      if (flags&UPD_F&&!(flags&UPD_S))
+        printf( "upd: %O gefunden in %s\n", obj[i],
+                environment(obj[i])?object_name(environment(obj[i])) 
+                : "keiner Umgebung" );
+      if (flags&UPD_A) _make(object_name(obj[i]), flags & ~(UPD_A|UPD_F),1 );
+    }
+    i++;
+  }
+  if (i < sizeof(obj)) 
+    call_out( #'_instance_upd/*'*/,2,file,flags,obj[i..],instances,0);
+  else
+    printf( "upd: %s: %d Instanzen %s\n", file, instances,
+            (flags & UPD_A) ? "aktualisiert" : "gefunden" );
+  return;
+}
+  
+  
+//
+// _do_make(): Alle geerbten Objekte bearbeiten (fuer -m/-v)
+// file:  Name des Files
+// clone: 0, wenn blueprint, ansonsten Clonenummer
+// flags: Kommandozeilenparameter
+// dep:   geschachteltes Array mit Meldungen (wg. Rekursion)
+// ready: Array der schon bearbeiteten Objekte (wg. Rekursion)
+// Rueckgabe: Array der Objektnamen, die bearbeitet wurden
+//            (Array in Array in ...)
+// 
+
+varargs private int _do_make( string file,int clone,int flags,mixed dep,
+                              string *ready )
+{
+  object obj;
+  string err;
+  string *ilist;
+  mixed downdeps;
+  int ret;
+  
+  if (!pointerp(ready)) ready = ({});
+  ready += ({ file });
+  
+  if ( !(obj = _reload(file,clone,flags,&err)))
+  {
+    dep += ({ err });
+    return 0;
+  }
+  
+  ilist = inherit_list(obj)-ready;
+  
+  downdeps = ({});
+  
+  while (sizeof(ilist))
+  {
+    ret = _do_make( ilist[0],0,flags, &downdeps, &ready )||ret;
+    ilist[0..0] = ({});
+    ilist -= ready;
+  }
+  
+  if ( ret||file_time(file)>program_time(obj)||(flags &UPD_I))
+    if ( _make( file, flags & ~(UPD_M|UPD_I) ,1) < 0 ) 
+      dep = ({ "{" + explode(file,"/")[<1] + "}", downdeps });
+    else{
+      dep = ({ "[" + explode(file,"/")[<1] + "]", downdeps });
+      ret = 1;
+    }
+  else if (flags&UPD_V) dep += ({ explode(file,"/")[<1], downdeps });
+  return ret;
+}
+
+
+//
+// _make_dep(): Ausgabe des Ererbungsbaumes
+// Objekte im Array dep
+// prefix enthaelt Zeilenanfang (fuer Rekursion)
+// Rueckgabe: String mit dem Vererbungsbaum des Objektes
+//
+
+private string _make_dep( mixed dep, string prefix )
+{
+  string ret;
+  int i, size;
+  
+  ret="";
+  size=sizeof(dep);
+  for (i=0; i<size;i++)
+    if (pointerp(dep[i]))
+      ret += _make_dep(dep[i],prefix + (i < (size-1) ? "| ":" "));
+    else 
+      ret += prefix + "+-" + dep[i] + "\n";
+  return ret;
+}
+
+
+//
+// _illegal_closure(): ist closure in arg an objekt gebunden?
+// arg: closure(-array/mapping)
+// Rueckgabe: 0 wenn alles okay
+//            1 wenn closure geloescht werden muss
+//
+
+private int _illegal_closure( mixed arg )
+{
+  int i, j;
+  string *indices;
+  
+  if ( closurep(arg) && !objectp(query_closure_object(arg)) )
+    return 1;
+  
+  if ( pointerp(arg) ){
+    for ( i = sizeof(arg); i--; )
+      if ( _illegal_closure(arg[i]) )
+        return 1;
+  }
+  else if ( mappingp(arg) ){
+    indices = m_indices(arg);
+    for ( i = sizeof(indices); i--; )
+      for ( j = get_type_info( arg, 1 ); j--; )
+        if ( _illegal_closure(arg[indices[i], j]) )
+          return 1;
+  }
+  return 0;
+}
+
+//
+// _make(): Update file
+// file:  Filename
+// flags: Kommandozeilenargumente
+//
+
+varargs static int _make(string file, int flags,int recursive)
+{
+  string msg, err, blue;
+  int inst;
+  object obj, inv_saver;
+  mixed tmp;
+  
+  msg = "";
+
+  if (!file) return printf( "upd: Kein Filename uebergeben!\n" ), RET_FAIL;
+    
+// Filename in Blue, Objektname in blue, Instanznummer in inst
+
+  if (sscanf(file,"%s#%d",blue,inst)==2) blue += ".c";
+  else blue = file + (file[<2..]==".c" ? "" : ".c");
+
+// Alle Instanzen durchsuchen im Falle von -a oder -f 
+
+  if ((flags & UPD_LOAD)&&find_object(file))
+    return printf("load: %s: Objekt ist schon geladen.\n",file),RET_OK;
+  
+  if ( flags & (UPD_F|UPD_A))
+  {
+    if (inst) return printf( "upd: %s: Eine Instanz kann keine " +
+                             "Clones haben.\n",file ), RET_FAIL;
+    if ((tmp=_update(file, 1,flags))==-1) 
+      return printf( "upd: %s: Kein Vollzugriff auf die " +
+                     "Datei erlaubt.\n",file), RET_FAIL;
+    if (tmp==0) return RET_FAIL;
+
+   tmp=clones(blue[0..<3],2);
+    if (sizeof(tmp))
+      call_out( #'_instance_upd/*'*/, 0, file,flags,tmp,sizeof(tmp),1);
+    else
+      printf( "upd: %s: Keine Clones vorhanden!\n", blue[0..<3]);
+
+    if ( (flags & UPD_F) && !(flags &(UPD_R|UPD_L|UPD_LOAD))) return RET_OK; 
+    // Nichts laden -> Auch kein Backup
+  }
+
+// Backupraum festlegen
+   
+  if( blue==INV_SAVE ) {
+                printf("upd: Achtung: Raum zum Zwischenspeichern soll geladen werden?!\n");
+        } 
+  if ( !(inv_saver=load_object(INV_SAVE)) )
+  {
+    printf("upd: %s: Raum zum Zwischenspeichern des " +
+           "Rauminhalts ist nicht ladbar.\n" +
+           "         %s\n",file,INV_SAVE);
+    return RET_FAIL;
+  }
+
+// Wenn das Objekt existiert bzw. Deep aktualisiert werden soll
+
+  if ( (!(flags&UPD_LOAD))&&
+       ((obj = find_object(file)) || (flags & (UPD_M|UPD_I))))
+  {
+    object *inv, env, *pl_inv;
+    mapping pro;
+    int i;
+    mixed configdata;
+    int restore_config;
+
+    // Wenn Objekt existiert, dann Inhalt und ggf. Daten aus Configure() oder
+    // Props sichern:
+    if (obj)
+    {
+      // im Fall UPD_C erfolgt _kein_ Auslesen und _keine_ Restauration
+      // mittels Configure()
+      if ( ! (flags & UPD_C ) )
+      {
+        catch(restore_config=(mixed)call_resolved(&configdata,obj,
+                                                  "Configure",0);
+              publish);
+        // Wenn UPD_CONF gesetzt wird, _muss_ das Objekt ein oeffentliches
+        // Configure() definieren, sonst erfolgt Abbruch.
+        if ((flags & UPD_CONF) && !restore_config)
+        {
+          printf("upd: %s: hat kein Configure(), Zerstoerung abgebrochen.\n",file);
+          return RET_FAIL;
+        }
+      }
+      if (!(flags&UPD_D)&&(flags&(UPD_L|UPD_R)))
+      {
+        if (i=sizeof(inv=(all_inventory(obj)-({0}))))
+        {
+          mixed items;
+          // Herausbekommen, ob hier Items existieren, die per AddItem 
+          // erzeugt werden. Die duerfen nicht gesichert werden.
+          items=(mixed)obj->QueryProp(P_ITEMS); // mixed, da array of arrays
+          if (pointerp(items)&&sizeof(items))
+          {
+            items=transpose_array(items)[0];
+            while (i--)
+              if (member(items, inv[i])==-1)
+                    inv[i]->move(inv_saver,NO_CHECK);
+          }
+          else // In diesem Objekt sind keine Items gesetzt.
+            while (i--) inv[i]->move(inv_saver,NO_CHECK);
+        }
+      }
+      else
+      {
+        inv=map( deep_inventory(obj), #'_save/*'*/, inv_saver )-({0});
+      }
+      env = environment(obj);
+      if ( flags & UPD_C )
+      {
+        pro = (mapping)(obj->QueryProperties());
+      }
+    }
+    else inv = ({});
+
+// Ererbte Objekte durchsuchen.
+    if ( flags & (UPD_M|UPD_I) )
+    {
+      mixed dep;
+      dep = ({});
+      _do_make( blue, inst, flags & ~(UPD_M|UPD_L|UPD_R|UPD_F|UPD_A), &dep );
+      printf( _make_dep( dep, "" ) + "\n" );
+    }
+   
+// Tatsaechlichen Update durchfuehren
+   
+    if ( _update(file, 0, flags)< 0) return RET_FAIL;
+    msg += (inst ? "zerstoert" : "aktualisiert");
+    
+// Neu laden ??
+    if ( flags & (UPD_R|UPD_L) )
+    {
+      if ( obj = _reload( blue,inst,flags, &err ) )
+        msg += ", " + (inst ? "neu geclont" : "neu geladen");
+     
+// Neu geladen: Properties wiederherstellen, Closures filtern 
+      if (!err)
+      {
+        if (!obj) obj = find_object(file);
+        // Wenn gewuenscht, Props zurueckschreiben (hat Prioritaet vor
+        // Configure(), weil explizit vom Magier angefordert).
+        if ( pro && (flags & UPD_C) )
+        {
+          string *names;
+          
+          names = m_indices(pro);
+          
+          // Closures in (mittlerweile) zerstoerten Objekten
+          // rausfiltern, damit die (hoffentlich korrekten) Closures
+          // im neu geclonten Objekt erhalten bleiben
+          for ( i = sizeof(names); i--; )
+            if ( _illegal_closure(pro[names[i], F_VALUE]) ||
+                 _illegal_closure(pro[names[i], F_QUERY_METHOD]) ||
+                 _illegal_closure(pro[names[i], F_SET_METHOD]) )
+              m_delete( pro, names[i] );
+          
+          obj->SetProperties(pro);
+          msg += ", Properties gesetzt";
+        }
+        // Wenn kein UPD_C, wird ggf. das Ergebnis von Configure() wieder
+        // uebergeben.
+        else if (restore_config)
+        {
+          int conf_res;
+          if (!catch(conf_res=(int)obj->Configure(configdata); publish)
+              && conf_res == 1)
+          {
+            msg += ", (re-)konfiguriert";
+          }
+          else
+          {
+            msg += ", (Re-)Konfiguration fehlgeschlagen";
+            if (flags & UPD_CONF)
+              printf("upd: Daten von %s konnten nicht rekonfiguriert werden: "
+                           "%O\n", file, configdata);
+          }
+        }
+        if (env)
+        {
+          if ( obj->move( env, NO_CHECK ) <= 0 )
+            printf( "upd: /%O konnte nicht in /%O zurueckbewegt werden\n",
+                    obj, env );
+          else
+            msg += ", bewegt";
+        }
+        if (i=sizeof(inv))
+        {
+          while(i--) if (inv[i]) inv[i]->move(obj, NO_CHECK );
+          msg += ", Inhalt zurueckbewegt";
+        }
+      }
+      else 
+        return printf( "upd: %s: %s", file, err ), RET_FAIL;
+    }
+  }
+  else 
+    if ( !_update(file, 0, flags) && (flags & (UPD_L|UPD_LOAD)) )
+      if ( !_reload( blue, inst, flags, &err ) )
+        return printf( "%s: %s: %s", (flags&UPD_LOAD?"load":"upd"),file, err ),
+          RET_FAIL;
+      else
+        msg += "geladen";
+  
+  if ( sizeof(msg)&&!(flags&UPD_S&&recursive) )
+    printf("%s: %s: %s.\n",(flags&UPD_LOAD?"load":"upd"),file,msg);
+  return RET_OK;
+}
+
+//
+// _upd: Objekte laden, zerstoeren und aktualisieren
+//
+
+static int _upd(string cmdline)
+{
+  int flags;
+  mixed *args;
+
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,UPD_OPTS,1);
+  if(flags==-1||!sizeof(args))
+    return USAGE("upd [-"+UPD_OPTS+"] <datei> [<datei> ..]");
+  if ((flags & UPD_C) && (flags & UPD_CONF))
+  {
+    printf("upd: -c und -C gleichzeitig werden nicht unterstuetzt.\n");
+    return 1;
+  }
+  args=file_list(args,MODE_UPD,0,"/");
+  if(!sizeof(args)) return printf("upd: Keine passende Datei gefunden!\n"),1;
+
+  args=map(args,(: $1[FULLNAME] :))-({0});
+
+  if(!sizeof(args))
+  {
+    printf("upd: Verzeichnisse koennen nicht aktualisiert werden!\n");
+    return 1;
+  }
+  asynchron(args,#'_make,flags,0,0);
+  return 1;
+}
+
+//
+// _load: Objekte laden
+//
+
+static int _load(string cmdline)
+{
+  int flags;
+  mixed *args;
+
+  cmdline=_unparsed_args();
+  args=parseargs(cmdline,&flags,"",1);
+  if(flags==-1||!sizeof(args))
+    return USAGE("load <datei> [<datei> ..]");
+  args=file_list(args,MODE_UPD,0,"/");
+  if(!sizeof(args)) return printf("load: Keine passende Datei gefunden!\n"),1;
+  args=map(args,(: (($1[FILESIZE]!=-2||find_object($1[FULLNAME]))?
+                          $1[FULLNAME]:0) :))-({0});
+
+  if(!sizeof(args))
+    return printf("load: Verzeichnisse koennen nicht geladen werden!\n"),1;
+  asynchron(args,#'_make,UPD_LOAD,0,0);
+  return 1;
+}
diff --git a/std/shells/orc.c b/std/shells/orc.c
new file mode 100644
index 0000000..95c73f6
--- /dev/null
+++ b/std/shells/orc.c
@@ -0,0 +1,203 @@
+#pragma strong_types,save_types
+
+inherit "std/player/base";
+
+#include <properties.h>
+#include <attributes.h>
+#include <wizlevels.h>
+#include <health.h>
+#include <new_skills.h>
+#include <language.h>
+#include <combat.h>
+#include <defines.h>
+#include <defuel.h>
+
+/*
+ * Orks:
+ * Orks sind eigentlich boese und blutruenstig, was auch oft genug zum 
+ * Vorschein tritt :) Wenn ein Ork zu heftig forscht, quengelt er rum 
+ * und weigert sich, bis er nicht wieder ein bisschen Blut verspritzt
+ * hat,
+*/ 
+#define F_MAX 500
+#define F_DEG 3 
+#define NO_EXAMINE ({ \
+    "Du knurrst: Ich will Blut, keine Bluemchen.", \
+    "Du grummelst: Bin ich ein Forscher, oder was?" \
+    })
+
+static int f_cnt, f_deg;
+
+int 
+QueryFCnt() {
+  return f_cnt;
+}
+
+int 
+SetFCnt(int fc) {
+  if(fc > -1 && fc < F_MAX)
+    f_cnt = fc;
+  return f_cnt;
+}
+  
+int
+QueryFDeg() {
+  return f_deg;
+}
+
+void 
+create() {
+  if (!clonep() || object_name(this_object()) == __FILE__[0..<3]) {
+      set_next_reset(-1);    
+      return;
+  }
+
+  mixed res;
+
+  base::create();
+
+  f_cnt=0;
+  f_deg=F_DEG;
+  
+  SetDefaultHome("/d/vland/morgoth/room/city/rathalle");
+  SetDefaultPrayRoom("/d/vland/morgoth/room/city/c0606");
+  SetProp(P_ATTRIBUTES_OFFSETS,([A_STR:3,A_INT:-1,A_CON:2]));
+  /* Kleine aeh grosse Muskelpakete */
+  SetProp(P_SKILL_ATTRIBUTE_OFFSETS,([SA_DAMAGE:110]));
+  SetProp(P_AVERAGE_SIZE,195);
+  SetProp(P_AVERAGE_WEIGHT,125000); // ziemlich schwer, viele Muskeln
+  SetProp(P_MATERIAL_KNOWLEDGE,([MATGROUP_DEAD:60,
+                                 MATGROUP_BIO:40, 
+                                 MATGROUP_ELEMENTAL: 20, 
+                                 MAT_BLOOD:100]));
+  SetProp(P_CHANNELS, QueryProp(P_CHANNELS) + ({"Uruk-Hai"}));
+  SetProp(P_RESISTANCE_STRENGTHS,
+	  ([ 
+     DT_FIRE : -0.2,
+     DT_HOLY :0.3,
+     DT_UNHOLY : -0.2,
+	   DT_ACID : 0.2 ]));
+
+  SetProp(P_MAX_FOOD,110);
+  SetProp(P_MAX_DRINK,110);
+  SetProp(P_MAX_ALCOHOL,150);
+  SetProp(P_DEFUEL_LIMIT_FOOD,50);
+  SetProp(P_DEFUEL_LIMIT_DRINK,70);
+  SetProp(P_DEFUEL_TIME_FOOD,300);
+  SetProp(P_DEFUEL_TIME_DRINK,400);
+  SetProp(P_DEFUEL_AMOUNT_FOOD,0.4);
+  SetProp(P_DEFUEL_AMOUNT_DRINK,0.35);
+
+  /* SP regenerieren sie nich ganz so schnell, dafuer sind sie
+   * ein bischen schneller bei Gift und Futter */
+  SetProp(P_SP_DELAY,HEAL_DELAY+1);
+  SetProp(P_POISON_DELAY,POISON_DELAY-1);
+  SetProp(P_FOOD_DELAY,FOOD_DELAY-1);
+
+  SetProp(P_MAGIC_RESISTANCE_OFFSET,
+          ([ MT_ANGRIFF : 500,
+        	   MT_ILLUSION : -250,
+             MT_BEHERRSCHUNG : -250,
+        	   MT_VERWANDLUNG : 500 ]));
+
+
+  if(!(res=QueryProp(P_HANDS)) || !pointerp(res) || (sizeof(res)<3))
+    res=({" mit starken Haenden",35,({DT_BLUDGEON, DT_RIP}) });
+  SetProp(P_HANDS,res);
+  /* Orks haben dicke Haut */
+  SetProp(P_BODY,20);
+
+  /* Groesse wird nur einmal gesetzt */
+  if(!QueryProp(P_SIZE)){
+    SetProp(P_SIZE,180+random(31));
+    Set(P_SIZE,SAVE,F_MODE_AS);
+  }
+
+  /* Dito Gewicht */
+  if(!QueryProp(P_WEIGHT) || (QueryProp(P_WEIGHT) == 75000)){
+    SetProp(P_WEIGHT,100000+random(25001)+random(25001));
+    Set(P_WEIGHT,SAVE,F_MODE_AS);
+  }
+}
+
+string 
+_query_race() {
+  return "Ork";
+}
+
+string 
+_query_real_race() {
+  return "Ork";
+}
+
+string 
+_query_racedescr() {
+  return break_string("Ein Ork. Die brutale Macht des Boesen. Ein "
+      "erbitterter Kaempfer, ohne Furcht vor dem Tod. So stellst Du "
+      "Dir einen Ork vor.\nDiese Orks sehen vielleicht ausserlich so "
+      "aus: Eine dicke und dunkle, lederartige Haut, die sicher "
+      "einiges an Schlaegen abhaelt. Lange Eckzaehne, die sicher boese "
+      "Wunden reissen koennen.\nDu spuerst, dass diese Orks hier ein "
+      "wenig anders sind. Ihren Drang nach dem Blut ihrer Feinde scheinen "
+      "sie recht gut unter Kontrolle zu haben, die meiste Zeit zumindest. "
+      "Sie sind in der Lage, friedlich zwischen den anderen Rassen zu "
+      "wandeln. Dennoch sind vor allem die Uruk-Hai Orks als Gegner nicht "
+      "zu unterschaetzen, sollte es doch einmal zu einem Kampf kommen.",
+      78,0,BS_LEAVE_MY_LFS);
+}
+
+int 
+QueryAllowSelect() { 
+  return 1; 
+}
+
+string 
+*_query_racestring() {
+  if (QueryProp(P_GENDER)==FEMALE)
+    return ({"Orkin","Orkin","Orkin","Orkin"});
+  return ({"Ork","Orkes","Ork","Ork"});
+}
+
+string 
+_query_default_guild(){
+  return "urukhai";
+}
+
+mixed 
+RaceDefault(string arg) {
+  if (!arg)
+    return 0;
+  switch(arg) {
+    case P_HANDS :
+      return ({" mit starken Haenden",35,({DT_BLUDGEON,DT_RIP}) });
+    case P_BODY :
+      return 25;
+  }
+  return base::RaceDefault(arg);
+}
+
+protected void heart_beat() {
+  ::heart_beat();
+
+  if(f_cnt > 0 && !--f_deg) {
+    f_cnt--;
+    f_deg=F_DEG;
+  }
+}
+
+void
+Attack(object enemy) {
+  if(f_cnt > 0)
+    f_cnt--;
+  return ::Attack(enemy);
+}
+
+varargs int 
+_examine(string str, int mode) {
+
+  if(++f_cnt > F_MAX) {
+    tell_object(this_object(),break_string(NO_EXAMINE[random(sizeof(NO_EXAMINE))],78));
+    return 1;
+  }
+  return ::_examine(str,mode);
+}
diff --git a/std/shells/testie.c b/std/shells/testie.c
new file mode 100644
index 0000000..18c42af
--- /dev/null
+++ b/std/shells/testie.c
@@ -0,0 +1,6 @@
+#pragma strong_types,save_types
+
+inherit "/std/shells/human";
+
+int QueryAllowSelect() { return 0; }
+