blob: d48370ed8aab7b1bdeb5052e26888929f49a9e24 [file] [log] [blame]
// (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;
}