Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/obj/tools/tester/test.c b/obj/tools/tester/test.c
new file mode 100644
index 0000000..dd70fa8
--- /dev/null
+++ b/obj/tools/tester/test.c
@@ -0,0 +1,1146 @@
+/*
+** Objekt-Tester - Mischung aus Rikus' Detailtester und Rochus' Test-NPC.
+**
+*****************************************************************************
+**
+** Urspruengliche Objekte:
+** ~~~~~~~~~~~~~~~~~~~~~~~
+** /players/rikos/obj/rdet.c Rikus@MorgenGrauen 25.05.96
+**
+** /players/rochus/mon/tester.c Rochus@MorgenGrauen 18.10.94
+**
+*****************************************************************************
+**
+** Dieses Objekt: [ Version 0.8 ]
+** ~~~~~~~~~~~~~~
+** /players/paracelsus/tools/otest.c Paracelsus@Morgengrauen 28.02.98
+**
+** Die Weitergabe, Verwendung oder Veraenderung ist nur erlaubt, wenn
+** diese Meldung nicht geaendert wird.
+** Die Benutzung erfolgt auf eigene Gefahr, jede Verantwortung wird
+** abgelehnt. Es wird keine Garantie gegeben, dass der Objekttester
+** einwandfrei, vollstaendig oder gar zufriedenstellend arbeitet.
+**
+*****************************************************************************
+**
+** ChangeLog:
+** ~~~~~~~~~~
+** V 0.1 28.02.98 11:00:00 Paracelsus
+**
+** Rikus' Raumtester kopiert, optimiert.
+**
+** V 0.2 28.02.98 11:30:00 Paracelsus
+**
+** Keine direkte Ausgabe mehr sondern
+** stattdessen ein More().
+**
+** V 0.3 28.02.98 13:00:00 Paracelsus
+**
+** Testen nicht mehr auf Raeume beschraenkt.
+**
+** V 0.4 28.02.98 16:00:00 Paracelsus
+**
+** Funktionen aus Rochus' Tester uebernommen
+**
+** V 0.5 28.02.98 18:00:00 Paracelsus
+**
+** Funktionalitaeten von Rikus und Rochus
+** aneinander angepasst.
+**
+** V 0.6 28.02.98 19:00:00 Paracelsus
+**
+** Gerueche und Geraeusche eingebaut,
+** erste Tests erfolgreich.
+**
+** V 0.7 28.02.98 19:30:00 Paracelsus
+**
+** Spaltenzahl einstellbar.
+**
+** V 0.8 01.03.98 19:30:00 Paracelsus
+**
+** Scannen ganzer Verzeichnisse. Geht jetzt
+** zumindest bei Raeumen.
+**
+** V 0.9 20.09.98 20:45:00 Paracelsus
+**
+** Umgestellt von heart_beat() auf
+** call_out(), damit this_player()
+** erhalten bleibt.
+** 13.10.08 Chagall
+**
+** _query_details() und
+** _query_special_details auf
+** QueryProp() umgestellt
+**
+****************************************************************************
+**
+** Eventuell auftretende Probleme:
+** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+** - Zu hohe eval_cost, wenn zu viele Details vorhanden sind.
+** Groesster bisher getesteter Raum (ohne Fehler) : 63907
+** Scheint also wohl doch kein Problem zu sein.
+**
+****************************************************************************
+**
+** Ideen/ToDo:
+** ~~~~~~~~~~~
+**
+** - NPC-Infos testen.
+**
+****************************************************************************
+*/
+
+#include <defines.h>
+#include <properties.h>
+#include <wizlevels.h>
+#include <terminal.h>
+
+#define DATAFILE "test.dat"
+#define DEFAULT_DATA "/obj/tools/tester/test.dat"
+
+#define P_OTEST_TYP "ob-test:typ"
+#define P_OTEST_SPL "ob-test:spalten"
+
+#define T_ROCHUS 1
+#define T_RIKUS 2
+
+#define T_PAUSE 4
+
+#pragma strong_types
+
+inherit "/std/thing";
+
+// Allgemein benoetigte globale Variablen
+
+int scantyp,spalten;
+mapping all_dets;
+mixed output;
+object master;
+
+// Globale Variablen fuer das scannen ganzer Directories
+
+int scanrun,scancount,scanpause,*scanerr;
+string scandir,*scanfiles;
+object testob;
+
+string x_long()
+{ string re,PRE,END;
+
+ switch (PL->QueryProp(P_TTY))
+ {
+ case "ansi" :
+ case "vt100" : PRE=BOLD; END=NORMAL; break;
+ default : PRE=""; END=""; break;
+ }
+
+ re = break_string(
+ "Mit diesem Objektpruefer kannst Du feststellen, welche Details, "+
+ "Gerueche oder Geraeusche in einem Raum bzw an einem Objekt noch "+
+ "nicht beschrieben sind.",78)+
+ "\n"+
+ "Syntax: %sotest [detail|smell|sound] {<objekt>[in mir|im raum]|"+
+ "hier}\n\n"+
+ " otype [rikus|rochus]\n\n"+
+ " ocolm [1|2|3|4|5|6|7|8|auto]\n\n"+
+ " otdir <verzeichnis> <ausgabefile>%s\n\n"+
+ break_string(
+ "Mit %sotype%s kann man festlegen, ob man im 'Rikus'- oder im "+
+ "'Rochus'-Modus scannen will, mit %socolm%s die anzahl der Ausgabe"+
+ "spalten und mit %sotest%s wird dann die Auswertung gestartet. "+
+ "Mit dem Kommando %sotdir%s kann man sogar ganze Verzeichnisse "+
+ "auf einmal testen lassen. Das dauert natuerlich eine Weile. "+
+ "Ausserdem muss ein Verzeichnis '/log/<magiername>/' bestehen.",78)+
+ "Derzeitiger Scantyp: %s'"+(scantyp==T_ROCHUS?"ROCHUS":"RIKUS")+
+ "'%s\n"+
+ "Derzeitige Spaltenzahl: %s%s%s\n%s";
+ return sprintf(re,PRE,END,PRE,END,PRE,END,PRE,END,PRE,END,PRE,END,PRE,
+ (spalten>0?sprintf("%d",spalten):"'AUTO'"),END,
+ (scanrun?sprintf(
+ "\nDerzeit Dirscan in: %s%s%s\n"+
+ "Angenommene Restzeit: %s(%s) [Fi:%d/%d|Er:%d|Sk:%d]%s\n",
+ PRE,scandir,END,PRE,
+ time2string("%h:%02m:%02s",(scanrun-1)*4*T_PAUSE),
+ (sizeof(scanfiles)-scanrun+1),(sizeof(scanfiles)),
+ scanerr[0],scanerr[1],END):""));
+}
+
+void create()
+{
+ if (!clonep(ME))
+ return;
+
+ ::create();
+
+// Allgemeine globale Variablen initialisieren
+
+ scantyp = T_ROCHUS;
+ spalten = 4;
+ all_dets = ([]);
+ output = 0;
+
+// Globale Variablen fuer den Directoryscan initialisieren
+
+ scandir = 0;
+ scanrun = 0;
+ scanfiles = ({});
+ scancount = 0;
+ scanpause = 0;
+ scanerr = ({0,0});
+
+// Properties
+
+ SetProp(P_SHORT,"Ein Objektpruefer") ;
+ Set(P_LONG,#'x_long,F_QUERY_METHOD);
+ SetProp(P_NAME,"Objektpruefer");
+ SetProp(P_GENDER,MALE);
+ SetProp(P_AUTOLOADOBJ,1);
+ SetProp(P_VALUE,0);
+ SetProp(P_WEIGHT,0);
+ SetProp(P_NODROP,1);
+ SetProp(P_NEVERDROP,1);
+
+ AddId( ({"pruefer","objektpruefer"}) );
+
+ AddCmd( "otest","search" );
+ AddCmd( "otype","scanart" );
+ AddCmd( "ocolm","spaltenzahl" );
+ AddCmd( "otdir","dirtesten" );
+}
+
+void init()
+{
+ ::init();
+ if (PL->QueryProp(P_TESTPLAYER) || IS_LEARNER(PL))
+ {
+ scantyp=(PL->QueryProp(P_OTEST_TYP)||T_ROCHUS);
+ spalten=(PL->QueryProp(P_OTEST_SPL)||4);
+ return;
+ }
+ if (find_call_out("removen") == -1)
+ call_out("removen",0);
+}
+
+/***************************************************************************
+**
+** Die Hilfsfunktionen des Objekttesters.
+**
+****************************************************************************
+*/
+
+void Output(string text)
+{
+ if (!text || !stringp(text))
+ return;
+ if (objectp(output))
+ output->More(text);
+ else if (stringp(output))
+ write_file(output,text);
+ else
+ write(text);
+}
+
+int removen()
+{
+ write("Dieses Tool ist nur fuer Testies und Magier!\n");
+ remove();
+ return 1;
+}
+
+string *gross(string s)
+{
+ return regexp(regexplode(s,"[^A-Za-z0-9]"),"\\<[A-Z]");
+}
+
+string *det_auswerten(string input)
+{ string *words,str,*re;
+ int anf,n,i;
+
+ if (scantyp==T_RIKUS)
+ return gross(input);
+
+ re = ({});
+ if (!input || !stringp(input))
+ return re;
+
+ words=regexplode(input,"[^A-Za-z0-9]");
+ n=sizeof(words);
+ if (!n)
+ return re;
+
+ anf=1;
+ for (i=0;i<n;i++)
+ {
+ str=words[i];
+ if (str=="" || str==" ")
+ continue;
+ if (str=="." || str==":" || str=="?" || str=="!")
+ {
+ anf=1;
+ continue;
+ }
+ if (sizeof(regexp(({str}),"[^A-Za-z0-9]")))
+ continue;
+ if (sizeof(regexp(({str}),"\\<[0-9]*\\>")))
+ continue;
+ if (str!=capitalize(str))
+ continue;
+ if (anf)
+ {
+ anf=0;
+ continue;
+ }
+ re += ({ str });
+ }
+ return re;
+}
+
+varargs mixed test_details(string str, string def)
+{ string *strs,ostr,*strs2,suf;
+ int i;
+
+ if (!str || !stringp(str) || !mappingp(all_dets))
+ return 0;
+
+ strs = ({str});
+ ostr = str;
+
+ if ((suf=str[<1..<1])=="s" || suf=="n" || suf=="e")
+ {
+ ostr = str[0..<2];
+ strs += ({ ostr });
+ ostr += ("("+suf+")");
+ }
+ if ((suf=str[<2..<1])=="es" || suf=="en")
+ {
+ ostr = str[0..<3];
+ strs += ({ ostr });
+ ostr += ("("+suf+")");
+ }
+ for ( strs2=({}),i=sizeof(strs)-1 ; i>=0 ; i--)
+ if (member(all_dets,strs[i]))
+ {
+ if (stringp(def) && all_dets[strs[i]]==def && str!=SENSE_DEFAULT)
+ continue;
+ strs2 += ({ strs[i] });
+ }
+ if (sizeof(strs2)>0)
+ return strs2;
+ return ostr;
+}
+
+string *eval_detail_entry(mixed key)
+{ mixed re,h;
+ string *ra;
+ int i;
+
+ if (!key || !stringp(key) || !mappingp(all_dets) || !member(all_dets,key))
+ return ({});
+
+ re=all_dets[key];
+ if (closurep(re))
+ re=funcall(re,key);
+ if (mappingp(re))
+ {
+ ra=filter(m_indices(re),#'stringp);
+ for ( h=({ re[0] }),i=sizeof(ra)-1 ; i>=0 ; i-- )
+ if (stringp(re[ra[i]]))
+ h += ({ re[ra[i]] });
+ else if (pointerp(re[ra[i]]))
+ h += re[ra[i]];
+ re=h;
+ }
+ if (pointerp(re))
+ return filter(re,#'stringp);
+ if (stringp(re))
+ return ({ re });
+ return ({});
+}
+
+/***************************************************************************
+**
+** Die Funktion, die die (Special)Details im Raum untersucht.
+**
+****************************************************************************
+*/
+
+int search_d(object r)
+{ int i,j,room;
+ mapping m;
+ string *s,s1,*s2,PRE,END,*special,*zufinden,*details,re,*uebergehen;
+ mixed mi;
+
+ if (!r || !objectp(r))
+ {
+ write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
+ return 1;
+ }
+
+// Die Ausgaben erfolgen zunaechst in einen String.
+
+ re="\n";
+
+// Handelt es sich um einen Raum?
+
+ room = (function_exists("int_long",r) ? 1 : 0 );
+
+// Terminaltyp des Magiers feststellen.
+
+ if (objectp(output))
+ switch (output->QueryProp(P_TTY))
+ {
+ case "ansi" :
+ case "vt100" : PRE=BOLD; END=NORMAL; break;
+ default : PRE=""; END=""; break;
+ }
+ else
+ {
+ PRE="";
+ END="";
+ }
+
+// Liste der zu uebergehenden Details erzeugen. Die verwendete Methode hat den
+// Vorteil, dass man nach einer Ergaenzung der Liste nicht das Tool neu laden
+// und clonen muss. Das Tool erwartet, die Liste DATAFILE im gleichen
+// Verzeichnis zu finden, in dem auch das Tool liegt.
+
+ s1=implode(explode(old_explode(object_name(ME),"#")[0],"/")[0..<2],"/")+"/"
+ DATAFILE;
+ if (file_size(s1)<1)
+ s1=DEFAULT_DATA;
+
+ uebergehen = regexp(regexplode(read_file(s1),"[^A-Za-z0-9]"),"\\<[a-z]");
+
+// Satz an Details, die auf jeden Fall vorhanden sein sollten, je nachdem
+// ob P_INDOORS gesetzt ist oder nicht.
+
+ if (room && r->QueryProp(P_INDOORS))
+ zufinden = ({"Boden","Decke","Wand","Waende","Raum"});
+ else if (room)
+ zufinden = ({"Boden","Himmel","Sonne","Wolke","Wolken"});
+ else
+ zufinden = ({});
+
+// Alle vorhandenen Details anzeigen.
+
+// details = sort_array(m_indices(r->_query_details()||([])),#'<);
+ details = sort_array(m_indices(r->QueryProp(P_DETAILS)||([])),#'<);
+
+ if (scanrun<1)
+ {
+ if ((i=sizeof(details))>0)
+ {
+ for ( s1="",--i; i>=0 ; i-- )
+ s1 += (details[i]+(i?"\n":""));
+
+ re += sprintf(sprintf("%sListe der vorhandenen Details:%s\n\n"+
+ "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
+ sprintf(".%d",spalten))+"s")),s1);
+ }
+ else
+ re += sprintf("%sKeine Details gefunden.%s\n\n",PRE,END);
+ }
+
+// Alle vorhandenen SpecialDetails anzeigen.
+
+// special=sort_array(m_indices(r->_query_special_details()||([])),#'<);
+ special=sort_array(m_indices(r->QueryProp(P_SPECIAL_DETAILS)||([])),#'<);
+
+ if (scanrun<1)
+ {
+ if ((i=sizeof(special))>0)
+ {
+ for ( s1="",--i ; i>=0 ; i-- )
+ s1 += (special[i]+(i?"\n":""));
+
+ re += sprintf(sprintf(
+ "%sListe der vorhandenen SpecialDetails:%s\n\n"+
+ "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
+ sprintf(".%d",spalten))+"s")),s1);
+ }
+ else
+ re += sprintf("%sKeine SpecialDetails gefunden.%s\n\n",PRE,END);
+ }
+
+// Die Listen der vorhandenen Details und SpecialDetails vereinigen.
+
+ details += special;
+
+// Details und SpecialDetails auswerten - gar nicht so einfach.
+
+ all_dets = r->Query(P_DETAILS);
+
+ for ( s=({}),i=sizeof(details)-1 ; i>=0 ; i--)
+ s += eval_detail_entry(details[i]);
+
+ for ( s2=({}),i=sizeof(s)-1 ; i>=0 ; i-- )
+ if (stringp(s[i]))
+ if (member(s2,s[i])==-1)
+ {
+ s2 += ({ s[i] });
+ zufinden+=det_auswerten(s[i]);
+ }
+
+// Grossgeschriebene Woerter aus der Langbeschreibung hinzufuegen.
+
+ if (function_exists("int_long",r))
+ zufinden += det_auswerten(
+ old_explode(r->int_long(master,master),"Es gibt ")[0]);
+ else
+ zufinden += det_auswerten(old_explode(r->long(),"enthaelt:")[0]);
+
+// Doppelte Eintraege eliminieren.
+
+ for ( s2=({}), i=sizeof(zufinden)-1 ; i>=0 ; i--)
+ if (member(s2,zufinden[i])==-1)
+ s2 += ({ zufinden[i] });
+
+// Alles klein machen.
+
+ zufinden=map(s2,#'lower_case);
+
+// Bei NPCs/Objekten die IDs rausfiltern.
+
+ if (!room)
+ zufinden -= r->QueryProp(P_IDS);
+
+// Die zu uebergehenden Details rausfiltern.
+
+ zufinden=filter((zufinden-uebergehen),#'stringp);
+
+// Schauen, welche Details fehlen und diese Ausgeben.
+
+ for ( s=({}),s2=({}),i=sizeof(zufinden)-1;i>=0;i--)
+ {
+ if (!(mi=test_details(zufinden[i])))
+ continue;
+ if (pointerp(mi))
+ {
+ for (j=sizeof(mi)-1 ; j>=0 ; j--)
+ if (member(s,mi[j])==-1)
+ s += ({ mi[j] });
+ }
+ else if (stringp(mi) && member(s2,mi)==-1)
+ s2 += ({ mi });
+ }
+
+ s = sort_array(s, #'<);
+ s2 = sort_array(s2,#'<);
+
+ if (scanrun<1)
+ {
+ if ((i=sizeof(s))>0)
+ {
+ for ( s1="",--i ; i>=0 ; i-- )
+ s1 += (s[i]+(i?"\n":""));
+
+ re += sprintf(sprintf("%sListe der gefundenen Details:%s\n\n"+
+ "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
+ sprintf(".%d",spalten))+"s")),s1);
+ }
+ else
+ re += sprintf("%sEs gibt keine Details.%s\n\n",PRE,END);
+ }
+
+ if ((i=sizeof(s2))>0)
+ {
+ for ( s1="",--i ; i>=0 ; i-- )
+ s1 += (s2[i]+(i?"\n":""));
+
+ re += sprintf(sprintf("%sListe der fehlenden Details:%s\n\n"+
+ "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
+ sprintf(".%d",spalten))+"s")),s1);
+ }
+ else
+ re += sprintf("%sEs fehlen keine Details.%s\n\n",PRE,END);
+
+ if (scanrun<1)
+ re += sprintf("%sFERTIG.%s\n",PRE,END);
+
+// Die eigentliche Textausgabe.
+
+ Output(re);
+
+ return 1;
+}
+
+/***************************************************************************
+**
+** Hauptfunktion fuer das Testen von Geraeuschen und Geruechen.
+**
+****************************************************************************
+*/
+
+int search_sense(object r, int sense)
+{ string re,PRE,END,WAS,*senses,s1,*zufinden,*s2,*s3,def;
+ int i,j;
+ mixed mi;
+
+ if (!r || !objectp(r))
+ {
+ write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
+ return 1;
+ }
+ if (sense==SENSE_SMELL)
+ {
+ all_dets=r->Query(P_SMELLS)||([]);
+ WAS="Gerueche";
+ }
+ else if (sense==SENSE_SOUND)
+ {
+ all_dets=r->Query(P_SOUNDS)||([]);
+ WAS="Geraeusche";
+ }
+ else
+ {
+ write("OTEST-ERROR: Illegaler sense-Wert in search_sense()\n");
+ return 1;
+ }
+
+ re = "\n";
+
+ zufinden = ({SENSE_DEFAULT});
+
+ def = all_dets[SENSE_DEFAULT];
+
+// Terminaltyp des Magiers feststellen.
+
+ if (objectp(output))
+ switch (output->QueryProp(P_TTY))
+ {
+ case "ansi" :
+ case "vt100" : PRE=BOLD; END=NORMAL; break;
+ default : PRE=""; END=""; break;
+ }
+ else
+ {
+ PRE="";
+ END="";
+ }
+
+ senses = sort_array(m_indices(all_dets),#'<);
+
+// Alle vorhandenen Sense-Details anzeigen.
+
+ if (scanrun<1)
+ {
+ if ((i=sizeof(senses))>0)
+ {
+ for ( s1="",--i; i>=0 ; i-- )
+ s1 += ((senses[i]==SENSE_DEFAULT?"DEFAULT":
+ senses[i])+(i?"\n":""));
+
+ re += sprintf(sprintf("%sListe der vorhandenen %s:%s\n\n"+
+ "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
+ sprintf(".%d",spalten))+"s")),s1);
+ }
+ else
+ re += sprintf("%sKeine %s gefunden.%s\n\n",PRE,WAS,END);
+ }
+
+
+// Sense-Details auswerten - geht wie bei Details.
+
+ for ( s2=({}),i=sizeof(senses)-1 ; i>=0 ; i--)
+ s2 += eval_detail_entry(senses[i]);
+
+ for ( s3=({}),i=sizeof(s2)-1 ; i>=0 ; i-- )
+ if (stringp(s2[i]))
+ if (member(s3,s2[i])==-1)
+ {
+ s3 += ({ s2[i] });
+ zufinden+=det_auswerten(s2[i]);
+ }
+
+// Testen, welche Sense-Details fehlen und anzeigen
+
+ for ( s2=({}),s3=({}),i=sizeof(zufinden)-1;i>=0;i--)
+ {
+ if (!(mi=test_details(zufinden[i],def)))
+ continue;
+ if (pointerp(mi))
+ {
+ for (j=sizeof(mi)-1 ; j>=0 ; j--)
+ if (member(s2,mi[j])==-1)
+ s2 += ({ mi[j] });
+ }
+ else if (stringp(mi) && member(s3,mi)==-1)
+ s3 += ({ mi });
+ }
+ s2 = sort_array(s2,#'<);
+ s3 = sort_array(s3,#'<);
+
+ if (scanrun<1)
+ {
+ if ((i=sizeof(s2))>0)
+ {
+ for ( s1="",--i ; i>=0 ; i-- )
+ s1 += ((s2[i]==SENSE_DEFAULT?"DEFAULT":s2[i])+(i?"\n":""));
+
+ re += sprintf(sprintf("%sListe der gefundenen %s:%s\n\n"+
+ "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
+ sprintf(".%d",spalten))+"s")),s1);
+ }
+ else
+ re += sprintf("%sEs gibt keine %s.%s\n\n",PRE,WAS,END);
+ }
+
+ if ((i=sizeof(s3))>0)
+ {
+ for ( s1="",--i ; i>=0 ; i-- )
+ s1 += ((s3[i]==SENSE_DEFAULT?"DEFAULT":s3[i])+(i?"\n":""));
+
+ re += sprintf(sprintf("%sListe der fehlenden %s:%s\n\n"+
+ "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
+ sprintf(".%d",spalten))+"s")),s1);
+ }
+ else
+ re += sprintf("%sEs fehlen keine %s.%s\n\n",PRE,WAS,END);
+
+ if (scanrun<1)
+ re += sprintf("%sFERTIG.%s\n",PRE,END);
+
+// Die eigentliche Textausgabe.
+
+ Output(re);
+
+ return 1;
+}
+
+/***************************************************************************
+**
+** Die Funktion, die die Geraeusche im Raum untersucht.
+**
+****************************************************************************
+*/
+
+int search_n(object r)
+{
+ if (!r || !objectp(r))
+ {
+ write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
+ return 1;
+ }
+
+ return search_sense(r,SENSE_SOUND);
+}
+
+/***************************************************************************
+**
+** Die Funktion, die die Gerueche im Raum untersucht.
+**
+****************************************************************************
+*/
+
+int search_m(object r)
+{
+ if (!r || !objectp(r))
+ {
+ write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
+ return 1;
+ }
+
+ return search_sense(r,SENSE_SMELL);
+}
+
+/***************************************************************************
+**
+** Die Funktion, die das eingegebene Kommando zerlegt und interpretiert.
+**
+****************************************************************************
+*/
+
+int search(string arg)
+{ string *in,dum;
+ object targ;
+ int wo;
+
+ if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
+ return removen();
+
+ if (scanrun)
+ {
+ write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
+ return 1;
+ }
+
+ notify_fail("OTEST-Syntax: otest [detail|smell|sound] "+
+ "{<objekt>[in mir|im raum]|hier}\n");
+
+ if (!arg || !stringp(arg) || sizeof(in=old_explode(arg," "))<1)
+ {
+ output=PL;
+ scanrun=0;
+ master=PL;
+ return search_d(environment(PL));
+ }
+
+ if (sizeof(in)>1)
+ {
+ arg=implode(in[1..]," ");
+ if (member(({"hier","raum",""}),arg)!=-1)
+ targ=environment(PL);
+ else
+ {
+ if (sscanf(arg,"%s in mir",dum))
+ {
+ wo=1;
+ arg=dum;
+ }
+ else if (sscanf(arg,"%s im raum",dum))
+ {
+ wo=-1;
+ arg=dum;
+ }
+ else wo=0;
+ if (wo!=-1)
+ targ=present(arg,PL);
+ if (!objectp(targ) && wo!=1)
+ targ=present(arg,environment(PL));
+ }
+ }
+ else
+ targ=environment(PL);
+ if (!objectp(targ))
+ {
+ write("OTEST-ERROR: Gewuenschtes Ziel nicht gefunden.\n");
+ return 0;
+ }
+
+ output=PL;
+ scanrun=0;
+ master=PL;
+
+ switch(in[0])
+ {
+ case "de" :
+ case "detail" :
+ case "details" :
+ return search_d(targ);
+ case "sm" :
+ case "smell" :
+ case "smells" :
+ return search_m(targ);
+ case "so" :
+ case "sound" :
+ case "sounds" :
+ return search_n(targ);
+ }
+ return 0;
+}
+
+/***************************************************************************
+**
+** Hier kann man den 'Scantyp' einstellen.
+**
+****************************************************************************
+*/
+
+int scanart(string arg)
+{ int h;
+
+ if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
+ return removen();
+
+ if (scanrun)
+ {
+ write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
+ return 1;
+ }
+
+ notify_fail("OTEST-Syntax: otype [rikus|rochus]\n");
+ if (!arg || !stringp(arg))
+ {
+ if (h=PL->QueryProp(P_OTEST_TYP))
+ scantyp=h;
+ if (!h)
+ {
+ PL->SetProp(P_OTEST_TYP,scantyp);
+ PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
+ }
+ printf("OTEST: Eingestellter Scantyp ist '%s'\n",
+ (scantyp==T_ROCHUS?"ROCHUS":"RIKUS"));
+ return 1;
+ }
+ if (member(({"rikus","rochus"}),arg)==-1)
+ return 0;
+ if (arg=="rochus")
+ {
+ scantyp=T_ROCHUS;
+ PL->SetProp(P_OTEST_TYP,scantyp);
+ PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
+ write("OTEST: Eingestellter Scantyp ist 'ROCHUS'\n");
+ return 1;
+ }
+ scantyp=T_RIKUS;
+ PL->SetProp(P_OTEST_TYP,scantyp);
+ PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
+ write("OTEST: Eingestellter Scantyp ist 'RIKUS'\n");
+ return 1;
+}
+
+/***************************************************************************
+**
+** Hier kann man die Spaltenzahl einstellen.
+**
+****************************************************************************
+*/
+
+int spaltenzahl(string arg)
+{ int h;
+
+ if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
+ return removen();
+
+ if (scanrun)
+ {
+ write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
+ return 1;
+ }
+
+ notify_fail("OTEST-Syntax: ocolm [1|2|3|4|5|6|7|8|auto]\n");
+
+ if (!arg || !stringp(arg))
+ {
+ if (h=PL->QueryProp(P_OTEST_SPL))
+ spalten=h;
+ if (!h)
+ {
+ PL->SetProp(P_OTEST_SPL,spalten);
+ PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
+ }
+ printf("OTEST: Eingestellte Spaltenzahl ist '%s'\n",
+ (spalten>0?sprintf("%d",spalten):"'AUTO'"));
+ return 1;
+ }
+ if (arg=="auto")
+ {
+ spalten=-1;
+ PL->SetProp(P_OTEST_SPL,spalten);
+ PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
+ write("OTEST: Eingestellte Spaltenzahl ist 'AUTO'\n");
+ return 1;
+ }
+ h = to_int(arg);
+ if (h<1 || h>8)
+ return 0;
+ spalten=h;
+ PL->SetProp(P_OTEST_SPL,spalten);
+ PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
+ printf("OTEST: Eingestellte Spaltenzahl ist %d\n",spalten);
+ return 1;
+}
+
+/***************************************************************************
+**
+** Hier kann man ganze Verzeichnisse durchscannen lassen
+**
+****************************************************************************
+*/
+
+int dirtesten(string arg)
+{ string vz,af,u,*dir;
+ int i,si;
+
+ if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
+ return removen();
+
+ if (scanrun)
+ {
+ write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
+ return 1;
+ }
+
+ if (object_name(ME)[0..2]=="/p/")
+ {
+ write(break_string("Ein Dirscan kann nur durchgefuehrt werden, "+
+ "wenn man den Pruefer in sein /players/-Verzeichnis kopiert "+
+ "hat oder von einem dort liegenden Objekt inherited.",78,
+ "OTEST: "));
+ return 1;
+ }
+
+ notify_fail("OTEST-Syntax: otdir <verzeichnis> <ausgabefile>\n");
+ if (!arg || !stringp(arg) || sscanf(arg,"%s %s",vz,af)!=2)
+ return 0;
+
+// Zielfilename testen/festlegen.
+
+ u=getuid(PL);
+ if (file_size("/log/"+u+"/")!=-2)
+ {
+ printf("OTEST: Es existiert kein Verzeichnis '/log/%s/'\n",u);
+ return 1;
+ }
+ for (i=sizeof(af)-1;i>=0;i--)
+ if (((si=af[i])<48 && si!=46) || (si>57 && si<65) || si>122 ||
+ (si>90 && si<97))
+ {
+ write("OTEST: Illegaler Filename fuer Ausgabefile.\n");
+ return 1;
+ }
+ u=sprintf("/log/%s/%s",u,af);
+
+// Zu untersuchendes Verzeichnis pruefen/einlesen.
+
+ if (!vz || !stringp(vz) || sizeof(vz)<3 || vz[0]!='/' || vz[<1]!='/')
+ {
+ write("OTEST: Verzeichnisname muss mit '/' beginnen und aufhoeren.\n");
+ return 1;
+ }
+ for (i=sizeof(af)-1;i>=0;i--)
+ if (((si=af[i])<46) || (si>57 && si<65) || si>122 || (si>90 && si<97))
+ {
+ write("OTEST: Illegaler Filename fuer Verzeichnis.\n");
+ return 1;
+ }
+ dir = get_dir(vz+"*.c");
+ if ((si=sizeof(dir))<1)
+ {
+ write("OTEST: Das gewuenschte Verzeichnis existiert nicht oder ist "+
+ "leer.\n");
+ return 1;
+ }
+
+ output = u;
+
+ if (stringp(catch
+ (i=write_file(output, sprintf("Teststart: %s\n\n",dtime(time())))))
+ && i!=1)
+ {
+ write(break_string(
+ sprintf("Fehler beim Schreiben in das File %s:\n%sAborting.",
+ output,u),78,"OTEST: ",1));
+ output = 0;
+ return 1;
+ }
+
+ scanrun = si+1;
+ scanfiles = dir;
+ scandir = vz;
+ scancount = 0;
+ master = PL;
+ scanerr = ({0,0});
+
+ call_out("x_heart_beat",T_PAUSE);
+
+ printf("OTEST: Scanne %d Files:\n"+
+ " %s => %s\n"+
+ "Zeit: etwa %s\n",si,vz,output,
+ time2string("%h:%02m:%02s",si*4*T_PAUSE));
+
+ return 1;
+}
+
+/***************************************************************************
+**
+** Das Scannen von Verzeichnissen wird ueber x_heart_beat() erledigt.
+**
+****************************************************************************
+*/
+
+void x_heart_beat()
+{ int nr;
+ string fn,er;
+
+ call_out("x_heart_beat",T_PAUSE);
+
+ if ((++scancount)>4)
+ {
+ scancount = 1;
+ testob = 0;
+ scanrun--;
+ }
+
+ nr=scanrun-2;
+ if (nr<0)
+ {
+ if (environment() && interactive(environment()))
+ environment()->Message(break_string("'otdir' beendet.\n"+
+ sprintf("Files: %d - Fehler: %d - Skips: %d",
+ sizeof(scanfiles),scanerr[0],scanerr[1]),
+ 78,"OTEST: ",1),MSGFLAG_TELL);
+
+ scanrun = 0;
+ scancount = 0;
+ output = 0;
+ scanfiles = ({});
+ scandir = 0;
+ testob = 0;
+ scanerr = ({0,0});
+
+ while(remove_call_out("x_heart_beat")!=-1);
+
+ return;
+ }
+ fn=scandir+scanfiles[nr];
+ if (fn[<2..]==".c")
+ fn=fn[0..<3];
+
+ if (scancount==1) // Testen, ob File ladbar
+ {
+ Output(sprintf("File: %s\n\n",fn));
+ er=catch(call_other(fn,"???"));
+ if (er && stringp(er))
+ {
+ Output(sprintf("Error: %s->Abort@Load\n\n",er));
+ scanrun--;
+ scancount = 0;
+ testob = 0;
+ scanerr[0] = scanerr[0]+1;
+ }
+ else
+ testob = find_object(fn);
+ return;
+ }
+ if (!objectp(testob))
+ {
+ Output("Objekt nicht gefunden\n-> Abort@Object.\n\n");
+ scanrun--;
+ scancount = 0;
+ scanerr[0] = scanerr[0]+1;
+ return;
+ }
+ if (!function_exists("int_long",testob))
+ {
+ Output("Objekt ist kein Raum -> SKIPPING.\n\n");
+ scanrun--;
+ scancount = 0;
+ testob = 0;
+ scanerr[1] = scanerr[1]+1;
+ return;
+ }
+ switch(scancount)
+ {
+ case 2 :
+ if ((er=catch(search_d(testob))) && stringp(er))
+ {
+ Output(sprintf("Error: %s-> Abort@Detail.\n\n",er));
+ scanrun--;
+ scancount = 0;
+ testob = 0;
+ scanerr[0] = scanerr[0]+1;
+ }
+ return;
+ case 3 :
+ if ((er=catch(search_sense(testob,SENSE_SMELL))) && stringp(er))
+ {
+ Output(sprintf("Error: %s-> Abort@Smell.\n\n",er));
+ scanrun--;
+ scancount = 0;
+ testob = 0;
+ scanerr[0] = scanerr[0]+1;
+ }
+ return;
+ case 4 :
+ if ((er=catch(search_sense(testob,SENSE_SOUND))) && stringp(er))
+ {
+ Output(sprintf("Error: %s-> Abort@Sound.\n\n",er));
+ scanrun--;
+ scancount = 0;
+ testob = 0;
+ scanerr[0] = scanerr[0]+1;
+ }
+ return;
+ }
+ return;
+}
diff --git a/obj/tools/tester/test.dat b/obj/tools/tester/test.dat
new file mode 100644
index 0000000..e720c76
--- /dev/null
+++ b/obj/tools/tester/test.dat
@@ -0,0 +1,5 @@
+der die das ich du er sie es wir ihr sie mein dein sein deiner euer an aus
+ein auch dafuer doch im naja wie deinen meinen deinem meinem sieht dich dies
+sueden norden westen osten suedosten suedwesten nordosten nordwesten diese
+dir dort hm ja nein als auf in man nach um dieser nicht deine von wenn am
+keine mud hier so
\ No newline at end of file