blob: dd70fa8ca23a899c8e93627a1a96cf802d9f5f1e [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001/*
2** Objekt-Tester - Mischung aus Rikus' Detailtester und Rochus' Test-NPC.
3**
4*****************************************************************************
5**
6** Urspruengliche Objekte:
7** ~~~~~~~~~~~~~~~~~~~~~~~
8** /players/rikos/obj/rdet.c Rikus@MorgenGrauen 25.05.96
9**
10** /players/rochus/mon/tester.c Rochus@MorgenGrauen 18.10.94
11**
12*****************************************************************************
13**
14** Dieses Objekt: [ Version 0.8 ]
15** ~~~~~~~~~~~~~~
16** /players/paracelsus/tools/otest.c Paracelsus@Morgengrauen 28.02.98
17**
18** Die Weitergabe, Verwendung oder Veraenderung ist nur erlaubt, wenn
19** diese Meldung nicht geaendert wird.
20** Die Benutzung erfolgt auf eigene Gefahr, jede Verantwortung wird
21** abgelehnt. Es wird keine Garantie gegeben, dass der Objekttester
22** einwandfrei, vollstaendig oder gar zufriedenstellend arbeitet.
23**
24*****************************************************************************
25**
26** ChangeLog:
27** ~~~~~~~~~~
28** V 0.1 28.02.98 11:00:00 Paracelsus
29**
30** Rikus' Raumtester kopiert, optimiert.
31**
32** V 0.2 28.02.98 11:30:00 Paracelsus
33**
34** Keine direkte Ausgabe mehr sondern
35** stattdessen ein More().
36**
37** V 0.3 28.02.98 13:00:00 Paracelsus
38**
39** Testen nicht mehr auf Raeume beschraenkt.
40**
41** V 0.4 28.02.98 16:00:00 Paracelsus
42**
43** Funktionen aus Rochus' Tester uebernommen
44**
45** V 0.5 28.02.98 18:00:00 Paracelsus
46**
47** Funktionalitaeten von Rikus und Rochus
48** aneinander angepasst.
49**
50** V 0.6 28.02.98 19:00:00 Paracelsus
51**
52** Gerueche und Geraeusche eingebaut,
53** erste Tests erfolgreich.
54**
55** V 0.7 28.02.98 19:30:00 Paracelsus
56**
57** Spaltenzahl einstellbar.
58**
59** V 0.8 01.03.98 19:30:00 Paracelsus
60**
61** Scannen ganzer Verzeichnisse. Geht jetzt
62** zumindest bei Raeumen.
63**
64** V 0.9 20.09.98 20:45:00 Paracelsus
65**
66** Umgestellt von heart_beat() auf
67** call_out(), damit this_player()
68** erhalten bleibt.
69** 13.10.08 Chagall
70**
71** _query_details() und
72** _query_special_details auf
73** QueryProp() umgestellt
74**
75****************************************************************************
76**
77** Eventuell auftretende Probleme:
78** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79** - Zu hohe eval_cost, wenn zu viele Details vorhanden sind.
80** Groesster bisher getesteter Raum (ohne Fehler) : 63907
81** Scheint also wohl doch kein Problem zu sein.
82**
83****************************************************************************
84**
85** Ideen/ToDo:
86** ~~~~~~~~~~~
87**
88** - NPC-Infos testen.
89**
90****************************************************************************
91*/
92
93#include <defines.h>
94#include <properties.h>
95#include <wizlevels.h>
96#include <terminal.h>
97
98#define DATAFILE "test.dat"
99#define DEFAULT_DATA "/obj/tools/tester/test.dat"
100
101#define P_OTEST_TYP "ob-test:typ"
102#define P_OTEST_SPL "ob-test:spalten"
103
104#define T_ROCHUS 1
105#define T_RIKUS 2
106
107#define T_PAUSE 4
108
109#pragma strong_types
110
111inherit "/std/thing";
112
113// Allgemein benoetigte globale Variablen
114
115int scantyp,spalten;
116mapping all_dets;
117mixed output;
118object master;
119
120// Globale Variablen fuer das scannen ganzer Directories
121
122int scanrun,scancount,scanpause,*scanerr;
123string scandir,*scanfiles;
124object testob;
125
126string x_long()
127{ string re,PRE,END;
128
129 switch (PL->QueryProp(P_TTY))
130 {
131 case "ansi" :
132 case "vt100" : PRE=BOLD; END=NORMAL; break;
133 default : PRE=""; END=""; break;
134 }
135
136 re = break_string(
137 "Mit diesem Objektpruefer kannst Du feststellen, welche Details, "+
138 "Gerueche oder Geraeusche in einem Raum bzw an einem Objekt noch "+
139 "nicht beschrieben sind.",78)+
140 "\n"+
141 "Syntax: %sotest [detail|smell|sound] {<objekt>[in mir|im raum]|"+
142 "hier}\n\n"+
143 " otype [rikus|rochus]\n\n"+
144 " ocolm [1|2|3|4|5|6|7|8|auto]\n\n"+
145 " otdir <verzeichnis> <ausgabefile>%s\n\n"+
146 break_string(
147 "Mit %sotype%s kann man festlegen, ob man im 'Rikus'- oder im "+
148 "'Rochus'-Modus scannen will, mit %socolm%s die anzahl der Ausgabe"+
149 "spalten und mit %sotest%s wird dann die Auswertung gestartet. "+
150 "Mit dem Kommando %sotdir%s kann man sogar ganze Verzeichnisse "+
151 "auf einmal testen lassen. Das dauert natuerlich eine Weile. "+
152 "Ausserdem muss ein Verzeichnis '/log/<magiername>/' bestehen.",78)+
153 "Derzeitiger Scantyp: %s'"+(scantyp==T_ROCHUS?"ROCHUS":"RIKUS")+
154 "'%s\n"+
155 "Derzeitige Spaltenzahl: %s%s%s\n%s";
156 return sprintf(re,PRE,END,PRE,END,PRE,END,PRE,END,PRE,END,PRE,END,PRE,
157 (spalten>0?sprintf("%d",spalten):"'AUTO'"),END,
158 (scanrun?sprintf(
159 "\nDerzeit Dirscan in: %s%s%s\n"+
160 "Angenommene Restzeit: %s(%s) [Fi:%d/%d|Er:%d|Sk:%d]%s\n",
161 PRE,scandir,END,PRE,
162 time2string("%h:%02m:%02s",(scanrun-1)*4*T_PAUSE),
163 (sizeof(scanfiles)-scanrun+1),(sizeof(scanfiles)),
164 scanerr[0],scanerr[1],END):""));
165}
166
167void create()
168{
169 if (!clonep(ME))
170 return;
171
172 ::create();
173
174// Allgemeine globale Variablen initialisieren
175
176 scantyp = T_ROCHUS;
177 spalten = 4;
178 all_dets = ([]);
179 output = 0;
180
181// Globale Variablen fuer den Directoryscan initialisieren
182
183 scandir = 0;
184 scanrun = 0;
185 scanfiles = ({});
186 scancount = 0;
187 scanpause = 0;
188 scanerr = ({0,0});
189
190// Properties
191
192 SetProp(P_SHORT,"Ein Objektpruefer") ;
193 Set(P_LONG,#'x_long,F_QUERY_METHOD);
194 SetProp(P_NAME,"Objektpruefer");
195 SetProp(P_GENDER,MALE);
196 SetProp(P_AUTOLOADOBJ,1);
197 SetProp(P_VALUE,0);
198 SetProp(P_WEIGHT,0);
199 SetProp(P_NODROP,1);
200 SetProp(P_NEVERDROP,1);
201
202 AddId( ({"pruefer","objektpruefer"}) );
203
204 AddCmd( "otest","search" );
205 AddCmd( "otype","scanart" );
206 AddCmd( "ocolm","spaltenzahl" );
207 AddCmd( "otdir","dirtesten" );
208}
209
210void init()
211{
212 ::init();
213 if (PL->QueryProp(P_TESTPLAYER) || IS_LEARNER(PL))
214 {
215 scantyp=(PL->QueryProp(P_OTEST_TYP)||T_ROCHUS);
216 spalten=(PL->QueryProp(P_OTEST_SPL)||4);
217 return;
218 }
219 if (find_call_out("removen") == -1)
220 call_out("removen",0);
221}
222
223/***************************************************************************
224**
225** Die Hilfsfunktionen des Objekttesters.
226**
227****************************************************************************
228*/
229
230void Output(string text)
231{
232 if (!text || !stringp(text))
233 return;
234 if (objectp(output))
235 output->More(text);
236 else if (stringp(output))
237 write_file(output,text);
238 else
239 write(text);
240}
241
242int removen()
243{
244 write("Dieses Tool ist nur fuer Testies und Magier!\n");
245 remove();
246 return 1;
247}
248
249string *gross(string s)
250{
251 return regexp(regexplode(s,"[^A-Za-z0-9]"),"\\<[A-Z]");
252}
253
254string *det_auswerten(string input)
255{ string *words,str,*re;
256 int anf,n,i;
257
258 if (scantyp==T_RIKUS)
259 return gross(input);
260
261 re = ({});
262 if (!input || !stringp(input))
263 return re;
264
265 words=regexplode(input,"[^A-Za-z0-9]");
266 n=sizeof(words);
267 if (!n)
268 return re;
269
270 anf=1;
271 for (i=0;i<n;i++)
272 {
273 str=words[i];
274 if (str=="" || str==" ")
275 continue;
276 if (str=="." || str==":" || str=="?" || str=="!")
277 {
278 anf=1;
279 continue;
280 }
281 if (sizeof(regexp(({str}),"[^A-Za-z0-9]")))
282 continue;
283 if (sizeof(regexp(({str}),"\\<[0-9]*\\>")))
284 continue;
285 if (str!=capitalize(str))
286 continue;
287 if (anf)
288 {
289 anf=0;
290 continue;
291 }
292 re += ({ str });
293 }
294 return re;
295}
296
297varargs mixed test_details(string str, string def)
298{ string *strs,ostr,*strs2,suf;
299 int i;
300
301 if (!str || !stringp(str) || !mappingp(all_dets))
302 return 0;
303
304 strs = ({str});
305 ostr = str;
306
307 if ((suf=str[<1..<1])=="s" || suf=="n" || suf=="e")
308 {
309 ostr = str[0..<2];
310 strs += ({ ostr });
311 ostr += ("("+suf+")");
312 }
313 if ((suf=str[<2..<1])=="es" || suf=="en")
314 {
315 ostr = str[0..<3];
316 strs += ({ ostr });
317 ostr += ("("+suf+")");
318 }
319 for ( strs2=({}),i=sizeof(strs)-1 ; i>=0 ; i--)
320 if (member(all_dets,strs[i]))
321 {
322 if (stringp(def) && all_dets[strs[i]]==def && str!=SENSE_DEFAULT)
323 continue;
324 strs2 += ({ strs[i] });
325 }
326 if (sizeof(strs2)>0)
327 return strs2;
328 return ostr;
329}
330
331string *eval_detail_entry(mixed key)
332{ mixed re,h;
333 string *ra;
334 int i;
335
336 if (!key || !stringp(key) || !mappingp(all_dets) || !member(all_dets,key))
337 return ({});
338
339 re=all_dets[key];
340 if (closurep(re))
341 re=funcall(re,key);
342 if (mappingp(re))
343 {
344 ra=filter(m_indices(re),#'stringp);
345 for ( h=({ re[0] }),i=sizeof(ra)-1 ; i>=0 ; i-- )
346 if (stringp(re[ra[i]]))
347 h += ({ re[ra[i]] });
348 else if (pointerp(re[ra[i]]))
349 h += re[ra[i]];
350 re=h;
351 }
352 if (pointerp(re))
353 return filter(re,#'stringp);
354 if (stringp(re))
355 return ({ re });
356 return ({});
357}
358
359/***************************************************************************
360**
361** Die Funktion, die die (Special)Details im Raum untersucht.
362**
363****************************************************************************
364*/
365
366int search_d(object r)
367{ int i,j,room;
368 mapping m;
369 string *s,s1,*s2,PRE,END,*special,*zufinden,*details,re,*uebergehen;
370 mixed mi;
371
372 if (!r || !objectp(r))
373 {
374 write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
375 return 1;
376 }
377
378// Die Ausgaben erfolgen zunaechst in einen String.
379
380 re="\n";
381
382// Handelt es sich um einen Raum?
383
384 room = (function_exists("int_long",r) ? 1 : 0 );
385
386// Terminaltyp des Magiers feststellen.
387
388 if (objectp(output))
389 switch (output->QueryProp(P_TTY))
390 {
391 case "ansi" :
392 case "vt100" : PRE=BOLD; END=NORMAL; break;
393 default : PRE=""; END=""; break;
394 }
395 else
396 {
397 PRE="";
398 END="";
399 }
400
401// Liste der zu uebergehenden Details erzeugen. Die verwendete Methode hat den
402// Vorteil, dass man nach einer Ergaenzung der Liste nicht das Tool neu laden
403// und clonen muss. Das Tool erwartet, die Liste DATAFILE im gleichen
404// Verzeichnis zu finden, in dem auch das Tool liegt.
405
406 s1=implode(explode(old_explode(object_name(ME),"#")[0],"/")[0..<2],"/")+"/"
407 DATAFILE;
408 if (file_size(s1)<1)
409 s1=DEFAULT_DATA;
410
411 uebergehen = regexp(regexplode(read_file(s1),"[^A-Za-z0-9]"),"\\<[a-z]");
412
413// Satz an Details, die auf jeden Fall vorhanden sein sollten, je nachdem
414// ob P_INDOORS gesetzt ist oder nicht.
415
416 if (room && r->QueryProp(P_INDOORS))
417 zufinden = ({"Boden","Decke","Wand","Waende","Raum"});
418 else if (room)
419 zufinden = ({"Boden","Himmel","Sonne","Wolke","Wolken"});
420 else
421 zufinden = ({});
422
423// Alle vorhandenen Details anzeigen.
424
425// details = sort_array(m_indices(r->_query_details()||([])),#'<);
426 details = sort_array(m_indices(r->QueryProp(P_DETAILS)||([])),#'<);
427
428 if (scanrun<1)
429 {
430 if ((i=sizeof(details))>0)
431 {
432 for ( s1="",--i; i>=0 ; i-- )
433 s1 += (details[i]+(i?"\n":""));
434
435 re += sprintf(sprintf("%sListe der vorhandenen Details:%s\n\n"+
436 "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
437 sprintf(".%d",spalten))+"s")),s1);
438 }
439 else
440 re += sprintf("%sKeine Details gefunden.%s\n\n",PRE,END);
441 }
442
443// Alle vorhandenen SpecialDetails anzeigen.
444
445// special=sort_array(m_indices(r->_query_special_details()||([])),#'<);
446 special=sort_array(m_indices(r->QueryProp(P_SPECIAL_DETAILS)||([])),#'<);
447
448 if (scanrun<1)
449 {
450 if ((i=sizeof(special))>0)
451 {
452 for ( s1="",--i ; i>=0 ; i-- )
453 s1 += (special[i]+(i?"\n":""));
454
455 re += sprintf(sprintf(
456 "%sListe der vorhandenen SpecialDetails:%s\n\n"+
457 "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
458 sprintf(".%d",spalten))+"s")),s1);
459 }
460 else
461 re += sprintf("%sKeine SpecialDetails gefunden.%s\n\n",PRE,END);
462 }
463
464// Die Listen der vorhandenen Details und SpecialDetails vereinigen.
465
466 details += special;
467
468// Details und SpecialDetails auswerten - gar nicht so einfach.
469
470 all_dets = r->Query(P_DETAILS);
471
472 for ( s=({}),i=sizeof(details)-1 ; i>=0 ; i--)
473 s += eval_detail_entry(details[i]);
474
475 for ( s2=({}),i=sizeof(s)-1 ; i>=0 ; i-- )
476 if (stringp(s[i]))
477 if (member(s2,s[i])==-1)
478 {
479 s2 += ({ s[i] });
480 zufinden+=det_auswerten(s[i]);
481 }
482
483// Grossgeschriebene Woerter aus der Langbeschreibung hinzufuegen.
484
485 if (function_exists("int_long",r))
486 zufinden += det_auswerten(
487 old_explode(r->int_long(master,master),"Es gibt ")[0]);
488 else
489 zufinden += det_auswerten(old_explode(r->long(),"enthaelt:")[0]);
490
491// Doppelte Eintraege eliminieren.
492
493 for ( s2=({}), i=sizeof(zufinden)-1 ; i>=0 ; i--)
494 if (member(s2,zufinden[i])==-1)
495 s2 += ({ zufinden[i] });
496
497// Alles klein machen.
498
499 zufinden=map(s2,#'lower_case);
500
501// Bei NPCs/Objekten die IDs rausfiltern.
502
503 if (!room)
504 zufinden -= r->QueryProp(P_IDS);
505
506// Die zu uebergehenden Details rausfiltern.
507
508 zufinden=filter((zufinden-uebergehen),#'stringp);
509
510// Schauen, welche Details fehlen und diese Ausgeben.
511
512 for ( s=({}),s2=({}),i=sizeof(zufinden)-1;i>=0;i--)
513 {
514 if (!(mi=test_details(zufinden[i])))
515 continue;
516 if (pointerp(mi))
517 {
518 for (j=sizeof(mi)-1 ; j>=0 ; j--)
519 if (member(s,mi[j])==-1)
520 s += ({ mi[j] });
521 }
522 else if (stringp(mi) && member(s2,mi)==-1)
523 s2 += ({ mi });
524 }
525
526 s = sort_array(s, #'<);
527 s2 = sort_array(s2,#'<);
528
529 if (scanrun<1)
530 {
531 if ((i=sizeof(s))>0)
532 {
533 for ( s1="",--i ; i>=0 ; i-- )
534 s1 += (s[i]+(i?"\n":""));
535
536 re += sprintf(sprintf("%sListe der gefundenen Details:%s\n\n"+
537 "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
538 sprintf(".%d",spalten))+"s")),s1);
539 }
540 else
541 re += sprintf("%sEs gibt keine Details.%s\n\n",PRE,END);
542 }
543
544 if ((i=sizeof(s2))>0)
545 {
546 for ( s1="",--i ; i>=0 ; i-- )
547 s1 += (s2[i]+(i?"\n":""));
548
549 re += sprintf(sprintf("%sListe der fehlenden Details:%s\n\n"+
550 "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
551 sprintf(".%d",spalten))+"s")),s1);
552 }
553 else
554 re += sprintf("%sEs fehlen keine Details.%s\n\n",PRE,END);
555
556 if (scanrun<1)
557 re += sprintf("%sFERTIG.%s\n",PRE,END);
558
559// Die eigentliche Textausgabe.
560
561 Output(re);
562
563 return 1;
564}
565
566/***************************************************************************
567**
568** Hauptfunktion fuer das Testen von Geraeuschen und Geruechen.
569**
570****************************************************************************
571*/
572
573int search_sense(object r, int sense)
574{ string re,PRE,END,WAS,*senses,s1,*zufinden,*s2,*s3,def;
575 int i,j;
576 mixed mi;
577
578 if (!r || !objectp(r))
579 {
580 write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
581 return 1;
582 }
583 if (sense==SENSE_SMELL)
584 {
585 all_dets=r->Query(P_SMELLS)||([]);
586 WAS="Gerueche";
587 }
588 else if (sense==SENSE_SOUND)
589 {
590 all_dets=r->Query(P_SOUNDS)||([]);
591 WAS="Geraeusche";
592 }
593 else
594 {
595 write("OTEST-ERROR: Illegaler sense-Wert in search_sense()\n");
596 return 1;
597 }
598
599 re = "\n";
600
601 zufinden = ({SENSE_DEFAULT});
602
603 def = all_dets[SENSE_DEFAULT];
604
605// Terminaltyp des Magiers feststellen.
606
607 if (objectp(output))
608 switch (output->QueryProp(P_TTY))
609 {
610 case "ansi" :
611 case "vt100" : PRE=BOLD; END=NORMAL; break;
612 default : PRE=""; END=""; break;
613 }
614 else
615 {
616 PRE="";
617 END="";
618 }
619
620 senses = sort_array(m_indices(all_dets),#'<);
621
622// Alle vorhandenen Sense-Details anzeigen.
623
624 if (scanrun<1)
625 {
626 if ((i=sizeof(senses))>0)
627 {
628 for ( s1="",--i; i>=0 ; i-- )
629 s1 += ((senses[i]==SENSE_DEFAULT?"DEFAULT":
630 senses[i])+(i?"\n":""));
631
632 re += sprintf(sprintf("%sListe der vorhandenen %s:%s\n\n"+
633 "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
634 sprintf(".%d",spalten))+"s")),s1);
635 }
636 else
637 re += sprintf("%sKeine %s gefunden.%s\n\n",PRE,WAS,END);
638 }
639
640
641// Sense-Details auswerten - geht wie bei Details.
642
643 for ( s2=({}),i=sizeof(senses)-1 ; i>=0 ; i--)
644 s2 += eval_detail_entry(senses[i]);
645
646 for ( s3=({}),i=sizeof(s2)-1 ; i>=0 ; i-- )
647 if (stringp(s2[i]))
648 if (member(s3,s2[i])==-1)
649 {
650 s3 += ({ s2[i] });
651 zufinden+=det_auswerten(s2[i]);
652 }
653
654// Testen, welche Sense-Details fehlen und anzeigen
655
656 for ( s2=({}),s3=({}),i=sizeof(zufinden)-1;i>=0;i--)
657 {
658 if (!(mi=test_details(zufinden[i],def)))
659 continue;
660 if (pointerp(mi))
661 {
662 for (j=sizeof(mi)-1 ; j>=0 ; j--)
663 if (member(s2,mi[j])==-1)
664 s2 += ({ mi[j] });
665 }
666 else if (stringp(mi) && member(s3,mi)==-1)
667 s3 += ({ mi });
668 }
669 s2 = sort_array(s2,#'<);
670 s3 = sort_array(s3,#'<);
671
672 if (scanrun<1)
673 {
674 if ((i=sizeof(s2))>0)
675 {
676 for ( s1="",--i ; i>=0 ; i-- )
677 s1 += ((s2[i]==SENSE_DEFAULT?"DEFAULT":s2[i])+(i?"\n":""));
678
679 re += sprintf(sprintf("%sListe der gefundenen %s:%s\n\n"+
680 "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
681 sprintf(".%d",spalten))+"s")),s1);
682 }
683 else
684 re += sprintf("%sEs gibt keine %s.%s\n\n",PRE,WAS,END);
685 }
686
687 if ((i=sizeof(s3))>0)
688 {
689 for ( s1="",--i ; i>=0 ; i-- )
690 s1 += ((s3[i]==SENSE_DEFAULT?"DEFAULT":s3[i])+(i?"\n":""));
691
692 re += sprintf(sprintf("%sListe der fehlenden %s:%s\n\n"+
693 "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
694 sprintf(".%d",spalten))+"s")),s1);
695 }
696 else
697 re += sprintf("%sEs fehlen keine %s.%s\n\n",PRE,WAS,END);
698
699 if (scanrun<1)
700 re += sprintf("%sFERTIG.%s\n",PRE,END);
701
702// Die eigentliche Textausgabe.
703
704 Output(re);
705
706 return 1;
707}
708
709/***************************************************************************
710**
711** Die Funktion, die die Geraeusche im Raum untersucht.
712**
713****************************************************************************
714*/
715
716int search_n(object r)
717{
718 if (!r || !objectp(r))
719 {
720 write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
721 return 1;
722 }
723
724 return search_sense(r,SENSE_SOUND);
725}
726
727/***************************************************************************
728**
729** Die Funktion, die die Gerueche im Raum untersucht.
730**
731****************************************************************************
732*/
733
734int search_m(object r)
735{
736 if (!r || !objectp(r))
737 {
738 write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
739 return 1;
740 }
741
742 return search_sense(r,SENSE_SMELL);
743}
744
745/***************************************************************************
746**
747** Die Funktion, die das eingegebene Kommando zerlegt und interpretiert.
748**
749****************************************************************************
750*/
751
752int search(string arg)
753{ string *in,dum;
754 object targ;
755 int wo;
756
757 if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
758 return removen();
759
760 if (scanrun)
761 {
762 write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
763 return 1;
764 }
765
766 notify_fail("OTEST-Syntax: otest [detail|smell|sound] "+
767 "{<objekt>[in mir|im raum]|hier}\n");
768
769 if (!arg || !stringp(arg) || sizeof(in=old_explode(arg," "))<1)
770 {
771 output=PL;
772 scanrun=0;
773 master=PL;
774 return search_d(environment(PL));
775 }
776
777 if (sizeof(in)>1)
778 {
779 arg=implode(in[1..]," ");
780 if (member(({"hier","raum",""}),arg)!=-1)
781 targ=environment(PL);
782 else
783 {
784 if (sscanf(arg,"%s in mir",dum))
785 {
786 wo=1;
787 arg=dum;
788 }
789 else if (sscanf(arg,"%s im raum",dum))
790 {
791 wo=-1;
792 arg=dum;
793 }
794 else wo=0;
795 if (wo!=-1)
796 targ=present(arg,PL);
797 if (!objectp(targ) && wo!=1)
798 targ=present(arg,environment(PL));
799 }
800 }
801 else
802 targ=environment(PL);
803 if (!objectp(targ))
804 {
805 write("OTEST-ERROR: Gewuenschtes Ziel nicht gefunden.\n");
806 return 0;
807 }
808
809 output=PL;
810 scanrun=0;
811 master=PL;
812
813 switch(in[0])
814 {
815 case "de" :
816 case "detail" :
817 case "details" :
818 return search_d(targ);
819 case "sm" :
820 case "smell" :
821 case "smells" :
822 return search_m(targ);
823 case "so" :
824 case "sound" :
825 case "sounds" :
826 return search_n(targ);
827 }
828 return 0;
829}
830
831/***************************************************************************
832**
833** Hier kann man den 'Scantyp' einstellen.
834**
835****************************************************************************
836*/
837
838int scanart(string arg)
839{ int h;
840
841 if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
842 return removen();
843
844 if (scanrun)
845 {
846 write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
847 return 1;
848 }
849
850 notify_fail("OTEST-Syntax: otype [rikus|rochus]\n");
851 if (!arg || !stringp(arg))
852 {
853 if (h=PL->QueryProp(P_OTEST_TYP))
854 scantyp=h;
855 if (!h)
856 {
857 PL->SetProp(P_OTEST_TYP,scantyp);
858 PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
859 }
860 printf("OTEST: Eingestellter Scantyp ist '%s'\n",
861 (scantyp==T_ROCHUS?"ROCHUS":"RIKUS"));
862 return 1;
863 }
864 if (member(({"rikus","rochus"}),arg)==-1)
865 return 0;
866 if (arg=="rochus")
867 {
868 scantyp=T_ROCHUS;
869 PL->SetProp(P_OTEST_TYP,scantyp);
870 PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
871 write("OTEST: Eingestellter Scantyp ist 'ROCHUS'\n");
872 return 1;
873 }
874 scantyp=T_RIKUS;
875 PL->SetProp(P_OTEST_TYP,scantyp);
876 PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
877 write("OTEST: Eingestellter Scantyp ist 'RIKUS'\n");
878 return 1;
879}
880
881/***************************************************************************
882**
883** Hier kann man die Spaltenzahl einstellen.
884**
885****************************************************************************
886*/
887
888int spaltenzahl(string arg)
889{ int h;
890
891 if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
892 return removen();
893
894 if (scanrun)
895 {
896 write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
897 return 1;
898 }
899
900 notify_fail("OTEST-Syntax: ocolm [1|2|3|4|5|6|7|8|auto]\n");
901
902 if (!arg || !stringp(arg))
903 {
904 if (h=PL->QueryProp(P_OTEST_SPL))
905 spalten=h;
906 if (!h)
907 {
908 PL->SetProp(P_OTEST_SPL,spalten);
909 PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
910 }
911 printf("OTEST: Eingestellte Spaltenzahl ist '%s'\n",
912 (spalten>0?sprintf("%d",spalten):"'AUTO'"));
913 return 1;
914 }
915 if (arg=="auto")
916 {
917 spalten=-1;
918 PL->SetProp(P_OTEST_SPL,spalten);
919 PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
920 write("OTEST: Eingestellte Spaltenzahl ist 'AUTO'\n");
921 return 1;
922 }
923 h = to_int(arg);
924 if (h<1 || h>8)
925 return 0;
926 spalten=h;
927 PL->SetProp(P_OTEST_SPL,spalten);
928 PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
929 printf("OTEST: Eingestellte Spaltenzahl ist %d\n",spalten);
930 return 1;
931}
932
933/***************************************************************************
934**
935** Hier kann man ganze Verzeichnisse durchscannen lassen
936**
937****************************************************************************
938*/
939
940int dirtesten(string arg)
941{ string vz,af,u,*dir;
942 int i,si;
943
944 if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
945 return removen();
946
947 if (scanrun)
948 {
949 write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
950 return 1;
951 }
952
953 if (object_name(ME)[0..2]=="/p/")
954 {
955 write(break_string("Ein Dirscan kann nur durchgefuehrt werden, "+
956 "wenn man den Pruefer in sein /players/-Verzeichnis kopiert "+
957 "hat oder von einem dort liegenden Objekt inherited.",78,
958 "OTEST: "));
959 return 1;
960 }
961
962 notify_fail("OTEST-Syntax: otdir <verzeichnis> <ausgabefile>\n");
963 if (!arg || !stringp(arg) || sscanf(arg,"%s %s",vz,af)!=2)
964 return 0;
965
966// Zielfilename testen/festlegen.
967
968 u=getuid(PL);
969 if (file_size("/log/"+u+"/")!=-2)
970 {
971 printf("OTEST: Es existiert kein Verzeichnis '/log/%s/'\n",u);
972 return 1;
973 }
974 for (i=sizeof(af)-1;i>=0;i--)
975 if (((si=af[i])<48 && si!=46) || (si>57 && si<65) || si>122 ||
976 (si>90 && si<97))
977 {
978 write("OTEST: Illegaler Filename fuer Ausgabefile.\n");
979 return 1;
980 }
981 u=sprintf("/log/%s/%s",u,af);
982
983// Zu untersuchendes Verzeichnis pruefen/einlesen.
984
985 if (!vz || !stringp(vz) || sizeof(vz)<3 || vz[0]!='/' || vz[<1]!='/')
986 {
987 write("OTEST: Verzeichnisname muss mit '/' beginnen und aufhoeren.\n");
988 return 1;
989 }
990 for (i=sizeof(af)-1;i>=0;i--)
991 if (((si=af[i])<46) || (si>57 && si<65) || si>122 || (si>90 && si<97))
992 {
993 write("OTEST: Illegaler Filename fuer Verzeichnis.\n");
994 return 1;
995 }
996 dir = get_dir(vz+"*.c");
997 if ((si=sizeof(dir))<1)
998 {
999 write("OTEST: Das gewuenschte Verzeichnis existiert nicht oder ist "+
1000 "leer.\n");
1001 return 1;
1002 }
1003
1004 output = u;
1005
1006 if (stringp(catch
1007 (i=write_file(output, sprintf("Teststart: %s\n\n",dtime(time())))))
1008 && i!=1)
1009 {
1010 write(break_string(
1011 sprintf("Fehler beim Schreiben in das File %s:\n%sAborting.",
1012 output,u),78,"OTEST: ",1));
1013 output = 0;
1014 return 1;
1015 }
1016
1017 scanrun = si+1;
1018 scanfiles = dir;
1019 scandir = vz;
1020 scancount = 0;
1021 master = PL;
1022 scanerr = ({0,0});
1023
1024 call_out("x_heart_beat",T_PAUSE);
1025
1026 printf("OTEST: Scanne %d Files:\n"+
1027 " %s => %s\n"+
1028 "Zeit: etwa %s\n",si,vz,output,
1029 time2string("%h:%02m:%02s",si*4*T_PAUSE));
1030
1031 return 1;
1032}
1033
1034/***************************************************************************
1035**
1036** Das Scannen von Verzeichnissen wird ueber x_heart_beat() erledigt.
1037**
1038****************************************************************************
1039*/
1040
1041void x_heart_beat()
1042{ int nr;
1043 string fn,er;
1044
1045 call_out("x_heart_beat",T_PAUSE);
1046
1047 if ((++scancount)>4)
1048 {
1049 scancount = 1;
1050 testob = 0;
1051 scanrun--;
1052 }
1053
1054 nr=scanrun-2;
1055 if (nr<0)
1056 {
1057 if (environment() && interactive(environment()))
1058 environment()->Message(break_string("'otdir' beendet.\n"+
1059 sprintf("Files: %d - Fehler: %d - Skips: %d",
1060 sizeof(scanfiles),scanerr[0],scanerr[1]),
1061 78,"OTEST: ",1),MSGFLAG_TELL);
1062
1063 scanrun = 0;
1064 scancount = 0;
1065 output = 0;
1066 scanfiles = ({});
1067 scandir = 0;
1068 testob = 0;
1069 scanerr = ({0,0});
1070
1071 while(remove_call_out("x_heart_beat")!=-1);
1072
1073 return;
1074 }
1075 fn=scandir+scanfiles[nr];
1076 if (fn[<2..]==".c")
1077 fn=fn[0..<3];
1078
1079 if (scancount==1) // Testen, ob File ladbar
1080 {
1081 Output(sprintf("File: %s\n\n",fn));
1082 er=catch(call_other(fn,"???"));
1083 if (er && stringp(er))
1084 {
1085 Output(sprintf("Error: %s->Abort@Load\n\n",er));
1086 scanrun--;
1087 scancount = 0;
1088 testob = 0;
1089 scanerr[0] = scanerr[0]+1;
1090 }
1091 else
1092 testob = find_object(fn);
1093 return;
1094 }
1095 if (!objectp(testob))
1096 {
1097 Output("Objekt nicht gefunden\n-> Abort@Object.\n\n");
1098 scanrun--;
1099 scancount = 0;
1100 scanerr[0] = scanerr[0]+1;
1101 return;
1102 }
1103 if (!function_exists("int_long",testob))
1104 {
1105 Output("Objekt ist kein Raum -> SKIPPING.\n\n");
1106 scanrun--;
1107 scancount = 0;
1108 testob = 0;
1109 scanerr[1] = scanerr[1]+1;
1110 return;
1111 }
1112 switch(scancount)
1113 {
1114 case 2 :
1115 if ((er=catch(search_d(testob))) && stringp(er))
1116 {
1117 Output(sprintf("Error: %s-> Abort@Detail.\n\n",er));
1118 scanrun--;
1119 scancount = 0;
1120 testob = 0;
1121 scanerr[0] = scanerr[0]+1;
1122 }
1123 return;
1124 case 3 :
1125 if ((er=catch(search_sense(testob,SENSE_SMELL))) && stringp(er))
1126 {
1127 Output(sprintf("Error: %s-> Abort@Smell.\n\n",er));
1128 scanrun--;
1129 scancount = 0;
1130 testob = 0;
1131 scanerr[0] = scanerr[0]+1;
1132 }
1133 return;
1134 case 4 :
1135 if ((er=catch(search_sense(testob,SENSE_SOUND))) && stringp(er))
1136 {
1137 Output(sprintf("Error: %s-> Abort@Sound.\n\n",er));
1138 scanrun--;
1139 scancount = 0;
1140 testob = 0;
1141 scanerr[0] = scanerr[0]+1;
1142 }
1143 return;
1144 }
1145 return;
1146}