Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/obj/tools/teller/adm/mk b/obj/tools/teller/adm/mk
new file mode 100755
index 0000000..5798264
--- /dev/null
+++ b/obj/tools/teller/adm/mk
@@ -0,0 +1,25 @@
+#!/usr/local/bin/perl
+
+$mode = 0;
+$T1="mixed|float|int|string|object|void|quoted_array|symbol|closure|mapping";
+$T2="mixed \*|float \*|int \*|string \*|object \*|void \*|quoted_array \*|symbol \*|closure \*|mixed \&";
+$TYPES="\($T1|$T2\)";
+
+while( <> ) {
+	chop $_;
+	if( $mode == 0 && $_ eq "%efuns" ) {
+		$mode = 1;
+	} elsif( $mode == 1 && $_ eq "%xcodes" ) {
+		$mode = 2;
+	} elsif( $_ =~ "#endif" && $mode == 3 ) {
+		$mode = 1;
+	} elsif( $mode == 1 ) {
+		if( $_ =~ m"#ifndef NATIVE" || $_ =~ m"#ifdef MALLOC_malloc" ) {
+			$mode = 3;
+		} elsif( $_ ne "" && $_ !~ m"^.\*" && $_ !~ "^#" ) {
+			s/default: \w*//;
+			s/$TYPES/mixed/g;
+			print "$_\n";
+		}
+	}
+}
diff --git a/obj/tools/teller/hilfe/array b/obj/tools/teller/hilfe/array
new file mode 100644
index 0000000..8253000
--- /dev/null
+++ b/obj/tools/teller/hilfe/array
@@ -0,0 +1,19 @@
+BEFEHL:
+	array, arr
+
+ARGUMENTE:
+	Alle Stackelemente bis zum letzten Lock.
+
+FUNKTION:
+	Alle Elemente werden zu einem Array zusammengefuegt. Der Lock
+	wird entfernt und das Array wieder auf den Stack gelegt.
+
+BEISPIELE:
+	,me "zap_msg", "Du kochst @@wen@@.\n" "@@ich@@ kocht @@wen@@.\n"
+	"@@ich@@ kocht Dich.\n" array !SetProp
+		Wandelt die drei Strings in ein Array um. Danach wird im
+		Spieler die Zapp-Meldung neu gesetzt. Das obige muss
+		natuerlich in einer Zeile eingegeben werden.
+
+SPIEHE AUCH:
+	"split", "lock"
diff --git a/obj/tools/teller/hilfe/call b/obj/tools/teller/hilfe/call
new file mode 100644
index 0000000..7597299
--- /dev/null
+++ b/obj/tools/teller/hilfe/call
@@ -0,0 +1,26 @@
+BEFEHL:
+	'funktion, ''funktion oder
+	->funktion, -->funktion
+
+ARGUMENTE:
+	Alle Stackelemente bis zum letzten Lock.
+	funktion -- Name einer lfun.
+
+FUNKTION:
+	Rufe in dem Objekt oberhalb des letzten Locks, die angegebene
+	Funktion auf und uebergib die folgenden Elemente des Stacks
+	(bis hinauf zum TOS) als Argumente. Entferne den Lock.
+	Wenn mit die Funktion mit zwei Apostrophen oder zwei Minuszeichen
+	gerufen wurde, lege das Ergebnis auf den Stack. (Bei einfachem
+	Apostroph bzw. Minuszeichen also nicht.)
+
+BEISPIEL:
+	,me "das Grauen am Morgen" 'set_title
+	Enspricht:
+	call_other( this_player(), "set_title", "das Grauen am Morgen" );
+
+WARNUNG:
+	Man sollte vorher nachschauen, ob nicht noch etwas auf dem Stack
+	liegt, denn wenn kein Lock da ist, wuerde die Funktion darin
+	aufgerufen werden (mit me und "das Grauen am Morgen" als Argumente),
+	Deshalb besser so: ,,me "das Grauen am Morgen" ''set_title
diff --git a/obj/tools/teller/hilfe/callefun b/obj/tools/teller/hilfe/callefun
new file mode 100644
index 0000000..61fde2a
--- /dev/null
+++ b/obj/tools/teller/hilfe/callefun
@@ -0,0 +1,25 @@
+BEFEHL:
+	`funktion, ``funktion oder
+	-*funktion, --*funktion
+
+ARGUMENTE:
+	Alle Stackelemente bis zum letzten Lock.
+	funktion -- Name einer efun.
+
+FUNKTION:
+	Rufe die angegebene efun auf, und uebergebe alle Stackelemente
+	bis zum letzten Lock als Argumente. Entferne den Lock.
+	Wenn die efun mit doppelten Backquotes oder Minuszeichen ('``' oder
+	'--*') aufgerufen wurde, lege das Ergebnis auf den Stack. (Bei
+	einfachem '`' also nicht.)
+
+BEISPIEL:
+	,me `environment
+	Enspricht:
+	environment( this_player() );
+
+WARNUNG:
+	Man sollte vorher nachschauen, ob nicht noch etwas auf dem Stack
+	liegt, denn wenn kein Lock da ist, werden zuaetzlich noch
+	ungewunschte Argumente mituebergeben.
+	Deshalb besser so: ,,me ``environment
diff --git a/obj/tools/teller/hilfe/callouts b/obj/tools/teller/hilfe/callouts
new file mode 100644
index 0000000..883042c
--- /dev/null
+++ b/obj/tools/teller/hilfe/callouts
@@ -0,0 +1,24 @@
+BEFEHL:
+	callouts
+	callouts!
+
+ARGUMENTE:
+	callouts: TOS String, nach dem gesucht wird.
+	callouts!: keine
+
+FUNKTION:
+	Gib eine Liste aller im Spiel laufenden call_outs aus. Ein call_out
+	wird in folgendem Format ausgegeben:
+	1.) Zeit, bis zum Aufruf der Funktion.
+	2.) Objekt, in dem die Funktion aufgerufen wird.
+	3.) Name der Funktion.
+	4.) Argument, das dem call_out uebergeben wird.
+
+	Wird der Befehl ohne Rufzeihen eingegeben, so werden nur die
+	Meldungen ausgegeben, die in den ersten drei (!) Argumenten
+	den angegebenen String enthalten.
+
+BEISPIEL:
+	,"go" callouts
+	Gibt alle Monster aus, die mittels der Funktion "go" umherlaufen.
+	(Es gibt aber auch welche, die mittels "Walk" laufen. :-)
diff --git a/obj/tools/teller/hilfe/cleanof b/obj/tools/teller/hilfe/cleanof
new file mode 100644
index 0000000..6557cf1
--- /dev/null
+++ b/obj/tools/teller/hilfe/cleanof
@@ -0,0 +1,16 @@
+BEFEHL:
+	cleanof, clnof
+
+ARGUMENTE:
+	Die zwei obersten Stackelemente.
+
+FUNKTION:
+	Zerstoere alle Objekte in dem zweiten Objekt auf dem Stack,
+	die sich unter dem Namen, der in TOS steht, angesprochen fuehlen.
+	Die Objekte werden aber nur removed, das das der empfohlene Weg
+	ist, Objekte zu zerstoeren. Sollen die Objekte wirklich hart zerstoert
+	werden, so kann man ein Rufzeichen an den Befehl anhaengen.
+	(Also 'cleanof!'.)
+
+SIEHE AUCH:
+	"remove", "destruct"
diff --git a/obj/tools/teller/hilfe/clear b/obj/tools/teller/hilfe/clear
new file mode 100644
index 0000000..0acb5dc
--- /dev/null
+++ b/obj/tools/teller/hilfe/clear
@@ -0,0 +1,9 @@
+BEFEHL:
+	clear, clr
+
+ARGUMENTE:
+	STACK
+
+FUNKTION:
+	Loesche den ganzen Stack. Die Objekte auf dem Stack werden aber
+	nicht destructed.
diff --git a/obj/tools/teller/hilfe/clone b/obj/tools/teller/hilfe/clone
new file mode 100644
index 0000000..1c5620b
--- /dev/null
+++ b/obj/tools/teller/hilfe/clone
@@ -0,0 +1,7 @@
+BEFEHL:
+
+ARGUMENTE:
+
+FUNKTION:
+
+BEISPIELE:
diff --git a/obj/tools/teller/hilfe/destruct b/obj/tools/teller/hilfe/destruct
new file mode 100644
index 0000000..24ed234
--- /dev/null
+++ b/obj/tools/teller/hilfe/destruct
@@ -0,0 +1,14 @@
+BEFEHL:
+	destruct, dest, des
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Zerstoere das Objekt auf dem TOS. In wirklichkeit wird aber nur remove
+	aufgerufen, das das die empfohlene Art derZerstoerung von Objekten
+	ist. Will man jedoch ein Objekt wirklich hart destructen, so
+	haenge man ein Rufzeichen ('!') an das Kommando (also 'destruct!').
+
+SIEHE AUCH:
+	"remove"
diff --git a/obj/tools/teller/hilfe/dump b/obj/tools/teller/hilfe/dump
new file mode 100644
index 0000000..07be46b
--- /dev/null
+++ b/obj/tools/teller/hilfe/dump
@@ -0,0 +1,16 @@
+BEFEHL:
+	dump
+	
+ARGUMENTE:
+	keins oder
+	TOS -- filename
+	
+FUNKTION:
+	Speichere alle selbstdefinierten Funktionen in der angegebenen
+	Datei ab. Ist der TOS kein String, so wird in der Datei
+	~/.memory.o gespeichert.
+
+	Es koennen nur Funktionen abgespeichert oder geladen werden!
+
+SIEHE AUCH:
+	"funktionen", "restore", "memory"
diff --git a/obj/tools/teller/hilfe/dup b/obj/tools/teller/hilfe/dup
new file mode 100644
index 0000000..3702b75
--- /dev/null
+++ b/obj/tools/teller/hilfe/dup
@@ -0,0 +1,9 @@
+BEFEHL:
+	dup
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Lege das Objekt, das oben auf dem Stack liegt, nocheinmal auf
+	den Stack, um es eventuell spaeter noch einmal wieder zu verwenden.
diff --git a/obj/tools/teller/hilfe/einleitung b/obj/tools/teller/hilfe/einleitung
new file mode 100644
index 0000000..0d19d03
--- /dev/null
+++ b/obj/tools/teller/hilfe/einleitung
@@ -0,0 +1,121 @@
+WICHTIG:
+	**********************
+	Das erste Zeichen muss ab jetzt ein Komma (,) sein. Bisher war
+	es ein Semikolon, aber das wechselwirkt ja mit dem emote.
+	**********************
+
+DER TELLERSTAPEL:
+
+	Der Tellerstapel ist ein stackorientiertes Magiertool.
+	Das heisst, man legt die Objekte, Strings oder was auch immer auf
+	den Stack und ruft als letztes die Funktion auf, die dann mit
+	dem Stackihnhalt irgendetwas macht. Das Ergebnis wird meistens
+	dann wieder auf dem Stack abgelegt.
+	Im grossen und ganzen dieses Tool von Macbeths Lupe inspiriert.
+
+	Im folgenden wird mit TOS (TopOfStack) das Ding bezeichnet, das
+	als letztes auf dem Stack abgelegt wurde.
+
+KOMMANDOS:
+
+	Jedes Kommando, das mit den Tellern ausgefuehrt werden soll,
+	wird mit ',' eingeleitet. Allerdings hat das Semikolon noch
+	eine weitere Funktion, aber dazu spaeter.
+
+DINGE AUF DEN STACK LEGEN:
+
+	Hinter dem Semikolon werden (beliebig viele) Stackoperationen
+	angegeben. Die meissten dieser Operationen legen irgendetwas auf
+	dem Stack ab. Will man Objekte auf dem Stack ablegen, so gibt
+	man einfach deren Filenamen an. Zahlen gibt man durch ein voran
+	gestelltes Doppelkreuz ('#') an. (Positive Zahlen gehen auch ohne.)
+	und Strings werden in Anfuehrungszeichen eingefasst, damit sie von
+	den Objekten unterschieden werden koennen. (Uebrigens ist das Zeichen
+	'\n' und das ESC-Zeichen ('\e') in Strings erlaubt.)
+
+STACKOPERATIONEN:
+
+	Stackoperationen, die den Stack nicht beeinflussen.
+
+		say     - Meldungen an Mitspieler ein- und ausschalten.
+			  Umstehende sehen normalerweise, wenn man mit den
+			  Tellern arbeitet, eine Meldung der Art:
+			  "Sowieso jongilert mit seinen Tellern." bzw
+			  "Sowieso faellt beim Jonglieren ein Teller herunter."
+		names   - Objekte mit oder ohne Namen bei Auflistungen
+			  ausgeben.
+		stack   - Gebe Stackinhalt aus (0 ist der TOS).
+		memory  - Gebe Inhalt der Variablen aus.
+		top     - Gebe den TOS aus.
+		inv     - Gebe eine Liste der Objekte aus,
+			  die sich im TOS-Objekt befinden.
+		scan    - Gebe relevante Daten zu dem Spieler auf dem TOS aus.
+
+	Stackoperationen, die mit selbstdefinierten Funktionen zu tuen
+	haben:
+
+		!	- Definiere eine neue Funktion.
+			  (Hilfe unter "funktionen".)
+		dump
+		restore - Speichern und Laden der benutzerdefinierten
+			  Funktionen
+
+	Stackoperationen, die etwas auf dem Stack ablegen:
+
+		me      - Lege dich selbst auf den Stack.
+		here    - Lege den Raum, in dem Du bist, auf den Stack.
+
+	Stackoperationen zu dessen Verwaltung:
+
+		dup     - Lege den TOS noch einmal auf den Stack.
+		pop     - Loesche den TOS vom Stack.
+		swap    - Verstauche den TOS mit dem Ding darunter.
+		clear   - Loesche den ganzen Stack.
+
+	Die folgenden Funktionen poppen ihre Parameter vom Stack herunter.
+
+	Funktionen mit einem Parameter:
+
+		clone   - Clone ein Objekt mit den angegebenen Filenamen.
+		          Lege das geclonte Objekt auf den Stack.
+		update  - Zerstoere die Blueprint des Objektes.
+		remove  - Zerstoere das Objekt.
+
+	Funktionen mit mehreren Parametern:
+
+		move	- Bewege das zweitoberste Element in das Oberste.
+		if      - suche abhaengig vom obersten Element eines der
+			  darunter liegenden aus.
+
+	Funktionen mit beliebig vielen Parametern:
+
+		Um zu wissen, wieviele der Stackelemente zu dem Funktions-
+		aufruf gehoeren, muss eine Information auf dem Stack
+		abgelegt werden. Dieses wird mit einem Lock (';') gemacht.
+		Unter dem Stichpunkt "lock" sind auch Beispiele.
+
+		array	- Fuege alle Elemente zu einem Array zusammen.
+		split	- Zerlege das Array auf dem Stack in Einzelteile.
+
+		->	- Rufe in dem untersten Objekt die hinter dem
+			  Pfeil stehende Funktion auf. Uebergebe alle
+			  dem Objekt folgenden Elemente als Parameter.
+		-->	- Dito. Lege aber das Ergebnis wieder auf
+			  auf dem Stack ab.
+			  (Hilfe ist unter dem Begriff "call" zu finden.)
+
+		-*	- Rufe die hinter dem -* stehende efun auf.
+			  uebergib alle Stackelemente als Parameter.
+		--*	- Dito mit Ergebnisrueckgabe.
+			  (Hilfe unter dem Begriff "callefun".)
+
+		@	- Fuehre den LPC-Code hinter dem Klammeraffen aus.
+		@@	- Dito mit Returnwert.
+			  (Hilfe unter "evaluate".)
+
+	Wie die Befehle im einzelnen funktionieren, kann man durch
+	";hilfe <Befehl>" erfahren. Thema ist im Allgemeneinen der
+	Befehlsname. Bei Ausnahmen bitte oben nachlesen. ;-)
+
+	Viel Spass damit
+		Rumata, die Goettin der Morgenroete.
diff --git a/obj/tools/teller/hilfe/evaluate b/obj/tools/teller/hilfe/evaluate
new file mode 100644
index 0000000..91f6e0a
--- /dev/null
+++ b/obj/tools/teller/hilfe/evaluate
@@ -0,0 +1,22 @@
+BEFEHL:
+	evaluate, eval
+	
+ARGUMENTE:
+	TOS - Name einer Funktion als String.
+	
+FUNKTION:
+	Der Name wird von Stack genommen.
+	Der unter Namen gespeicherte Wert wird ausgewertet. Fuer normale
+	Werte bedeutet das, dass sie auf den Stack gelegt werden. Funktionen
+	werden ausgewertet.
+	
+BEISPIEL:
+	,!Q !1 pl !0 ->QueryProp
+	,rumata title Q
+		liefert direkt den Titel.
+	,rumata title "Q" eval
+		tut das selbe, nur das "Q" als String
+		zwischendurch auf dem Stack liegt.
+
+SIEHE AUCH:
+	"funktionen"
diff --git a/obj/tools/teller/hilfe/funktionen b/obj/tools/teller/hilfe/funktionen
new file mode 100644
index 0000000..dee7d75
--- /dev/null
+++ b/obj/tools/teller/hilfe/funktionen
@@ -0,0 +1,25 @@
+BEFEHL:
+	!funktionsname text
+	
+ARGUMENTE:
+	text -- der *ganze* Rest der Zeile
+	
+FUNKTION:
+	Erzeuge aus text eine neue Funktion mit dem angegebenen Namen. Dieser
+	Name ist als neuer Befehl innerhalb der Teller benutzbar wie die
+	eingebauten Befehle.
+	Wird ein Befehl ausgefuehrt, bekommt er auf einem neuen Stack seine
+	Parameter uebergeben. Was am Ende des Funktionsaufrufes auf dem
+	Stack legt, wird dann auf den urspruenglichen abgelegt.
+
+BEISPIEL:
+	,!Query !1 pl !0 -->QueryProp
+	Definiere die Funktion "Query", sie hat zwei Parameter (!0 und !1),
+	wobei !0 der TOS ist.
+	,rumata title Query
+		Liefert dann den Titel von Rumata auf dem Stack zurueck, da
+		am Ende der Auswertung dieser auf dem Stack liegen wuerde.
+	,!Demo !1 stk
+	,1 2 3 4 Demo
+		Zeigt einen Stack auf dem das zweitoberste Element von dem
+		ursprungsstack liegt; in diesem Fall also 3.
diff --git a/obj/tools/teller/hilfe/general b/obj/tools/teller/hilfe/general
new file mode 100644
index 0000000..826d743
--- /dev/null
+++ b/obj/tools/teller/hilfe/general
@@ -0,0 +1,17 @@
+Das sind die Befehle, die die magischen Teller zur Zeit beherrschen:
+(Letzte Aenderung am 20.01.1995 an den mit % markierten Funktionen,
+die mit * sind neu! AB JETZT GIBT ES AUCH FUNKTIONEN! )
+
+array       destruct    here        memory%     rekinv      split
+call        dump*       if*         message     remove      stack
+callefun    dup         inv         move        restore*    swap
+callouts    einleitung  living      names       rupdate     todo
+cleanof     evaluate*   lock        object      say         top
+clear       FUNKTIONEN* lpc         player      scan        update
+clone       general     me          pop         snoop       vars
+
+Mit ",hilfe <Befehl>" kannst Du Informationen zu den Befehlen abfragen.
+Wenn Du garnix verstehst, dann versuche mal ",hilfe einleitung". :-)
+
+WICHTIG: Das Semikolon wird nicht mehr unterstuetzt, stattdessen
+	kann nur noch das Komma benutzt werden.
diff --git a/obj/tools/teller/hilfe/here b/obj/tools/teller/hilfe/here
new file mode 100644
index 0000000..d0ebdf6
--- /dev/null
+++ b/obj/tools/teller/hilfe/here
@@ -0,0 +1,8 @@
+BEFEHL:
+	here
+
+ARGUMENTE:
+	Keins
+
+FUNKTION:
+	Lege den Raum, in man sich befindet oben auf den Stack.
diff --git a/obj/tools/teller/hilfe/if b/obj/tools/teller/hilfe/if
new file mode 100644
index 0000000..6994717
--- /dev/null
+++ b/obj/tools/teller/hilfe/if
@@ -0,0 +1,22 @@
+BEFEHL:
+	if
+	
+ARGUMENTE:
+	wenn sonst bedingung(TOS)
+	
+FUNKTION:
+	Wenn der TOS Null ist, liefere das drittoberste Element vom Stack,
+	sonst das zweitoberste. Dieser Befehl ist insbesondere im Zusammen-
+	hang mit "evaluate" interessant.
+	
+BEISPIEL:
+	,"bla" "blubb" 0 if
+		Liefert "blubb"
+	,"bla" "bluibb" 1 if
+		Liefert "bla"
+	,"Q" "R" test if evaluate
+		Werte Q aus, wenn der Wert "test" nicht null ist.
+		Anderenfalls werte R aus.
+
+SIEHE AUCH:
+	"evaluate", "funktionen"
diff --git a/obj/tools/teller/hilfe/inv b/obj/tools/teller/hilfe/inv
new file mode 100644
index 0000000..e943800
--- /dev/null
+++ b/obj/tools/teller/hilfe/inv
@@ -0,0 +1,17 @@
+BEFEHL:
+	inv
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Gebe alle Objekte an, die sich in dem Objekt TOS befinden.
+	Gib einen Fehler aus, wenn TOS kein Objekt ist.
+	TOS bleibt auf dem Stack, da dieser Befehl meistens dazu benutzt
+	wird, ein Objekt auf den Stack zu legen und dann bestimmte
+	Objekte in ihm zu suchen, und dann diese zu holen.
+
+BEISPIELE:
+	,me inv
+	Dann sieht man .... ".2 /bla/bla/bla/objekt" und man kann dann
+	mittels ,.2 dieses Objekt holen.
diff --git a/obj/tools/teller/hilfe/living b/obj/tools/teller/hilfe/living
new file mode 100644
index 0000000..90606a7
--- /dev/null
+++ b/obj/tools/teller/hilfe/living
@@ -0,0 +1,17 @@
+BEFEHL:
+	living, lv
+
+ARGUMENTE:
+	TOS -- Name eines Monsters
+
+FUNKTION:
+	Hole einen Namen vom Stack und lege stattdessen das entsprechende
+	Monsterobjekt auf den Stack. Gebe eine Fehlermeldung aus, wenn kein
+	derartiges Monster vorhanden ist.
+
+BEISPIELE:
+	,"ork" living
+	Sucht den erstbesten Ork.
+
+SIEHE AUCH:
+	"object", "player"
diff --git a/obj/tools/teller/hilfe/lock b/obj/tools/teller/hilfe/lock
new file mode 100644
index 0000000..f470db3
--- /dev/null
+++ b/obj/tools/teller/hilfe/lock
@@ -0,0 +1,26 @@
+BEFEHL:
+	,
+
+ARGUMENTE:
+	Keine
+
+FUNKTION:
+	Lege einen 'Lock' auf dem Stack ab. Anhand eines Locks erkennen
+	Funktionen, die eine varibale Anzahl von Argumenten vom Stack
+	nehmen koennen, wieviele der Argumente fuer sie bestimmt sind.
+
+	Wichtig: Das Komma am Anfag jeder Eingabezeile ist KEIN Lock.
+
+BEISPIELE:
+	,me, 1 2 3 array
+		Es werden nur die Zahlen 1 2 und 3 in das Array aufgenommen,
+		nicht der Spieler selbst. Auf dem Stack liegen nacher der
+		Spieler und das Array.
+	,here, me "rumata" ->id
+		"id" wird im Spieler mit einem Argument ("rumata") aufgerufen.
+	,here me "rumata" ->id	
+		Hier wird die Funktion im Raum mit zwei Argumenten aufgerufen,
+		was hier natuerlich keinen Sinn macht.
+
+SIEHE AUCH:
+	"array", "split", "call", "callefun", "evaluate"
diff --git a/obj/tools/teller/hilfe/lpc b/obj/tools/teller/hilfe/lpc
new file mode 100644
index 0000000..bfa0e01
--- /dev/null
+++ b/obj/tools/teller/hilfe/lpc
@@ -0,0 +1,21 @@
+BEFEHL:
+	@ text
+	@@ text
+	
+ARGUMENTE:
+	text -- der ganze(!) Rest der Eingabezeile.
+	Der Stack bis zum letzten Lock.
+	
+FUNKTION:
+	Fuehre den LPC-Code <text> direkt aus. Dabei koennen die Argumente
+	vom Stack mit @<nummer>@ eingesetzt werden. Wichtig, wenn man ein
+	Ergebnis weiterberechnen will, muss man auch ein 'return' um
+	LPC-Code benutzt haben.
+
+	Bei der Ausfuehrung werden nicht alle Include-Dateien eingeladen.
+	
+BEISPIEL:
+	,me @ write( @0@->name(WER)+"\n" )
+	Gibt Deinen Namen aus.
+	,me @@ return @0@->name(WER)
+	Gibt den Namen zurueck und legt ihn auf den Stack.
diff --git a/obj/tools/teller/hilfe/me b/obj/tools/teller/hilfe/me
new file mode 100644
index 0000000..8861f45
--- /dev/null
+++ b/obj/tools/teller/hilfe/me
@@ -0,0 +1,8 @@
+BEFEHL:
+	me
+
+ARGUMENTE:
+	Keine
+
+FUNKTION:
+	Lege den Eigentuemer (Dich!) oben auf den Stack.
diff --git a/obj/tools/teller/hilfe/memory b/obj/tools/teller/hilfe/memory
new file mode 100644
index 0000000..d012451
--- /dev/null
+++ b/obj/tools/teller/hilfe/memory
@@ -0,0 +1,15 @@
+BEFEHL:
+	memory, mem
+
+ARGUMENTE:
+	Keine
+
+FUNKTION:
+	Zeige den Inhalt aller Variablen an, die man angelegt hat.
+	Normalerweise wird der Inhalt in der Form Name = Inhalt angezeigt.
+	Ist unter dem Namen eine Funktion gespeichert, wird
+		Name > Inhalt
+	angezeigt, um Funktionen von Strings unterscheiden zu koennen.
+
+SIEHE AUCH:
+	"vars", "funktionen"
diff --git a/obj/tools/teller/hilfe/message b/obj/tools/teller/hilfe/message
new file mode 100644
index 0000000..656d94a
--- /dev/null
+++ b/obj/tools/teller/hilfe/message
@@ -0,0 +1,13 @@
+KOMMANDO:
+	message [to <spieler>]
+	msg [to <spieler>]
+
+FUNKTION:
+	Wenn man ganze Textbloecke sagen moechte, kann man das mit diesem
+	Befehl tun. Nach Eingabe von 'message' wird jede Eingabe direkt fuer
+	alle im Raum sichtbar oder fuer den angegebenen Spieler ausgegeben.
+	Mit '**' kann man wieder auf normale Eingabe zurueckschalten.
+
+ACHTUNG:
+	Dieser Befehl gehoert nicht zu denen, die mittels ',' eingeleitet
+	werden.
diff --git a/obj/tools/teller/hilfe/move b/obj/tools/teller/hilfe/move
new file mode 100644
index 0000000..b181c34
--- /dev/null
+++ b/obj/tools/teller/hilfe/move
@@ -0,0 +1,14 @@
+BEFEHL:
+	move, mv
+
+ARGUMENTE:
+	obj -- Objekt, das bewegt werden soll.
+	ziel(TOS) -- Raum, in den das Objekt soll
+
+FUNKTION:
+	Bewege das Objekt in den angegebenen Raum. Die meisten Sicherungen
+	werden bei diesem Verschiueben umgangen, also vorsicht!
+
+BEISPIELE:
+	,me "~/workroom" ob mv
+		Man geht in den eigenen Workroom.
diff --git a/obj/tools/teller/hilfe/names b/obj/tools/teller/hilfe/names
new file mode 100644
index 0000000..4eebc3b
--- /dev/null
+++ b/obj/tools/teller/hilfe/names
@@ -0,0 +1,17 @@
+BEFEHL:
+	names, nam
+
+ARGUMENTE:
+	keine
+
+FUNKTION:
+	Normalerweise werden der Filename und der Name (QueryProp(P_NAME))
+	angezeigt, wenn man den Stack oder aehnliches betrachtet.
+	Mit diesem Befehl schaltet man den Namen aus oder an.
+
+	Durch Anschauen der Teller kann man feststellen, ob die Namen oder
+	nur die Filenamen angezeigt werden.
+
+SIEHE AUCH:
+	"inv", "stack", "move", "top", ...
+	Andere Schalter: "say", "inform"
diff --git a/obj/tools/teller/hilfe/object b/obj/tools/teller/hilfe/object
new file mode 100644
index 0000000..145b30a
--- /dev/null
+++ b/obj/tools/teller/hilfe/object
@@ -0,0 +1,22 @@
+BEFEHL:
+	object, ob
+
+ARGUMENTE:
+	TOS -- Name eines Objektes
+
+FUNKTION:
+	Hole einen Namen vom Stack und lege stattdessen das entsprechende
+	Objekt auf den Stack. Falls es kein geladenes Objekt dieses Namens,
+	wohl aber eine (nicht geladene) Blueprint, so wird diese geladen
+
+BEISPIELE:
+	,"players/rumata/workroom" ob
+	Macht das selbe wie ',/players/rumata/workroom', da die Teller
+	Filenamen automatisch zu erkennen versuchen.
+	,"~rumata/workroom" ob
+	geht auch.
+	,"~/workroom" ob
+	liefert den eigenen Workroom.
+
+SIEHE AUCH:
+	"living", "player"
diff --git a/obj/tools/teller/hilfe/player b/obj/tools/teller/hilfe/player
new file mode 100644
index 0000000..e2caa16
--- /dev/null
+++ b/obj/tools/teller/hilfe/player
@@ -0,0 +1,21 @@
+BEFEHL:
+	player, pl
+
+ARGUMENTE:
+	TOS -- Name eines Spielers
+
+FUNKTION:
+	Hole einen Namen vom Stack und lege stattdessen das entsprechende
+	Spielerobjekt auf den Stack.
+
+	Am Ende des Spielernamens ist ein Stern ('*') als Wildcard erlaubt.
+	Die Namen nicht eingeloggter Spieler muessen in jedem Fall ausge-
+	schrieben werden.
+
+
+BEISPIELE:
+	,"rumata" pl
+	Legt Rumata auf den Stack.
+
+SIEHE AUCH:
+	"living", "object"
diff --git a/obj/tools/teller/hilfe/pop b/obj/tools/teller/hilfe/pop
new file mode 100644
index 0000000..c30dc08
--- /dev/null
+++ b/obj/tools/teller/hilfe/pop
@@ -0,0 +1,8 @@
+BEFEHL:
+	pop
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Nimm das oberste Element vom Stack.
diff --git a/obj/tools/teller/hilfe/rekinv b/obj/tools/teller/hilfe/rekinv
new file mode 100644
index 0000000..cb51bd2
--- /dev/null
+++ b/obj/tools/teller/hilfe/rekinv
@@ -0,0 +1,12 @@
+BEFEHL:
+	rekinv
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Dieser Befehl mach das selbe wie "inv", zeigt aber rekursiv
+	auch den Inhalt der enthaltenen Objekte an.
+
+SIEHE AUCH:
+	"inv"
diff --git a/obj/tools/teller/hilfe/remove b/obj/tools/teller/hilfe/remove
new file mode 100644
index 0000000..dff2437
--- /dev/null
+++ b/obj/tools/teller/hilfe/remove
@@ -0,0 +1,16 @@
+BEFEHL:
+	remove, rem
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Zerstoere das Objekt auf dem TOS. Gib dem Objekt die Gelegenheit,
+	Aufraeumarbeiten durchzufuehren.
+
+BEISPIELE:
+	,me remove
+	Man loggt sich selber aus.
+
+SIEHE AUCH:
+	"destruct"
diff --git a/obj/tools/teller/hilfe/restore b/obj/tools/teller/hilfe/restore
new file mode 100644
index 0000000..ad20a35
--- /dev/null
+++ b/obj/tools/teller/hilfe/restore
@@ -0,0 +1,15 @@
+BEFEHL:
+	restore
+	
+ARGUMENTE:
+	keins oder
+	TOS -- filename
+	
+FUNKTION:
+	Lade die in der Datei gespeicherten Funktionen. Wird kein Filename
+	angegeben, so wird die Datei ~/.memory.o ausgelesen.
+
+	Es koennen nur Funktionen abgespeichert oder geladen werden!
+
+SIEHE AUCH:
+	"funktionen", "dump", "memory"
diff --git a/obj/tools/teller/hilfe/rupdate b/obj/tools/teller/hilfe/rupdate
new file mode 100644
index 0000000..85f033e
--- /dev/null
+++ b/obj/tools/teller/hilfe/rupdate
@@ -0,0 +1,25 @@
+BEFEHL:
+	roomupdate, rupdate, rupd, rup
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Zerstoere den Raum und lade ihn neu, damit Aenderungen der Files
+	aktiv werden koennen. Sorge dafuer, dass die Objekte in dem alten Raum
+	in den neuen hinuebergerettet werden. (Diese Eigenschaft kann mittels
+	des Sternchens ('*') abgeschaltet werden.)
+	
+	Gebe dem Raum jedoch Gelegenheit, Aufraeumarbeiten zu taetigen. Soll
+	der Raum wirklich hart zerstoert werden, so ist ein Rufzeichen an den
+	Befehl anzuhaengen. (also `rupdate!', ein Stern muss vor dem Rufzeichen
+	stehen, also `rupdate*!' und nicht `rupdate!*'.)
+	Wichtig: Raeume, die keine Blueprint sind, koennen nicht mit diesem
+	Befehl aktualisiert werden.
+
+BEISPIELE:
+	,here rupdate
+	Aktualisiert den Raum, in dem der Magier sich befindet.
+
+SIEHE AUCH:
+	"update"
diff --git a/obj/tools/teller/hilfe/say b/obj/tools/teller/hilfe/say
new file mode 100644
index 0000000..cf23357
--- /dev/null
+++ b/obj/tools/teller/hilfe/say
@@ -0,0 +1,17 @@
+BEFEHL:
+	say
+
+ARGUMENTE:
+	keine
+
+FUNKTION:
+	Schalte die Meldung, die andere Spieler bekommen, wenn man
+	mit den Tellern arbeitet, aus oder an.
+
+	Ist man unsichtbar, gibt es in keinem Fall eine Meldung.
+
+	Durch Anschauen der Teller kann man feststellen, ob Mispieler
+	die Meldungen bekommen.
+
+SIEHE AUCH:
+	"names", "inform"
diff --git a/obj/tools/teller/hilfe/scan b/obj/tools/teller/hilfe/scan
new file mode 100644
index 0000000..7c251fd
--- /dev/null
+++ b/obj/tools/teller/hilfe/scan
@@ -0,0 +1,17 @@
+BEFEHL:
+	scan
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Wenn der TOS ein Spieler oder ein Monster ist, so gib die
+	spielrelevanten Informationen zu ihm aus. Wenn der TOS ein
+	String ist, so wird der Spieler mit diesem Namen gesucht.
+
+BEISPIELE:
+	,me scan
+	,"jof" pl scan (oder kuerzer: ;"jof" scan)
+
+SIEHE AUCH:
+	"player"
diff --git a/obj/tools/teller/hilfe/snoop b/obj/tools/teller/hilfe/snoop
new file mode 100644
index 0000000..1be1300
--- /dev/null
+++ b/obj/tools/teller/hilfe/snoop
@@ -0,0 +1,11 @@
+BEFEHLE:
+	snoop
+
+ARGUMENTE:
+	keine
+
+FUNKTION:
+	Zeige laufende Snoopvorgaenge an.
+
+	Wenn der Snooper einen hoeheren Magierlevel als man selbst hat,
+	wird der Snoop nicht angezeigt.
diff --git a/obj/tools/teller/hilfe/split b/obj/tools/teller/hilfe/split
new file mode 100644
index 0000000..319025a
--- /dev/null
+++ b/obj/tools/teller/hilfe/split
@@ -0,0 +1,14 @@
+BEFEHL:
+	split, spl
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Zerlege den Array, der auf dem Stack liegt und lege die
+	einzelnen Elemente (das Element mit Index 0 zuunterst)
+	auf dem Stack ab. Wenn der Stack vorher nicht leer war,
+	lege vorher ein Lock auf den Stack.
+
+SIEHE AUCH:
+	"array", "lock"
diff --git a/obj/tools/teller/hilfe/stack b/obj/tools/teller/hilfe/stack
new file mode 100644
index 0000000..c8f182e
--- /dev/null
+++ b/obj/tools/teller/hilfe/stack
@@ -0,0 +1,18 @@
+BEFEHL:
+	stack, stk
+	
+ARGUMENTE:
+	STACK
+	
+FUNKTION:
+	Zeige alle Dinge an, die auf dem Stack liegen.
+	
+BEISPIEL:
+	,me here; 1 2 array stk
+	Ergibt (zum Beispiel):
+	0: ({
+	     1
+	     2
+	   })
+	1: /room/gilde (ein Raum)
+	2: /std/shells/magier#7691 (Atamur)
diff --git a/obj/tools/teller/hilfe/swap b/obj/tools/teller/hilfe/swap
new file mode 100644
index 0000000..befafe3
--- /dev/null
+++ b/obj/tools/teller/hilfe/swap
@@ -0,0 +1,8 @@
+BEFEHL:
+	swap
+
+ARGUMENTE:
+	Die obersten 2 Stackelemente.
+
+FUNKTION:
+	Vertausche die beiden obersten Elemente vom Stack.
diff --git a/obj/tools/teller/hilfe/todo b/obj/tools/teller/hilfe/todo
new file mode 100644
index 0000000..662cefb
--- /dev/null
+++ b/obj/tools/teller/hilfe/todo
@@ -0,0 +1,14 @@
+Was noch kommen soll:
+
+	Doku verbessern, da eine Stackmachine nicht jedermanns Sache ist.
+	(schon ",hilfe einleitung" gemacht?)
+
+	Alles, was nicht player ist, aus dem Raum herausraeumen.
+	<cleanup> ?
+
+Was NICHT kommen soll:
+
+	Alarm, wenn man angeschaut wird. (Wozu auch? :-)
+
+Weitere Ideen werden von Rumata gerne entgegengenommen.
+Aber bitte nicht dauernd anlabern, sondern als mail :-)
diff --git a/obj/tools/teller/hilfe/top b/obj/tools/teller/hilfe/top
new file mode 100644
index 0000000..2b07fa9
--- /dev/null
+++ b/obj/tools/teller/hilfe/top
@@ -0,0 +1,23 @@
+BEFEHL:
+	top
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Zeigt das Objekt an, das auf dem Stack zuoberst liegt (=TOS).
+
+BEISPIELE:
+	;me top
+	Zeige das Objekt, das man selbst ist, an.
+
+	;here top
+	Zeige den Raum, in dem man sich befindet.
+
+	;; 1 2 3 array top (Das zweite ';' ist wichtig)
+	Ergibt:
+	TOS= ({
+	       1
+	       2
+	       3
+	     })
diff --git a/obj/tools/teller/hilfe/update b/obj/tools/teller/hilfe/update
new file mode 100644
index 0000000..bd35aad
--- /dev/null
+++ b/obj/tools/teller/hilfe/update
@@ -0,0 +1,22 @@
+BEFEHL:
+	update, upd
+
+ARGUMENTE:
+	TOS
+
+FUNKTION:
+	Zerstoere die Blueprint des Objektes, das auf dem Stack liegt, damit
+	Aenderungen der Files aktiv werden koennen. Gebe der Blueprint
+	jedoch Gelegenheit, Aufraeumarbeiten zu taetigen. Soll die Blueprint
+	wirklich hart zerstoert werden, so ist ein Rufzeichen an den Befehl
+	anzuhaengen. (also `update!')
+	Wichtig: Das geclonte Objekt, ueber das die Blueprint zerstoert wird,
+	bleibt erhalten, ebenso wie alle anderen geclonten Objekte.
+
+BEISPIELE:
+	,me .teddy update
+	Zerstoert die Blueprint vom Teddy, den man hat. (Das ist natuerlich nur
+	fuer Magier sinnvoll, die das File editieren konnten.)
+
+SIEHE AUCH:
+	"roomupdate"
diff --git a/obj/tools/teller/hilfe/vars b/obj/tools/teller/hilfe/vars
new file mode 100644
index 0000000..1c6deab
--- /dev/null
+++ b/obj/tools/teller/hilfe/vars
@@ -0,0 +1,23 @@
+BEFEHLE:
+	<varname, >varname
+
+ARGUMENTE:
+	TOS 
+	varname -- String
+
+FUNKTION:
+	>varname
+		Speichere das oberste Element des Stacks in der Variable
+		"varname" ab.
+	<varname
+		Kopiere den Inhalt der Variable "varname" auf den Stack.
+		Wenn der Inhalt der Variable eine Funktion ist, wo wird
+		diese in Stringform auf den Stack gelegt und nicht aus-
+		gewertet.
+
+	Es koennen ausser Objekten auch Arrays, Strings und Integers
+	in Variablen gespeichert werden. Wird eine 0 in einer Variable
+	gespeichert, so wird die Variable wieder geloescht.
+
+SIEHE AUCH:
+	"memory"
diff --git a/obj/tools/teller/t_base.c b/obj/tools/teller/t_base.c
new file mode 100644
index 0000000..8336d3b
--- /dev/null
+++ b/obj/tools/teller/t_base.c
@@ -0,0 +1,361 @@
+// ----------------------------------------------------------------------
+// Die Basis- und Hilfsfunktionen der Teller.
+// Stack und Memory
+// ----------------------------------------------------------------------
+#include "teller.h"
+
+#include <moving.h>
+#include <terminal.h>
+
+static mixed *stack;
+static mapping memory;
+static object *oldinv;
+static bool mit_namen;
+static bool fehler_passiert;
+static bool mit_say;
+static bool secureinv;
+static bool dologaccess;
+static bool pretty;
+static bool do_profile;
+
+static mixed top();
+static mixed pop();
+static void push( mixed ob );
+
+static void dump_obj( mixed ob, int indent );
+
+void create()
+{
+	stack = ({});
+	memory = ([]);
+	mit_namen = TRUE;
+	fehler_passiert = FALSE;
+	mit_say = TRUE;
+	secureinv = FALSE;
+	dologaccess = FALSE;
+	pretty = TRUE;
+}
+
+// ----------------------------------------------------------------------
+// Hilfsfunktionen
+// ----------------------------------------------------------------------
+
+static int error( string msg )
+{
+	write( "Fehler in "+msg+".\n" );
+	fehler_passiert = TRUE;
+	return FALSE;
+}
+
+static int memo( string msg )
+{
+	write( "MEMO: "+msg+".\n" );
+	return FALSE;
+}
+
+static int calcinv( string str )
+{
+	object* obs;
+	object ob;
+	int val;
+
+	if( sscanf( str, "%d", val ) == 1 )
+	{
+		obs = all_inventory(top());
+		if( val<0 || val>=sizeof(obs) )
+			return error( "'.': Kein Objekt mit dieser Nummer" );
+		pop();
+		push(obs[val]);
+		return TRUE;
+	}
+
+	if( !(ob=present(str,top())) )
+		return error( "'.': Kein Objekt namens \""+str+"\" gefunden" );
+	pop();
+	push(ob);
+	return TRUE;
+}
+
+static mixed push_str( string str )
+{
+	return
+		push( implode(old_explode( implode(old_explode( implode(old_explode(
+					" "+str+" ",
+				"\\n"),"\n"), "\\e"),ESC), "\\b"),"\b")
+		[1..<2] );
+}
+
+static void do_move( object ob, mixed dest )
+{
+	int weight;
+
+	weight = ob->QueryWeight();
+	if( environment(ob) )
+		environment(ob)->AddWeight(-weight);
+	ob->move(dest,M_NOCHECK);
+	dest->AddWeight(weight);
+}
+
+void heart_beat()
+{
+	object *newinv;
+	object owner;
+	int i,j;
+
+	if( owner=find_player(getuid()) )
+	{
+		newinv = sort_array( all_inventory(owner), lambda( ({'a,'b}),
+			({ #'<,
+				({ #'object_name, 'a }),
+				({ #'object_name, 'b })
+			})
+		) );
+		if( pointerp(oldinv) )
+		{
+			for( i=0,j=0; i<sizeof(newinv) && j<sizeof(oldinv) ; )
+			{
+				if( newinv[i] == oldinv[j] )
+				{ i++; j++; }
+				else if( object_name(newinv[i]) > object_name(oldinv[j]) )
+				{
+					tell_object(owner,
+						"MEMO: \""+object_name(newinv[i])+"\" entered inventory.\n" );
+					i++;
+				}
+				else
+					j++;
+			}
+			for( ; i<sizeof(newinv) ; i++ )
+				tell_object( owner,
+					"MEMO: \""+object_name(newinv[i])+"\" entered inventory.\n" );
+		}
+	}
+	oldinv = newinv;
+}
+
+// ----------------------------------------------------------------------
+// Dumpfunktionen
+// ----------------------------------------------------------------------
+
+static void dump_array( mixed* ob, int indent )
+{
+	int i;
+	for( i=0; i<sizeof(ob); i++ )
+	{
+		printf( "%*s", indent, "" );
+		dump_obj( ob[i], indent );
+	}
+}
+
+static void dump_mapping( mapping ob, int indent )
+{
+	mixed *index;
+	mixed key;
+	int i,j,values;
+
+	index = m_indices( ob );
+	values = get_type_info(ob)[1];
+	for( i=0; i<sizeof(index); i++ )
+	{
+		key = index[i];
+		printf( "%*s", indent, "" );
+		dump_obj( key, indent );
+		for( j=0; j<values; j++ )
+		{
+			printf( "%*s: ", indent+1, "" );
+			dump_obj( ob[key,j], indent+3 );
+		}
+	}
+}
+
+static void dump_obj( mixed ob, int indent )
+{
+	if( !pretty )
+	{
+		printf( "%O\n", ob );
+		return;
+	}
+	if( intp(ob) )
+		write( ob + "\n" );
+	else if( floatp(ob) )
+		printf( "%1.5f\n", ob );
+	else if( stringp(ob) )
+	{
+		if ( ob==";" )
+			write( ";\n" );
+		else
+		{
+			write( "\"" + implode(old_explode( implode(old_explode( implode(old_explode(
+							" "+ob+" ",
+						 "\n"),"\\n"), ESC), "\\e"), "\b"),"\\b")
+						 [1..<2] + "\"\n"
+			);
+		}
+	}
+	else if( objectp(ob) )
+	{
+		if( mit_namen )
+			write( object_name(ob)+" ("+ob->name(WER,0)+")\n" );
+		else
+			write( object_name(ob)+"\n" );
+	}
+	else if( mappingp(ob) )
+	{
+		write( "([\n" );
+		dump_mapping( ob, indent + 2 );
+		printf( "%*s\n", indent + 2, "])" );
+	}
+	else if( pointerp(ob) )
+	{
+		write( "({\n" );
+		dump_array( ob, indent+2 );
+		printf( "%*s\n", indent+2 , "})" );
+	}
+	else
+		printf( "%O\n", ob );
+}
+
+// ----------------------------------------------------------------------
+// Speicherfunktionen
+// ----------------------------------------------------------------------
+
+static void do_recall( mixed arg )
+{
+	if( member(memory,arg) )
+		push( memory[arg,0] );
+}
+
+static void do_store( mixed arg )
+{
+	if ( sizeof(stack) )
+	{
+		if( !top() )
+			memory = m_delete(memory,arg);
+		else
+			memory += ([ arg: top(); 0 ]);
+	}
+	else
+		memo( "Es wurde kein Wert in \""+arg+"\" gespeichert" );
+}
+
+// ----------------------------------------------------------------------
+// Stack-Funktionen
+// ----------------------------------------------------------------------
+
+static void push( mixed ob )
+{
+	stack = ({ ob }) + stack;
+}
+
+static mixed pop()
+{
+	mixed answer;
+
+	if( !sizeof( stack ) )
+		return FALSE;
+	answer = stack[0];
+	stack = stack[1..];
+	return answer;
+}	
+
+static mixed top()
+{
+	if( sizeof(stack) )
+		return stack[0];
+}
+
+static varargs int becomes_obj( mixed argv)
+{
+	object ob;
+
+	if( !pointerp(argv) ) // default ist der stack !
+		argv = stack;
+	if( !sizeof(argv) )
+		return FALSE; 
+	if( stringp(argv[0]) && !catch(call_other(argv[0],"?")) )
+	{
+	  argv[0] = find_object(argv[0]);
+		return TRUE;
+	}
+	else
+		return objectp(argv[0]);
+}
+
+static isSubStr( pl, str, len )
+{
+	return getuid(pl)[0..len] == str;
+}
+
+static becomes_pl(argv)
+{
+	object pl;
+	object* pllist;
+	string str;
+	int len;
+
+	if( !argv ) argv = stack;
+	if( !sizeof(argv) || ( becomes_obj() && !interactive(argv[0]) ) )
+		return FALSE;
+	if( stringp(argv[0]) )
+	{
+		str = lower_case( argv[0] );
+		pl = 0;
+		if( str[<1..<1] == "*" )
+		{	
+			str = str[0..<2];
+			len = sizeof(str) - 1;
+			pllist = filter( users(), #'isSubStr, str, len );
+			if( sizeof(pllist) == 1 )
+			{
+				pl=pllist[0];
+				argv[0] = pl;
+			}
+		}
+		if( !pl && pl=find_player(argv[0]) )
+			argv[0] = pl;
+		return pl;
+	}
+	return argv[0];
+}
+
+static DumpObj( ob )
+{
+  string ans;
+  int i,j;
+
+  if( intp(ob) )
+    return ""+ob;
+  else if( stringp(ob) )
+    return "\""+implode(explode(ob,"\n"),"\\n")+"\"";
+  else if( objectp(ob) )
+    return "\""+object_name(ob)+"\"";
+  else if( mappingp(ob) )
+  {
+    ans="([";
+    for( i=0; i<sizeof(ob)-1; i++ )
+      ans += DumpMapp(ob,i)+",";
+    // rely on right value of i
+    return ans+DumpMapp(ob,i)+"])";
+  }
+  else
+  {
+    ans="({";
+    for( i=0; i<sizeof(ob)-1; i++ )
+      ans += DumpObj(ob[i])+",";
+    // rely on right value of i
+    return ans+DumpObj(ob[i])+"})";
+  }
+}
+
+static DumpMapp(ob,i)
+{
+  int j,vz;
+  string ans;
+
+  vz = get_type_info(ob)[1];
+  ans = DumpObj(m_indices(ob)[i])+":";
+  for( j=0; j<vz-1; j++ )
+    ans += DumpObj(ob[m_indices(ob)[i],j])+";";
+  // rely on value of j
+  return ans + DumpObj(ob[m_indices(ob)[i],j]);
+}
diff --git a/obj/tools/teller/t_cmds.c b/obj/tools/teller/t_cmds.c
new file mode 100644
index 0000000..68fa5d3
--- /dev/null
+++ b/obj/tools/teller/t_cmds.c
@@ -0,0 +1,1000 @@
+// ----------------------------------------------------------------------
+// Builtinkommandos der Teller.
+// ----------------------------------------------------------------------
+#include "teller.h"
+inherit T_BASE;
+
+#include <moving.h>
+#include <attributes.h>
+#include <terminal.h>
+#include <wizlevels.h>
+
+static void do_rinv( object env, int depth );
+static scan_obj( object player, object obj );
+static void mk_waitfor( mixed waitfor );
+static void mk_autoload( mixed autoload );
+static int do_roomupdate( int destflag, int noitems );
+static int do_cleanof( int strong );
+
+// from teller.c
+static int do_cmd( string str );
+
+static int cmd_clear()
+{
+	stack = ({});
+	return TRUE;
+}
+
+static int cmd_pop()
+{
+	if( !sizeof(stack) )
+		return error( "pop: Der Stack ist leer" );
+	pop();
+	return TRUE;
+}
+
+static int cmd_top()
+{
+	if( !sizeof(stack) )
+		return error( "top: Der Stack ist leer" );
+	write( "TOS= " );
+	dump_obj( top(), 5 );
+	return TRUE;
+}
+
+static int cmd_swap()
+{
+	mixed tmp;
+
+	if( sizeof(stack)<2 )
+		return error( "swap: Keine 2 Elemente auf dem Stack" );
+	tmp = stack[0];
+	stack[0] = stack[1];
+	stack[1] = tmp;
+	return TRUE;
+}
+
+static int cmd_dup()
+{
+	if( !sizeof(stack) )
+		return error( "dup: Der Stack ist leer" );
+	push(top());
+	return TRUE;
+}
+
+static int cmd_here()
+{
+	push(environment(PL));
+	return TRUE;
+}
+
+static int cmd_stack()
+{
+  int i;
+  if( !sizeof(stack) )
+    return memo( "Der Stack ist leer" );
+
+  for( i=0; i<sizeof(stack); i++ )
+  {
+    printf( "%2d: ", i );
+    dump_obj( stack[i], 4 );
+  }
+  return TRUE;
+}
+
+static int cmd_inv()
+{
+  int i;
+  object ob;
+
+	if( !becomes_obj() )
+		return error( "inv: TOS ist kein Objekt" );
+  write( "Inventar von " );
+  dump_obj( top(), 13 );
+  for( i=0, ob=first_inventory(top()); ob; ob=next_inventory(ob), i++ )
+  {
+    printf( "%2d. ", i );
+    dump_obj( ob, 4 );
+  }
+  return TRUE;
+}
+
+static int cmd_rekinv()
+{
+	if( !becomes_obj() )
+		return error( "rekinv: TOS ist kein Objekt" );
+	write( "Inventar von " );
+	dump_obj( top(), 13 );
+
+	do_rinv( top(), 2 );
+	return TRUE;
+}
+
+static void do_rinv( object env, int depth )
+{
+	int i;
+	object ob;
+
+	for( i=0, ob=first_inventory(env); ob; ob=next_inventory(ob), i++ )
+	{
+		printf( "%*d. ", depth, i );
+		dump_obj( ob, 2+depth );
+		do_rinv( ob, depth+2 );
+	}
+}
+
+static int cmd_me()
+{
+	push( PL );
+	return TRUE;
+}
+
+// Uebernommen aus dem Teddy (mit freundlicher Genehmigung von Sir).
+static int cmd_scan()
+{
+	object obj;
+
+	if( !becomes_pl() && ( !objectp(top()) || !living(top()) ) )
+	{
+		if( stringp(top()) && file_size( "/save/"+top()[0..0]+"/"+top()+".o") > 0 )
+		{
+			obj = clone_object( T_PLAYER );
+			obj->Load( top() );
+			obj->SetProp( P_NAME, capitalize( pop() ) );
+			scan_obj( TRUE, obj );
+			destruct( obj );
+			return TRUE;
+		}
+		return error( "scan: TOS ist kein Lebewesen" );
+	}
+
+	scan_obj( query_once_interactive( top() ), pop() );
+	return TRUE;
+}
+
+static int WizLevel( object obj )
+{
+	if( obj->Notlogged() )
+		return query_wiz_level( lower_case(obj->playername()) );
+	else
+		return query_wiz_level( obj );
+}
+
+static string IpName( object obj )
+{
+	string ip_name, ip_num, nm;
+
+	if( obj->Notlogged() )
+	{
+		// Aus Umstellungsgruenden werden CALLED_FROM_IP und IP_NAME
+		// abgefragt. IP_NAME ist neuer.
+
+		nm = lower_case(obj->playername());
+		ip_name = obj->QueryProp(P_CALLED_FROM_IP);
+		if( !ip_name ) ip_name = obj->Query(P_IP_NAME);
+		return ip_name + " ("
+			+ dtime(get_dir("/save/"+nm[0..0]+"/"+nm+".o",4)[0]) +")";
+	}
+	else
+	{
+		nm = lower_case( obj->name(RAW) );
+		ip_name = query_ip_name( obj );
+		if( ip_name == "" || !ip_name )
+		{
+			ip_name = obj->QueryProp(P_CALLED_FROM_IP);
+			if( !ip_name ) ip_name = obj->Query(P_IP_NAME);
+			return ip_name + " ("
+				+ dtime(get_dir("/save/"+nm[0..0]+"/"+nm+".o",4)[0]) +")";
+		}
+		return ip_name + " [" + query_ip_number(obj) + "]";
+	}
+}
+
+string IdleTime( object obj )
+{
+	if( obj->Notlogged() ) return "-nicht da-";
+	if( query_ip_number(obj) ) return ""+query_idle(obj);
+	return "-netztot-";
+}
+
+static scan_obj( object player, object obj )
+{
+	string title, level, gender, room, testpl,
+		weapon, armour, quest, stat_str, *arr;
+	int i,ac;
+	object weaponobj, *list, *gegner;
+	mixed *hands, *quests, *stats;
+
+	// 1.Zeile : Name Titel - Rasse - [ Wizlevel ]
+	title = obj->QueryProp(P_TITLE);
+
+  if( !player )
+    level = "Monster" ;
+  else if( WizLevel( obj ) < WIZARD_LVL )
+	{
+		if( testpl=obj->QueryProp( P_TESTPLAYER ) )
+		{
+			if( stringp(testpl) )
+				level = "("+testpl+")";
+			else
+				level = "Testspieler";
+		}
+		else if( WizLevel( obj ) >= SEER_LVL )
+			level = "Seher";
+		else
+			level = "Spieler" ;
+	}
+  else if( WizLevel( obj ) >= GOD_LVL )
+    level = "MudGott" ;
+  else if( WizLevel( obj ) >= ARCH_LVL )
+    level = "Erzmagier" ;
+  else if( WizLevel( obj ) >= LORD_LVL )
+    level = "Regionsmagier" ;
+  else
+    level = "Magier" ;
+
+  if( !obj->short() )
+    level += ", unsichtbar" ;
+  if( obj -> QueryProp( P_FROG ) )
+    level += ", Frosch" ;
+  if( obj->QueryProp( P_GHOST ) )
+  	level += ", tot";
+	if( obj->Notlogged() )
+		level += ", ausgeloggt";
+	if(obj->QueryProp(P_SECOND) )
+		level +=", Zweitie";
+
+	if( environment(obj) )
+		room = object_name(environment( obj ));
+	else
+		room = "-nirgends-";
+
+  printf( "%s %s %s[ %s ].\nBefindet sich in %s.\n",
+		obj->name(RAW), title? title : "",
+		stringp(obj->QueryProp(P_RACE)) ? "- "+obj->QueryProp(P_RACE)+" - " : "",
+		level, room ) ;
+
+	// 1 abc Zeile : Host,Email,Snooper
+	if( player )
+	{
+		printf( "Host.......: %s\n", IpName(obj) );
+		printf( "E-Mail.....: %s.\n", obj->QueryProp(P_MAILADDR) );
+		if( !obj->Notlogged() && query_snoop(obj) )
+			printf( "Snooper....: %s.\n", capitalize(getuid(query_snoop(obj))) );
+
+		printf( "Vorsicht...: %11d Kurzmodus.: %11s Magierblick....: %11s.\n",
+			obj->QueryProp(P_WIMPY), obj->QueryProp(P_BRIEF) ? "-an-" : "-aus-",
+			obj->QueryProp(P_WANTS_TO_LEARN) ? "-an-" : "-aus-" );
+		printf( "Idlezeit...: %11s Alter.....: %11s Verheiratet mit: %-11s.\n",
+			IdleTime(obj), time2string("%5d:%02h:%02m",obj->QueryProp(P_AGE)*2),
+			(stringp(obj->QueryProp(P_MARRIED)) ? obj->QueryProp(P_MARRIED) : "-" )
+		);
+	}
+
+  // 2.Zeile : HP, SP und XP
+  printf( "Lebenspkt..: [%4d/%4d] Magiepkt..: [%4d/%4d].\n" +
+    "Questpunkte: [%4d/%4d] Erfahrung.: %11d.\n",
+    obj->QueryProp(P_HP), obj->QueryProp(P_MAX_HP),
+		obj->QueryProp(P_SP), obj->QueryProp(P_MAX_SP),
+		obj->QueryProp(P_QP), "/secure/questmaster"->QueryMaxQP(),
+		obj->QueryProp(P_XP) );
+
+  // 3.Zeile : FOOD, DRINK, ALCOHOL
+  printf( "Nahrung....: [%4d/%4d] Fluessigk.: [%4d/%4d] " +
+    "Alkohol........: [%4d/%4d].\n",
+    obj->QueryProp(P_FOOD), obj->QueryProp(P_MAX_FOOD),
+    obj->QueryProp(P_DRINK), obj->QueryProp(P_MAX_DRINK),
+    obj->QueryProp(P_ALCOHOL), obj->QueryProp(P_MAX_ALCOHOL) ) ;
+
+  // 4.Zeile : Geschlecht, Alignment, Level
+  switch( obj->QueryProp(P_GENDER) )
+  {
+    case FEMALE : gender = "weiblich   " ; break ;
+    case MALE   : gender = "maennlich  " ; break ;
+    default     : gender = "neutrum    " ; break ;
+  }
+  printf(
+		"Geschlecht.: %s Charakter.: %11d (Magier)Stufe..: [%4s/%4d].\n", 
+    gender, obj->QueryProp(P_ALIGN),
+		player ? WizLevel(obj)+"" : "-", obj->QueryProp(P_LEVEL) );
+
+	// 5.Zeile : Geld, Gewicht, Playerkills
+	printf( "Geld.......: %11d Traegt....: %11d Playerkills....: %11d.\n",
+		obj->QueryMoney(), obj->query_weight_contents(),
+		obj->QueryProp(P_KILLS) );
+
+  // 6.Zeile : stati
+  stats = obj->QueryProp(P_ATTRIBUTES) ;
+	arr = m_indices( stats );
+  stat_str = "" ;
+  for( i = 0; i < sizeof( arr ); i++ ) {
+    stat_str += capitalize(arr[ i ]) + "[" + stats[arr[ i ]];
+    if( ac = obj->QueryAttributeOffset(arr[i]) ) {
+    	stat_str += "+" + ac;
+    }
+    stat_str += "], ";
+  }
+
+  if( stat_str == "" )
+    stat_str = "Keine" ;
+  else
+    stat_str = stat_str[0..sizeof( stat_str ) - 3] ;
+  printf( "Attribute..: %s.\n", stat_str ) ;
+
+  // 7.Zeile : Waffe( Dateiname )[ AC ]
+  // 8.Zeile : Ruestung(en)[ WC ]
+	weaponobj=obj->QueryProp(P_WEAPON);
+	if( weaponobj )
+    weapon = weaponobj->name(RAW) + " (" + 
+      object_name( weaponobj ) + ") [" +
+      weaponobj->QueryProp(P_WC) + "]" ;
+	else
+	{
+		hands = obj->QueryProp(P_HANDS);
+		weapon = sprintf( "kaempft%s [%d]", hands[0], hands[1] );
+	}
+	ac = 0;
+	list = obj->QueryProp(P_ARMOURS);
+	armour = "";
+	for( i = 0; i < sizeof( list ); i++ )
+	{
+     armour += ( list[i]->name(RAW) + "[" +
+         list[i]->QueryProp(P_AC) + "]" + ", ") ;
+		 ac += list[i]->QueryProp(P_AC);
+	}
+
+  if( armour == "" )
+    armour = "Keine  " ;
+
+	arr = old_explode( break_string( armour[0..<3]+sprintf(" =>[%d]",
+		ac+obj->QueryProp(P_BODY) ), 65 ), "\n" ) ;
+	armour = arr[ 0 ] ;
+	for( i = 1; i < sizeof( arr ); i++ )
+		armour += "\n             " + arr[ i ] ;
+  printf( "Waffe......: %s.\nRuestung...: %s.\n", weapon, armour ) ;
+
+	gegner = obj->QueryEnemies();
+	if( pointerp(gegner) )
+	{
+		gegner = gegner[0];
+		for( i=0; i<sizeof(gegner); i++ )
+		{
+			if( i==0 ) printf( "Gegner.....: "); else printf( "             " );
+			if( !objectp(gegner[i]) )
+				printf( "<%O>\n", gegner[i] );
+			else
+				printf( "%s (%s)\n", gegner[i]->name(WER,0), object_name(gegner[i]) );
+		}
+	}
+
+	mk_waitfor( obj->QueryProp(P_WAITFOR) );
+
+	mk_autoload( obj->QueryProp(P_AUTOLOAD) );
+
+	return TRUE;
+}
+
+static void mk_waitfor( mixed waitfor )
+{
+	string str;
+	int i;
+
+	if( !pointerp(waitfor) || sizeof(waitfor)==0 )
+		return;
+	str = "Waiting for: ";
+	for( i=sizeof(waitfor)-1; i>0; i-- )
+		str += waitfor[i] + ", ";
+	str += waitfor[0];
+	write( str+"\n" );
+}
+	
+static void mk_autoload( mixed autoload )
+{
+	string str, *objlist;
+	int i;
+
+	if( !mappingp(autoload) )
+		return;
+	str = "Autoload...: ";
+	objlist = m_indices(autoload);
+	for( i=sizeof(objlist)-1; i>=0; i-- )
+	{
+		str += "\"" + objlist[i] + "\"\n";
+		if( i>0 )
+			str += "             ";
+	}
+	write( str );
+}
+
+static void print_memory_line( string key, object data, int flag )
+{
+  printf( " %-10s%s ", key, (flag ? ">" : "=") );
+  dump_obj( data, 13 );
+}
+	
+static int cmd_memory()
+{
+  int i;
+  if( !sizeof(memory) )
+    return memo( "Keine Variablen definiert" );
+
+  walk_mapping( memory, #'print_memory_line );
+  return TRUE;
+}
+
+static int cmd_array()
+{
+  mixed *array;
+  mixed ob;
+
+	if( !sizeof(stack) )
+		return error( "array: Der Stack ist leer" );
+  array = ({});
+  while( sizeof(stack) && (ob=pop()) && ob!=";" )
+    array = ({ob}) + array;
+  push( array );
+	return TRUE;
+}
+
+static int cmd_split()
+{
+  mixed *array;
+  int i;
+
+	if( !pointerp(top()) )
+		return error( "split: TOS ist kein Array" );
+  array=pop();
+  if( sizeof(stack) )
+    push( ";" );
+  for( i=0; i<sizeof(array); i++ )
+    push(array[i]);
+	return TRUE;
+}
+
+static int cmd_player()
+{
+	object ob;
+	string str;
+
+	str = top();
+	if( !stringp(str) )
+		return error( "player: TOS ist kein String" );
+	ob = becomes_pl();
+	if( !ob )
+		return error( "player: Keinen Spieler namens \""+str+"\" gefunden" );
+	//pop();
+	//push(ob);
+	return TRUE;
+}
+
+static int cmd_object()
+{
+	object ob;
+	string err,fnam;
+
+	if( !stringp(top()) )
+		return error( "object: TOS ist kein String" );
+	ob = find_object(top());
+	if( !ob )
+	{
+		if( !(fnam=this_player()->find_file(top(),".c")) )
+			return error( "object: Kein Objekt namens \""+top()+"\" gefunden" );
+		if( err=(catch(call_other(fnam,"?"))) )
+			return error( "object: Fehler beim Laden: "+err[1..<3] );
+		ob = find_object(fnam);
+	}
+	pop();
+	push(ob);
+	return TRUE;
+}
+
+static int cmd_living()
+{
+	object ob;
+	if( !stringp(top()) )
+		return error( "object: TOS ist kein String" );
+	ob = find_living(top());
+	if( !ob )
+		return error( "object: Kein Objekt namens \""+top()+"\" gefunden" );
+	pop();
+	push(ob);
+	return TRUE;
+}
+
+static int cmd_say()
+{
+	mit_say = !mit_say;
+	if( mit_say )
+		memo( "Meldungen an Mitspieler an" );
+	else
+		memo( "Meldungen an Mitspieler aus" );
+	return TRUE;
+}
+
+static int cmd_names()
+{
+	mit_namen = !mit_namen;
+	if( mit_namen )
+		memo( "Namen werden angezeigt" );
+	else
+		memo( "Namen werden nicht angezeigt" );
+	return TRUE;
+}
+
+static int cmd_secureinv()
+{
+	secureinv = !secureinv;
+	if( secureinv )
+		memo( "Inventory wird ueberwacht" );
+	else
+		memo( "Inventory wird nicht ueberwacht" );
+	set_heart_beat(secureinv);
+	return TRUE;
+}
+
+static int cmd_logaccess()
+{
+	dologaccess = !dologaccess;
+	if( dologaccess )
+		memo( "Zugriffe werden gemeldet" );
+	else
+		memo( "Zugriffe werden nicht gemeldet" );
+	return TRUE;
+}
+
+static int cmd_destruct_bang()
+{
+	if( !becomes_obj() )
+		return error( "destruct: TOS ist kein Objekt" );
+	destruct(pop());
+	return TRUE;
+}
+
+static int cmd_destruct()
+{
+	if( !becomes_obj() )
+		return error( "remove: TOS ist kein Objekt" );
+	memo( "destruct: TOS wird 'removed'!" );
+	top()->remove();
+	if( top() )
+		memo( "destruct: TOS lebt noch." );
+	else
+		pop();
+	return TRUE;
+}
+
+static int cmd_remove()
+{
+	if( !becomes_obj() )
+		return error( "remove: TOS ist kein Objekt" );
+	top()->remove();
+	if( top() )
+		memo( "destruct: TOS lebt noch." );
+	else
+		pop();
+	return TRUE;
+}
+
+static int cmd_update()
+{
+	object blue;
+
+	if( !becomes_obj() )
+		return error( "update: TOS ist kein Objekt" );
+	blue = find_object(old_explode(object_name(top()),"#")[0]);
+	blue->remove();
+	if( blue )
+		memo( "update: TOS lebt noch" );
+	else
+		pop();
+	return TRUE;
+}
+
+static int cmd_update_bang()
+{
+	if( !becomes_obj() )
+		return error( "update: TOS ist kein Objekt" );
+	destruct(find_object(old_explode(object_name(pop()),"#")[0]));
+	return TRUE;
+}
+
+static int cmd_roomupdate()
+{
+	return do_roomupdate( FALSE, FALSE );
+}
+
+static int cmd_roomupdate_bang()
+{
+	return do_roomupdate( TRUE, FALSE );
+}
+
+static int cmd_extroomupdate()
+{
+	return do_roomupdate( FALSE, TRUE );
+}
+
+static int cmd_extroomupdate_bang()
+{
+	return do_roomupdate( TRUE, TRUE );
+}
+
+// Hilfsfunktionen zum Filtern von Items
+static object *collect_items;
+static void collect( object* data ) { collect_items += ({ data[0] }); }
+
+static int do_roomupdate( int destflag, int noitems )
+{
+	object tmproom,newroom;
+	object *inv;
+	string errmsg;
+	string *file;
+	object *items;
+	int i;
+
+	if( !becomes_obj() )
+		return error( "roomupdate: TOS ist kein Objekt" );
+	file = old_explode( object_name( top() ), "#" );
+	if( sizeof(file) > 1 )
+		return error( "roomupdate: TOS ist keine Blueprint" );
+	if( file[0] == "/room/void" )
+		return error( "roomupdate: Die `void' darf nicht geupdatet werden" );
+
+	// ----- Rettung	
+	tell_room( top(),
+		"Der Raum verschwimmt vor Deinen Augen, um sich zu erneuern.\n"
+	);
+	tmproom = clone_object( "/room/void" );
+
+	if( noitems )
+	  // Nur Spieler kommen raus.
+		inv = filter( all_inventory(top()), #'query_once_interactive );
+	else
+	{ // Dinge, die P_ITEMS sind, bleiben da!
+		collect_items = ({});
+		map( top()->QueryProp(P_ITEMS), #'collect ); 
+		inv = all_inventory(top()) - collect_items;
+	}
+
+	for( i=sizeof(inv)-1; i>=0; i-- )
+		inv[i]->move( tmproom, M_NOCHECK | M_SILENT | M_NO_SHOW );
+
+	// ----- Vernichtung
+	if( destflag )
+		destruct( pop() );
+	else
+	{
+		top()->remove();
+		if( top() )
+			memo( "roomupdate : TOS ist nicht verschwunden." );
+		else
+			pop();
+	}
+
+	// ----- Neuerschaffung
+	errmsg = catch( call_other( file[0], "?" ) );
+	if( errmsg )
+	{
+		tell_room( tmproom, "Der Raum verbleicht in ein Nichts.\n" );
+		push( file[0] );
+		return error( "updateroom: " + errmsg[1..<2] );
+	}
+
+	// ----- Restaurierung
+	newroom = find_object( file[0] );
+	for( i=sizeof(inv)-1; i>=0; i-- )
+		if( objectp(inv[i]) ) // Objekte koennten sich beim ersten move zerstoeren.
+			inv[i]->move( newroom, M_NOCHECK | M_SILENT | M_NO_SHOW );
+	tell_room( newroom, "Die Konturen werden wieder scharf.\n" );
+	destruct( tmproom );
+	return TRUE;
+}
+
+static int cmd_clone()
+{
+	if( !stringp(top()) )
+		return error( "clone: TOS ist kein String" );
+	if( file_size(top()+".c")<=0 )
+		return error( "clone: Kein solches File" );
+	push(clone_object(pop()));
+	//do_move( top(), environment(PL) );
+	//top()->move(PL,M_GET|M_SILENT);
+	return TRUE;
+}
+
+static int cmd_move()
+{
+	object ob;
+
+	if( !becomes_obj() )
+		return error( "move: Ziel ist kein Objekt" );
+	ob = pop();
+	if( !becomes_obj() )
+		return error( "move: Kein solcher Gegenstand" );
+	do_move( pop(), ob );
+	return TRUE;
+}
+
+static int cmd_cleanof_bang()
+{
+	return do_cleanof( TRUE );
+}
+
+static int cmd_cleanof()
+{
+	return do_cleanof( FALSE );
+}
+
+static int do_cleanof( int strong )
+{
+	object *inv;
+	int i;
+	string clean_id;
+
+	if( !stringp(top()) )
+		return error( "cleanof: TOS ist kein String" );
+	clean_id = pop();
+	if( !becomes_obj() )
+	{
+		push( clean_id );
+		return error( "cleanof: Kein Objekt zum Leeren" );
+	}
+	for( i=0, inv=all_inventory(pop()); i<sizeof(inv); i++ )
+		if( inv[i]->id(clean_id) )
+		{
+			if( strong )
+				destruct( inv[i] );
+			else
+				inv[i]->remove();
+		}
+	return TRUE;
+}
+
+static int cmd_snoopers()
+{
+	object* u, snooper;
+	int i, flag;
+
+	flag = 0;
+	u = users();
+	for( i=0; i<sizeof(u); i++ )
+	{
+		if( snooper = query_snoop(u[i]) )
+		{
+			flag = 1;
+			printf( "%s wird gesnooped von: %s.\n",
+				capitalize(getuid(u[i])), capitalize(getuid(snooper)) );
+		}
+	}
+	if( !flag )
+		memo( "Momentan wird niemand gesnooped" );
+	return TRUE;
+}
+
+static int cmd_ping()
+{
+	object pl;
+
+	if( !becomes_pl() )
+		return error( "ping: TOS ist kein Spieler" );
+
+	pl=pop();
+	call_out( "ping", 0, ({ pl, 5 }) );
+	return TRUE;
+}
+
+static void ping( mixed* argv )
+{
+	if( !argv[0] || --argv[1] < 0 ) return;
+	tell_object( argv[0], BEEP+PL->name(WER)+" pingt Dich an.\n" );
+	call_out( "ping", 1, argv );
+}
+
+static void do_calloutinfo( mixed* call )
+{
+	int l,i;
+
+	if( pointerp(call) )
+	{
+		printf( "%5d:%O->%O(", call[2], call[0], call[1]);
+		if( (l=sizeof(call))>3 ) {
+			for( ; l>=3 && !call[--l]; ) ;
+			for( i=3; i<=l; i++ ) printf( "%O%s", call[i], (i==l)?"":"," );
+		}
+		write(")\n");
+	}
+}
+
+static int cmd_callouts_bang()
+{
+	mixed *calls;
+	object obj;
+	string name;
+	int i,j;
+
+	calls = call_out_info();
+	if( !pointerp(calls) || !sizeof(calls) )
+	{
+		memo( "Keine Callouts vorhanden" );
+		return TRUE;
+	}
+	map( calls, #'do_calloutinfo );
+	return TRUE;
+}
+
+static void do_calloutinfo2( mixed* call, string str )
+{
+	string s;
+	int i,l;
+
+	if( pointerp(call) )
+	{
+		s = sprintf( "%5d:%O->%O(", call[2], call[0], call[1]);
+		if( sizeof(explode(s,str)) > 1 )
+		{
+			write( s );
+			if( (l=sizeof(call))>3 ) {
+				for( ; l>=3 && !call[--l]; ) ;
+				for( i=3; i<=l; i++ ) printf( "%O%s", call[i], (i==l)?"":"," );
+			}
+			write(")\n");
+		}
+	}
+}
+
+static int cmd_callouts()
+{
+	mixed *calls;
+	object obj;
+	string str;
+	int i,j;
+
+	if( !stringp(top()) )
+		return error( "TOS ist kein String" );
+	str = pop();
+	calls = call_out_info();
+	if( !pointerp(calls) || !sizeof(calls) )
+	{
+		memo( "Keine Callouts vorhanden" );
+		return TRUE;
+	}
+	map( calls, #'do_calloutinfo2, str );
+	return TRUE;
+}
+
+static int cmd_heartbeats()
+{
+	mixed *beats;
+	int i;
+	object env;
+	string enam;
+
+	beats = heart_beat_info();
+	if( !pointerp(beats) || !sizeof(beats) )
+	{
+		memo( "Keine Heartbeats vorhanden" );
+		return TRUE;
+	}
+	for( i=0; i<sizeof(beats); i++ )
+	{
+		env = environment(beats[i]);
+		enam = env ? object_name(env) : "-- nirgends --";
+		printf( "%-35s %-35s\n", object_name(beats[i]), enam );
+	}
+	return TRUE;
+}
+
+static int cmd_wer()
+{
+	object* ppl;
+	string* pl;
+	int i;
+
+	ppl = sort_array( users(), lambda( ({ 'x, 'y }),
+		({ #'<, ({ #'query_ip_number, 'x }), ({ #'query_ip_number, 'y }) })
+	));
+	pl = ({});
+	for( i=0; i<sizeof(ppl); i++ )
+	{
+		pl += ({ sprintf( "%'.'-14s %-15s %3d %s \n",
+				capitalize(geteuid(ppl[i])),
+				query_ip_number(ppl[i]),
+				query_wiz_level(ppl[i])>0 ? query_wiz_level(ppl[i])
+					: ppl[i]->QueryProp(P_LEVEL),
+				query_wiz_level(ppl[i])>0 ? "W" : "P"
+		) });
+	}
+	write( implode(pl,"") );
+	return TRUE;
+}
+
+static int cmd_debuginfo()
+{
+	if( !becomes_obj() )
+		return error( "dinfo: TOS ist kein Objekt" );
+	debug_info( 0, pop() );
+	return TRUE;
+}
+
+static int cmd_pretty()
+{
+	pretty = !pretty;
+	if( pretty )
+		memo( "Schoenmodus an" );
+	else
+		memo( "Schoenmodus aus" );
+	return TRUE;
+}
+
+static int cmd_doprofile()
+{
+	do_profile=!do_profile;
+	if( do_profile )
+		memo( "Profile wird geladen" );
+	else
+		memo( "Profile wird nicht geladen" );
+	return TRUE;
+}
+
+static int cmd_evaluate()
+{
+	string str;
+	if( !sizeof(stack) ) return error( "evaluate: Stack ist leer" );
+	if( !stringp(top()) ) return error( "evaluate: TOS ist kein String" );
+	str = pop();
+	return do_cmd( str );
+}
+
+static void write_memory( string nam, string str, int flag, string file )
+{
+	if( flag ) write_file( file, nam + " = " + str + "\n" );
+}
+
+static int cmd_dump()
+{
+	string file;
+
+	if( !sizeof(stack) || !stringp(top()) )
+		file = "/players/"+getuid(PL)+"/.memory.o";
+	else
+		file = pop();
+	rm( file );
+	write_file( file, "# Dump des Tellerstapels vom " + dtime(time()) + "\n" );
+	write_file( file, "# Owner = "+capitalize(getuid(PL))+"\n" );
+	walk_mapping( memory, #'write_memory, file );
+	return TRUE;
+}
+
+static int restore_line( string line )
+{
+	string nam,str;
+	if( sscanf( line, "%s = %s", nam, str ) != 2 )
+		return error( "restore: Fehler im file" );
+	memory += ([ nam: str; 1 ]);
+  return 1;
+}
+
+static int cmd_restore()
+{
+	string str, *lines;
+
+	if( !sizeof(stack) || !stringp(top()) )
+		str = "/players/"+getuid(PL)+"/.memory.o";
+	else
+		str = pop();
+
+	if(file_size(str)<=0)
+		return error( "restore: kann '"+str+"' nicht laden" );
+	lines = regexp( old_explode( read_file(str), "\n" ), "^[^#]" );
+	map( lines, #'restore_line );
+	return TRUE;
+}
+
+static int cmd_if()
+{
+	if( sizeof(stack) < 3 )
+		return error( "if: zuwenig Argumente" );
+	if( !pop() )
+		cmd_swap();
+	pop();
+	return TRUE;
+}
diff --git a/obj/tools/teller/t_efun.c b/obj/tools/teller/t_efun.c
new file mode 100644
index 0000000..c1a2ded
--- /dev/null
+++ b/obj/tools/teller/t_efun.c
@@ -0,0 +1,416 @@
+static efun_regexp( arg1, arg2 )
+{
+	return regexp( arg1, arg2 );
+}
+
+static efun_all_inventory( arg )
+{
+	return all_inventory( arg );
+}
+
+static efun_break_string( arg1, arg2, arg3 )
+{
+	return break_string( arg1, arg2, arg3 );
+}
+
+static efun_capitalize( arg )
+{
+	return capitalize( arg );
+}
+
+static efun_cat( arg1, arg2, arg3 )
+{
+	return cat( arg1, arg2, arg3 );
+}
+
+static efun_clear_bit( arg1, arg2 )
+{
+	return clear_bit( arg1, arg2 );
+}
+
+static efun_crypt( arg1, arg2 )
+{
+	return crypt( arg1, arg2 );
+}
+
+static efun_ctime( arg )
+{
+	return ctime( arg );
+}
+
+static efun_debug_info( arg1, arg2 )
+{
+	return debug_info( arg1, arg2 );
+}
+
+static efun_deep_inventory( arg )
+{
+	return deep_inventory( arg );
+}
+
+static efun_environment( arg )
+{
+	return environment( arg );
+}
+
+static efun_explode( arg1, arg2 )
+{
+	return old_explode( arg1, arg2 );
+}
+
+static efun_file_name( arg )
+{
+	return object_name( arg );
+}
+
+static efun_file_size( arg )
+{
+	return file_size( arg );
+}
+
+static efun_filter_array( arg1, arg2, arg3, arg4 )
+{
+	return filter( arg1, arg2, arg3, arg4 );
+}
+
+static efun_find_call_out( arg )
+{
+	return find_call_out( arg );
+}
+
+static efun_find_living( arg )
+{
+	return find_living( arg );
+}
+
+static efun_find_object( arg )
+{
+	return find_object( arg );
+}
+
+static efun_find_player( arg )
+{
+	return find_player( arg );
+}
+
+static efun_function_exists( arg1, arg2 )
+{
+	return function_exists( arg1, arg2 );
+}
+
+static efun_implode( arg1, arg2 )
+{
+	return implode( arg1, arg2 );
+}
+
+static efun_interactive( arg )
+{
+	return interactive( arg );
+}
+
+static efun_intp( arg )
+{
+	return intp( arg );
+}
+
+static efun_last_reboot_time()
+{
+	return last_reboot_time();
+}
+
+static efun_living( arg )
+{
+	return living( arg );
+}
+
+static efun_lower_case( arg )
+{
+	return lower_case( arg );
+}
+
+static efun_get_dir( arg1, arg2 )
+{
+	return get_dir( arg1, arg2 );
+}
+
+static efun_map_array( arg1, arg2, arg3, arg4 )
+{
+	return map( arg1, arg2, arg3, arg4 );
+}
+
+static efun_member( arg1, arg2 )
+{
+	return member( arg1, arg2 );
+}
+
+static efun_objectp( arg )
+{
+	return objectp( arg );
+}
+
+static efun_pointerp( arg )
+{
+	return pointerp( arg );
+}
+
+static efun_present( arg1, arg2 )
+{
+	return present( arg1, arg2 );
+}
+
+static efun_process_string( arg )
+{
+	return process_string( arg );
+}
+
+static efun_query_actions( arg1, arg2 )
+{
+	return query_actions( arg1, arg2 );
+}
+
+static efun_query_idle( arg )
+{
+	return query_idle( arg );
+}
+
+static efun_query_ip_name( arg )
+{
+	return query_ip_name( arg );
+}
+
+static efun_query_ip_number( arg )
+{
+	return query_ip_number( arg );
+}
+
+static efun_query_load_average()
+{
+	return query_load_average();
+}
+
+static efun_query_snoop( arg )
+{
+	return query_snoop( arg );
+}
+
+static efun_random( arg )
+{
+	return random( arg );
+}
+
+static efun_read_bytes( arg1, arg2, arg3 )
+{
+	return read_bytes( arg1, arg2, arg3 );
+}
+
+static efun_read_file( arg1, arg2, arg3 )
+{
+	return read_file( arg1, arg2, arg3 );
+}
+
+static efun_remove_call_out( arg )
+{
+	return remove_call_out( arg );
+}
+
+static efun_remove_interactive( arg )
+{
+	return remove_interactive( arg );
+}
+
+static efun_rusage()
+{
+	return rusage();
+}
+
+static efun_say( arg1, arg2 )
+{
+	if( !arg2 ) return say( arg1 );
+	return say( arg1, arg2 );
+}
+
+static efun_set_bit( arg1, arg2 )
+{
+	return set_bit( arg1, arg2 );
+}
+
+static efun_set_heart_beat( arg )
+{
+	return set_heart_beat( arg );
+}
+
+static efun_set_living_name( arg )
+{
+	return set_living_name( arg );
+}
+
+static efun_sizeof( arg )
+{
+	return sizeof( arg );
+}
+
+static efun_sort_array( arg1, arg2, arg3 )
+{
+	return sort_array( arg1, arg2, arg3 );
+}
+
+static efun_stringp( arg )
+{
+	return stringp( arg );
+}
+
+static efun_strlen( arg )
+{
+	return sizeof( arg );
+}
+
+static efun_tail( arg )
+{
+	return tail( arg );
+}
+
+static efun_shout( arg )
+{
+	return shout( arg );
+}
+
+static efun_tell_object( arg1, arg2 )
+{
+	return tell_object( arg1, arg2 );
+}
+
+static efun_tell_room( arg1, arg2, arg3 )
+{
+	return tell_room( arg1, arg2, arg3 );
+}
+
+static efun_test_bit( arg1, arg2 )
+{
+	return test_bit( arg1, arg2 );
+}
+
+static efun_time()
+{
+	return time();
+}
+
+static efun_unique_array( arg1, arg2, arg3 )
+{
+	return unique_array( arg1, arg2, arg3 );
+}
+
+static efun_users()
+{
+	return users();
+}
+
+static efun_version()
+{
+	return version();
+}
+
+static efun_write( arg )
+{
+	return write( arg );
+}
+
+static efun_write_bytes( arg1, arg2, arg3 )
+{
+	return write_bytes( arg1, arg2, arg3 );
+}
+
+static efun_write_file( arg1, arg2 )
+{
+	return write_file( arg1, arg2 );
+}
+
+static efun_geteuid( arg )
+{
+	return geteuid( arg );
+}
+
+static efun_getuid( arg )
+{
+	return getuid( arg );
+}
+
+static efun_first_inventory( arg )
+{
+	return first_inventory( arg );
+}
+
+static efun_next_inventory( arg )
+{
+	return next_inventory( arg );
+}
+
+static efun_inherit_list( arg )
+{
+	return inherit_list( arg );
+}
+
+static efun_strstr( arg1, arg2, arg3 )
+{
+	return strstr( arg1, arg2, arg3 );
+}
+
+static efun_program_time( arg )
+{
+	return program_time( arg );
+}
+
+static efun_get_error_file( arg1, arg2 )
+{
+	return get_error_file( arg1, arg2 );
+}
+
+static efun_set_prompt( arg1, arg2 )
+{
+	return set_prompt( arg1, arg2 );
+}
+
+static efun_filter_objects( arg1, arg2, arg3 )
+{
+	return filter_objects( arg1, arg2, arg3 );
+}
+
+static efun_map_objects( arg1, arg2, arg3 )
+{
+	return map_objects( arg1, arg2, arg3 );
+}
+
+static efun_transpose_array( arg )
+{
+	return transpose_array( arg );
+}
+
+static efun_query_once_interactive( arg )
+{
+	return query_once_interactive( arg );
+}
+
+static efun_wizlist( arg )
+{
+	wizlist( arg );
+	return 1;
+}
+
+static efun_mkdir( str )
+{
+	return mkdir( str );
+}
+
+static efun_rm( str )
+{
+	return rm( str );
+}
+
+static efun_country( str )
+{
+	return country( str );
+}
+
+static efun_dtime( val )
+{
+	return dtime( val );
+}
diff --git a/obj/tools/teller/t_player.c b/obj/tools/teller/t_player.c
new file mode 100644
index 0000000..f72b100
--- /dev/null
+++ b/obj/tools/teller/t_player.c
@@ -0,0 +1,60 @@
+// ----------------------------------------------------------------------
+// Zwischenobjekt zum Lesen der Spielerdaten auch von nichteingeloggten.
+// ----------------------------------------------------------------------
+#include "teller.h"
+
+inherit "std/player/base";
+
+create() {
+	used_attributes_offsets = ([]);
+}
+
+string name;
+string race;
+string hands;
+mapping autoload;
+
+_query_name() { return name; }
+playername() { return name; }
+_set_name( str ) { return name=str; }
+
+_query_race()
+{
+	if( race ) return race;
+		
+	return "/secure/master"
+		->query_player_object(lower_case(name))
+		->QueryProp(P_RACE);
+}
+
+_query_hands()
+{
+	if( hands ) return hands;
+	return ({ " nicht", 0 });
+}
+
+_query_autoload()
+{
+	return autoload;
+}
+
+Load( str )
+{
+	restore_object( "/save/"+str[0..0]+"/"+str );
+}
+
+Notlogged() { return TRUE; }
+
+QueryMoney()
+{
+	if( !mappingp(autoload) )
+		return 0;
+	return autoload["/items/money"];
+}
+
+QueryEnemies()
+{
+        return ({({}),({})});
+}
+
+QueryAttributeOffset( arr ) { return "?"; }
diff --git a/obj/tools/teller/teller.c b/obj/tools/teller/teller.c
new file mode 100644
index 0000000..5f34f06
--- /dev/null
+++ b/obj/tools/teller/teller.c
@@ -0,0 +1,686 @@
+// ----------------------------------------------------------------------
+// Tellerstapel, ein Stackorientiertes magiertool.
+// Rumata 15.09.93
+// ----------------------------------------------------------------------
+#include "teller.h"
+inherit "std/secure_thing";
+inherit T_CMDS;
+inherit T_EFUN;
+inherit "std/more";
+
+#include "/secure/wizlevels.h"
+
+nosave mapping tcommands;
+nosave string owner_name;
+
+void logaccess( string s );
+static void do_msg( string s, object o );
+static string|int parseNext( string str, mixed auxstack, string funname );
+static mixed nextAlpha( string s );
+static varargs void restore_stack( string* argv, int args );
+static int do_call( string fun, int mit_return );
+static int do_call_efun( string fun, int mit_return );
+static int do_lpc( string str, int mit_return );
+static int do_cmd( string str );
+int error( string s );
+
+static void tAddCmd( mixed cmd )
+{
+	int i;
+
+	//if (find_player("rikus")) tell_object(find_player("rikus"),sprintf("%O\n",cmd));
+	if( !pointerp(cmd) )
+    m_add(tcommands, cmd, cmd);
+	else
+		for( i=0; i<sizeof(cmd); i++ )
+      m_add(tcommands, cmd[i], cmd[0]);
+}
+
+void create()
+{
+	if( IS_BLUE(ME) ) return;
+	if( !find_player(getuid()) ) return;
+	owner_name = find_player(getuid())->name(WESSEN,1);
+
+	secure_thing::create();
+	t_cmds::create();
+	SetProp( P_NAME, "Tellerstapel" );
+	SetProp( P_GENDER, MALE );
+	AddId( ({"teller","stapel","tellerstapel"}) );
+	SetProp( P_NODROP, "Wozu denn?\n" );
+	SetProp( P_NEVERDROP, 1 );
+	SetProp( P_READ_MSG, "Die Gravur besagt: 'Aus der Rumata-Manufaktur'\n" );
+	tcommands = ([]);
+	
+	tAddCmd( "say" );
+	tAddCmd( ({"names","nam"}) );
+	tAddCmd( "secureinv" );
+	tAddCmd( "logaccess" );
+	tAddCmd( "pretty" );
+	tAddCmd( "doprofile" );
+	tAddCmd( ({"clear","clr"}));
+	tAddCmd( "pop" );
+	tAddCmd( "dup" );
+	tAddCmd( "swap" );
+	tAddCmd( ({"evaluate","eval"}) );
+
+	tAddCmd( "here" );
+	tAddCmd( "me" );
+
+	tAddCmd( ({"memory","mem"}) );
+	tAddCmd( "dump" );
+	tAddCmd( "restore" );
+	tAddCmd( "top" );
+	tAddCmd( "wer" );
+	tAddCmd( ({"stack","stk"}) );
+	tAddCmd( ({"snoopers","snoop"}) );
+	tAddCmd( "callouts" );
+	tAddCmd( ({"callouts_bang","callouts!"}) );
+	tAddCmd( ({"heartbeats","beats"}) );
+	tAddCmd( "inv" );
+	tAddCmd( ({"rekinv","rinv"}) );
+	tAddCmd( "scan" );
+	tAddCmd( "if" );
+
+	tAddCmd( ({"array","arr"}) );
+	tAddCmd( ({"split","spl"}) );
+	tAddCmd( ({"player","pl"}) );
+	tAddCmd( ({"living","lv"}) );
+	tAddCmd( ({"object","ob"}) );
+
+	tAddCmd( ({"debuginfo","dinfo"}) );
+	tAddCmd( ({"clone","cln"}) );
+	tAddCmd( ({"update","upd"}) );
+	tAddCmd( ({"update_bang","update!","upd!"}) );
+	tAddCmd( ({"move","mv"}) );
+	tAddCmd( ({"destruct","dest","des"}) );
+	tAddCmd( ({"remove","rem"}) );
+	tAddCmd( ({"destruct_bang","destruct!","dest!","des!","remove!","rem!"}) );
+	tAddCmd( ({"roomupdate","rupdate","rupd","rup"}) );
+	tAddCmd( ({"roomupdate_bang","roomupdate!","rupdate!","rupd!","rup!"}) );
+	tAddCmd( ({"extroomupdate","rupdate*","rupd*","rup*"}) );
+	tAddCmd( ({"extroomupdate_bang","roomupdate*!","rupdate*!","rupd*!","rup*!",
+		"rup!*" }) );
+	tAddCmd( ({"cleanof","clnof"}) );
+	tAddCmd( ({"cleanof_bang","cleanof!","clnof!"}) );
+
+	tAddCmd( "ping" );
+}
+
+void init()
+{
+	//logaccess( "init" );
+	::init();
+	if ( !IS_WIZARD(PL) || environment()!=PL )
+		return;
+	add_action( "parse", ",", 1 );
+	add_action( "jonglier", "jonglier", 1 );
+	add_action( "message", "message" );
+	add_action( "message", "msg" );
+}
+
+short()
+{
+	logaccess( "short" );
+	return "Ein Stapel Teller.\n";
+}
+
+id( str )
+{
+	logaccess( "id" );
+	return ::id(str);
+}
+
+name( casus, dem, force )
+{
+	logaccess( "name" );
+	return ::name( casus, dem, force );
+}
+
+long()
+{
+	string answer;
+	
+	answer =
+		 "Du betrachtest "+owner_name+" magischen Tellerstapel. Die einzelnen Teller sind\n"
+		+"bis auf eine kleine Inschrift auf dem Boden weiss. Wenn Du hiermit\n"
+		+"jonglierst, kann ALLES passieren.\n";
+
+	if( getuid(PL) == getuid() )
+	{
+		answer +=
+			( mit_say
+				? "Die Teller sind beim Jonglieren sichtbar.\n"
+				: "Die Teller sind beim Jonglieren unsichtbar.\n"
+			) + ( mit_namen
+				? "Die Teller nennen die Dinge beim Namen.\n"
+				: "Die Teller nennen die Dinge beim Filenamen.\n"
+			) + ( pretty
+				? "Die Teller haben ein verschnoerkeltes Muster.\n"
+				: "Die Teller sind geradezu schmucklos.\n"
+			) + ( dologaccess
+				? "Die Teller spueren Zugriffe.\n"
+				: ""
+			) + ( secureinv
+				? "Die Teller bewachen Dein Inventar.\n"
+				: ""
+			) + ( do_profile
+				? "Die Teller werden beim Einloggen aktiv.\n"
+				: ""
+			);
+	} 
+	return answer; 	
+}
+
+void _set_autoloadobj( mixed val )
+{
+	if( !pointerp(val) ) return;
+	val += ({ 0,0,0,0,0,0 });
+	mit_namen = val[0];
+	mit_say = val[1];	
+	set_heart_beat( secureinv = val[2] );
+	dologaccess = val[3];
+	pretty = val[4];
+	do_profile = val[5];
+	if( do_profile ) call_out( "_load_profile", 0, this_player() );
+}
+
+mixed _query_autoloadobj()
+{
+	return ({ mit_namen, mit_say, secureinv, dologaccess, pretty,
+		do_profile });
+}
+
+void _load_profile( object pl )
+{
+	string pf,errmsg;
+
+	if( geteuid() && pl && geteuid(pl)==geteuid()
+		&& file_size(pf="/players/"+geteuid()+"/.profile.c")>0
+		&& (errmsg=catch(call_other(pf,"setup",pl)))
+	)
+		printf( "Error loading profile: %O\n", errmsg );
+}
+
+void logaccess( string str )
+{
+	if( RPL && dologaccess && getuid()!=getuid(RPL) && find_player(getuid())
+		&& previous_object() && getuid(previous_object()) != ROOTID
+		&& query_wiz_level(getuid())>=query_wiz_level(getuid(RPL))
+	)
+		tell_object( find_player(getuid()), "MEMO: " + str + "() von "
+			+ RPL->name(WEM) + " via ["
+			+ object_name(previous_object())+"].\n"
+		);
+	if( secureinv && find_player(getuid()) && !member(heart_beat_info(),ME) )
+	{
+		tell_object( find_player(getuid()), "MEMO: heart_beat restartet!.\n" );
+		set_heart_beat(TRUE);
+	}
+}
+
+// ----------------------------------------------------------------------
+// Hilfe-Funktionen
+// ----------------------------------------------------------------------
+static int secure()
+{
+	int i;
+	if( process_call() || secure_level()<query_wiz_level(RPL) ) return 0;
+	for( i=0; previous_object(i)==RPL; i++ )
+		;
+	return (!previous_object(i) || previous_object()==ME)
+		 && getuid()==getuid(RPL) && IS_WIZARD(RPL);
+}
+
+int jonglier( string str )
+{
+	string arg;
+
+	logaccess( "jongliere" );
+	if( !str || id(str) || sscanf( str, "mit %s", arg ) == 1 )
+	{
+		if( !secure() )
+			write(
+				"Dieser Tellerstapel ist nichts fuer Dich. Suche Dir einen eigenen.\n"
+			);
+		else
+			write(
+			  "Der Jonglierbefehl lautet \";\" oder \",\".\n"
+			+	"\";hilfe <befehl>\" gibt Dir Hilfestellung.\n"
+			);
+		return TRUE;
+	}
+  return 0;
+}
+			
+static int zeige_hilfe( string str )
+{
+	if( !stringp(str) ) str = "general";
+	str = implode( old_explode( HELP(str), "/../" ), "/" );
+	if( file_size(str) > 0 )
+	{
+		More( str, 1 );
+		return TRUE;
+	}
+	write( "Zu diesem Thema gibt es keine Hilfe.\n" );
+	return TRUE;
+}
+
+int message( string str )
+{
+	string pl;
+	object dest;
+
+	if( !secure() ) return FALSE;
+
+	if( str )
+	{
+		if( sscanf( str, "to %s", pl ) == 1 )
+			str = pl;
+		if( !(dest = find_player(str) ) )
+		{
+			write( capitalize(str) + " ist nicht eingeloggt.\n" );
+			return TRUE;
+		}
+	}
+	else
+		dest = 0;
+
+	do_msg( "<Mitteilung von "+PL->name(WEM)+">", dest );
+	write( "Mitteilung"
+		+ ( dest ? " an " + dest->name(WEN) : "" )
+		+ " kann mit '**' beendet werden.\n" );
+
+	input_to( "more_message", 0, dest );
+	return TRUE;
+}
+
+static void do_msg( string str, object obj )
+{
+	if( obj )
+		tell_object( obj, str + "\n" );
+	else
+		say( str + "\n" );
+}
+
+static int more_message( string str, object obj )
+{
+	if( str != "**" )
+	{
+		do_msg( str, obj );
+		input_to( "more_message", 0, obj );
+	}
+	else
+		do_msg( "<Ende der Mitteilung>", obj );
+	return TRUE;
+}
+
+// ----------------------------------------------------------------------
+// Parse-Funktionen
+// ----------------------------------------------------------------------
+int parse( string str )
+{
+	int i;
+	string arg, rest;
+
+	if( !secure() ) return FALSE;
+
+	// Die Hilfe faellt aus der allgemeinen Syntax heraus !
+	if( query_verb()[1..] == "hilfe" || query_verb()[1..] == "help" )
+		return zeige_hilfe( str );
+
+	if( str=this_player()->_unparsed_args() )
+		str = query_verb()[1..]+" "+str;
+	else
+		str = query_verb()[1..];
+
+	fehler_passiert = FALSE;
+	while( !fehler_passiert && str && str!="" )
+		str = parseNext( str, ({}), "-ROOT-" );
+
+	if( mit_say && !PL->QueryProp(P_INVIS) )
+	{
+		if( !fehler_passiert )
+			say( PL->name(WER)+" jongliert mit "
+				+ PL->QPP(MALE,WEM,PLURAL)+" Tellern.\n" );
+		else
+			say( PL->name(WEM)+" faellt beim Jonglieren ein Teller herunter.\n" );
+	}
+	if( !fehler_passiert )
+		write( "OK.\n" );
+	return TRUE;
+}
+
+static string|int parseNext( string str, mixed auxstack, string funname )
+{
+	mixed *res;
+	string arg, rest;
+	bool mit_return;
+	int num;
+
+	while( str!="" && str[0]==' ' )
+		str = str[1..];
+	if( str=="" )
+		return FALSE;
+
+	switch( str[0] )
+	{
+		case ';': // ---------------------------------------- Kommandobeginn
+		case ',':
+			push( ";" );
+			return str[1..];
+		case '\"': // --------------------------------------- Stringkonstante
+			if( sscanf( str, "\"%s\"%s", arg, rest )==2 )
+			{
+				/* test auf numerisch fehlt hier noch */
+				push_str( arg );
+				return rest;
+			}
+			if( !sscanf( str, "\"%s\"", arg ) )
+				return error( "String ohne Ende" );
+			push_str( arg );
+			return FALSE;
+		case '#': // ---------------------------------------- Zahl
+			res = nextAlpha( str[1..] );
+			if( sscanf( res[0], "%d", num ) == 1 )
+			{
+				push( num );
+				return res[1];
+			}
+			return error( "'#': keine erlaubte Zahl" );
+		case '^': // ---------------------------------------- Hole env
+			if( !becomes_obj() )
+				return error( "'^': TOS ist kein Objekt" );
+			if( !environment(top()) )
+				return error( "'^': TOS hat kein Environment" );
+			push(environment(pop()));
+			return str[1..];
+		case '.': // ---------------------------------------- Hole aus inv
+			if( !becomes_obj() )
+				return error( "'.': TOS ist kein Objekt" );
+			res = nextAlpha( str[1..] );
+			calcinv( res[0] );
+			return res[1];
+		case '<': // ---------------------------------------- Recall
+			if( !sscanf( str, "<%s", arg ) || arg=="" )
+				return error( "'<': Variablenname fehlt" );
+			res = nextAlpha( str[1..] );
+			do_recall(res[0]);
+			return res[1];
+		case '>': // ---------------------------------------- Store
+			if( !sscanf( str, ">%s", arg ) || arg=="" )
+				return error( "'>': Variablenname fehlt" );
+			res = nextAlpha( str[1..] );
+			do_store(res[0]);
+			return res[1];
+		case '-': // ---------------------------------------- Call mit '-'
+			str = str[1..];
+			if( mit_return = (str[0] == '-') )
+				str = str[1..];
+			res = nextAlpha( str[1..] );
+			switch( str[0] )
+			{
+				case '>':
+					if( do_call( res[0], mit_return ) )
+						return res[1];
+					break;
+				case '*':
+					if( do_call_efun( res[0], mit_return ) )
+						return res[1];
+					break;
+				default:
+					return error( "'-': '>' oder '*' erwartet" );
+			}
+			return FALSE;
+		case '\'': // --------------------------------------- Call
+			str = str[1..];
+			if( mit_return = (str[0] == '\'') )
+				str = str[1..];
+			res = nextAlpha( str );
+			if( do_call( res[0], mit_return ) )
+				return res[1];
+			return FALSE;
+		case '`': // --------------------------------------- Call Efun
+			str = str[1..];
+			if( mit_return = (str[0] == '`') )
+				str = str[1..];
+			res = nextAlpha( str );
+			if( do_call_efun( res[0], mit_return ) )
+				return res[1];
+			return FALSE;
+		case '@': // --------------------------------------- Evaluate
+			str = str[1..];
+			if( mit_return = (str[0] == '@') )
+				str = str[1..];
+			if( do_lpc( str, mit_return ) )
+				return FALSE;
+			return FALSE;
+		case '!': // ------------------------------------------- META
+			if( sscanf(str,"!%d%s",num,arg)==2 )
+			{
+				if( num>=sizeof(auxstack) )
+					return error( "'"+funname+"': zu weing Argumente" );
+				push( auxstack[num] );
+			}
+			else
+			{
+				res = nextAlpha( str[1..] );
+				memory += ([ res[0]: res[1]; 1 ]);
+				return FALSE;
+			}
+			return arg;
+		default: // ----------------------------------------- default
+			res = nextAlpha( str );
+			do_cmd(res[0]);
+			return res[1];
+	}
+	return memo( "Etwas Seltsames ist passiert" );
+}
+
+static int do_cmd( string str )
+{
+	string fun, filename, *spl;
+	mixed* oldstack;
+	int i,max,num;
+
+	if( member(memory,str) )
+	{
+		fun = memory[str,0];
+		if( !memory[str,1] ) // normale Variablen
+		{
+			push( fun );
+			return TRUE;
+		}
+		oldstack = stack;
+		stack = ({});
+		spl = regexplode( fun, "![0-9][0-9]*" );
+		max = -1;
+		for( i=1; i<sizeof(spl); i+=2 )
+			if( sscanf(spl[i],"!%d",num) && max<num ) max = num;
+
+		while( !fehler_passiert && fun && fun!="" )
+			fun = parseNext( fun, oldstack, str );
+		if( fehler_passiert )
+		{
+			stack = oldstack;
+			return FALSE;
+		}
+		stack = stack + oldstack[(max+1)..];
+		return TRUE;
+	}
+  else if (fun=tcommands[str])
+		return call_other(ME,"cmd_"+fun);
+
+	if( sscanf( str, "%d", i ) )
+		push( i );
+	else
+	{
+		filename = MASTER->_get_path(str,getuid());
+		if( filename[<1] == '.' )
+			filename = filename[0..<2];
+		if( file_size( filename+".c" ) != -1 )
+			push( filename );
+		else
+			push( str );
+	}
+	return TRUE;
+}
+
+static mixed nextAlpha( string str )
+{
+	int pos;
+
+	for( 
+		pos=0;
+		pos<sizeof(str) && member( " #\";,^.><", str[pos] ) == -1;
+		pos++
+	)
+		;
+
+	if( pos==sizeof(str) )
+		return ({ str, 0 });
+	else
+		return ({ str[0..pos-1], str[pos..] });
+}
+
+static varargs void restore_stack( string* argv, int args )
+{
+	int i;
+	if( !args )
+		args = sizeof(argv);
+	if( sizeof(stack) ) push( ";" );
+	for( i=0; i<args; i++ )
+		push(argv[i]);
+}
+
+static int do_call( string fun, int mit_return )
+{
+	int args;
+	string err;
+	mixed result;
+	mixed arg, *argv;
+
+	argv = ({});
+	while( sizeof(stack) && (arg=pop())!=";" )
+		argv = ({arg}) + argv;
+	if( !becomes_obj(argv) )
+	{
+		restore_stack( argv );
+		return error( "call: Funktion nicht an Objekt gerichtet" );
+	}
+	if( !function_exists(fun,argv[0]) )
+	{
+		restore_stack(argv);
+		return error( "call: Funktion nicht gefunden" );
+	}
+
+	args = sizeof(argv);
+	argv += ({ 0,0,0,0,0 });
+	err=(catch(result=call_other(argv[0],fun,
+		argv[1],argv[2],argv[3],argv[4],argv[5])));
+	if( err )
+	{
+		restore_stack( argv, args );
+		return error( "call: "+err[1..<2] );
+	}
+	else
+	{
+		write( "=> " );
+		dump_obj( result, 3 );
+		if( mit_return )
+			push( result );
+	}
+	return TRUE;
+}
+
+static int do_call_efun( string fun, int mit_return )
+{
+	int args;
+	string err;
+	mixed result;
+	mixed arg, *argv;
+
+	argv = ({});
+	while( sizeof(stack) && (arg=pop())!=";" )
+		argv = ({arg}) + argv;
+
+	if( !function_exists( "efun_"+fun ) )
+		return error( "call efun: \""+fun+"\" nicht benutzbar" );
+	fun = "efun_"+fun;
+
+	args = sizeof(argv);
+	argv += ({ 0,0,0,0,0 });
+	err=(catch(result=call_other(ME,fun,
+			argv[0],argv[1],argv[2],argv[3],argv[4])));
+	if( err )
+	{
+		restore_stack( argv, args );
+		return error( "call efun: "+err[1..<2] );
+	}
+	else
+	{
+		write( "=> " );
+		dump_obj( result, 3 );
+		if( mit_return )
+			push( result );
+	}
+	return TRUE;
+}
+
+static int do_lpc( string str, int mit_return )
+{
+	int args, val;
+	string err;
+	string file, cmd, pre, post;
+	mixed result;
+	mixed arg, *argv;
+
+	argv = ({});
+	while( sizeof(stack) && (arg=pop())!=";" )
+		argv = argv + ({arg});
+
+	file = "/players/"+getuid()+"/.teller";
+	cmd = "#include <language.h>\n#include <properties.h>\n"
+		+ "#include <moving.h>\n#include <defines.h>\n#include <terminal.h>\n"
+		+ "#include <wizlevels.h>\n#include <ansi.h>\ncreate(){}doit(){";
+
+	while( str!="" && sscanf( str, "%s@%s", pre, post ) == 2 )
+	{
+		if( sscanf( str, "%s@%d@%s", pre, val, post ) == 3 )
+		{
+			if( sizeof(argv)<=val || val<0 )
+			{
+				restore_stack( argv, args );
+				return error( "lpc: Illegaler Index auf den Stack" );
+			}
+			cmd += pre + DumpObj(argv[val]);
+			str = post;
+		}
+		else
+			if( sscanf( str, "%s@%s", pre, post ) == 2 )
+			{
+				cmd += pre + "@";
+				str = post;
+			}
+	}
+	cmd += str;
+	rm( file+".c" );
+	write_file( file+".c" , cmd+";}\n" );
+	if( find_object(file) ) destruct( find_object(file) );
+	err=(catch(result=call_other(file,"doit")));
+	if( err )
+	{
+		//rm( file+".c" );
+		restore_stack( argv, args );
+		return error( "lpc: "+err[1..<2] );
+	}
+	else
+	{
+		//rm( file+".c" );
+		write( "=> " );
+		dump_obj( result, 3 );
+		if( mit_return )
+			push( result );
+	}
+	return TRUE;
+}
diff --git a/obj/tools/teller/teller.h b/obj/tools/teller/teller.h
new file mode 100644
index 0000000..841d796
--- /dev/null
+++ b/obj/tools/teller/teller.h
@@ -0,0 +1,22 @@
+#ifndef _TELLER_H_
+#define _TELLER_H_
+
+#include <properties.h>
+#include <language.h>
+#include <defines.h>
+
+#define TRUE 1
+#define FALSE 0
+#define bool int
+
+#define INFORMER "/secure/merlin"
+//#define MASTER "/secure/master"
+
+#define T_BASE "/obj/tools/teller/t_base"
+#define T_EFUN "/obj/tools/teller/t_efun"
+#define T_CMDS "/obj/tools/teller/t_cmds"
+#define T_PLAYER "/obj/tools/teller/t_player"
+
+#define HELP(x) ("/obj/tools/teller/hilfe/"+(x))
+
+#endif