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