blob: 0410781d10a99f54d3b251a1cc00e5017f132db9 [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
Zesstrad39f73d2018-11-09 00:01:15 +0100111inherit "/std/secure_thing";
MG Mud User88f12472016-06-24 23:31:02 +0200112
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
Zesstraff356512018-08-27 20:20:36 +0200167protected void create()
MG Mud User88f12472016-06-24 23:31:02 +0200168{
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
Zesstraff356512018-08-27 20:20:36 +0200210public varargs void init(object origin)
MG Mud User88f12472016-06-24 23:31:02 +0200211{
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;
MG Mud User88f12472016-06-24 23:31:02 +0200368 string *s,s1,*s2,PRE,END,*special,*zufinden,*details,re,*uebergehen;
369 mixed mi;
370
371 if (!r || !objectp(r))
372 {
373 write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
374 return 1;
375 }
376
377// Die Ausgaben erfolgen zunaechst in einen String.
378
379 re="\n";
380
381// Handelt es sich um einen Raum?
382
383 room = (function_exists("int_long",r) ? 1 : 0 );
384
385// Terminaltyp des Magiers feststellen.
386
387 if (objectp(output))
388 switch (output->QueryProp(P_TTY))
389 {
390 case "ansi" :
391 case "vt100" : PRE=BOLD; END=NORMAL; break;
392 default : PRE=""; END=""; break;
393 }
394 else
395 {
396 PRE="";
397 END="";
398 }
399
400// Liste der zu uebergehenden Details erzeugen. Die verwendete Methode hat den
401// Vorteil, dass man nach einer Ergaenzung der Liste nicht das Tool neu laden
402// und clonen muss. Das Tool erwartet, die Liste DATAFILE im gleichen
403// Verzeichnis zu finden, in dem auch das Tool liegt.
404
405 s1=implode(explode(old_explode(object_name(ME),"#")[0],"/")[0..<2],"/")+"/"
406 DATAFILE;
407 if (file_size(s1)<1)
408 s1=DEFAULT_DATA;
409
410 uebergehen = regexp(regexplode(read_file(s1),"[^A-Za-z0-9]"),"\\<[a-z]");
411
412// Satz an Details, die auf jeden Fall vorhanden sein sollten, je nachdem
413// ob P_INDOORS gesetzt ist oder nicht.
414
415 if (room && r->QueryProp(P_INDOORS))
416 zufinden = ({"Boden","Decke","Wand","Waende","Raum"});
417 else if (room)
418 zufinden = ({"Boden","Himmel","Sonne","Wolke","Wolken"});
419 else
420 zufinden = ({});
421
422// Alle vorhandenen Details anzeigen.
423
424// details = sort_array(m_indices(r->_query_details()||([])),#'<);
425 details = sort_array(m_indices(r->QueryProp(P_DETAILS)||([])),#'<);
426
427 if (scanrun<1)
428 {
429 if ((i=sizeof(details))>0)
430 {
431 for ( s1="",--i; i>=0 ; i-- )
432 s1 += (details[i]+(i?"\n":""));
433
434 re += sprintf(sprintf("%sListe der vorhandenen Details:%s\n\n"+
435 "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
436 sprintf(".%d",spalten))+"s")),s1);
437 }
438 else
439 re += sprintf("%sKeine Details gefunden.%s\n\n",PRE,END);
440 }
441
442// Alle vorhandenen SpecialDetails anzeigen.
443
444// special=sort_array(m_indices(r->_query_special_details()||([])),#'<);
445 special=sort_array(m_indices(r->QueryProp(P_SPECIAL_DETAILS)||([])),#'<);
446
447 if (scanrun<1)
448 {
449 if ((i=sizeof(special))>0)
450 {
451 for ( s1="",--i ; i>=0 ; i-- )
452 s1 += (special[i]+(i?"\n":""));
453
454 re += sprintf(sprintf(
455 "%sListe der vorhandenen SpecialDetails:%s\n\n"+
456 "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
457 sprintf(".%d",spalten))+"s")),s1);
458 }
459 else
460 re += sprintf("%sKeine SpecialDetails gefunden.%s\n\n",PRE,END);
461 }
462
463// Die Listen der vorhandenen Details und SpecialDetails vereinigen.
464
465 details += special;
466
467// Details und SpecialDetails auswerten - gar nicht so einfach.
468
469 all_dets = r->Query(P_DETAILS);
470
471 for ( s=({}),i=sizeof(details)-1 ; i>=0 ; i--)
472 s += eval_detail_entry(details[i]);
473
474 for ( s2=({}),i=sizeof(s)-1 ; i>=0 ; i-- )
475 if (stringp(s[i]))
476 if (member(s2,s[i])==-1)
477 {
478 s2 += ({ s[i] });
479 zufinden+=det_auswerten(s[i]);
480 }
481
482// Grossgeschriebene Woerter aus der Langbeschreibung hinzufuegen.
483
484 if (function_exists("int_long",r))
485 zufinden += det_auswerten(
486 old_explode(r->int_long(master,master),"Es gibt ")[0]);
487 else
488 zufinden += det_auswerten(old_explode(r->long(),"enthaelt:")[0]);
489
490// Doppelte Eintraege eliminieren.
491
492 for ( s2=({}), i=sizeof(zufinden)-1 ; i>=0 ; i--)
493 if (member(s2,zufinden[i])==-1)
494 s2 += ({ zufinden[i] });
495
496// Alles klein machen.
497
498 zufinden=map(s2,#'lower_case);
499
500// Bei NPCs/Objekten die IDs rausfiltern.
501
502 if (!room)
503 zufinden -= r->QueryProp(P_IDS);
504
505// Die zu uebergehenden Details rausfiltern.
506
507 zufinden=filter((zufinden-uebergehen),#'stringp);
508
509// Schauen, welche Details fehlen und diese Ausgeben.
510
511 for ( s=({}),s2=({}),i=sizeof(zufinden)-1;i>=0;i--)
512 {
513 if (!(mi=test_details(zufinden[i])))
514 continue;
515 if (pointerp(mi))
516 {
517 for (j=sizeof(mi)-1 ; j>=0 ; j--)
518 if (member(s,mi[j])==-1)
519 s += ({ mi[j] });
520 }
521 else if (stringp(mi) && member(s2,mi)==-1)
522 s2 += ({ mi });
523 }
524
525 s = sort_array(s, #'<);
526 s2 = sort_array(s2,#'<);
527
528 if (scanrun<1)
529 {
530 if ((i=sizeof(s))>0)
531 {
532 for ( s1="",--i ; i>=0 ; i-- )
533 s1 += (s[i]+(i?"\n":""));
534
535 re += sprintf(sprintf("%sListe der gefundenen Details:%s\n\n"+
536 "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
537 sprintf(".%d",spalten))+"s")),s1);
538 }
539 else
540 re += sprintf("%sEs gibt keine Details.%s\n\n",PRE,END);
541 }
542
543 if ((i=sizeof(s2))>0)
544 {
545 for ( s1="",--i ; i>=0 ; i-- )
546 s1 += (s2[i]+(i?"\n":""));
547
548 re += sprintf(sprintf("%sListe der fehlenden Details:%s\n\n"+
549 "%s\n\n",PRE,END,("%-#78"+(spalten<1?"":
550 sprintf(".%d",spalten))+"s")),s1);
551 }
552 else
553 re += sprintf("%sEs fehlen keine Details.%s\n\n",PRE,END);
554
555 if (scanrun<1)
556 re += sprintf("%sFERTIG.%s\n",PRE,END);
557
558// Die eigentliche Textausgabe.
559
560 Output(re);
561
562 return 1;
563}
564
565/***************************************************************************
566**
567** Hauptfunktion fuer das Testen von Geraeuschen und Geruechen.
568**
569****************************************************************************
570*/
571
572int search_sense(object r, int sense)
573{ string re,PRE,END,WAS,*senses,s1,*zufinden,*s2,*s3,def;
574 int i,j;
575 mixed mi;
576
577 if (!r || !objectp(r))
578 {
579 write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
580 return 1;
581 }
582 if (sense==SENSE_SMELL)
583 {
584 all_dets=r->Query(P_SMELLS)||([]);
585 WAS="Gerueche";
586 }
587 else if (sense==SENSE_SOUND)
588 {
589 all_dets=r->Query(P_SOUNDS)||([]);
590 WAS="Geraeusche";
591 }
592 else
593 {
594 write("OTEST-ERROR: Illegaler sense-Wert in search_sense()\n");
595 return 1;
596 }
597
598 re = "\n";
599
600 zufinden = ({SENSE_DEFAULT});
601
602 def = all_dets[SENSE_DEFAULT];
603
604// Terminaltyp des Magiers feststellen.
605
606 if (objectp(output))
607 switch (output->QueryProp(P_TTY))
608 {
609 case "ansi" :
610 case "vt100" : PRE=BOLD; END=NORMAL; break;
611 default : PRE=""; END=""; break;
612 }
613 else
614 {
615 PRE="";
616 END="";
617 }
618
619 senses = sort_array(m_indices(all_dets),#'<);
620
621// Alle vorhandenen Sense-Details anzeigen.
622
623 if (scanrun<1)
624 {
625 if ((i=sizeof(senses))>0)
626 {
627 for ( s1="",--i; i>=0 ; i-- )
628 s1 += ((senses[i]==SENSE_DEFAULT?"DEFAULT":
629 senses[i])+(i?"\n":""));
630
631 re += sprintf(sprintf("%sListe der vorhandenen %s:%s\n\n"+
632 "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
633 sprintf(".%d",spalten))+"s")),s1);
634 }
635 else
636 re += sprintf("%sKeine %s gefunden.%s\n\n",PRE,WAS,END);
637 }
638
639
640// Sense-Details auswerten - geht wie bei Details.
641
642 for ( s2=({}),i=sizeof(senses)-1 ; i>=0 ; i--)
643 s2 += eval_detail_entry(senses[i]);
644
645 for ( s3=({}),i=sizeof(s2)-1 ; i>=0 ; i-- )
646 if (stringp(s2[i]))
647 if (member(s3,s2[i])==-1)
648 {
649 s3 += ({ s2[i] });
650 zufinden+=det_auswerten(s2[i]);
651 }
652
653// Testen, welche Sense-Details fehlen und anzeigen
654
655 for ( s2=({}),s3=({}),i=sizeof(zufinden)-1;i>=0;i--)
656 {
657 if (!(mi=test_details(zufinden[i],def)))
658 continue;
659 if (pointerp(mi))
660 {
661 for (j=sizeof(mi)-1 ; j>=0 ; j--)
662 if (member(s2,mi[j])==-1)
663 s2 += ({ mi[j] });
664 }
665 else if (stringp(mi) && member(s3,mi)==-1)
666 s3 += ({ mi });
667 }
668 s2 = sort_array(s2,#'<);
669 s3 = sort_array(s3,#'<);
670
671 if (scanrun<1)
672 {
673 if ((i=sizeof(s2))>0)
674 {
675 for ( s1="",--i ; i>=0 ; i-- )
676 s1 += ((s2[i]==SENSE_DEFAULT?"DEFAULT":s2[i])+(i?"\n":""));
677
678 re += sprintf(sprintf("%sListe der gefundenen %s:%s\n\n"+
679 "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
680 sprintf(".%d",spalten))+"s")),s1);
681 }
682 else
683 re += sprintf("%sEs gibt keine %s.%s\n\n",PRE,WAS,END);
684 }
685
686 if ((i=sizeof(s3))>0)
687 {
688 for ( s1="",--i ; i>=0 ; i-- )
689 s1 += ((s3[i]==SENSE_DEFAULT?"DEFAULT":s3[i])+(i?"\n":""));
690
691 re += sprintf(sprintf("%sListe der fehlenden %s:%s\n\n"+
692 "%s\n\n",PRE,WAS,END,("%-#78"+(spalten<1?"":
693 sprintf(".%d",spalten))+"s")),s1);
694 }
695 else
696 re += sprintf("%sEs fehlen keine %s.%s\n\n",PRE,WAS,END);
697
698 if (scanrun<1)
699 re += sprintf("%sFERTIG.%s\n",PRE,END);
700
701// Die eigentliche Textausgabe.
702
703 Output(re);
704
705 return 1;
706}
707
708/***************************************************************************
709**
710** Die Funktion, die die Geraeusche im Raum untersucht.
711**
712****************************************************************************
713*/
714
715int search_n(object r)
716{
717 if (!r || !objectp(r))
718 {
719 write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
720 return 1;
721 }
722
723 return search_sense(r,SENSE_SOUND);
724}
725
726/***************************************************************************
727**
728** Die Funktion, die die Gerueche im Raum untersucht.
729**
730****************************************************************************
731*/
732
733int search_m(object r)
734{
735 if (!r || !objectp(r))
736 {
737 write("OTEST-ERROR: Kein (existierendes) Zielobjekt gefunden!\n");
738 return 1;
739 }
740
741 return search_sense(r,SENSE_SMELL);
742}
743
744/***************************************************************************
745**
746** Die Funktion, die das eingegebene Kommando zerlegt und interpretiert.
747**
748****************************************************************************
749*/
750
751int search(string arg)
Zesstra1e4209d2021-04-19 09:27:57 +0200752{ string *arg_array,dum;
MG Mud User88f12472016-06-24 23:31:02 +0200753 object targ;
754 int wo;
755
756 if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
757 return removen();
758
759 if (scanrun)
760 {
761 write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
762 return 1;
763 }
764
765 notify_fail("OTEST-Syntax: otest [detail|smell|sound] "+
766 "{<objekt>[in mir|im raum]|hier}\n");
767
Zesstra1e4209d2021-04-19 09:27:57 +0200768 if (!arg || !stringp(arg) || sizeof(arg_array=old_explode(arg," "))<1)
MG Mud User88f12472016-06-24 23:31:02 +0200769 {
770 output=PL;
771 scanrun=0;
772 master=PL;
773 return search_d(environment(PL));
774 }
775
Zesstra1e4209d2021-04-19 09:27:57 +0200776 if (sizeof(arg_array)>1)
MG Mud User88f12472016-06-24 23:31:02 +0200777 {
Zesstra1e4209d2021-04-19 09:27:57 +0200778 arg=implode(arg_array[1..]," ");
MG Mud User88f12472016-06-24 23:31:02 +0200779 if (member(({"hier","raum",""}),arg)!=-1)
780 targ=environment(PL);
781 else
782 {
783 if (sscanf(arg,"%s in mir",dum))
784 {
785 wo=1;
786 arg=dum;
787 }
788 else if (sscanf(arg,"%s im raum",dum))
789 {
790 wo=-1;
791 arg=dum;
792 }
793 else wo=0;
794 if (wo!=-1)
795 targ=present(arg,PL);
796 if (!objectp(targ) && wo!=1)
797 targ=present(arg,environment(PL));
798 }
799 }
800 else
801 targ=environment(PL);
802 if (!objectp(targ))
803 {
804 write("OTEST-ERROR: Gewuenschtes Ziel nicht gefunden.\n");
805 return 0;
806 }
807
808 output=PL;
809 scanrun=0;
810 master=PL;
811
Zesstra1e4209d2021-04-19 09:27:57 +0200812 switch(arg_array[0])
MG Mud User88f12472016-06-24 23:31:02 +0200813 {
814 case "de" :
815 case "detail" :
816 case "details" :
817 return search_d(targ);
818 case "sm" :
819 case "smell" :
820 case "smells" :
821 return search_m(targ);
822 case "so" :
823 case "sound" :
824 case "sounds" :
825 return search_n(targ);
826 }
827 return 0;
828}
829
830/***************************************************************************
831**
832** Hier kann man den 'Scantyp' einstellen.
833**
834****************************************************************************
835*/
836
837int scanart(string arg)
838{ int h;
839
840 if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
841 return removen();
842
843 if (scanrun)
844 {
845 write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
846 return 1;
847 }
848
849 notify_fail("OTEST-Syntax: otype [rikus|rochus]\n");
850 if (!arg || !stringp(arg))
851 {
852 if (h=PL->QueryProp(P_OTEST_TYP))
853 scantyp=h;
854 if (!h)
855 {
856 PL->SetProp(P_OTEST_TYP,scantyp);
857 PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
858 }
859 printf("OTEST: Eingestellter Scantyp ist '%s'\n",
860 (scantyp==T_ROCHUS?"ROCHUS":"RIKUS"));
861 return 1;
862 }
863 if (member(({"rikus","rochus"}),arg)==-1)
864 return 0;
865 if (arg=="rochus")
866 {
867 scantyp=T_ROCHUS;
868 PL->SetProp(P_OTEST_TYP,scantyp);
869 PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
870 write("OTEST: Eingestellter Scantyp ist 'ROCHUS'\n");
871 return 1;
872 }
873 scantyp=T_RIKUS;
874 PL->SetProp(P_OTEST_TYP,scantyp);
875 PL->Set(P_OTEST_TYP,SAVE,F_MODE_AS);
876 write("OTEST: Eingestellter Scantyp ist 'RIKUS'\n");
877 return 1;
878}
879
880/***************************************************************************
881**
882** Hier kann man die Spaltenzahl einstellen.
883**
884****************************************************************************
885*/
886
887int spaltenzahl(string arg)
888{ int h;
889
890 if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
891 return removen();
892
893 if (scanrun)
894 {
895 write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
896 return 1;
897 }
898
899 notify_fail("OTEST-Syntax: ocolm [1|2|3|4|5|6|7|8|auto]\n");
900
901 if (!arg || !stringp(arg))
902 {
903 if (h=PL->QueryProp(P_OTEST_SPL))
904 spalten=h;
905 if (!h)
906 {
907 PL->SetProp(P_OTEST_SPL,spalten);
908 PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
909 }
910 printf("OTEST: Eingestellte Spaltenzahl ist '%s'\n",
911 (spalten>0?sprintf("%d",spalten):"'AUTO'"));
912 return 1;
913 }
914 if (arg=="auto")
915 {
916 spalten=-1;
917 PL->SetProp(P_OTEST_SPL,spalten);
918 PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
919 write("OTEST: Eingestellte Spaltenzahl ist 'AUTO'\n");
920 return 1;
921 }
922 h = to_int(arg);
923 if (h<1 || h>8)
924 return 0;
925 spalten=h;
926 PL->SetProp(P_OTEST_SPL,spalten);
927 PL->Set(P_OTEST_SPL,SAVE,F_MODE_AS);
928 printf("OTEST: Eingestellte Spaltenzahl ist %d\n",spalten);
929 return 1;
930}
931
932/***************************************************************************
933**
934** Hier kann man ganze Verzeichnisse durchscannen lassen
935**
936****************************************************************************
937*/
938
939int dirtesten(string arg)
940{ string vz,af,u,*dir;
941 int i,si;
942
943 if (!(PL->QueryProp(P_TESTPLAYER)) && !IS_LEARNER(PL))
944 return removen();
945
946 if (scanrun)
947 {
948 write("Derzeit wird ein Verzeichnis gescanned. Bitte warten.\n");
949 return 1;
950 }
951
952 if (object_name(ME)[0..2]=="/p/")
953 {
954 write(break_string("Ein Dirscan kann nur durchgefuehrt werden, "+
955 "wenn man den Pruefer in sein /players/-Verzeichnis kopiert "+
956 "hat oder von einem dort liegenden Objekt inherited.",78,
957 "OTEST: "));
958 return 1;
959 }
960
961 notify_fail("OTEST-Syntax: otdir <verzeichnis> <ausgabefile>\n");
962 if (!arg || !stringp(arg) || sscanf(arg,"%s %s",vz,af)!=2)
963 return 0;
964
965// Zielfilename testen/festlegen.
966
967 u=getuid(PL);
968 if (file_size("/log/"+u+"/")!=-2)
969 {
970 printf("OTEST: Es existiert kein Verzeichnis '/log/%s/'\n",u);
971 return 1;
972 }
973 for (i=sizeof(af)-1;i>=0;i--)
974 if (((si=af[i])<48 && si!=46) || (si>57 && si<65) || si>122 ||
975 (si>90 && si<97))
976 {
977 write("OTEST: Illegaler Filename fuer Ausgabefile.\n");
978 return 1;
979 }
980 u=sprintf("/log/%s/%s",u,af);
981
982// Zu untersuchendes Verzeichnis pruefen/einlesen.
983
984 if (!vz || !stringp(vz) || sizeof(vz)<3 || vz[0]!='/' || vz[<1]!='/')
985 {
986 write("OTEST: Verzeichnisname muss mit '/' beginnen und aufhoeren.\n");
987 return 1;
988 }
989 for (i=sizeof(af)-1;i>=0;i--)
990 if (((si=af[i])<46) || (si>57 && si<65) || si>122 || (si>90 && si<97))
991 {
992 write("OTEST: Illegaler Filename fuer Verzeichnis.\n");
993 return 1;
994 }
995 dir = get_dir(vz+"*.c");
996 if ((si=sizeof(dir))<1)
997 {
998 write("OTEST: Das gewuenschte Verzeichnis existiert nicht oder ist "+
999 "leer.\n");
1000 return 1;
1001 }
1002
1003 output = u;
1004
1005 if (stringp(catch
1006 (i=write_file(output, sprintf("Teststart: %s\n\n",dtime(time())))))
1007 && i!=1)
1008 {
1009 write(break_string(
1010 sprintf("Fehler beim Schreiben in das File %s:\n%sAborting.",
1011 output,u),78,"OTEST: ",1));
1012 output = 0;
1013 return 1;
1014 }
1015
1016 scanrun = si+1;
1017 scanfiles = dir;
1018 scandir = vz;
1019 scancount = 0;
1020 master = PL;
1021 scanerr = ({0,0});
1022
1023 call_out("x_heart_beat",T_PAUSE);
1024
1025 printf("OTEST: Scanne %d Files:\n"+
1026 " %s => %s\n"+
1027 "Zeit: etwa %s\n",si,vz,output,
1028 time2string("%h:%02m:%02s",si*4*T_PAUSE));
1029
1030 return 1;
1031}
1032
1033/***************************************************************************
1034**
1035** Das Scannen von Verzeichnissen wird ueber x_heart_beat() erledigt.
1036**
1037****************************************************************************
1038*/
1039
1040void x_heart_beat()
1041{ int nr;
1042 string fn,er;
1043
1044 call_out("x_heart_beat",T_PAUSE);
1045
1046 if ((++scancount)>4)
1047 {
1048 scancount = 1;
1049 testob = 0;
1050 scanrun--;
1051 }
1052
1053 nr=scanrun-2;
1054 if (nr<0)
1055 {
1056 if (environment() && interactive(environment()))
1057 environment()->Message(break_string("'otdir' beendet.\n"+
1058 sprintf("Files: %d - Fehler: %d - Skips: %d",
1059 sizeof(scanfiles),scanerr[0],scanerr[1]),
1060 78,"OTEST: ",1),MSGFLAG_TELL);
1061
1062 scanrun = 0;
1063 scancount = 0;
1064 output = 0;
1065 scanfiles = ({});
1066 scandir = 0;
1067 testob = 0;
1068 scanerr = ({0,0});
1069
1070 while(remove_call_out("x_heart_beat")!=-1);
1071
1072 return;
1073 }
1074 fn=scandir+scanfiles[nr];
1075 if (fn[<2..]==".c")
1076 fn=fn[0..<3];
1077
1078 if (scancount==1) // Testen, ob File ladbar
1079 {
1080 Output(sprintf("File: %s\n\n",fn));
1081 er=catch(call_other(fn,"???"));
1082 if (er && stringp(er))
1083 {
1084 Output(sprintf("Error: %s->Abort@Load\n\n",er));
1085 scanrun--;
1086 scancount = 0;
1087 testob = 0;
1088 scanerr[0] = scanerr[0]+1;
1089 }
1090 else
1091 testob = find_object(fn);
1092 return;
1093 }
1094 if (!objectp(testob))
1095 {
1096 Output("Objekt nicht gefunden\n-> Abort@Object.\n\n");
1097 scanrun--;
1098 scancount = 0;
1099 scanerr[0] = scanerr[0]+1;
1100 return;
1101 }
1102 if (!function_exists("int_long",testob))
1103 {
1104 Output("Objekt ist kein Raum -> SKIPPING.\n\n");
1105 scanrun--;
1106 scancount = 0;
1107 testob = 0;
1108 scanerr[1] = scanerr[1]+1;
1109 return;
1110 }
1111 switch(scancount)
1112 {
1113 case 2 :
1114 if ((er=catch(search_d(testob))) && stringp(er))
1115 {
1116 Output(sprintf("Error: %s-> Abort@Detail.\n\n",er));
1117 scanrun--;
1118 scancount = 0;
1119 testob = 0;
1120 scanerr[0] = scanerr[0]+1;
1121 }
1122 return;
1123 case 3 :
1124 if ((er=catch(search_sense(testob,SENSE_SMELL))) && stringp(er))
1125 {
1126 Output(sprintf("Error: %s-> Abort@Smell.\n\n",er));
1127 scanrun--;
1128 scancount = 0;
1129 testob = 0;
1130 scanerr[0] = scanerr[0]+1;
1131 }
1132 return;
1133 case 4 :
1134 if ((er=catch(search_sense(testob,SENSE_SOUND))) && stringp(er))
1135 {
1136 Output(sprintf("Error: %s-> Abort@Sound.\n\n",er));
1137 scanrun--;
1138 scancount = 0;
1139 testob = 0;
1140 scanerr[0] = scanerr[0]+1;
1141 }
1142 return;
1143 }
1144 return;
1145}