MG-spezifische Ergaenzen zu Driver efun manpages

neue Manpages, welche Ergaenzungen, Bemerkungen oder
Beispiele zu Manpages zu efuns aus dem Driver
enthalten.

Change-Id: Ia33f28857d5acc21f1ade3abe86a04052d8f6728
diff --git a/doc/sphinx/efun-mg.index.rst b/doc/sphinx/efun-mg.index.rst
new file mode 100644
index 0000000..8ef041c
--- /dev/null
+++ b/doc/sphinx/efun-mg.index.rst
@@ -0,0 +1,16 @@
+.. Morgengrauen-Mudlib - efun-Doku.
+
+MG-Manpages fuer efuns
+======================
+
+Fuer einige efuns haben wir Ergaenzungen, Bemerkungen oder Beispiele
+zu den Manpages aus dem Driver erstellt. Diese sind im Folgenden zu
+finden.
+
+Verzeichnis der dokumentierten sefuns im Morgengrauen:
+
+.. toctree::
+   :maxdepth: 1
+   :glob:
+
+   efun-mg/*
diff --git a/doc/sphinx/efun-mg/add_action.rst b/doc/sphinx/efun-mg/add_action.rst
new file mode 100644
index 0000000..cac361a
--- /dev/null
+++ b/doc/sphinx/efun-mg/add_action.rst
@@ -0,0 +1,54 @@
+add_action(E)
+=============
+
+BEMERKUNGEN
+-----------
+
+  1. Das Verhalten dieser efun wird durch AddCmd aus /std/thing/commands.c
+     komfortabler widergespiegelt. Darauf sollte man zurueckgreifen.
+  2. add_action() sollte immer innerhalb von init() benutzt werden
+  3. das definierende Objekt muss im inventory des Spielers oder
+     environment() des kommandogebenden Lebewesens sein
+  4. im init() spaeter eingetragene Kommandos oder spaeter hinzukommende
+     Objekte werden bei der Kommandoauswertung VOR den alten beruecksichtigt.
+     (Daher bewegt sich das Xtool der Magier regelmaessing neu in das
+      Inventory, um immer "erstes" Objekt zu sein.)
+
+BEISPIELE
+---------
+
+  1. ein Kommando in einem Schirm
+
+    .. code-block:: pike
+
+      void init() {
+        ::init();
+        add_action("action_oeffne", "oeffne");
+      }
+
+      int action_oeffne(string str) {
+        if(stringp(str) && id(str)) // Argument da und bin ich gemeint?
+        {
+          write("Du oeffnest den Schirm.\n");
+          say(break_string(this_player()->Name(WER)+" oeffnet einen Schirm.",
+                78));
+          return 1;
+        }
+        notify_fail("Was willst Du oeffnen?\n");
+        return 0;
+      }
+
+   2. Kommandoblockierer:
+      frueher beliebt um Spieler lahmzulegen, da es _alle_ Kommandos 
+      triggert. Heute jedoch dafuer eher P_DISABLE_COMMANDS verwenden.
+      *Achtung*: siehe Implikation von (4) oben.
+
+     .. code-block:: pike
+
+       add_action("action_nothing", "",1 );
+       ...
+       int action_nothing(string str) {
+         write("Dir sind die Haende gebunden.\n");
+         return 1;
+       }
+
diff --git a/doc/sphinx/efun-mg/all_inventory.rst b/doc/sphinx/efun-mg/all_inventory.rst
new file mode 100644
index 0000000..56ed12c
--- /dev/null
+++ b/doc/sphinx/efun-mg/all_inventory.rst
@@ -0,0 +1,10 @@
+all_inventory
+=============
+
+BEMERKUNGEN
+-----------
+
+Gerade bei sehr vollen Objekten ist first_inventory() und 
+next_inventory() eine gute Alternative, die die Erzeugung langer Arrays
+vermeidet.
+
diff --git a/doc/sphinx/efun-mg/call_out.rst b/doc/sphinx/efun-mg/call_out.rst
new file mode 100644
index 0000000..ec64239
--- /dev/null
+++ b/doc/sphinx/efun-mg/call_out.rst
@@ -0,0 +1,10 @@
+call_out
+========
+
+WARNUNG
+-------
+  Bitte nie call_out(..., 0) in rekursiven Callouts nutzen und in anderen
+  Anwendungen sehr vorsichtig damit sein. So ein Callout wuerde direkt nach
+  nach dem aktuellen Callout ausgefuehrt und man erhaelt wirklich eine
+  Verzoegerung von 0.
+
diff --git a/doc/sphinx/efun-mg/count_bits.rst b/doc/sphinx/efun-mg/count_bits.rst
new file mode 100644
index 0000000..bb700c5
--- /dev/null
+++ b/doc/sphinx/efun-mg/count_bits.rst
@@ -0,0 +1,9 @@
+count_bits
+==========
+
+BEMERKUNGEN
+-----------
+
+  Arbeitet eigentlich nur sinnvoll auf Bitstrings, nicht auf allgemeinen
+  Strings! :)
+
diff --git a/doc/sphinx/efun-mg/environment.rst b/doc/sphinx/efun-mg/environment.rst
new file mode 100644
index 0000000..04cf5c1
--- /dev/null
+++ b/doc/sphinx/efun-mg/environment.rst
@@ -0,0 +1,61 @@
+environment
+===========
+
+BEMERKUNGEN
+-----------
+
+  Blueprints, wie zum Beispiel Raeume haben oft kein environment(). Man sollte
+  daher ueberpruefen, ob ein environment() existiert, wenn man darin oder
+  darauf eine Funktion aufrufen will.
+
+BEISPIELE
+---------
+
+   .. code-block:: pike
+
+     // In der Variable "raum" steht der Raum, in dem sich der Spieler
+     // derzeit aufhaelt - das kann auch 0 sein!
+
+     raum = environment(this_player());
+
+     // Dieses Objekt hat noch kein environment, da es eben erst geclont
+     // wurde. Ergo steht in env eine 0.
+     obj = clone_object("/std/thing");
+     env = environment(obj);
+
+     // alle Methoden die auf Environment arbeiten, sollten das vorher
+     // pruefen - insbesondere tell_room()
+     if(this_player() && environment(this_player()) &&
+        objectp(o=present("schild",environment(this_player()))) {
+
+      write("Du klebst Deine Plakette auf "+o->name(WEN)+".\n");
+      tell_room(environment(this_player()), break_string(
+            this_player()->Name(WER)+" pappt einen Aufkleber auf "
+            +o->name(WEN)+".",78), ({this_player()}));
+     }
+
+     // wenn Dinge sehr offensichtlich in Leuten kaputtgehen wird es
+     // komplexer (man kann das natuerlich noch weiter schachteln oder
+     // ueber all_environment() versuchen zu loesen
+     if(environment()) {
+      object ee;
+      ee=environment(environment());
+      if(living(environment()))
+      {
+        tell_object(environment(),Name(WER)+" zerfaellt.\n");
+        if(ee)
+          tell_room(ee, environment()->Name(WESSEN)
+               +" "+name(RAW)+" zerfaellt.\n", ({environment()}));
+      }
+      else if(ee && living(ee))
+      {
+        if(environment()->QueryProp(P_TRANSPARENT))
+          tell_object(ee, Name(WER)+" zerfaellt in Deine"
+              + (environment()->QueryProp(P_PLURAL) ? "n" : 
+                  (environment()->QueryProp(P_GENDER)==FEMALE?"r":"m"))
+              + environment()->name(RAW)+".\n");
+      }
+      else
+        tell_room(environment(),Name(WER)+" zerfaellt.\n");
+     }
+
diff --git a/doc/sphinx/efun-mg/file_size.rst b/doc/sphinx/efun-mg/file_size.rst
new file mode 100644
index 0000000..134cde2
--- /dev/null
+++ b/doc/sphinx/efun-mg/file_size.rst
@@ -0,0 +1,21 @@
+file_size
+=========
+
+BEISPIELE
+---------
+
+  .. code-block:: pike
+
+      Ein Spieler soll seinen Plan abfragen koennen:
+
+      #include <sys/files.h>
+      if(file_size("/p/service/loco/plans/"+
+                   getuid(this_player())+".plan") <= FSIZE_NOFILE)
+      {
+        write("Du hast keinen eigenen Plan festgelegt.\n");
+        return 1;
+      }
+
+      this_player()->More(read_file("/p/service/loco/plans/"+
+                          getuid(this_player())+".plan");
+
diff --git a/doc/sphinx/efun-mg/filter.rst b/doc/sphinx/efun-mg/filter.rst
new file mode 100644
index 0000000..92244d8
--- /dev/null
+++ b/doc/sphinx/efun-mg/filter.rst
@@ -0,0 +1,95 @@
+filter
+======
+
+BEMERKUNGEN
+-----------
+
+  1. Achtung, die Elemente in 'arr' werden nicht tief kopiert, sind sie
+     also selbst Arrays oder Mappings, so fuehrt eine spaetere Aenderung
+     im Rueckgabe-Arrays zur Aenderung im Ursprungsarray:
+
+     .. code-block:: pike
+
+       int *i, *j;
+       i=({({1,2,3}),({4,5,6})});
+       j=filter(i, #'sizeof);     // filtert leere Arrays heraus
+       j[0][0]=8;
+
+    fuehrt zu: i==j==({({8,2,3}),({4,5,6})});
+
+  2. Das Kopieren in das Rueckgabemapping erfolgt fuer jedes Element nach
+     Ausfuehrung der Filtermethode. Aenderungen der Werte im Array in dieser
+     Methode (globale Variable/Uebergabe als Referenz an filter)
+     schlagen sich also im Rueckgabearray nieder.
+
+  3. Fuer Arrays wirkt filter() wie filter_array(), fuer Mappings stellt
+     filter() eine Verallgemeinerung von filter_indices() dar.
+
+BEISPIELE
+---------
+
+::
+
+    ### Filtere alle Lebewesen in einem Raum in ein Array ###
+    filter(all_inventory(this_object()),#'living);
+
+    ### Filtere alle tauben Spieler im Raum in ein Array ###
+    static int filter_isdeaf(object who) {
+      return (interactive(who) && who->QueryProp(P_DEAF));
+    }
+
+    filter(all_inventory(this_object()), #'filter_isdeaf);
+
+
+    ### Filtern von Idlern (>=1 Sekunde idle) ###
+    // Folgend identische Resultate, aber andere Ansaetze:
+
+    #1: nutzt die Efun query_idle() als Lfun-Closure (ideal hier)
+        idle_usr = filter(users(), #'query_idle );
+
+    #2: mit Filtermethode
+        int check_if_idle(object user) {
+          return query_idle(user);
+        }
+
+        #2a: filtert mittels der Lfun im selben Objekt die Idler in das
+             Rueckgabearray
+             idle_usr = filter(users(), "check_if_idle");
+             idle_usr = filter(users(), "check_if_idle", this_object());
+
+        #2b: ruft die Lfun check_if_idle() als Lfun-Closure (Funktions-
+             pointer)
+             idle_usr = filter(users(), #'check_if_idle );
+
+    #3: Nutzt eine Inline-Closure
+        idle_usr = filter(users(), function int (object user) {
+                     return query_idle(user);
+                   } );
+
+    ### Filtern von Idlern (>=20 Sekunden idle) mit Extraparameter ###
+    // Folgend identische Resultate, aber andere Ansaetze:
+
+    #1: die Efun koennen wir nicht mehr direkt nutzen, weil sie
+        diesen Parameter nicht unterstuetzt
+       // idle_usr = filter(users(), #'query_idle );
+
+    #2: mit separater Filtermethode ... mit neuem Parameter
+        int check_if_idle(object user, int length) {
+          return query_idle(user)>length;
+        }
+
+        #2a: filtert mittels der Lfun im selben Objekt die Idler in das
+             Rueckgabearray ... mit drittem Parameter!
+             idle_usr = filter(users(), "check_if_idle", this_object(), 20);
+
+        #2b: ruft die Lfun check_if_idle() als Lfun-Closure (Funktions-
+             pointer)
+             idle_usr = filter(users(), #'check_if_idle, 20);
+
+    #3: Nutzt eine Inline-Closure
+        idle_usr = filter(users(), function int (object user, int length) {
+                     return (query_idle(user) > length); 
+                     }, 20);
+
+----------------------------------------------------------------------------
+23.09.2019, Zesstra
diff --git a/doc/sphinx/efun-mg/filter_objects.rst b/doc/sphinx/efun-mg/filter_objects.rst
new file mode 100644
index 0000000..07ec616
--- /dev/null
+++ b/doc/sphinx/efun-mg/filter_objects.rst
@@ -0,0 +1,27 @@
+filter_objects
+==============
+
+BEMERKUNGEN
+-----------
+
+  Werden Pfade angegeben, so wird versucht ein Objekt zu laden, falls
+  dieses nicht existiert.
+
+BEISPIELE
+---------
+
+  .. code-block:: pike
+
+     // gibt alle tauben Personen wieder
+     deaf=filter_objects(users(), "QueryProp", P_DEAF);
+
+     // gibt alle blinden Personen wieder
+     blind=filter_objects(users(), "QueryProp", P_BLIND);
+
+     // filtert alle Objekte auf eine bestimmte ID (-> present)
+     idmatch=filter_objects(arr, "id", "irgendwasID");
+
+     // gibt alle Autoloader wieder
+     al=filter_objects(all_inventory(this_player()),
+                      "QueryProp", P_AUTOLOADOBJ);
+
diff --git a/doc/sphinx/efun-mg/find_call_out.rst b/doc/sphinx/efun-mg/find_call_out.rst
new file mode 100644
index 0000000..53ef4d0
--- /dev/null
+++ b/doc/sphinx/efun-mg/find_call_out.rst
@@ -0,0 +1,35 @@
+find_call_out
+=============
+
+BEISPIELE
+---------
+
+  .. code-block:: pike
+
+    // Findet sich kein call_out auf die Funktion 'func', so kann er
+    // gestartet werden. (Wichtig falls der call_out nicht mehrfach
+    // aufgerufen werden soll).
+
+    if(find_call_out("func")==-1)
+      call_out("func",5);
+
+BEMERKUNGEN
+-----------
+
+  Die Suche nach call_out()s auf Closures funktioniert nur, wenn der
+  genaue Wert der Closure gesucht wird.
+
+  .. code-block:: pike
+
+    // Das funktioniert:
+        closure cl = symbol_function("main", obj);
+        call_out(cl, 2);
+        find_call_out(cl);
+
+    // Das funktioniert nicht:
+        call_out(symbol_function("main", obj), 2);
+        find_call_out(symbol_function("main", obj));
+
+  Ein Codebeispiel, um alle call_out()s auf eine Funktion zu entfernen,
+  findet sich in der Manpage zu remove_call_out().
+
diff --git a/doc/sphinx/efun-mg/get_eval_cost.rst b/doc/sphinx/efun-mg/get_eval_cost.rst
new file mode 100644
index 0000000..7608ebc
--- /dev/null
+++ b/doc/sphinx/efun-mg/get_eval_cost.rst
@@ -0,0 +1,42 @@
+get_eval_cost
+=============
+
+BEMERKUNGEN
+-----------
+
+  Der Maximalwert betraegt zur Zeit 1.500.000 Ticks (Stand: 2020).
+
+  Sollten die Ticks waehrend der Ausfuehrung irgendwo auf 0 fallen,,
+  wird ein Fehler der Art "too long eval" erzeugt.
+
+  Diese Funktion dient dazu, solche Fehler zu verhindern oder genauer zu
+  lokalisieren an welchen Stellen im Code wieviel Ticks verbraucht werden.
+
+
+BEISPIELE
+---------
+
+  .. code-block:: pike
+
+      // Ticks zaehlen
+      void foo()
+      {
+        int prev, used, i;
+
+        prev=get_eval_cost(); // Merken, was bis hierhin verbraucht wurde 
+        for (i=0;i<=1000;i++) // Dann kommt der zu testende Code, zB eine
+        {                     // Schleife
+          ...
+        }
+        used=prev-get_eval_cost(); // Berechnung der Differenz
+        printf("Die Schleife verbrauchte %d Ticks.\n", used);
+      }
+
+      // Ticks im Auge behalten bei der Ausfuehrung
+      foreach(...)
+      {
+        ... // komplexer code
+        if (get_eval_cost() < 100000)
+          break;
+      }
+
diff --git a/doc/sphinx/efun-mg/lambda.rst b/doc/sphinx/efun-mg/lambda.rst
new file mode 100644
index 0000000..13bf050
--- /dev/null
+++ b/doc/sphinx/efun-mg/lambda.rst
@@ -0,0 +1,26 @@
+lambda
+======
+
+BEMERKUNGEN
+-----------
+
+  Von der Verwendung wird aus Lesbarkeits- und Wartungsgruenden dringend
+  abgeraten.
+
+BEISPIEL
+--------
+
+  Das Beispiel dient nur der Illustration, nicht zur Nachahmung. Bitte
+  verwendet lfun- oder inline-Closures.
+
+  .. code-block:: pike
+
+    // Lambdas werden gern eingesetzt, um komplexere Filter zu schreiben
+    // Allerdings kann jede Lambda dabei auch durch eine Inline-Closure
+    // oder eine LFun-Closure ersetzt werden.
+    filter(users(),
+      lambda(({'x}),
+             ({#'==,
+               ({#'call_other,'x,"QueryProp",P_SECOND}),"gloinson"
+            })));
+
diff --git a/doc/sphinx/efun-mg/limited.rst b/doc/sphinx/efun-mg/limited.rst
new file mode 100644
index 0000000..7378b17
--- /dev/null
+++ b/doc/sphinx/efun-mg/limited.rst
@@ -0,0 +1,13 @@
+limited
+=======
+
+BEMERKUNGEN
+-----------
+
+  Diese Funktion kann bei uns mudlibweit genutzt werden. Allerdings wird
+  nur die _Reduktion_ von LIMIT_EVAL zugelassen, alle anderen Limits
+  duerfen _nicht_ veraendert werden. Hierbei ist zu beachten, dass das
+  Limit fuer LIMIT_EVAL um min. 1000 Ticks unter den noch verfuegbaren
+  Ticks liegen muss (get_eval_cost()).
+  Fuer LIMIT_COST sind nur 0 und -100 zugelassen.
+
diff --git a/doc/sphinx/efun-mg/map_objects.rst b/doc/sphinx/efun-mg/map_objects.rst
new file mode 100644
index 0000000..675d708
--- /dev/null
+++ b/doc/sphinx/efun-mg/map_objects.rst
@@ -0,0 +1,29 @@
+map_objects
+===========
+
+BEMERKUNGEN
+-----------
+
+ Werden Pfade angegeben, so wird versucht ein Objekt zu laden, falls
+ dieses nicht existiert.
+
+BEISPIELE
+---------
+
+  .. code-block:: pike
+
+   // ersetze alle Objekte durch ihre Namen
+   arr=map_objects(inputarr, "name");
+
+   // ersetze alle Objekte durch ihre Namen im Genitiv
+   arr=map_objects(inputarr, "name", WESSEN);
+
+   // AeQUIVALENZCODE (nicht empfohlen, nur zum Verstaendnis!):
+   int i;
+   object *ret; mixed *input;
+
+   i=sizeof(input);
+   ret=allocate(i);
+   while(i--)
+     ret[i]=input[i]->fun([extra1, extra2, ...]);
+
diff --git a/doc/sphinx/efun-mg/raise_error.rst b/doc/sphinx/efun-mg/raise_error.rst
new file mode 100644
index 0000000..5794722
--- /dev/null
+++ b/doc/sphinx/efun-mg/raise_error.rst
@@ -0,0 +1,10 @@
+raise_error
+===========
+
+BEMERKUNGEN
+-----------
+
+  Der String sollte umgebrochen oder wenigstens mit einem \n terminiert
+  werden, da die Ausgabe direkt an den interaktiven Magier erfolgen
+  kann bzw. auf dem Debug-Kanal das letzte Zeichen entfernt wird.
+
diff --git a/doc/sphinx/efun-mg/random.rst b/doc/sphinx/efun-mg/random.rst
new file mode 100644
index 0000000..09d77a9
--- /dev/null
+++ b/doc/sphinx/efun-mg/random.rst
@@ -0,0 +1,29 @@
+BEISPIELE
+---------
+
+  .. code-block:: pike
+
+    // Einfache Abfrage z.B. aus der HitFunc einer Waffe:
+    if(random(101) >= 70)
+      return random(11);
+    else
+      return 0;
+
+    // Spieler soll in einen zufaellig ausgewaehlten Raum gemovt
+    // werden: 
+    string *dest = ({ "raum1","raum2","raum3","raum4","raum5" });
+    this_player()->move(dest[random(sizeof(dest))],M_GO);
+
+    // Es soll eine zufaellige Meldung ausgegeben werden:
+    tell_object(this_player(),
+     ({ "Es knackt.\n", "Dir ist kalt.\n", "Du schwitzt.\n",
+        "Du bekommst Angst.\n", "Hinter Dir knackt es im Gebuesch.\n",
+        "Ein kuehler Wind kommt auf.\n" })[random(6)]);
+    // Hinweis: ist es nicht sehr effizient, dafuer staendig ein Array neu zu
+    // erzeugen.
+
+  Wie man sieht, gibt es fuer random() viele schoene Einsatz-
+  moeglichkeiten. Wobei letzteres Beispiel ueber AddRoomMessage
+  (fuer Raeume) viel einfacher umzusetzen ist.
+
+
diff --git a/doc/sphinx/efun-mg/replace_program.rst b/doc/sphinx/efun-mg/replace_program.rst
new file mode 100644
index 0000000..ede8144
--- /dev/null
+++ b/doc/sphinx/efun-mg/replace_program.rst
@@ -0,0 +1,11 @@
+replace_program
+===============
+
+BEMERKUNGEN
+-----------
+
+  Raeume benutzen replace_program automatisch. Es selten sinnvoll
+  oder notwendig, replace_program selbst einzusetzen!
+  Wenn ihr es einsetzt, ist vermutlich eine Konsultaton mit einem
+  Erzmagier (fuer Driver oder Mudlib) sinnvoll.
+
diff --git a/doc/sphinx/efun-mg/save_object.rst b/doc/sphinx/efun-mg/save_object.rst
new file mode 100644
index 0000000..815a844
--- /dev/null
+++ b/doc/sphinx/efun-mg/save_object.rst
@@ -0,0 +1,14 @@
+save_object
+===========
+
+BEMERKUNGEN
+-----------
+
+  Bitte beachten, dass diese efun im MG durch eine Sefun ueberschrieben
+  wird und deren Manpage auch lesen!
+
+  Damit ein Objekt in Verzeichnisse der Region/des Magiers schreiben
+  kann, muss es entsprechende Rechte, also eine gueltige EUID
+  besitzen. Viele Objekte setzen diese im create() automatisch. Ansonsten ist
+  an passender Stelle ein Aufruf von seteuid() noetig.
+
diff --git a/doc/sphinx/efun-mg/say.rst b/doc/sphinx/efun-mg/say.rst
new file mode 100644
index 0000000..4bc340e
--- /dev/null
+++ b/doc/sphinx/efun-mg/say.rst
@@ -0,0 +1,13 @@
+say
+===
+
+BEMERKUNGEN
+-----------
+
+  * da say() in der Vergangenheit wg. des Automatismus der Zielbestimmung oft
+    an die falschen Spieler ausgegeben hat, wird von der Verwendung abgeraten.
+  * Bitte ReceiveMsg() benutzen, sofern sinnvoll
+  * fuer laengere Meldungen sollte break_string() verwendet werden
+  * say(<str>) ist verhaltensgleich zu
+    tell_room(environment(), <str>, ({this_player()||this_object()}))
+
diff --git a/doc/sphinx/efun-mg/set_next_reset.rst b/doc/sphinx/efun-mg/set_next_reset.rst
new file mode 100644
index 0000000..e4b2d27
--- /dev/null
+++ b/doc/sphinx/efun-mg/set_next_reset.rst
@@ -0,0 +1,30 @@
+set_next_reset
+==============
+
+BEISPIELE
+---------
+
+  .. code-block:: pike
+
+     // ein Objekt mit verkuerzter reset()-Zeit
+     void create() {
+       ...
+       set_next_reset(15*60);	// ~ 15 Minuten
+       ...
+     }
+
+     void reset() {
+       set_next_reset(900);	// die muss im reset() immer wieder
+       ::reset();           // neu gesetzt werden
+     }
+
+     // ein Objekt, dessen Blueprint keinen reset() bekommen soll
+     void create() {
+       if(!clonep(this_object())) {
+         set_next_reset(-1);
+         return;
+       }
+       ::create();
+       ...
+     }
+
diff --git a/doc/sphinx/efun-mg/sort_array.rst b/doc/sphinx/efun-mg/sort_array.rst
new file mode 100644
index 0000000..57ffd65
--- /dev/null
+++ b/doc/sphinx/efun-mg/sort_array.rst
@@ -0,0 +1,55 @@
+sort_array
+==========
+
+BEMERKUNGEN
+-----------
+
+   Achtung, die Elemente in 'arr' werden nicht tief kopiert, sind sie
+   also selbst Arrays oder Mappings, so fuehrt eine Aenderung im Rueckgabe-
+   Array zur Aenderung im Ursprungsarray.
+
+BEISPIELE
+---------
+
+  1. Sortieren von Zahlen in aufsteigender Reihenfolge
+
+    .. code-block:: pike
+
+       int *arr = ({ 3, 8, 1, 3 })
+
+       // Folgend identische Resultate, aber andere Ansaetze:
+       #1: nutzt die 'Efun' > als Lfun-Closure (ideal hier):
+           sort_array(arr, #'>);
+
+       #2: mit Sortierfunktion im selben Objekt:
+           int is_greater (int a, int b) {
+             return a > b;
+           }
+
+       #2a: sortiert mittels der Lfun im selben Objekt die Elemente in das
+            Rueckgabearray
+            sort_array(arr, "is_greater", this_object())
+            sort_array(arr, "is_greater")
+
+       #2b: nutzt die Lfun is_greater() als Lfun-Closure (Funktionspointer)
+            sort_array(arr, #'is_greater)
+
+       #3: Nutzt eine Inline-Closure
+           sort_array(arr, function int (int a, int b) {
+             return a > b; } );
+
+     Resultat in allen Faellen: ({1,3,3,8})
+
+   2. Sortieren von geschachtelten Arrays
+
+     .. code-block:: pike
+
+       arr = ({ ({ "foo", 3 }), ({ "quux", 1 }), ... })
+
+       // Vorgehen identisch, allerdings muss die Sortierfunktion
+       // angepasst werden:
+
+       int is_greater (<string|int> *a, <string|int> *b) {
+         return a[1] > b[1];
+       }
+
diff --git a/doc/sphinx/efun-mg/tell_room.rst b/doc/sphinx/efun-mg/tell_room.rst
new file mode 100644
index 0000000..59ceca0
--- /dev/null
+++ b/doc/sphinx/efun-mg/tell_room.rst
@@ -0,0 +1,49 @@
+tell_room
+=========
+
+BEMERKUNGEN
+-----------
+
+  Wird in einem catch_msg() der Wert von <msg> veraendert, erhalten
+  alle nachfolgenden Objekte das veraenderte <msg> (Referenz!)
+
+BEISPIELE
+---------
+
+  .. code-block:: pike
+
+    // Dies ist ein einfaches Beispiel fuer eine Meldung an alle An-
+    // wesenden im Raum.
+
+    tell_room(this_object(),"Ein leichter Wind kommt auf.\n");
+
+    // Diese Meldung wird im Raum /d/ebene/ark/raum.c ausgegeben, dieser
+    // Raum muss nicht derjenige sein, in dem das tell_room() ausgefuehrt
+    // wird.
+
+    tell_room("/d/ebene/ark/raum","Ein leichter Wind kommt auf.\n");
+
+
+    // Diese Meldung wird an alle Anwesenden im Raum AUSSER this_player()
+    // (der diese Meldung ausgeloest hat) ausgegeben. Der muss eine ge-
+    // sonderte Meldung ueber sein Stolpern per write() oder
+    // tell_object() bekommen.
+    tell_room(this_object(),
+              break_string(this_player()->Name()+" stolpert.", 78),
+              ({ this_player() }));
+    tell_object(this_player(), "Du stolperst.\n");
+
+    // Ein Beispiel mit zwei Objekten, das zeigt, wie das Zusammenspiel
+    // von catch_tell() und tell_room() ablaueft. Objekt1 ist ein
+    // Lebewesen mit Namen "Dummymonster", Objekt2 verteilt die Meldung:
+
+    Objekt1 (ein Lebewesen, steht im Env von this_player()):
+        void catch_tell(string str) {
+            write("Empfangen: "+str+"\n");
+        }
+
+    Objekt2:
+        void fun() {
+            tell_room(environment(this_player()), "Hallo Welt!\n");
+        }
+
diff --git a/doc/sphinx/efun-mg/walk_mapping.rst b/doc/sphinx/efun-mg/walk_mapping.rst
new file mode 100644
index 0000000..9e49145
--- /dev/null
+++ b/doc/sphinx/efun-mg/walk_mapping.rst
@@ -0,0 +1,32 @@
+walk_mapping
+============
+
+BEISPIELE
+---------
+
+  In einem Mapping (Keys: Spielerobjekte) soll auf alle Werte etwas drauf
+  addiert werden:
+
+  .. code-block:: pike
+
+     // Liste mit Spielern durchgehen ...
+     mapping x=([ [/human:liafar]:  20,
+                  [/dwarf:mesirii]: 50,
+                  [/elf:zarniya]:   40,
+                  [/feline:turbo]:  30]);
+
+     // ... und Werte aendern:
+     void add_val(object key, int val, int add) {
+       if(key->InFight())
+         val+=add;
+       else
+         val-=add;
+     }
+
+     // verschiedene Aufrufarten, identisches Resultat:
+     walk_mapping(x, "add_val", 0, 10);
+     walk_mapping(x, "add_val", this_object(), 10
+     walk_mapping(x, "add_val", "/players/jof/addierobjektmitmethode", 10);
+
+     walk_mapping(x, #'add_val, 10);
+