Added public files

Roughly added all public files. Probably missed some, though.
diff --git a/items/kraeuter/virtual_compiler.c b/items/kraeuter/virtual_compiler.c
new file mode 100644
index 0000000..d48370e
--- /dev/null
+++ b/items/kraeuter/virtual_compiler.c
@@ -0,0 +1,300 @@
+// (c) by Padreic (Padreic@mg.mud.de)
+
+#pragma no_inherit,no_clone,strong_types,rtt_checks
+
+#include <defines.h>
+#include <properties.h>
+#include <v_compiler.h>
+#include <items/kraeuter/kraeuter.h>
+#include <wizlevels.h>
+
+inherit "/std/virtual/v_compiler";
+inherit "/std/thing/language";
+inherit "/std/thing/description";
+
+// mit Hilfe dieses mappings kommt man sowohl an die ID und die Eigenschaften,
+// als auch an die Liste der Raeume in denen das Kraut mit dem filenamen room
+// gefunden werden kann.
+// ([ "key": ({ ({eigenschaften}), ([raeume]) }) ])
+private mapping krautdaten;
+
+// AN: enthaelt die Liste der gueltigen Kraeuter-Dateinamen ohne .c
+// am Ende. Ich vermute, dass es deswegen ein Mapping ist, damit in 
+// Validate() einfach member() drauf gemacht werden kann und man nur 0/1
+// als Rueckgabewerte pruefen muss, statt -1 bei nem member() auf ein Array.
+private mapping validfiles;
+
+public void update(mapping data)
+{
+  if (previous_object() == find_object(PLANTMASTER))
+  {
+    krautdaten = data;
+    validfiles = mkmapping(m_indices(krautdaten));
+  }
+}
+
+// Wird benutzt, um kurze IDs von Kraeutern zu raten. Diese IDs werden
+// eingetragen, wenn der Krautname die ID als Teilstring enthaelt.
+#define IDLIST ({ "klee", "rebe", "hahnenfuss", "rettich", "kraut", "wurz",\
+                     "moos", "enzian", "rautenwicke", "pilz", "nelke",\
+                     "lichtnelke", "wicke", "zwiebel", "hanf", "kresse"})
+
+void create()
+{
+   seteuid(getuid());
+
+   v_compiler::create();
+   description::create();
+
+   SetProp(P_COMPILER_PATH, __DIR__);
+   SetProp(P_STD_OBJECT, PLANTITEM);
+   
+   PLANTMASTER->UpdateVC();
+}
+
+string Validate(string file)
+{
+   if (!stringp(file)) return 0;
+   file = ::Validate(explode(file, "#")[0]);
+#if MUDNAME == "MorgenGrauen"
+   return (member(validfiles, file) ? file : 0);
+#else
+   return file;
+#endif
+}
+
+private nosave object simul_efun;
+
+// fuer SIMUL_EFUN_FILE
+#include <config.h>
+
+// AN: Funktion liefert das clonende Objekt als dessen Blueprint-Namen,
+// indem es den Caller-Stack durchlaeuft und nach einem Objekt sucht,
+// das weder der Master, noch ein Simul-Efun-Objekt, noch dieser VC selbst
+// ist. Der Name des gefundenen Objekts wird zurueckgegeben, oder 0.
+nomask private string get_cloner()
+{
+   int i;
+   object po;
+
+   if (!simul_efun)
+   {
+      if (!(simul_efun=find_object(SIMUL_EFUN_FILE)))
+         simul_efun=find_object(SPARE_SIMUL_EFUN_FILE);
+   }
+   // wenn sie jetzt nicht existiert - auch gut, dann gibt es halt keine
+   // sefuns.
+
+   for (i=0; po=previous_object(i); i++)
+   {
+      if (po==master() || po==simul_efun || po==ME || po==previous_object())
+         continue;
+      return BLUE_NAME(po);
+   }
+   return 0;
+}
+
+// Konfiguriert das erzeugte Objekt entsprechend der dafuer im Kraeutermaster
+// bekannten Daten. Vergibt auf die Plant-ID.
+varargs string CustomizeObject(string file)
+{
+   if (previous_object()->QueryPlantId()) return 0; // bereits initialisiert
+   
+   if (stringp(file))
+      file=Validate(file);
+   else file=::CustomizeObject();
+   if (!file) return 0;
+
+   closure sp=symbol_function("SetProp", previous_object());
+   mixed arr=krautdaten[file];
+   if (pointerp(arr))
+   {
+      // Welches Objekt clont das File?
+      string cloner = get_cloner();
+      string rooms = arr[1];
+      mixed props = arr[0];
+      // Wird das Kraut legal von einem eingetragenen Cloner erzeugt? Nur dann
+      // bekommt es eine gueltige Plant-ID.
+     int legal=member(rooms, get_cloner()) || cloner==PLANTMASTER;
+     if (!legal && this_interactive() && IS_ARCH(this_interactive()))
+        legal=1;
+     
+      // Konfiguriert wird das Objekt dann, wenn es per VC erzeugt wird oder
+      // ein Clone einer per VC erzeugten BP ist - d.h. wenn es nicht aus
+      // einem real existierenden File auf der Platte existiert. Das ist dann
+      // der Fall, wenn der Loadname gleich dem Standardplantobjekt des VC
+      // ist.
+      if (load_name(previous_object())==PLANTITEM)
+      {
+        if ((props[INGREDIENT_NAME]=="Klee") ||
+            (props[INGREDIENT_NAME][<4..]=="klee")) {
+           funcall(sp, P_NAME, ({ props[INGREDIENT_NAME],
+                                  props[INGREDIENT_NAME]+"s",
+                                  props[INGREDIENT_NAME],
+                                  props[INGREDIENT_NAME]}));
+        }
+        else funcall(sp, P_NAME,     props[INGREDIENT_NAME]);
+        funcall(sp, P_NAME_ADJ, props[INGREDIENT_ADJ]);
+        funcall(sp, P_GENDER,   props[INGREDIENT_GENDER]);
+        funcall(sp, P_LONG,     props[INGREDIENT_LONG]);
+        funcall(sp, PLANT_ROOMDETAIL, props[INGREDIENT_ROOMDETAIL]);
+        if (props[INGREDIENT_DEMON]==RAW) {
+           funcall(sp, P_ARTICLE, 0);
+           funcall(sp, P_SHORT, previous_object()->Name(WER));
+           funcall(sp, P_ARTICLE, 1);
+        }
+        else funcall(sp, P_SHORT,
+             previous_object()->Name(WER,props[INGREDIENT_DEMON]));
+        previous_object()->AddId(lowerstring(props[INGREDIENT_NAME]));
+        // bei zusammengesetzten Namen, auch den hauptnamen akzeptieren
+        string str=lowerstring(props[INGREDIENT_NAME]);
+        string *names=explode(str, "-");
+        if (sizeof(names)>1) previous_object()->AddId(names[<1]);
+        names=explode(str, " ");
+        if (sizeof(names)>1) previous_object()->AddId(names[<1]);
+        foreach(string id: IDLIST)
+        {
+          if (strstr(str, id)==-1) continue;
+          previous_object()->AddId(id);
+          break;
+        }
+        // Adjective vorher deklinieren
+        str=props[INGREDIENT_ADJ];
+        if (stringp(str))
+        {
+          str=DeclAdj(lowerstring(str), WEN, 0);
+          previous_object()->AddAdjective(str);
+        }
+      }  // Ende Konfiguration eines VC-erzeugten Objekts
+      // Plant-ID wird fuer alle Objekte auf irgendwas gesetzt.
+      previous_object()->SetPlantId(legal ? props[INGREDIENT_ID] : -1);
+   }
+   // Keine Krautdaten bekannt...
+   else
+   {
+     funcall(sp, P_NAME,     "Kraut");
+     funcall(sp, P_GENDER,   NEUTER);
+     funcall(sp, P_SHORT,    "Ein Testkraut ("+capitalize(file)+")");
+     funcall(sp, P_LONG,     "Ein nicht naeher spezifiziertes Testkraut.\n");
+     funcall(sp, PLANT_ROOMDETAIL,
+         "Ein nicht naeher spezifiziertes Testkraut ("
+         +capitalize(file)+").\n");
+     previous_object()->AddId("kraut");
+     previous_object()->SetPlantId(-1);
+   }
+   return file;
+}
+
+int NoParaObjects()
+{   return 1;   }
+
+// AN: Funktion erzeugt aus den vorliegenden Daten der Kraeuterliste ein
+// physikalisch existierendes File in diesem Verzeichnis, zB wenn die Daten
+// erweitert werden sollen. Die Kraeuterliste stellt nur generische Objekte
+// zur Verfuegung, die keine Details haben. Wenn die Objekte ausgeschmueckt
+// werden sollen, koennen diese auch als Datei hier liegen.
+// Wird vom Plantmaster aus gerufen. Die Existenz von Klartext-
+// Fehlermeldungen laesst darauf schliessen, dass diese Funktion dafuer
+// vorgesehen war, vom Planttool aus gerufen zu werden. Dies wird dadurch
+// bestaetigt, dass dort wie hier alle von Magiern benutzbaren Kommando-
+// funktionen mit _ beginnen (_showplant(), _addroom() etc.), und die
+// Kommandofunktion im Planttool generell in der Lage ist, alle _*() 
+// im Plantmaster zu rufen, sofern existent und fuer den Magier freigegeben.
+// AN/TODO: ggf. sollte man hier noch pruefen, ob die VC-Blueprint des
+// angeforderten Krautes gerade existiert, denn sonst wuerde das auf der
+// Platte liegende, scheinbar (nicht) geladene Objekt nicht mit dem
+// VC-Objekt uebereinstimmen. Evtl. reicht es aus, die Blueprint einfach
+// zu zerstoeren und neuzuladen.
+int _createfile(string filename)
+{
+   int i;
+   string str, short, long, gender, *name, roomdetail;
+   string *ids;
+   string plantfile;
+
+/*   if (object_name(previous_object())!=PLANTMASTER) {
+      write("Illegal usage of _createfile()!\n");
+      return 1;   
+   }*/
+// ^^^ Zook, ggf.spaeter wieder Kommentar entfernen. 
+
+   mixed arr;
+   if (!pointerp(arr=krautdaten[filename])) {
+      write("Unknown plant '"+filename+"'.\n");
+      return 1;
+   }
+   if (file_size(PLANTDIR+filename+".c")>=0) {
+      write("error: file "+PLANTDIR+filename+".c already exists.\n");
+      return 1;
+   }
+   mixed props = arr[0];
+
+   // Kurzbeschreibung erzeugen
+   SetProp(P_NAME,     props[INGREDIENT_NAME]);
+   SetProp(P_NAME_ADJ, props[INGREDIENT_ADJ]);
+   SetProp(P_GENDER,   props[INGREDIENT_GENDER]);
+   if (props[INGREDIENT_DEMON]==RAW) {
+       SetProp(P_ARTICLE, 0);
+       short=Name(WER);
+       SetProp(P_ARTICLE, 1);
+   }
+   else short=Name(WER,props[INGREDIENT_DEMON]);
+   ids = ({ lowerstring(props[INGREDIENT_NAME]) });
+   // bei zusammengesetzten Namen, auch den hauptnamen akzeptieren
+   str=lowerstring(props[INGREDIENT_NAME]);
+   name=explode(str, "-");
+   if (sizeof(name)>1) ids += ({ name[<1] });
+   name=explode(str, " ");
+   if (sizeof(name)>1) ids += ({ name[<1] });
+   for (i=sizeof(IDLIST)-1; i>=0; i--) {
+       if (strstr(str, IDLIST[i], 0)==-1) continue;
+       ids += ({ IDLIST[i] });
+       break;
+   }
+   switch(props[INGREDIENT_GENDER]) {
+     case MALE:   gender="MALE"; break;
+     case FEMALE: gender="FEMALE"; break;
+     case NEUTER: gender="NEUTER"; break;
+     default: gender=props[INGREDIENT_GENDER];
+   }
+   long="    \""+implode(old_explode(props[INGREDIENT_LONG], "\n"), 
+                   "\\n\"\n   +\"")+"\\n\"";
+   roomdetail="    \""+implode(
+      old_explode(props[INGREDIENT_ROOMDETAIL], "\n"), "\\n\"\n   +\"")+
+      "\\n\"";
+   plantfile=
+    "#pragma strong_types,rtt_checks\n\n"
+    "#include <properties.h>\n"
+    "#include <items/kraeuter/kraueter.h>\n"
+    "#include <items/kraeuter/kraeuterliste.h>\n\n"
+    "inherit STDPLANT;\n\n"
+    "protected void create()\n"
+    "{\n"
+    "  ::create();\n";
+   plantfile+="  customizeMe("+upperstring(filename)+");\n";
+   plantfile+=
+    "  SetProp(P_NAME,     \""+props[INGREDIENT_NAME]+"\");\n"
+    "  SetProp(P_NAME_ADJ, \""+(props[INGREDIENT_ADJ]||"")+"\");\n"
+    "  SetProp(P_GENDER,   "+gender+");\n"
+    "  SetProp(P_LONG,     \n"+
+    long+");\n"
+    "  SetProp(PLANT_ROOMDETAIL, \n"+
+    roomdetail+");\n"
+    "  SetProp(P_SHORT,    \""+short+"\");\n";
+   plantfile+="  AddId(({";
+   for (i=sizeof(ids)-1; i>=0; i--)
+     plantfile+=" \""+ids[i]+"\",";
+   plantfile[<1]=' ';
+   plantfile+="}));\n";
+   // Adjective vorher deklinieren
+   if (stringp(short=props[INGREDIENT_ADJ])) {
+     short=DeclAdj(lowerstring(short), WEN, 0)[0..<2];
+     plantfile+="  AddAdjective(\""+short+"\");\n";
+   }
+   plantfile+="}\n";
+   write(plantfile);
+   //write_file(PLANTDIR+filename+".c", plantfile);
+   write("Filename: "+PLANTDIR+filename+".c\n");
+   return 1;
+}
+