Merge branch 'master' of ssh://mgg/mudlib-public
diff --git a/std/player/channel.c b/std/player/channel.c
index f1521f7..b29240d 100644
--- a/std/player/channel.c
+++ b/std/player/channel.c
@@ -68,7 +68,7 @@
       + (IS_LEARNER(this_object()) ? WIZARD_SHORTCUTS : ([])));
 }
 
-static mixed _query_localcmds()
+static <int|string>** _query_localcmds()
 {
   return ({({"-","ChannelParser", 1, 0}),
            ({"ebene", "ChannelAdmin", 0, 0}),
@@ -76,9 +76,9 @@
          });
 }
 
-mixed RegisterChannels()
+string* RegisterChannels()
 {
-  mixed err;
+  string* err;
   if(extern_call() &&
      previous_object() != find_object(CHMASTER)) return;
   c_status = 0;
@@ -96,10 +96,10 @@
   return err;
 }
 
-mixed RemoveChannels()
+string* RemoveChannels()
 {
   closure cl;
-  mixed err=({});
+  string* err=({});
   if(extern_call() &&
      previous_object() != find_object(CHMASTER)) return;
   if(!c_status) c_status = 1;
@@ -112,10 +112,9 @@
   return err;
 }
 
-varargs private string getName(mixed x, int fall) {
-  
-  mixed o = closurep(x) ? query_closure_object(x) : x;
-  if(stringp(o) && sizeof(o) && (x = find_object(o))) 
+varargs private string getName(string|object|closure x, int fall) {
+  string|object o = closurep(x) ? query_closure_object(x) : x;
+  if(stringp(o) && sizeof(o) && (x = find_object(o)))
     o = x;
   
   // Objekte
@@ -216,11 +215,12 @@
 
 private void createList(string n, mixed a, mixed m, mixed l)
 {
-  int pos; string sh, *mem;
-  if((pos = member(map(m_values(shortcut), #'lower_case/*'*/), n)) != -1)
+  int pos = member(map(m_values(shortcut), #'lower_case/*'*/), n);
+  string sh = "";
+  if(pos != -1)
     sh = m_indices(shortcut)[pos];
-  else sh = "";
-  mem=map(a[I_MEMBER],#'getName/*'*/, WER);
+
+  string* mem=map(a[I_MEMBER],#'getName/*'*/, WER);
   mem-=({"<MasteR>"});
   l += ({ sprintf("%-12.12'.'s %c[%-1.1s] %|12.12' 's (%-|3' 'd) %-42.42s\n",
                   a[I_NAME], (member(m, n) != -1 ? '*' : ' '), sh,
@@ -235,9 +235,10 @@
 
 private mixed getChannel(string ch)
 {
-  mixed ff;
-  if(!sizeof(ch)) ch = QueryProp(P_STD_CHANNEL);
-  if(shortcut && shortcut[ch]) ch = shortcut[ch];
+  if(!sizeof(ch))
+    ch = QueryProp(P_STD_CHANNEL);
+  if(shortcut && shortcut[ch])
+    ch = shortcut[ch];
   return CHMASTER->find(ch, this_object());
 }
 
@@ -340,7 +341,7 @@
         }
         else
         {
-          mixed list; list = ({});
+          string* list = ({});
           if(cmd[1][<1] == '!')
             l -= mkmapping(m_indices(l) - QueryProp(P_CHANNELS));
           walk_mapping(l, #'createList/*'*/, QueryProp(P_CHANNELS), &list);
@@ -358,14 +359,13 @@
     }
     case '*':
     {
-      mixed hist; int amount;
-      if(!pointerp(hist = CHMASTER->history(ch, this_object())) 
-              || !sizeof(hist))
+      mixed hist = CHMASTER->history(ch, this_object());
+      if(!pointerp(hist) || !sizeof(hist))
       {
         write("Es ist keine Geschichte fuer '"+ch+"' verfuegbar.\n");
         return 1;
       }
-      
+
       //(Zesstra) cmd hat offenbar immer 3 Elemente...
       //bei -all* ({"","all*",""})
       //bei -all*10 ({"","all*,"10"})
@@ -374,7 +374,7 @@
         amount = to_int(cmd[2]);
       else 
         amount=sizeof(hist);*/
-      amount=to_int(cmd[2]);
+      int amount=to_int(cmd[2]);
       if (amount <= 0 || amount >= sizeof(hist))
         amount=sizeof(hist);
 
@@ -437,7 +437,7 @@
 int ChannelAdmin(string args)
 {
   string n, descr, sh, cn;
-  mixed pa, tmp;
+  mixed tmp;
   args = _unparsed_args();
   notify_fail("Benutzung: ebene <Abkuerzung>=<Ebene>\n"
               "           ebene <Abkuerzung>=\n"
@@ -552,7 +552,7 @@
     write("Du stellst die Ebenen ab.\n");
     return 1;
   }
-  pa = old_explode(args, " ");
+  string* pa = old_explode(args, " ");
   if(!strstr("abkuerzungen", pa[0]))
   {
     string txt; txt = "";
diff --git a/std/room/kraeuter.c b/std/room/kraeuter.c
index 24f5193..92f4f56 100644
--- a/std/room/kraeuter.c
+++ b/std/room/kraeuter.c
@@ -9,15 +9,24 @@
 #include <defines.h>
 #include <living/combat.h> // Fuer P_FREE_HANDS
 
+public int AddPlantDetail(string filename);
+
 // Standardwert von 2 h fuer vollstaendige Regeneration des Krautes. 
 // Einfaches Nachwachsen ist typischerweise die Haelfte davon.
 #define STD_WACHSTUM  7200
 #define BS(x)         break_string(x, 78)
 
-// Struktur (6 Eintraege pro Kraut):
-// ([ filename : ({ Zeit_bis_nachgewachsen, Zeit_bis_komplett_regeneriert,
-//                  Kraut-IDs, Kraut-Adjektive, Kraut->Name(WER,1),
-//                  ID_des_Bewacher-NPCs }) ])
+// Struktur (7 Eintraege pro Kraut):
+struct plantinfo {
+  int regrow;          // Zeit_bis_nachgewachsen
+  int regeneration;    // Zeit_bis_komplett_regeneriert
+  int pickable;        // per Standardkommanod pflueckbar?
+  string *ids;         // Kraut-IDs
+  string *adj;         // Kraut-Adjektive
+  string name;         // Kraut->Name(WER,1)
+  string *guards;       // ID_des_Bewacher-NPCs
+};
+// ([ filename : struct plantinfo ])
 mapping plantMap = ([]);
 
 // kann benutzt werden um schnell und einfach eine Pflanze in einem Raum
@@ -28,99 +37,102 @@
 // 1 -> Erfolg; -1 -> filename ungueltig
 varargs int AddPlant(string filename, string|string* npcId)
 {
-  mixed arr;
-
-  // Dateiname nicht uebergeben? Dann tun wir erstmal gar nix.
-  if (!stringp(filename)) 
+  // Eintrag und Details etc. hinzufuegen, wenn nicht erfolgreich, auch mit -1
+  // beenden.
+  if (AddPlantDetail(filename) == -1)
     return -1;
-  object ob=load_object(filename);
-   
-  // Wenn wir zu dem Kraut schon Daten haben (erkennbar an >2 Eintraegen),
-  // werfen wir einen Fehler, damit das beim Laden des Raumes schon
-  // erkannt wird.
-  if (pointerp(arr=plantMap[filename]) && sizeof(arr)>2)
-    raise_error("AddPlant(): "+filename+" already exists.\n");
 
-  // IDs und Adjektive parsen und den Datensatz zusammenstellen
-  string *ids = ob->Query(P_IDS, F_VALUE)-({ "Ding" });
-  string *adj = ob->Query(P_ADJECTIVES, F_VALUE);
-  
-  if (!pointerp(arr) || sizeof(arr)<2) 
-    arr = ({0,0});
-  if ( !npcId )
-    npcId = ({});
-  else if (stringp(npcId))
-    npcId = ({npcId});
-  plantMap[filename]=({arr[0], arr[1], ids, adj, ob->Name(WER, 1), npcId });
-   
-  // Details erzeugen aus Adjektiven und IDs
-  adj = ob->QueryProp(P_NAME_ADJ);
-  
-  // aktuelles Geschlecht zwischenspeichern, wird spaeter wiederhergestellt
-  int gender = Query(P_GENDER, F_VALUE);
-  Set(P_GENDER, ob->Query(P_GENDER, F_VALUE), F_VALUE);
-  
-  // erzeugt fuer jede moegliche Kombination aus Adjektiv im Akkusativ
-  // und ID des Krautes ein Detail.
-  adj = map(adj, #'DeclAdj, WEN, 0);
+  struct plantinfo plant = plantMap[filename];
 
-  string *det=({});
-  foreach(string _id : ids) {
-    foreach(string _adj : adj) {
-      det += ({ _adj + _id });
-    }
+  // es ist pflueckbar
+  plant->pickable = 1;
+
+  // Bewacher noch eintragen
+  if (npcId)
+  {
+    if (stringp(npcId))
+      plant->guards = ({npcId});
+    else
+      plant->guards = npcId;
   }
-
-  det += ids;
-  // keine existierenden Details ueberschreiben
-  det -= m_indices(Query(P_DETAILS, F_VALUE) || ([]));
-  if (sizeof(det)) 
-    AddDetail(det, ob->Query(PLANT_ROOMDETAIL, F_VALUE));
-  
-  // Eine Befehlsfunktion brauchen wir natuerlich auch.
+  // Eine Befehlsfunktion brauchen wir dann natuerlich auch.
   AddCmd(({"pflueck", "pfluecke", "ernte"}), "_pfluecken");
-  
-  return 1;
+
+  // erfolgreich fertig
+ return 1;
 }
 
 // Wenn jemand per Hand das Plantdetail hinzufuegen moechte...
 // z.B. bei Verwendung von GetPlant() anstelle von AddPlant()
-void AddPlantDetail(string filename)
+// Im Gegensatz zu AddPlant() fuegt es kein Kommando zum Pfluecken hinzu und
+// traegt keine Bewacher ein.
+// 1 -> Erfolg; -1 -> filename ungueltig
+public int AddPlantDetail(string filename)
 {
-  // Pfad in Objektpointer wandeln
+  // Dateiname nicht uebergeben? Dann tun wir erstmal gar nix.
+  if (!stringp(filename))
+    return -1;
   object ob=load_object(filename);
-   
-  // Details erzeugen
-  string *det = ({});
-  string *ids = ob->Query(P_IDS, F_VALUE)-({ "Ding" });
-  string *adj = ob->QueryProp(P_NAME_ADJ);
+
+  // Wenn wir zu dem Kraut schon Daten haben, werfen wir einen Fehler, damit
+  // das beim Laden des Raumes schon erkannt wird.
+  struct plantinfo plant = plantMap[filename];
+  if (structp(plant))
+    raise_error("AddPlant(): "+filename+" already exists.\n");
+
+  plant = (<plantinfo>);
+  // IDs und Adjektive parsen und den Datensatz zusammenstellen
+  plant->ids = ob->Query(P_IDS, F_VALUE)-({ "Ding" });
+  plant->adj = ob->Query(P_ADJECTIVES, F_VALUE);
+  // Keine Bewacher
+  plant->guards = ({});
+  // Ausserdem ist es nicht pflueckbar per Standardkommando (pickable nicht
+  // gesetzt)
+  // Und eintragen
+  plantMap[filename] = plant;
+
+  // Details erzeugen aus Adjektiven und IDs
+  string *name_adj = ob->QueryProp(P_NAME_ADJ);
+
   // aktuelles Geschlecht zwischenspeichern, wird spaeter wiederhergestellt
-  int gender=Query(P_GENDER, F_VALUE);
-  Set(P_GENDER, ob->Query(P_GENDER, F_VALUE));
+  int gender = Query(P_GENDER, F_VALUE);
+  Set(P_GENDER, ob->Query(P_GENDER, F_VALUE), F_VALUE);
+
   // erzeugt fuer jede moegliche Kombination aus Adjektiv im Akkusativ
   // und ID des Krautes ein Detail.
-  adj = map(adj, #'DeclAdj, WEN, 0);
-  foreach(string _id : ids) {
-    foreach(string _adj : adj) {
+  name_adj = map(name_adj, #'DeclAdj, WEN, 0);
+
+  // Geschlecht zuruecksetzen
+  Set(P_GENDER, gender, F_VALUE);
+
+  string *det=({});
+  foreach(string _id : plant->ids) {
+    foreach(string _adj : name_adj) {
       det += ({ _adj + _id });
     }
   }
-  AddDetail(det+ids, ob->Query(PLANT_ROOMDETAIL, F_VALUE));
-  // Geschlecht zuruecksetzen
-  Set(P_GENDER, gender, F_VALUE);
+
+  det += plant->ids;
+  // keine existierenden Details ueberschreiben
+  det -= m_indices(Query(P_DETAILS, F_VALUE) || ([]));
+  if (sizeof(det))
+    AddDetail(det, ob->Query(PLANT_ROOMDETAIL, F_VALUE));
+
+  return 1;
 }
 
 // Prueft, ob die Pflanze zu "filename" in diesem Raum schon nachgewachsen
 // ist.
 protected int CheckPlant(string filename)
 {
-  mixed arr=plantMap[filename];
-  if (!pointerp(arr) || sizeof(arr)<2) {
-    arr=plantMap[filename]=({ 0, 0 });
-  }
+  struct plantinfo plant = plantMap[filename];
+  // Wenn es keinen Eintrag gibt, gibt es offenbar keine Pflanze
+  if (!structp(plant))
+    return 0;
+
   // Solange die Zeit arr[0] noch nicht erreicht ist, ist das Kraut nicht 
   // nachgewachsen, dann gibt es gar nix.
-  return (time()>arr[0]);
+  return (time() > plant->regrow);
 }
 
 // Moechte man AddPlant() nicht benutzen, weil man die Pflanze nicht einfach
@@ -130,32 +142,34 @@
 // nachgewachsen.
 object GetPlant(string filename)
 {
-  int *arr=plantMap[filename];
-  if (!pointerp(arr) || sizeof(arr)<2)
-  {
-     arr=plantMap[filename]=({ 0, 0 });
-  }
-  // arr[0] enthaelt den Zeitpunkt, wann das Kraut nachgewachsen ist,
-  int nachgewachsen = arr[0];
-  // arr[1] denjenigen, wann es vollstaendig regeneriert ist.
-  int regeneriert = arr[1];
+  struct plantinfo plant = plantMap[filename];
+  // Wenn es keinen Eintrag gibt, gibt es offenbar keine Pflanze
+  if (!structp(plant))
+    return 0;
+
+  // regrow enthaelt den Zeitpunkt, wann das Kraut nachgewachsen ist,
+  // regeneration denjenigen, wann es vollstaendig regeneriert ist.
 
   // Vor dem Nachgewachsen-Zeitpunkt kann man gar nix ernten.
-  if (time()<nachgewachsen) return 0; // noch nicht nachgewachsen
+  if (time() < plant->regrow)
+    return 0; // noch nicht nachgewachsen
 
   // Restzeit bis zur vollstaendigen Regeneration.
-  regeneriert-=time();
-  
+  int regeneriert = plant->regeneration - time();
+
   // Wenn vollstaendig regeneriert, ist STD_WACHSTUM die neue Zeit bis zur
-  // Regeneration. Wenn noch nicht vollstaendig regenriert, Restzeit
+  // Regeneration. Wenn noch nicht vollstaendig regeneriert, Restzeit
   // verdoppeln und STD_WACHSTUM nochmal drauf addieren.
-  regeneriert = (regeneriert<=0 ? STD_WACHSTUM 
-                                : (regeneriert*2)+STD_WACHSTUM);
-  // nachgewachsen ist die halbe Regenerationszeit
-  arr[0]=nachgewachsen=time()+(regeneriert/2);
-  // Zeit voelliger Regeneration
-  arr[1]=regeneriert+=time();
-  
+  if (regeneriert<=0)
+    regeneriert = STD_WACHSTUM;
+  else
+    regeneriert = (regeneriert*2)+STD_WACHSTUM;
+
+  // Zeitpunkt des Nachwachsen ist die halbe Regenerationszeit
+  plant->regrow = time() + (regeneriert/2);
+  // Zeitpunkt voelliger Regeneration
+  plant->regeneration = regeneriert + time();
+
   return clone_object(filename);
 }
 
@@ -170,17 +184,17 @@
   mixed ids = Query(P_IDS, F_VALUE);
   mixed adj = Query(P_ADJECTIVES, F_VALUE);
 
-  foreach(string key, mixed krautinfo : plantMap) 
+  foreach(string key, struct plantinfo plant : plantMap) 
   {
-    if ( sizeof(krautinfo) != 6 )
+    if ( !structp(plant) || !plant->pickable )
       continue;
- 
+
     // IDs und Adjektive des Krautes kopieren 
-    Set(P_IDS, krautinfo[2], F_VALUE);
-    Set(P_ADJECTIVES, krautinfo[3], F_VALUE);
+    Set(P_IDS, plant->ids, F_VALUE);
+    Set(P_ADJECTIVES, plant->adj, F_VALUE);
 
     // Syntaxpruefung wird dann mit id() gemacht.
-    if (id(str)) 
+    if (id(str))
     {
       object ob;
       object bewacher;
@@ -188,14 +202,14 @@
 
       // Liste der eingetragenen Bewacher-IDs durchlaufen und pruefen, ob
       // mindestens einer davon anwesend ist.
-      foreach( string npcId : krautinfo[5] )
+      foreach( string npcId : plant->guards )
       {
         bewacher = present(npcId, ME);
         if (objectp(bewacher))
           break;
       }
-      
-      if ( !PL->QueryProp(P_FREE_HANDS) ) 
+
+      if ( !PL->QueryProp(P_FREE_HANDS) )
       {
         tell_object(PL, BS("Du hast keine Hand frei, um etwas pfluecken "
           "zu koennen."));
@@ -208,7 +222,7 @@
           "zunaechst um "+bewacher->QueryPronoun(WEN)+" kuemmern."));
       }
       // Wenn GetPlant() ein Objekt liefert, kann was gepflueckt werden.
-      else if ( objectp(ob=GetPlant(key)) ) 
+      else if ( objectp(ob=GetPlant(key)) )
       {
         if ( ob->move(PL, M_GET) == MOVE_OK )
         {
@@ -225,7 +239,7 @@
       // Wenn alles nicht, dann ist das Kraut noch nicht wieder da.
       else 
       {
-        write(BS(krautinfo[4]+" ist noch nicht reif genug "
+        write(BS(plant->name+" ist noch nicht reif genug "
           +"und muss erst noch etwas wachsen."));
         break;
       }