Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/obj/tools/MGtool.c b/obj/tools/MGtool.c
new file mode 100644
index 0000000..727f34f
--- /dev/null
+++ b/obj/tools/MGtool.c
@@ -0,0 +1,1823 @@
+/*
+ * MGtool-1.3
+ * File: MGtool.c
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#pragma strict_types
+
+inherit "/std/thing/properties";
+
+#include <properties.h>
+#if !defined(QUERYCACHED)
+#define QUERYCACHED 4096
+#endif
+#if !defined (SETCACHED)
+#define SETCACHED 4096
+#endif
+#include <moving.h>
+#include "/secure/wizlevels.h"
+#include "/secure/config.h"
+#include <userinfo.h>
+#include <defines.h>
+
+#include "MGtool/tool.h"
+
+#include "MGtool/toollib.h"
+
+#define XDBG 1
+
+nosave object cloner;
+nosave object msgto=NULL;
+nosave string *manpath=({TOOL_PATH+"/man.d/",
+ "/doc/efun/",
+ "/doc/lfun/",
+ "/doc/w/",
+ "/doc/helpdir/",
+ "/doc/LPC/",
+ "/doc/std/",
+ "/doc/concepts/",
+ ""});
+nosave string morefile=NULL;
+nosave string *scriptline=NULL;
+nosave string *history=allocate(MAX_HISTORY);
+nosave int moreflag=FALSE;
+nosave int moreoffset=1;
+nosave int term=NULL;
+nosave int scriptsize=NULL;
+nosave int nostore=FALSE;
+nosave int xlight=0;
+nosave int pipe_in=FALSE;
+nosave int pipe_out=FALSE;
+nosave int pipe_ovr=TRUE;
+nosave string pipe_if=NULL;
+nosave string pipe_of=NULL;
+nosave int xtk=FALSE;
+nosave mapping variable=([]);
+nosave string *cmds;
+private nosave mapping line_buffer=([]);
+private nosave string line_buffer_name="";
+private nosave string more_searchexpr="";
+int morelines=MORE_LINES;
+int modi=(MODE_FIRST|MODE_PROTECT|MODE_SHORT);
+
+#include "MGtool/toollib.c"
+#include "MGtool/toolcmd.c"
+
+#define SafeReturn(x) \
+{ \
+ cmds=({}); \
+ pipe_in=FALSE; \
+ pipe_of=NULL; \
+ pipe_ovr=TRUE; \
+ pipe_out=FALSE; \
+ pipe_of=NULL; \
+ return (x); \
+}
+
+/*----------------------------------------------------------------------
+ * check some security aspects
+ */
+
+static int security()
+{
+ object prev;
+
+ if( process_call() || getuid()!=getuid(cloner) ) return FALSE; // Rumata
+
+ TK("UID: "+getuid(ME)+" cloner:"+getuid(cloner));
+// TK("prev: "+object_name(PREV)+" me:"+object_name(ME));
+ if(prev=PREV)
+ {
+ if(!cloner)
+ return TRUE;
+ if(getuid(prev)==ROOTID||IS_ARCH(prev))
+ return TRUE;
+ if(prev==ME)
+ return TRUE;
+ return secure_level()>=query_wiz_level(cloner); // Rumata
+ //return getuid(prev)==getuid()&&geteuid(prev)==geteuid()&&cloner==RTP;
+ }
+ else
+ return cloner==NULL;
+}
+
+/*----------------------------------------------------------------------
+ * own write function
+ */
+
+static int Write(string str)
+{
+ if(!stringp(str) || str=="")
+ return FALSE;
+ if(!cloner && objectp(this_player()))
+ write(str);
+ else
+ tell_object(cloner, str);
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------
+ * own command function
+ */
+
+static int Command(string str)
+{
+ int i;
+ TK("Command: str: "+(str?str:"(NULL)"));
+ nostore++;
+ if(MODE(MODE_ECHO))
+ WLN("Doing: "+str);
+ i=(int)cloner->command_me(str);
+ nostore--;
+ return i;
+}
+
+/*----------------------------------------------------------------------
+ * object searching
+ */
+
+static varargs object XFindObj(string str, int silent)
+{
+ object obj, env;
+ string *strs;
+ int i, s, cnt;
+
+ if(!str)
+ return NULL;
+ TK("XFindObj: str: "+(str?str:"(NULL)"));
+ env=ENV(cloner);
+ str=string_replace(str, "\\.","°01");
+ str=string_replace(str, "\\^", "°02");
+ str=string_replace(str, "\\$", "°03");
+ str=string_replace(str, "\\\\", "\\");
+ if (find_object(str)) return find_object(str);
+ if (file_size(str)>1) {
+ call_other(str, "???");
+ return find_object(str);
+ }
+ s=sizeof(strs=strip_explode(str, "."));
+ while(s--)
+ {
+ if(strs[i]=="m"||strs[i]=="me")
+ strs[i]=RNAME(cloner);
+ else if(strs[i]=="h"||strs[i]=="here")
+ strs[i]=object_name(ENV(cloner));
+ if(obj=FindObj(strs[i++],env,(silent?1:0)))
+ env=obj;
+ else
+ break;
+ }
+ return obj;
+}
+
+static varargs object FindObj(string str, object env, int silent)
+{
+ object obj, *inv;
+ string tmp;
+ int num, e;
+
+ if (!stringp(str) || !sizeof(str) || !objectp(env))
+ return NULL;
+ str=string_replace(str, "°01", ".");
+ while(str[e++]=='^')
+ ;
+ str=str[--e..<1];
+ str=string_replace(str, "°02", "^");
+ if(obj=VarToObj(str))
+ ;
+ else if(str[0]=='')
+ str=string_replace(str, "°03", "$");
+ else if(sscanf(str, "%d", num)&&(inv=all_inventory(env)))
+ {
+ if(num>0&&num<=sizeof(inv))
+ obj=inv[num-1];
+ else
+ {
+ WDLN("Specified object number out of range [1-"+sizeof(inv)+"]");
+ return NULL;
+ }
+ }
+ if(obj||(obj=present(str, env))||
+ (obj=find_player(LOWER(str)))||
+ (obj=find_living(str))||
+ (obj=find_object(long_path(str))))
+ {
+ while(e--)
+ {
+ if(!(obj=ENV(obj)))
+ {
+ W("Specified object has no environment [");
+ while(e--)
+ W("^");
+ WDLN(str+"]");
+ return NULL;
+ }
+ }
+ }
+ else
+ if(!silent)
+ WDLN("Specified object does not exist ["+str+"]");
+ return obj;
+}
+
+/*----------------------------------------------------------------------
+ * object variable handling
+ */
+
+static object VarToObj(string str)
+{
+ if (!stringp(str) || !sizeof(str) || str[0]!='$')
+ return NULL;
+ switch(str)
+ {
+ case "$m":
+ case "$me":
+ return cloner;
+ case "$h":
+ case "$here":
+ return ENV(cloner);
+ default:
+ return variable[str[1..<1]];
+ }
+ return(NULL); //never reached
+}
+
+static string VarToFile(string str)
+{
+ return source_file_name(VarToObj(str));
+}
+
+static string VarToPureFile(string str)
+{
+ return pure_file_name(VarToObj(str));
+}
+
+/*----------------------------------------------------------------------
+ * object description printing
+ */
+
+static void PrintObj(object obj, string file)
+{
+ object item, tmp;
+ string str;
+ int i;
+
+ SECURE1();
+ if(!obj)
+ return;
+ PrintShort("Short: ", obj, file);
+ if(!file||file=="")
+ WLN("Long :");
+ else
+ write_file(file,"Long :\n");
+ if(query_once_interactive(obj))
+ str=capitalize(getuid(obj));
+ else
+ {
+ if(object_name(obj)[0..26]=="/d/unterwelt/objekte/teddy#" &&
+ IS_ARCH(this_interactive()))
+ str="Ein Teddy (stumm)";
+ else
+ {
+ if(str=(string)obj->QueryProp(P_INT_LONG))
+ ;
+ else if(str=(string)obj->QueryProp(P_LONG))
+ ;
+ else
+ str="- no long description -\n";
+ }
+ }
+ if(!file||file=="")
+ W(str);
+ else
+ write_file(file,str);
+ FORALL(item, obj)
+ {
+ if(!i)
+ if(!file||file=="")
+ WLN("Content:");
+ else
+ write_file(file,"Content:\n");
+ PrintShort(ARIGHT(++i+". ", 4, " "), item, file);
+ }
+}
+
+static string ObjFile(object obj)
+{
+ return "["+short_path(object_name(obj))+"]";
+}
+
+static varargs void PrintShort(string pre, object obj, string file)
+{
+ string str;
+
+ SECURE1();
+ if(!obj)
+ return;
+ if(MODE(MODE_SHORT))
+ {
+ if (query_once_interactive(obj))
+ str=capitalize(getuid(obj));
+ else
+ {
+ if(!((str=(string)obj->QueryProp(P_INT_SHORT))||
+ (str=(string)obj->QueryProp(P_SHORT))))
+ if(is_player(obj))
+ str=CRNAME(obj)+" (invisible)";
+ else
+ str="- no short description -";
+ }
+ str=ALEFT(sprintf("%O ",str), 34, ".")+" ";
+ }
+ else
+ str="";
+ if(interactive(obj))
+ str+="i";
+ else if(living(obj))
+ str+="l";
+ else
+ str+=".";
+ str+=(shadow(obj, 0) ? "s" : ".");
+ if(!file||file=="")
+ WLN((pre+CAP(str)+" "+ObjFile(obj))[0..79]);
+ else
+ write_file(file,(pre+CAP(str)+" "+ObjFile(obj))[0..79]+"\n");
+}
+
+static varargs void DeepPrintShort(object env, int indent, string pre, string file)
+{
+ int i;
+ object item;
+ string str;
+
+ SECURE1();
+ if(!env)
+ return;
+ for(i=indent,str=""; i--; str+=" ");
+ if(pre)
+ str+=pre;
+ if(!file||file=="")
+ W(str);
+ else
+ write_file(file,str);
+ i++;
+ PrintShort("",env,file);
+ FORALL(item, env)
+ DeepPrintShort(item,indent+1,ARIGHT((++i)+". ",4," "),file);
+}
+
+static string break_string_hard(string str, int len, string pre)
+{
+ int s,p,t;
+ string tmp;
+
+ if(!str||!(s=sizeof(str)))
+ return "";
+ t=len-(p=sizeof(pre))-1;
+
+ tmp="";
+ while(p+s>len)
+ {
+ tmp+=pre+str[0..t]+"\n";
+ str=str[t+1..];
+ s-=t;
+ }
+ if(sizeof(str))
+ tmp+=pre+str[0..]+"\n";
+ return tmp;
+}
+
+static void dprop(string key, mixed data, object obj)
+{
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,break_string_hard(mixed_to_string(obj->QueryProp(key),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
+ else
+ W(break_string_hard(mixed_to_string(obj->QueryProp(key),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
+}
+
+static string propflags(string key, object ob)
+{
+ int tmp;
+ string *flags;
+ tmp=(int)ob->Query(key,1);
+ flags=({});
+ tmp&SAVE ? flags+=({"SAV"}) : flags+=({" "});
+ tmp&PROTECTED ? flags+=({"PRO"}) : flags+=({" "});
+ tmp&SECURED ? flags+=({"SEC"}) : flags+=({" "});
+ tmp&NOSETMETHOD ? flags+=({"NSM"}) : flags+=({" "});
+ tmp&SETMNOTFOUND ? flags+=({"SMN"}) : flags+=({" "});
+ tmp&QUERYMNOTFOUND ? flags+=({"QMN"}) : flags+=({" "});
+ tmp&QUERYCACHED ? flags+=({"QCA"}) : flags+=({" "});
+ tmp&SETCACHED ? flags+=({"SCA"}) : flags+=({" "});
+ return ""+implode(flags,"|");
+}
+
+static void dprop2(string key, mixed data, object ob)
+{
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,break_string_hard(mixed_to_string(propflags(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
+ else
+ W(break_string_hard(mixed_to_string(propflags(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
+}
+
+static mixed propmethods(string key, object ob)
+{
+ return (mixed)ob->Query(key,2);
+}
+
+static void dprop3(string key, mixed data, object ob)
+{
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,break_string_hard(mixed_to_string(propmethods(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
+ else
+ W(break_string_hard(mixed_to_string(propmethods(key,ob),MAX_RECURSION),78,ALEFT(key+" ",18,".")+" = "));
+}
+
+static void DumpProperties(object obj, int flag)
+{
+ SECURE1();
+ if(!obj)
+ return;
+ PIPE_DELETE(pipe_of);
+ switch (flag) {
+ case 0:
+ walk_mapping(((mapping *)(obj->__query_properties()))[0],#'dprop,obj); //')
+ break;
+ case 1:
+ walk_mapping(((mapping *)(obj->__query_properties()))[0],#'dprop2,obj); //')
+ break;
+ case 2:
+ walk_mapping(((mapping *)(obj->__query_properties()))[0],#'dprop3,obj); //')
+ break;
+ }
+}
+
+/*----------------------------------------------------------------------
+ * moving objects
+ */
+
+static int MoveObj(object obj1, object obj2, int silent)
+{
+ int err;
+ object oldenv;
+
+ SECURE2(FALSE);
+ if(!(obj1&&obj2))
+ return FALSE;
+ oldenv=ENV(obj1);
+ err=(int)obj1->move(obj2, M_SILENT|M_NOCHECK);
+ if(!silent)
+ switch(err)
+ {
+ case ME_PLAYER:
+ WDLN("Object returned ME_PLAYER");
+ if(oldenv && oldenv != ENV(obj1))
+ WDLN("Object has been moved");
+ return FALSE;
+ case ME_TOO_HEAVY:
+ WDLN("Object returned ME_TOO_HEAVY");
+ if(oldenv && oldenv != ENV(obj1))
+ WDLN("Object has been moved");
+ return FALSE;
+ case ME_CANT_TPORT_IN:
+ WDLN("Object returned ME_CANT_TPORT_IN");
+ if(oldenv && oldenv != ENV(obj1))
+ WDLN("Object has been moved");
+ return FALSE;
+ case ME_CANT_TPORT_OUT:
+ WDLN("Object returned ME_CANT_TPORT_OUT");
+ if(oldenv && oldenv != ENV(obj1))
+ WDLN("Object has been moved");
+ return FALSE;
+ default:
+ WDLN("Object returned unknown return value");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------
+ * save destructing of objects
+ */
+
+static void Destruct(object obj)
+{
+ if(!obj || !this_object())
+ return;
+ catch(obj->remove());
+ if(objectp(obj) && !query_once_interactive(obj))
+ destruct(obj);
+}
+
+static void DeepClean(object obj)
+{
+ if(!obj)
+ return;
+ filter(filter(deep_inventory(obj), "is_not_player", ME),
+ "Destruct", ME);
+ if(is_not_player(obj))
+ Destruct(obj);
+}
+
+/*----------------------------------------------------------------------
+ * Show the inheritance tree of objects
+ */
+
+static object *SubNodes(object obj)
+{
+ int s;
+ object *objs;
+ string *inlist;
+
+ if(!obj)
+ return NULL;
+ inlist=inherit_list(obj);
+ s=sizeof(inlist);
+ objs=({});
+ while(s-->1)
+ objs=({find_object(inlist[s])})+objs;
+ return objs;
+}
+
+static void Inheritance(object obj, string func, string pre)
+{
+ int i, s;
+ object *ln;
+ string str;
+
+ if(!obj)
+ return;
+ str=pre+" "+ObjFile(obj);
+ if(func)
+ {
+ str=ALEFT(str+" ", 50, ".");
+ if(function_exists(func, obj)==object_name(obj))
+ str+=ARIGHT(" "+func, 19, ".");
+ else
+ str+=ARIGHT("", 19, ".");
+ }
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,str+"\n");
+ else
+ WLN(str);
+ ln=SubNodes(obj);
+ for(i=0; i<sizeof(ln); i++)
+ ln=ln-SubNodes(ln[i]);
+ s=sizeof(ln);
+ for(i=0; i<s; i++)
+ Inheritance(ln[i], func, pre+".....");
+}
+
+/*----------------------------------------------------------------------
+ * file name handling
+ */
+
+static string XFile(string file)
+{
+ TK("XFile: file: "+(file?file:"(NULL)"));
+ if(file)
+ switch(file[0])
+ {
+ case '@':
+ return source_file_name(XFindObj(file[1..<1]));
+ case '$':
+ return source_file_name(XFindObj(file));
+ default:
+ return old_explode(long_path(file),"#")[0];
+ }
+ return NULL;
+}
+
+static string XFindFile(string file)
+{
+ TK("XFindFile: file: "+(file?file:"(NULL)"));
+ if(file=XFile(file))
+ {
+ if(file_size(file)>=0)
+ return file;
+ if(file[<3..<1]!=".c" && file_size(file+".c")>0)
+ return file+".c";
+ }
+ WDLN("File not found or not readable ["+short_path(file)+"]");
+ return NULL;
+}
+
+/*----------------------------------------------------------------------
+ * file printing, searching and executing
+ */
+
+static void XMoreFile(string file, int flag)
+{
+ int s,size;
+
+ SECURE1();
+ if(!file)
+ return;
+
+ // term=(string)cloner->QueryProp(P_TTY)!="dumb";
+ if((size=(file_size(morefile=long_path(file))))>0)
+ {
+ if(size>100000)
+ WDLN("Warning: large file");
+ MoreFile(NULL);
+ }
+ else if(flag)
+ WDLN("Cannot read file");
+}
+
+/*
+static string read_buffer(string filename, int start, int number)
+{
+ mixed tmp;
+ string result;
+ int current;
+
+ if(!filename||filename=="")
+ return "";
+ if(number<=1)
+ number=1;
+ number--;
+ result="";
+ if(filename!=line_buffer_name)
+ {
+ // TK("read_buffer: initializing");
+ line_buffer=([]);
+ line_buffer_name=filename;
+ current=0;
+ }
+ else
+ current=start;
+
+ while(current<=start+number && stringp((tmp=load_buffer(current++))))
+ if(current>=start)
+ result+=tmp;
+ return result;
+}
+
+static string load_buffer(int line)
+{
+ int i, current, start, length, *idx;
+
+ if(intp(line_buffer[line]))
+ {
+ // TK("load_buffer: Notfound: "+line);
+ current=line;
+ while(current>0&&intp(line_buffer[--current]));
+ for(i=current;i<=line;i++)
+ {
+ // TK("load_buffer: trying: "+i);
+ if(i>0)
+ idx=line_buffer[i-1];
+ else
+ idx=({0,0});
+ length=read_line((start=idx[0]+idx[1]));
+ // TK("load_buffer: "+start+"/"+length);
+ line_buffer[i]=({start,length});
+ }
+ }
+ idx=line_buffer[line];
+ return
+ read_bytes(line_buffer_name,idx[0],idx[1]);
+}
+
+static int read_line(int offset)
+{
+ mixed loc_buf;
+ int length, pos;
+
+ // TK("read_line: "+offset);
+ length=0;
+ while(!intp((loc_buf=read_bytes(line_buffer_name,offset+length,1024))))
+ {
+ if((pos=member(loc_buf,'\n'))>=0)
+ return length+pos+1;
+ length+=1024;
+ }
+ return length;
+}
+*/
+
+static void MoreFile(string str)
+{
+ int i, off;
+ string f, l, r;
+
+ SECURE1();
+
+ if (str /*&& sizeof(str)*/)
+ {
+ if( !sizeof(str) ) str="\0";
+ if(term)
+ W("M[1M");
+ switch(str[0])
+ {
+ case 'q':
+ case 'x':
+ moreflag=FALSE;
+ moreoffset=1;
+ if(morefile==TMP_FILE||morefile==PIPE_FILE)
+ rm(morefile);
+ return NULL;
+ break;
+ case 'P':
+ case 'U':
+ moreflag=FALSE;
+ moreoffset=moreoffset-morelines;
+ case 'p':
+ case 'u':
+ moreoffset=moreoffset-2*morelines;
+ break;
+ case 'D':
+ case 'N':
+ moreoffset+=morelines;
+ case 0: /* RETURN */
+ case 'd':
+ if(moreflag)
+ {
+ moreflag=FALSE;
+ moreoffset=1;
+ if(morefile==TMP_FILE)
+ rm(morefile);
+ return;
+ }
+ break;
+ case '/':
+ moreoffset--;
+ more_searchexpr=str[1..<1];
+ case 'n':
+ i=moreoffset-morelines+1;
+ if(more_searchexpr=="")
+ {
+ WDLN("No previous regular expression");
+ return;
+ }
+ if(!regexp(({"dummy"}), more_searchexpr))
+ WDLN("Bad regular expression");
+ else
+ while((l=read_file(morefile, i++, 1))&&
+ !sizeof(regexp(({l}), more_searchexpr)))
+ ;
+ if(l)
+ {
+ WLN("*** Skipping ...");
+ moreoffset=i-1;
+ }
+ else
+ {
+ WLN("*** Pattern not found");
+ moreoffset-=morelines;
+ }
+ break;
+ case '0'..'9':
+ sscanf(str, "%d", i);
+ moreoffset=i;
+ break;
+ }
+ }
+ else
+ {
+ moreoffset=1;
+ moreflag=FALSE;
+ }
+ if(moreoffset<1)
+ moreoffset=1;
+ if(CatFile())
+ W("*** More: q,u,U,d,D,/<regexp>,<line> ["+(moreoffset-1)+"] *** ");
+ else
+ {
+ W("*** More: q,u,U,d,D,/<regexp>,<line> ["+(moreoffset-1)+"=EOF] *** ");
+ moreflag=TRUE;
+ }
+ input_to("MoreFile");
+ return;
+}
+
+// Schade eigentlich das ich es neuschreiben musste, aber es ist
+// schneller neu geschrieben als durch die undokumentieren alten Funktionen
+// durchzusteigen... *seufz*
+// Padreic
+
+static string last_file, *last_file_buffer;
+static int last_file_date, last_file_size, last_file_complete;
+
+static string sread_line(int num)
+{
+ if (!morefile) return "";
+ if (last_file!=morefile || last_file_date!=file_time(morefile)) {
+ if (!(last_file=read_bytes(morefile, 0, 50000))) return "";
+ last_file_date=file_time(morefile);
+ last_file_buffer=explode(last_file, "\n");
+ last_file_size=sizeof(last_file_buffer);
+ if (sizeof(last_file)==50000 && last_file[<1]!='\n') {
+ last_file_size--; // letzte Zeile nicht vollstaendig gelesen
+ last_file_complete=0;
+ }
+ else if (file_size(morefile)>50000)
+ last_file_complete=0;
+ else last_file_complete=1;
+ last_file=morefile;
+ }
+ if (num==0) num=1;
+ // bei zu grossen Files nicht mehr alles buffern...
+ if (num>last_file_size) {
+ if (last_file_complete) return "";
+ return (read_file(morefile, num, 1) || "");
+ }
+ return last_file_buffer[num-1]+"\n";
+}
+
+static int CatFile()
+{
+ int end;
+ string l;
+
+ end=moreoffset+morelines;
+ while(moreoffset<end)
+// if((l=read_file(morefile, moreoffset, 1))!="")
+ if((l=sread_line(moreoffset))!="")
+ {
+ moreoffset++;
+ W(l);
+ }
+ else
+ return FALSE;
+// if(read_file(morefile, moreoffset+1, 1)!="")
+ if(sread_line(moreoffset+1)!="")
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static int XGrepFile(string pat, string file, int mode)
+{
+ int i, j, f, s, fsize;
+ string tfile, *tmp, *ts, t;
+
+ SECURE2(FALSE);
+ TK("XGrepFile: pat: "+pat+" file: "+file+" mode: "+mode);
+ if(!(pat&&file))
+ return FALSE;
+ tfile=TMP_FILE;
+ fsize=file_size(file);
+ for(i=0,f=0; i<fsize && t=read_bytes(file, i, 50000); i+=50000)
+ tmp=strip_explode(t,"\n");
+ if (t && t[<1]!='\n' && sizeof(t)==50000) {
+ i-=sizeof(tmp[<1]);
+ tmp=tmp[0..<2];
+ }
+ if(s=sizeof(tmp))
+ {
+ for(j=0;j<s;j++)
+ {
+ if(sizeof(ts=regexp(({(mode&XGREP_ICASE?lower_case(tmp[j]):tmp[j])}),pat)))
+ {
+ if(!(mode&XGREP_REVERT))
+ {
+ if(!f++)
+ write_file(tfile, "*** File: "+file+" ***\n");
+ write_file(tfile, tmp[j]+"\n");
+ }
+ }
+ else if(mode&XGREP_REVERT)
+ {
+ if(!f++)
+ write_file(tfile, "*** File: "+file+" ***\n");
+ write_file(tfile, tmp[j]+"\n");
+ }
+ }
+ }
+ return TRUE;
+}
+
+static void XExecFile(int line)
+{
+ int i;
+
+ if(!scriptline)
+ return;
+ for(i=line; i<scriptsize&&i<line+EXEC_LINES; i++)
+ {
+ if(!scriptline[i])
+ continue;
+ if(!Command(scriptline[i]))
+ {
+ scriptline=NULL;
+ return;
+ }
+ }
+ if(i<scriptsize)
+ call_out("XExecFile", EXEC_TIME, i);
+ else
+ scriptline=NULL;
+}
+
+static void XmtpScript(string dir, string file, string opt)
+{
+ int s, t;
+ string *files;
+
+ s=sizeof(files=get_dir(dir+"/*"));
+ while(s--)
+ {
+ t=sizeof(files[s])-1;
+ if(files[s] == ".." || files[s] == "." || files[s][t] == '~' ||
+ (files[s][0] == '#' && files[s][t] == '#'))
+ continue;
+ if(file_size(dir+"/"+files[s])==-2)
+ {
+ write_file(file, "mkdir "+files[s]+" ; cd "+files[s]+"\n");
+ XmtpScript(dir+"/"+files[s], file, opt);
+ write_file(file, "cd ..\n");
+ }
+ else
+ write_file(file, "mtp -r "+opt+" "+dir+"/"+files[s]+"\n");
+ }
+}
+
+/*----------------------------------------------------------------------
+ * player properties handling
+ */
+
+static string PlayerIdle(object obj)
+{
+ string str;
+ int i, tmp;
+
+ if(!obj)
+ return NULL;
+ if((i=query_idle(obj))>=60)
+ {
+ str=ARIGHT(""+(i/3600), 2, "0");
+ i-=(i/3600)*3600;
+ str+="'"+ARIGHT(""+(i/60), 2, "0");
+ }
+ else
+ str=".....";
+ return str;
+}
+
+static string PlayerAge(object obj)
+{
+ string str;
+ int i, tmp;
+
+ if(!obj)
+ return NULL;
+ i=(int)obj->QueryProp(P_AGE);
+ str=" "+ARIGHT(""+(i/43200), 4, ".");
+ i-=(i/43200)*43200;
+ return str+":"+ARIGHT(""+(i/1800), 2, "0");
+}
+
+static string crname(object who)
+{
+ string uid, lname;
+
+ if((uid=getuid(who))==ROOTID &&
+ object_name(who)[0..7]=="/secure/" &&
+ (lname=(string)who->loginname()))
+ return CAP(lname);
+ return CAP(uid);
+}
+
+static string PlayerWho(object obj)
+{
+ object tmp;
+ string str, stmp;
+ str=ARIGHT(""+LEVEL(obj) , 3, " ");
+ str+=ALEFT(" "+crname(obj)+" ", 12, ".");
+ str+=PlayerAge(obj);
+ str+=((int)obj->QueryProp(P_GENDER)==1 ? " m " : " f ");
+ str+=(obj->QueryProp(P_FROG)) ? "f" : ".";
+ str+=(obj->QueryProp(P_GHOST)) ? "g" : ".";
+ str+=(obj->QueryProp(P_INVIS)) ? "i" : ".";
+ str+=(query_editing(obj)||query_input_pending(obj) ? "e" : ".");
+ str+=(obj->QueryProp(P_AWAY)) ? "a" : ".";
+ str+=" "+PlayerIdle(obj)+" ";
+ str+=(tmp=ENV(obj)) ? ObjFile(tmp) : "- fabric of space -";
+ return str;
+}
+
+static string PlayerMail(object obj, int flag)
+{
+ string pre;
+
+ pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
+ return pre+"mail: "+obj->QueryProp(P_MAILADDR);
+}
+
+static string PlayerIP(object obj, int flag)
+{
+ string pre;
+
+ pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
+ return pre+"host: "+query_ip_name(obj)+" ("+query_ip_number(obj)+")";
+}
+
+static string PlayerRace(object obj, int flag)
+{
+ string tmp, pre;
+
+ pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
+ pre=pre+"race: "+ALEFT(obj->QueryProp(P_RACE)+" ", 10, ".")+" guild: ";
+ tmp=(string)obj->QueryProp(P_GUILD);
+ return tmp ? pre+tmp : pre+"- none -";
+}
+
+static string PlayerDomain(object obj, int flag)
+{
+ int i, s;
+ mixed *uinfo;
+ string *domains, pre;
+
+ pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
+ pre+="domainlord of: ";
+ uinfo=(mixed*)MASTER->get_userinfo(getuid(obj));
+ if(uinfo&&(domains=uinfo[3])&&(s=sizeof(domains)))
+ {
+ for(i=0; i<s; i++)
+ {
+ pre += CAP(domains[i]);
+ if(i<s-1)
+ pre += ", ";
+ }
+ }
+ return pre;
+}
+
+static string PlayerStats(object obj, int flag)
+{
+ string pre;
+
+ pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
+ pre+="hp="+ARIGHT(obj->QueryProp(P_HP), 3, "0");
+ pre+="/"+ARIGHT(obj->QueryProp(P_MAX_HP), 3, "0");
+ pre+=" sp="+ARIGHT(obj->QueryProp(P_SP), 3, "0");
+ pre+="/"+ARIGHT(obj->QueryProp(P_MAX_SP), 3, "0");
+ pre+=" food="+ARIGHT(obj->QueryProp(P_FOOD), 3, "0");
+ pre+="/"+ARIGHT(obj->QueryProp(P_MAX_FOOD), 3, "0");
+ pre+=" drink="+ARIGHT(obj->QueryProp(P_DRINK), 3, "0");
+ pre+="/"+ARIGHT(obj->QueryProp(P_MAX_DRINK), 3, "0");
+ pre+=" exps="+obj->QueryProp(P_XP);
+ return pre;
+}
+
+static string PlayerSnoop(object obj, int flag)
+{
+ string tmp, pre;
+ object victim;
+
+ pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
+ pre=pre+"is snooped by: ";
+ if(victim=query_snoop(obj))
+ pre+=ARIGHT(" "+crname(victim), 12, ".");
+ else
+ pre+="............";
+ return pre;
+}
+
+static string PlayerCmdAvg(object obj, int flag)
+{
+ string pre;
+
+ pre=(flag) ? ALEFT(crname(obj)+" ", 12, ".")+" " : "";
+ return pre+"cmdavg: "+(int)obj->_query_command_average();
+}
+
+
+/*----------------------------------------------------------------------
+ * msg input to objects
+ */
+
+static void XMsgSay(string str)
+{
+ if(str=="."||str=="**")
+ {
+ WLN("[End of message]");
+ say("[End of message]\n");
+ }
+ else
+ {
+ say(str+"\n");
+ input_to("XMsgSay");
+ }
+}
+
+static void XMsgTell(string str)
+{
+ if(str=="."||str=="**")
+ {
+ WLN("[End of message]");
+ tell_object(msgto, "[End of message]\n");
+ }
+ else
+ {
+ tell_object(msgto, str+"\n");
+ input_to("XMsgTell");
+ }
+}
+
+static void XMsgShout(string str)
+{
+ if(str=="."||str=="**")
+ {
+ WLN("[End of message]");
+ shout("[End of message]\n");
+ }
+ else
+ {
+ shout(str+"\n");
+ input_to("XMsgShout");
+ }
+}
+
+/*----------------------------------------------------------------------
+ * own object moving
+ */
+
+int move(mixed dest)
+{
+ move_object(ME, cloner?cloner:dest);
+ return TRUE;
+}
+
+/*----------------------------------------------------------------------
+ * object id
+ */
+
+int id(string str)
+{
+ if(!security()&&MODE(MODE_SCANCHK)&&RTP&&!IS_ARCH(RTP))
+ WDLN(crname(RTP)+" scanned you (id) ["+query_verb()+"] "+
+ (PREV ? ObjFile(PREV) : "[destructed object]"));
+ return LOWER(str)==LOWER(TOOL_NAME);
+}
+
+/*----------------------------------------------------------------------
+ * short and long description
+ */
+
+string short()
+{
+ return _query_short()+".\n";
+}
+
+string _query_short()
+{
+ string sh; // added by Rumata
+ if(cloner)
+ {
+ if((!security())&&MODE(MODE_SCANCHK)&&!IS_ARCH(RTP))
+ WDLN(crname(RTP)+" scanned you (short) ["+query_verb()+"] "+
+ (PREV ? ObjFile(PREV) : "[destructed object]"));
+ if( sh=Query(P_SHORT) ) return sh; // added by Rumata
+ return cloner->name(WESSEN)+" "+TOOL_TITLE+" ["+
+ ctime(time())[11..18]+"]";
+ }
+ return TOOL_TITLE;
+}
+
+string long()
+{
+ return _query_long();
+}
+
+string _query_long()
+{
+ if(cloner&&!security()&&MODE(MODE_SCANCHK)&&!IS_ARCH(RTP))
+ {
+ WDLN(crname(RTP)+" scanned you (long) ["+query_verb()+"] "+
+ (PREV ? ObjFile(PREV) : "[destructed object]"));
+ }
+ return
+ "This is "+TOOL_NAME+" version "+TOOL_VERSION+
+ " (maintained by Kirk@MorgenGrauen)\n"+
+ "Original copyright held by Hyp.\n"+
+ "Gamedriver patchlevel: "+__VERSION__+" master object: "+__MASTER_OBJECT__+
+ "\n\nDo 'xhelp' for more information.\n";
+}
+
+string name(mixed dummy1, mixed dummy2)
+{
+ return _query_short();
+}
+
+/*----------------------------------------------------------------------
+ * light stuff
+ */
+
+int _query_light()
+{
+ return xlight;
+}
+
+int _set_light(int x)
+{
+ return xlight;
+}
+
+/*----------------------------------------------------------------------
+ * Autoloading
+ */
+
+mixed *_query_autoloadobj()
+{
+ return AUTOLOAD_ARGS;
+}
+
+void _set_autoloadobj(mixed *args)
+{
+ WLN(TOOL_TITLE+" ...");
+ if(!pointerp(args))
+ ;
+ else if(sizeof(args)!=3)
+ ;
+ else if(!stringp(args[0]))
+ ;
+ else if(!intp(args[1]))
+ ;
+ else if(!intp(args[2]))
+ ;
+ else
+ {
+ if((string)args[0]!=TOOL_INTERNAL)
+ {
+ WLN("*****************************");
+ WLN("*** NEW EDITION ***");
+ WLN("*** do 'xtool news' for ***");
+ WLN("*** more information ***");
+ WLN("*****************************");
+ }
+ modi=(int)args[1];
+ morelines=(int)args[2];
+ return;
+ }
+ W("(bad autoload, using default)\n");
+}
+
+/*----------------------------------------------------------------------
+ * creation, updating and initialization stuff
+ */
+
+void update_tool(mixed *args, object obj)
+{
+ SECURE1();
+ if(!(obj&&args))
+ return;
+ Destruct(PREV);
+ _set_autoloadobj(args);
+ move(obj);
+}
+
+void create()
+{
+ object obj;
+
+ if(member(object_name(),'#')<0)
+ return;
+ if(!cloner&&!((cloner=TP)||(cloner=ENV(ME)))&&!interactive(cloner))
+ destruct(ME);
+ if(!IS_LEARNER(cloner))
+ destruct(ME);
+ SetProp(P_NODROP,"Das waere zu gefaehrlich.\n");
+ SetProp(P_NEVERDROP,1);
+ SetProp(P_NOBUY,1);
+ if(file_size(SAVE_FILE+".o")>0)
+ {
+ WDLN("Loading "+TOOL_TITLE+" settings");
+ restore_object(SAVE_FILE);
+ }
+ if(MODE(MODE_FIRST))
+ call_out("move",0,cloner);
+ call_out("add_insert_hook",1,ME);
+}
+
+void TK(string str)
+{
+ if (!xtk)
+ return;
+ tell_object(cloner,"XTOOL: "+str+"\n");
+}
+
+int Xtk(string str)
+{
+ xtk=!xtk;
+ WDLN("Xtool internal tracing "+(xtk?"enabled":"disabled"));
+ return TRUE;
+}
+
+void add_insert_hook(object obj)
+{
+ if(objectp(obj))
+ cloner->AddInsertHook(obj);
+}
+
+void init()
+{
+ object first, prev;
+
+ if(member(object_name(),'#')<0) return;
+ first=first_inventory(ENV(ME));
+ if(MODE(MODE_PROTECT)&&is_player(first)&&!IS_ARCH(first))
+ {
+ WDLN("WARNING: "+crname(first)+" tried to move into your inventory");
+ tell_object(first, "You cannot move yourself into "+
+ crname(cloner)+"'s inventory.\n");
+ call_out("DropObj",0,first);
+ return;
+ }
+ else if(MODE(MODE_FIRST)&&first!=ME)
+ move(cloner);
+ else actions();
+}
+
+void DropObj(object obj)
+{
+ if(!obj||!objectp(obj))
+ return;
+ obj->move(ENV(cloner),M_NOCHECK|M_NO_SHOW);
+}
+
+#define ACTIONS\
+([\
+ "xcallouts" : "Xcallouts";0;1,\
+ "xcall" : "Xcall";0;1,\
+ "xcat" : "Xcat";1;1,\
+ "xcd" : "Xcd";0;0,\
+ "xclean" : "Xclean";0;0,\
+ "xclone" : "Xclone";0;0,\
+ "xuclone" : "Xuclone";0;0,\
+ "xcmds" : "Xcmds";0;1,\
+ "xdbg" : "Xdbg";0;0,\
+ "xdclean" : "Xdclean";0;0,\
+ "xddes" : "Xddes";0;0,\
+ "xdes" : "Xdes";0;0,\
+ "xdest" : "Xdes";0;0,\
+ "xdlook" : "Xdlook";0;1,\
+ "xdo" : "Xdo";0;0,\
+ "xdupdate" : "Xdupdate";0;0,\
+ "xecho" : "Xecho";0;0,\
+ "xeval" : "Xeval";0;1,\
+ "xforall" : "Xforall";0;0,\
+ "xgoto" : "Xgoto";0;0,\
+ "xhbeats" : "Xhbeats";0;1,\
+ "xgrep" : "Xgrep";1;1,\
+ "xhead" : "Xhead";1;1,\
+ "xhelp" : "Xhelp";0;0,\
+ "xinventory": "Xinventory";0;1,\
+ "xids" : "Xids";0;0,\
+ "xinfo" : "Xinfo";0;0,\
+ "xinherit" : "Xinherit";0;1,\
+ "xlag" : "Xlag";0;0,\
+ "xlight" : "Xlight";0;0,\
+ "xload" : "Xload";0;0,\
+ "xlook" : "Xlook";0;1,\
+ "xlpc" : "Xlpc";0;0,\
+ "xman" : "Xman";0;0,\
+ "xmore" : "Xmore";1;0,\
+ "xmove" : "Xmove";0;0,\
+ "xmsg" : "Xmsg";1;0,\
+ "xmtp" : "Xmtp";0;0,\
+ "xproc" : "Xproc";0;1,\
+ "xprof" : "Xprof";0;0,\
+ "xprops" : "Xprops";0;1,\
+ "xquit" : "Xquit";0;0,\
+ "xscan" : "Xscan";0;0,\
+ "xset" : "Xset";0;0,\
+ "xsh" : "Xsh";0;0,\
+ "xsort" : "Xsort";1;1,\
+ "xtail" : "Xtail";1;1,\
+ "xtk" : "Xtk";0;0,\
+ "xtool" : "Xtool";0;0,\
+ "xtrace" : "Xtrace";0;0,\
+ "xtrans" : "Xtrans";0;0,\
+ "xupdate" : "Xupdate";0;0,\
+ "xwc" : "Xwc";1;0,\
+ "xwho" : "Xwho";0;1,\
+ ])
+
+static string PrepareLine(string str)
+{
+ return str;
+}
+
+static string QuoteLine(string str)
+{
+ string *tmp,*tmp2;
+ int i, i2, len, len2, qd, qs;
+
+ str=string_replace(str,"\\\\","°BSHL");
+ str=string_replace(str,"\\\"","°DBLQ");
+ str=string_replace(str,"\\\'","°SGLQ");
+ str=string_replace(str,"\\|","°PIPE");
+ str=string_replace(str,"||","°OROR");
+ str=string_replace(str,"->","°LARR");
+ str=string_replace(str,"\\$","°DOLR");
+ tmp=regexplode(str,"(\"|')");
+ len=sizeof(tmp);
+ qd=qs=0;
+ for(i=0;i<len;i++)
+ {
+ if(i%2)
+ {
+ if(tmp[i]=="'")
+ qd=(!qs?!qd:qd);
+ else
+ qs=(!qd?!qs:qs);
+ if((tmp[i]=="\""&&!qd)||(tmp[i]=="'"&&!qs))
+ tmp[i]="";
+ }
+ else
+ {
+ if(!qd)
+ {
+ len2=sizeof(tmp2=regexplode(tmp[i],"\\$[^ ][^ ]*"));
+ for(i2=0;i2<len2;i2++)
+ if(i2%2)
+ {
+ TK("QuoteLine: "+tmp2[i2][1..]);
+ tmp2[i2]=(string)XFindObj((tmp2[i2])[1..]);
+ }
+ tmp[i]=implode(tmp2,"");
+ }
+ }
+ }
+ if(qd||qs)
+ return NULL;
+ str=implode(tmp,"");
+ TK("QuoteLine: str: "+str);
+ return str;
+}
+
+static string UnquoteLine(string str)
+{
+ str=string_replace(str,"°BSHL","\\");
+ str=string_replace(str,"°DBLQ","\"");
+ str=string_replace(str,"°SGLQ","\'");
+ str=string_replace(str,"°DQUO","");
+ str=string_replace(str,"°SQUO","");
+ str=string_replace(str,"°PIPE","|");
+ str=string_replace(str,"°OROR","||");
+ str=string_replace(str,"°LARR","->");
+ str=string_replace(str,"°DOLR","$");
+ TK("UnquoteLine: str: "+str);
+ return str;
+}
+
+static string *ExplodeCmds(string str)
+{
+ string *tmp;
+
+ tmp=regexplode(str,"\\||>|>>");
+ while(tmp[<1]=="")
+ tmp=tmp[0..<2];
+ return tmp;
+}
+
+varargs int ParseLine(string str)
+{
+ string verb, arg;
+ int ret;
+
+ TK("ParseLine: str: "+(str?str:""));
+ if(!sizeof(cmds))
+ {
+ // this is a single command or beginning of a command pipe
+ verb=query_verb();
+
+ // return on unknown commands
+ if(!verb||!sizeof(verb)||!GetFunc(verb,TRUE))
+ return FALSE;
+
+ str=(string)this_player()->_unparsed_args();
+ pipe_in=FALSE;
+ pipe_of=NULL;
+ pipe_ovr=TRUE;
+ pipe_out=FALSE;
+ pipe_of=NULL;
+ // pass arguments to some special functions unparsed
+ if(member(({"xlpc","xcall","xeval"}),verb)>=0)
+ {
+#ifdef XDBG
+ TK("ParseLine: special func: "+verb);
+#endif
+ ret=CallFunc(verb,str);
+ SafeReturn(ret);
+ }
+ // ok, here we go
+ pipe_in=pipe_out=FALSE;
+ pipe_if=pipe_of=NULL;
+ pipe_ovr=TRUE;
+ if(file_size(PIPE_FILE)>=0)
+ rm(PIPE_FILE);
+ if (str&&str!="")
+ {
+ if(!(str=QuoteLine(str)))
+ {
+ WDLN("Unterminated quotation");
+ SafeReturn(TRUE);
+ }
+ cmds=ExplodeCmds(str);
+ }
+ else
+ cmds=({""});
+ arg=strip_string(cmds[0]);
+ }
+ else
+ {
+ cmds[0]=strip_string(cmds[0]);
+ TK("ParseLine: cmds[0]: "+cmds[0]);
+ if(sscanf(cmds[0],"%s %s",verb,arg)!=2)
+ {
+ verb=cmds[0];
+ arg="";
+ }
+ }
+ cmds=cmds[1..];
+ TK("ParseLine: verb: "+verb);
+ if (!verb||!sizeof(verb)||!GetFunc(verb,TRUE))
+ SafeReturn(FALSE);
+ TK("ParseLine(1): arg: "+arg+" cmds: "+sprintf("%O",cmds));
+ switch(sizeof(cmds))
+ {
+ case 0:
+ ret=CallFunc(verb,strip_string(UnquoteLine(arg)));
+ SafeReturn(ret);
+ break;
+
+ case 1:
+ WDLN("Missing rhs of command pipe");
+ SafeReturn(TRUE);
+ break;
+
+ default:
+ pipe_out=TRUE;
+ switch(cmds[0])
+ {
+ case "|":
+ pipe_of=PIPE_FILE;
+ pipe_ovr=TRUE;
+ cmds=cmds[1..];
+ break;
+
+ case ">":
+ pipe_ovr=TRUE;
+ if(sizeof(cmds)!=2)
+ {
+ WDLN("Illegal IO redirection");
+ SafeReturn(TRUE);
+ }
+ pipe_of=cmds[1];
+ cmds=({});
+ break;
+
+ case ">>":
+ pipe_ovr=FALSE;
+ if(sizeof(cmds)!=2)
+ {
+ WDLN("Illegal IO redirection");
+ SafeReturn(TRUE);
+ }
+ pipe_of=cmds[1];
+ cmds=({});
+ break;
+ }
+ }
+ TK("ParseLine(2): arg: "+arg+" cmds: "+sprintf("%O",cmds));
+ if(!CallFunc(verb,strip_string(arg)))
+ SafeReturn(FALSE);
+ pipe_in=pipe_out;
+ pipe_if=pipe_of;
+ pipe_ovr=FALSE;
+ pipe_out=FALSE;
+ pipe_of=NULL;
+ if(sizeof(cmds))
+ call_out("ParseLine",0);
+ else
+ SafeReturn(TRUE);
+ return TRUE;
+}
+
+static int CallFunc(string verb, string str)
+{
+ string fun;
+
+ fun=GetFunc(verb,FALSE);
+#ifdef XDBG
+ TK("CallFunc: verb: "+verb+" str: "+str);
+ TK("CallFunc: resolved function: "+(fun?fun:"(unresolved)"));
+#endif
+ if(str=="")
+ str=NULL;
+ return fun?(int)call_other(ME,fun,str):FALSE;
+}
+
+static string GetFunc(string verb, int test)
+{
+ string fun,*keys,key;
+ int i,len;
+
+ TK("GetFunc: verb: "+verb);
+
+ if(verb[0..0]!="x") // Assume all commands start with "x"
+ return 0;
+
+ if (!(fun=(string)ACTIONS[verb,0])) { // Try exact hit first
+ key="";
+ len=sizeof(verb);
+ for (i=sizeof(keys=m_indices(ACTIONS))-1;i>=0;i--) {
+ TK(" trying: "+keys[i]);
+ if(sizeof(keys[i])>=len&&keys[i][0..len-1]==verb) {
+ if(sizeof(key)) {
+ WLN("Das ist nicht eindeutig ...");
+ return 0;
+ }
+ fun=ACTIONS[keys[i],0];
+ key=keys[i];
+ //break;
+ }
+ }
+ } else
+ key=verb;
+
+ if(test)
+ return fun;
+
+ if (key) {
+#ifdef XDBG
+ TK("GetFunc: fun: "+fun+" (key: "+key+")\n"+
+ "pipe_in: "+(pipe_in?"TRUE ":"FALSE ")+(pipe_if?pipe_if:"(NULL)")+"\n"+
+ "pipe_out: "+(pipe_out?"TRUE ":"FALSE ")+(pipe_of?pipe_of:"(NULL)")+"\n"+
+ "pipe_ovr: "+(pipe_ovr?"TRUE":"FALSE"));
+#endif
+ if (pipe_in&&!ACTIONS[key,PIPE_IN])
+ {
+ // this command does not read pipes
+#ifdef XDBG
+ TK("Illegal rhs of command pipe \""+fun+"\"\n");
+#endif
+ notify_fail("Illegal rhs of command pipe \""+fun+"\"\n");
+ return 0;
+ }
+ else if (pipe_out&&!ACTIONS[key,PIPE_OUT])
+ {
+ // this command does not feed pipes
+#ifdef XDBG
+ TK("Illegal lhs of command pipe \""+fun+"\"\n");
+#endif
+ notify_fail("Illegal lhs of command pipe \""+fun+"\"\n");
+ return 0;
+ }
+ }
+ return fun;
+}
+
+void actions()
+{
+ if (!cloner||!RTP||cloner==RTP||query_wiz_level(cloner)<=query_wiz_level(RTP))
+ add_action("ParseLine","",1);
+ add_action("CommandScan", "", 1);
+}
+
+/*----------------------------------------------------------------------
+ * the checking stuff
+ */
+
+void InsertNotify(object obj)
+{
+ if(!cloner)
+ return;
+ if(MODE(MODE_FIRST) && find_call_out("move")==-1)
+ call_out("move",0,cloner);
+ if(MODE(MODE_INVCHECK))
+ write_newinvobj(obj);
+}
+
+static void VarCheck(int show)
+{
+ int i, s;
+ foreach(string k, mixed v : variable)
+ {
+ if (v) continue;
+ if(show) WDLN("*** Variable $"+k+" has been destructed");
+ m_delete(variable, k);
+ }
+}
+
+
+int write_newinvobj(object obj)
+{
+ if(obj) WDLN("*** New object in inventory "+ObjFile(obj));
+ return(1);
+}
+
+/*----------------------------------------------------------------------
+ * catch all commands, absorb forces and check history
+ */
+
+int CommandScan(string arg)
+{
+ string verb, cmd;
+ object rtp;
+ rtp=RTP;
+
+ if(!cloner&&!(cloner=rtp)) destruct(ME);
+
+ if((!MODE(MODE_PROTECT))||security()||
+ query_wiz_level(cloner)<query_wiz_level(rtp))
+ {
+ verb=query_verb();
+ if(verb&&DoHistory(verb+(arg ? " "+arg : "")))
+ return TRUE;
+ nostore=FALSE;
+ return FALSE;
+ }
+ else
+ {
+ if(rtp)
+ {
+ WDLN("Your "+TOOL_TITLE+" protects you from a force by "+crname(rtp)+
+ " ["+query_verb()+(arg ? " "+arg+"]" : "]"));
+ tell_object(rtp, crname(cloner)+"'s "+TOOL_TITLE+
+ " absorbes your force.\n");
+ }
+ else
+ {
+ WDLN("Your "+TOOL_TITLE+" protects you from a force ["+
+ query_verb()+(arg ? " "+arg+"]" : "]"));
+ }
+ return TRUE;
+ }
+}
+
+int DoHistory(string line)
+{
+ int i;
+ string cmd, *strs;
+
+ SECURE2(FALSE);
+ if(!stringp(line) || !sizeof(line))
+ return TRUE;
+ else if(line=="%!")
+ {
+ WLN("Current command history:");
+ for(i=MAX_HISTORY; i; --i)
+ if(history[i-1])
+ {
+ W(" "+ARIGHT(""+i, 2, " ")+": ");
+ if(sizeof(history[i-1])>70)
+ WLN(ALEFT(history[i-1], 70, " "));
+ else
+ WLN(history[i-1]);
+ }
+ return TRUE;
+ }
+ else if(line[0..1]=="%%" && (cmd=history[0]+line[2..<1]))
+ {
+ Command(cmd);
+ return TRUE;
+ }
+ else if(line[0]=='^'&&(strs=strip_explode(line, "^")))
+ {
+ if(sizeof(strs)&&strs[0]&&(cmd=history[0]))
+ {
+ if(sizeof(strs)==2)
+ cmd=string_replace(cmd, strs[0], strs[1]);
+ else
+ cmd=string_replace(cmd, strs[0], "");
+ nostore--;
+ Command(cmd);
+ nostore++;
+ return TRUE;
+ }
+ }
+ else if(line[0]=='%' && (sscanf(line[1..<1], "%d", i)))
+ {
+ i= i>0 ? i : 1;
+ i= i<=MAX_HISTORY ? i : MAX_HISTORY;
+ if(cmd=history[i-1])
+ Command(cmd);
+ return TRUE;
+ }
+ else if(line[0]=='%')
+ {
+ for(i=0; i<MAX_HISTORY; i++)
+ {
+ if(history[i]&&
+ history[i][0..sizeof(line)-2]==line[1.. <1])
+ {
+ Command(history[i]);
+ return TRUE;
+ }
+ }
+ }
+ else if(nostore<1)
+ history=({line})+history[0..MAX_HISTORY-2];
+ return FALSE;
+}
+
diff --git a/obj/tools/MGtool/man.d/xcall b/obj/tools/MGtool/man.d/xcall
new file mode 100644
index 0000000..43e21ea
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xcall
@@ -0,0 +1,21 @@
+SYNOPSIS
+ xcall <object>-><function>(<expression>)
+
+DESCRIPTION
+ Calls the lfun <function> of the <object> with <expression> as
+ argument. The <properties.h> are included. Three objects are allready
+ defined on invokation. "me" represents the onwer of the Xtool. "here"
+ is the current room and "obj" is the object which lfun is called.
+ To use the object access syntax described above, a function called
+ "get(string)" can be used. If the call returned an object, the variable
+ "$result" will be set to this object.
+ xcall includes a private ~/.xtool.h, if it exists, to support user
+ defined macros.
+
+EXAMPLES
+ xcall $me->QueryProp(P_LONG)
+ xcall /std/thing#145->SetProp(P_SHORT,"a small thing")
+ xcall /secure/master->add_domain_wiz("hell", "hyp")
+ xcall $me->move(get("^deepthought"),"go")
+ (the last one uses the function get() to find the room where our god is)
+
diff --git a/obj/tools/MGtool/man.d/xcallouts b/obj/tools/MGtool/man.d/xcallouts
new file mode 100644
index 0000000..79adfa6
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xcallouts
@@ -0,0 +1,16 @@
+SYNOPSIS
+ xcallouts [search pattern]
+ or
+ xcallouts (when writing to a pipe)
+
+DESCRIPTION
+ With no argument it shows all your callouts. With a regexp as argument,
+ all matching callouts will be printed. When writing to a pipe, all
+ call_outs will be printed and the search pattern is not allowed.
+
+EXAMPLES
+ xcallouts obj Show all callouts with the string "obj" in it.
+ xcallouts . Show all callouts. Please never do this if it isn't
+ really neccessary. It just costs time - and what do you
+ want to do with this mass of information?
+
diff --git a/obj/tools/MGtool/man.d/xclean b/obj/tools/MGtool/man.d/xclean
new file mode 100644
index 0000000..dcc488e
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xclean
@@ -0,0 +1,12 @@
+SYNOPSIS
+ xclean [object]
+
+DESCRIPTION
+ Clean the inventory of the object, but don't destruct any living.
+ With no argument the current room will be cleaned. The objects
+ are removed with the lfun remove().
+
+EXAMPLE
+ xclean $me.bag
+ Clean my bag.
+
diff --git a/obj/tools/MGtool/man.d/xclone b/obj/tools/MGtool/man.d/xclone
new file mode 100644
index 0000000..00c1b7a
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xclone
@@ -0,0 +1,13 @@
+SYNOPSIS
+ xclone <filename>
+
+DESCRIPTION
+ Clones an object. On error, the error log file will be printed.
+ Moves the object (if possible) into your inventory. If the object
+ has been cloned successfully, the variable "$clone" will be set,
+ to make sure we don't lose the object out of sight :)
+
+EXAMPLE
+ xclone /std/thing
+ xcall $clone->SetShort("a BIG thing!");
+
diff --git a/obj/tools/MGtool/man.d/xdbg b/obj/tools/MGtool/man.d/xdbg
new file mode 100644
index 0000000..5609f2f
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdbg
@@ -0,0 +1,14 @@
+SYNOPSIS
+ xdbg <object>
+
+DESCRIPTION
+ Prints out debug information buy using the efun debug_info().
+ Not all of these information is useful but it gives you information
+ of how many variables, functions, inherited objetcs and so on a object
+ has. It also shows if an object is living, if its heart beat is turned
+ on, when the next call of reset() will be (but don't take this value
+ not too seriously) etc.
+
+EXAMPLE
+ xdbg $me
+
diff --git a/obj/tools/MGtool/man.d/xdclean b/obj/tools/MGtool/man.d/xdclean
new file mode 100644
index 0000000..79f9093
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdclean
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xdclean <object>
+
+DESCRIPTION
+ Same as xclean, but makes a deep clean.
+
diff --git a/obj/tools/MGtool/man.d/xddes b/obj/tools/MGtool/man.d/xddes
new file mode 100644
index 0000000..a235645
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xddes
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xddes <object>
+
+DESCRIPTION
+ Same as xdes, but makes a deep destruct.
+
diff --git a/obj/tools/MGtool/man.d/xdes b/obj/tools/MGtool/man.d/xdes
new file mode 100644
index 0000000..17bf984
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdes
@@ -0,0 +1,8 @@
+SYNOPSIS
+ xdes <object>
+
+DESCRIPTION
+ Destruct an object using by first calling the lfun remove() of the
+ object and if its still "alive" then destruct it with the efun
+ destruct().
+
diff --git a/obj/tools/MGtool/man.d/xdlook b/obj/tools/MGtool/man.d/xdlook
new file mode 100644
index 0000000..6f7772f
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdlook
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xdlook <object>
+
+DESCRIPTION
+ Same as look, but takes a deep look at the object.
+
diff --git a/obj/tools/MGtool/man.d/xdo b/obj/tools/MGtool/man.d/xdo
new file mode 100644
index 0000000..cefa5f1
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdo
@@ -0,0 +1,14 @@
+SYNOPSIS
+ xdo [<number1>#]<command1>[;[<number2>#]<command2>] ...
+
+DESCRIPTION
+ Perform multiple command execution.
+
+ Examples:
+ xdo 5#smile (smile 5 times)
+
+ xdo l;i (look around in the room and then in your inventory)
+
+ xdo s;9#w;3#n;kill shaman;get sword from corpse;3#s;9#e;n;...
+ (you know this one :)
+
diff --git a/obj/tools/MGtool/man.d/xdupdate b/obj/tools/MGtool/man.d/xdupdate
new file mode 100644
index 0000000..b3752b9
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdupdate
@@ -0,0 +1,8 @@
+SYNOPSIS
+ xdupdate <filename>
+
+DESCRIPTION
+ Update an object including all its inherited objects.
+
+EXAMPLE
+ xdupdate /std/player.c
diff --git a/obj/tools/MGtool/man.d/xeval b/obj/tools/MGtool/man.d/xeval
new file mode 100644
index 0000000..f532bdf
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xeval
@@ -0,0 +1,18 @@
+SYNOPSIS
+ xeval <expression>
+
+DESCRIPTION
+ Execute an LPC expression. Inside the <expression>, "me" and "here" are
+ predefined objects (guess for what :). Here we can also use the function
+ "get()" to find an object using the object access syntax. If the
+ Expression returns an object the variable "$result" will be set to this.
+ xeval includes a private ~/.xtool.h, if it exists, to support user
+ defined macros.
+
+
+EXAMPLES
+ Just do it!
+ xeval users()
+ xeval getuid(me)
+ xeval get("$me.xtool")
+
diff --git a/obj/tools/MGtool/man.d/xforall b/obj/tools/MGtool/man.d/xforall
new file mode 100644
index 0000000..17558f4
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xforall
@@ -0,0 +1,29 @@
+SYNOPSIS
+ xforall <filepattern> <command>
+
+DESCRIPTION
+ Execute <command> for all matching files. The <command> string can
+ contain replacment marks. Currently there are five of these marks:
+ - "!!" this mark stands for the full file name.
+ - "!e" stands for the extension of the file name.
+ - "!f" stands for the file name without extension and directory name.
+ - "!h" stands for the full directory name of the files.
+ - "!r" stands for the full file name without file extension.
+ - "!t" stands for the file name without the directory name.
+
+ If the full file name would be "/directory/file.ext" then
+ "!!" equals "/directory/file.ext"
+ "!e" equals "ext"
+ "!f" equals "file"
+ "!h" equals "/directory"
+ "!r" equals "/directory/file"
+ "!t" equals "file.ext"
+
+EXAMPLES
+ xforall ~/room/*.c xcall !r->reset();
+ Call the reset() function in all your rooms.
+
+ xforall ~/obj/* mv !! !h/oldobj/!f.!e.old
+ Move all files from your "obj" dir into the "obj/oldobj" dir and change
+ the extensions.
+
diff --git a/obj/tools/MGtool/man.d/xgoto b/obj/tools/MGtool/man.d/xgoto
new file mode 100644
index 0000000..df4ccba
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xgoto
@@ -0,0 +1,16 @@
+SYNOPSIS
+ xgoto [object]
+
+DESCRIPTION
+ Go inside <object>. Without an argument you will leave into your
+ workroom. If <object> is a living thing, goto it's environment
+ (never tested until now, when going to a living thing, inside
+ a living thing :)
+
+EXAMPLES
+ xgoto /room/shop
+ xgoto shop (both are the same, because if there is no shop in
+ the current directory, a "/room/" will be appended
+ to the argument)
+ xgoto public enemy (do this only when you are really bored)
+
diff --git a/obj/tools/MGtool/man.d/xgrep b/obj/tools/MGtool/man.d/xgrep
new file mode 100644
index 0000000..8914fcb
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xgrep
@@ -0,0 +1,25 @@
+SYNOPSIS
+ xgrep [-iv] <regexp> <filepattern>
+ or
+ xgrep [-iv] <regexp> (when reading from a pipe)
+
+DESCRIPTION
+ Search for the regular expression <regexp> in all files matching the
+ <filepattern>.
+ Works simular to the Unix command "grep". The reslut will be written
+ to <STDOUT> and may be piped into another command.
+
+OPTIONS
+ -v reverts the sense of <regexp>.
+
+ -i matches case-insensitive
+
+EXAMPLES
+ xgrep Deepthought /log/SHOUTS
+ This will search throught the shout log file for any line which has
+ the word "Deepthought" in it.
+
+ xgrep create\(\) *.c
+ This will search for all lines of all lpc code files in the current dir
+ which have the function "create()" defined.
+
diff --git a/obj/tools/MGtool/man.d/xhbeats b/obj/tools/MGtool/man.d/xhbeats
new file mode 100644
index 0000000..3a897f3
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xhbeats
@@ -0,0 +1,18 @@
+SYNOPSIS
+ xhbeats [search pattern]
+ or
+ xhbeats (when writing to a pipe)
+
+DESCRIPTION
+ With no argument it shows all your objects which have a running heart
+ beat. With a regexp as argument, all matching objects will be printed.
+ When writing to a pipe, all hearbeats will be printed and a search
+ pattern is not allowed.
+
+EXAMPLES
+ xhbeats obj Show all objects which have a running heart beat at the
+ object names with the string "obj" in it.
+ xhbeats . Show all callouts. Please don't do this if it isn't
+ really neccessary. It just costs time - and what do you
+ want to do with this information?
+
diff --git a/obj/tools/MGtool/man.d/xhead b/obj/tools/MGtool/man.d/xhead
new file mode 100644
index 0000000..5801055
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xhead
@@ -0,0 +1,11 @@
+SYNOPSIS
+ xhead <-#> <file>
+ or
+ xhead <-#> (when reading from a pipe)
+
+DESCRIPTION
+ xhead prints the first part of a given file; It reads from a pipe
+ if no file is given.
+
+EXAMPLES
+ xhead -10 workroom.c prints the first 10 lines of the file workroom.c.
diff --git a/obj/tools/MGtool/man.d/xhelp b/obj/tools/MGtool/man.d/xhelp
new file mode 100644
index 0000000..b0aa7d4
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xhelp
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xhelp
+
+DESCRIPTION
+ Show the main help file.
+
diff --git a/obj/tools/MGtool/man.d/xids b/obj/tools/MGtool/man.d/xids
new file mode 100644
index 0000000..67ef761
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xids
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xids <object>
+
+DESCRIPTION
+ Show the user id and the effective user id of the <object>.
+
diff --git a/obj/tools/MGtool/man.d/xinherit b/obj/tools/MGtool/man.d/xinherit
new file mode 100644
index 0000000..ef02f3e
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xinherit
@@ -0,0 +1,16 @@
+SYNOPSIS
+ xinherit <object> [function]
+
+DESCRIPTION
+ Show the inheritance tree of an object and if optional specified
+ display all occurencies of the function.
+ The inheritance tree is perhaps not the one you expect to see. In
+ fact its the one the gamedriver really uses. That means if for
+ example two object inherit each other or in any other case of recursion
+ it will not be shown. Or if an object A inherits object B and C
+ and object B also inherits object C, the object C will only displayed
+ once (because the gamedriver also inherits object once).
+
+EXAMPLE
+ xinherit $me
+
diff --git a/obj/tools/MGtool/man.d/xlag b/obj/tools/MGtool/man.d/xlag
new file mode 100644
index 0000000..fd28114
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xlag
@@ -0,0 +1,16 @@
+SYNOPSIS
+ xlag
+
+DESCRIPTION
+ xlag displays the current system LAG by comparing the actual
+ processed heartbeats with the initial heartbeat rate (1/2s).
+ Values will we displayed for the last minute, the last 15 minutes
+ and the last hour.
+
+EXAMPLE
+ Letzte 60 min: ####### (7.2%)
+ Letzte 15 min: ######## (8.3%)
+ Letzte Minute: ######### (9.4%)
+
+AVAILABILITY
+ xlag requires /players/kirk/obj/lag-o-daemon.c to be loaded.
diff --git a/obj/tools/MGtool/man.d/xload b/obj/tools/MGtool/man.d/xload
new file mode 100644
index 0000000..00db877
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xload
@@ -0,0 +1,15 @@
+SYNOPSIS
+ xload <filename>
+
+DESCRIPTION
+ Update and load the object specified by the filename. If you update
+ your current environment, all players will be moved silently into
+ "/std/void" and after successful updating and loading back into it.
+
+EXAMPLES
+ xload $here
+ Update and reload the current room (but without a trip into the void :).
+
+ xload obj/little_thing.c
+ Update and load it.
+
diff --git a/obj/tools/MGtool/man.d/xlook b/obj/tools/MGtool/man.d/xlook
new file mode 100644
index 0000000..259bc9e
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xlook
@@ -0,0 +1,7 @@
+SYNOPSIS
+ xlook [object]
+
+DESCRIPTION
+ Look at the object. If the argument is ommitted, look inside the
+ current room.
+
diff --git a/obj/tools/MGtool/man.d/xlpc b/obj/tools/MGtool/man.d/xlpc
new file mode 100644
index 0000000..8f471ed
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xlpc
@@ -0,0 +1,20 @@
+SYNOPSIS
+ xlpc <lpc code>
+
+DESCRIPTION
+ Execute pure LPC code. "me" and "here" are predefined objects. Also the
+ <properties.h> will be included. The function "get(string)" can be used
+ for accessing objects. If the execution returns an object the variable
+ "$result" will set to this object.
+
+EXAMPLES
+ xlpc int i;object *o;o=users();for(i=0;i<sizeof(o);i++)o[i]->
+ SetProp(P_FROG,1);
+ (Let all users be slimy frogs :)
+
+ xlpc int i;object *o;o=users();for(i=0;i<sizeof(o);i++)
+ o[i]->SetProp(P_TITLE,get("$me")->QueryProp(P_TITLE));
+ (Give all users your prefered title. Take a look of the use of get().)
+
+ Both commands must be written in one line of course!
+
diff --git a/obj/tools/MGtool/man.d/xman b/obj/tools/MGtool/man.d/xman
new file mode 100644
index 0000000..9b56ad1
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xman
@@ -0,0 +1,17 @@
+SYNOPSIS
+ xman <topic>
+
+DESCRIPTION
+ Searches in some special directories under /doc for the given topic
+ or command. If there are two equal topics in different directories
+ the one found first will be printed.
+
+EXAMPLES
+ xman xman
+ xman xforall
+ xman efun/destruct
+ xman w/destruct
+ xman move
+ xman thing
+ xman domains
+
diff --git a/obj/tools/MGtool/man.d/xmore b/obj/tools/MGtool/man.d/xmore
new file mode 100644
index 0000000..bcd9250
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xmore
@@ -0,0 +1,12 @@
+SYNOPSIS
+ xmore <filename> [start]
+
+DESCRIPTION
+ Prints out a file and if a starting line is given, then the printing
+ will start there. On ansi or vt100 terminals the status line will be
+ overstroked to give a harmonic view of the file.
+
+EXAMPLES
+ xmore ~/workroom.c
+ xmore $here (this will show the source of the current room)
+
diff --git a/obj/tools/MGtool/man.d/xmove b/obj/tools/MGtool/man.d/xmove
new file mode 100644
index 0000000..b4c0aec
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xmove
@@ -0,0 +1,13 @@
+SYNOPSIS
+ xmove <object> into <object>
+
+DESCRIPTION
+ Moves one object into another or give the reason why the move failed.
+
+EXAMPLES
+ xmove $clone into $me
+ If you cloned an object with xclone but the object couldn't be moved
+ then this can be used to get the reason for it.
+
+ xmove hyp into ^wurzel (this is a silent form of going to other players)
+
diff --git a/obj/tools/MGtool/man.d/xmsg b/obj/tools/MGtool/man.d/xmsg
new file mode 100644
index 0000000..175b780
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xmsg
@@ -0,0 +1,11 @@
+SYNOPSIS
+ xmsg [to <object>|all]
+
+DESCRIPTION
+ Send a message. If no arguments are given the message will be send into
+ the room. If second argument is "to" then send the message to the
+ specified <object>. If second argument is "all" then send the message to
+ all players in the mud.
+ This command can be used to send text via cut&paste to someone without
+ putting a "say", "tell" or "shout" infront of each line.
+
diff --git a/obj/tools/MGtool/man.d/xmtp b/obj/tools/MGtool/man.d/xmtp
new file mode 100644
index 0000000..9d74a9c
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xmtp
@@ -0,0 +1,24 @@
+SYNOPSIS
+ xmtp [options] <directory> <file>
+
+DESCRIPTION
+ Create a script file for transfering complete directories with mtp.
+ If your mtp needs extra arguments (except of the -r option which
+ stands for reading files) for example the -g option then you can add
+ then to the command.
+ This command works recursively and can cause a to deep recursion or
+ a too long evaluation error when trying to make a script for huge
+ directories like "/players" for example.
+ If the <file> allready exists it will not be removed instead the script
+ will simply added to the end of the file.
+
+EXAMPLE
+ xmtp -gtubmud /basic ~/basic.csh
+ Create a script file "basic.csh" to transfer the whole content of the
+ "/basic" directory.
+
+ On your host you then just create a directory (normally with the same
+ name give to the xmtp command), change into the directory and read
+ the script file with "mtp -r basic.csh". Then just execute the script
+ with "csh" or "sh".
+
diff --git a/obj/tools/MGtool/man.d/xproc b/obj/tools/MGtool/man.d/xproc
new file mode 100644
index 0000000..16d0aa1
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xproc
@@ -0,0 +1,13 @@
+SYNOPSIS
+ xproc [-c] [-l] [-m] [-u] [-v]
+
+DESCRIPTION
+ xproc prints information from the /proc filesystem to the screen.
+ The format is totally unformatted! (I can't help it for now...)
+ Without any option, it display the machines load averages.
+
+ -c: cpu information
+ -l: load averages
+ -m: memory usage
+ -u: machine's uptime
+ -v: kernel version
diff --git a/obj/tools/MGtool/man.d/xprops b/obj/tools/MGtool/man.d/xprops
new file mode 100644
index 0000000..f8f0dfe
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xprops
@@ -0,0 +1,15 @@
+SYNOPSIS
+ xprops [-f|-m] <object>
+
+DESCRIPTION
+ Prints out all properties of <object> which are currently defined
+ in /sys/properties.h.
+
+OPTIONS
+ -f List property flags verbose
+
+ -m List property methods
+
+EXAMPLE
+ xprops $me
+
diff --git a/obj/tools/MGtool/man.d/xscan b/obj/tools/MGtool/man.d/xscan
new file mode 100644
index 0000000..7f7b450
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xscan
@@ -0,0 +1,7 @@
+SYNOPSIS
+ xscan
+
+DESCRIPTION
+ Scan current room for netdead players and check variables.
+ (There will follow more checking routines like snoop, invis etc. :)
+
diff --git a/obj/tools/MGtool/man.d/xset b/obj/tools/MGtool/man.d/xset
new file mode 100644
index 0000000..cb7c66d
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xset
@@ -0,0 +1,15 @@
+SYNOPSIS
+ xset [$<name>=<object>]
+
+DESCRIPTION
+ Without an argument all current variable settings will be shown and
+ destructed objects removed from the list of variables.
+ With argument the specified variable will be set.
+
+EXAMPLES
+ xset $deep=deepthought
+ xset $xtool=$me.xtool
+ xset $god=$deep
+ xset $last_result=$result
+ xset $3=^$1.3
+
diff --git a/obj/tools/MGtool/man.d/xsh b/obj/tools/MGtool/man.d/xsh
new file mode 100644
index 0000000..1377992
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xsh
@@ -0,0 +1,12 @@
+SYNOPSIS
+ xsh <filename>
+
+DESCRIPTION
+ Read in a file and execute each line of it as a command given from the
+ keyboard.
+
+EXAMPLE
+ xsh ~/setup.xsh
+ Execute the file "~/setup.xsh". This way you can set up your aliases or
+ other parameters for other tools if the setting gone lost.
+
diff --git a/obj/tools/MGtool/man.d/xsort b/obj/tools/MGtool/man.d/xsort
new file mode 100644
index 0000000..dfea2da
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xsort
@@ -0,0 +1,11 @@
+SYNOPSIS
+ xsort [-r] <file>
+ or
+ xsort [-r] (when reading from a pipe)
+
+DESCRIPTION
+ xsort sort all lines of a given file in increasing/decreasing order.
+ If no file is given it reads from a pipe.
+
+EXAMPLES
+ xsort -r workroom.c sorts all lines of workroom.c in reverse order.
diff --git a/obj/tools/MGtool/man.d/xtail b/obj/tools/MGtool/man.d/xtail
new file mode 100644
index 0000000..44c2300
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xtail
@@ -0,0 +1,12 @@
+SYNOPSIS
+ xtail <-|+#> <file>
+ or
+ xtail <-|+#> (when reading from a pipe)
+
+DESCRIPTION
+ xtail prints the last part of a given file; It reads from a pipe
+ if no file is given.
+
+EXAMPLES
+ xtail -10 workroom.c prints the last 10 lines of the file workroom.c.
+ xtail +10 workroom.c prints all lines of workroom.c beginning at line 10.
diff --git a/obj/tools/MGtool/man.d/xtool b/obj/tools/MGtool/man.d/xtool
new file mode 100644
index 0000000..62d0614
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xtool
@@ -0,0 +1,45 @@
+SYNOPSIS
+ xtool [update|heart=<on|off>|first=<on|off>|protect=<on|off>|
+ invcheck=<on|off>|envcheck=<on|off>|ndcheck=<on|off>|
+ varcheck=<on|off>|short=<on|off>|echo=<on|off>|
+ more=<amount>|kill|news|save|load|reset]
+
+DESCRIPTION
+ This command is used to set some tool-specific behaviours.
+ - "update" clones a new Xtool and destructs the old one. This should
+ only be done when working on the source of the tool and to get a fast
+ update. Settings and aliases will be reached through the new clone.
+ - "heart=<on|off>" turns the heart beat of the tool on or off.
+ The heart beat is for a higher security and to keep the other checks
+ running. If you just want to use the Xtool as a passive tool without
+ any checks then turn the heart beat off.
+ - "first=<on|off>" turns the automatic moving into the pole position
+ of your inventory on or off. Turning it off, avoids struggle with
+ other tools which behave same, but also reduces security. The history
+ mechanism will also capture the less commands.
+ - "protect=<on|off>" turns on/off the protection mode of the Xtool.
+ It will protect you from forces of other wizards and of player objects
+ which try to move into your inventory.
+ - "invcheck=<on|off>" turns the automatic check of your inventory on or
+ off. If turned on, all new objects in your inventory will be reported.
+ - "envcheck=<on|off>" like "invcheck" but checks your environment, the
+ content of the current room.
+ - "ndcheck=<on|off>" sets the netdeadchecking mode of the Xtool.
+ - "short=<on|off>" turns displaying of short descriptions on or off.
+ This is to avoid to get on other wizards nerves, when they have a tool
+ that notifies inventory checks (like this tool does :). But the main
+ reason is to cope with bad short descriptions of objects. For
+ example if you want to destruct it a bug in the short desc. would
+ make it nearly impossible to do so.
+ - "more=<amount>" sets the amount of lines that will be displayed at one
+ time with the xmore command. Will be removed soon because there is a
+ player property called P_PAGESIZE to take care of it.
+ - "echo=<on|off>" turns the echoing of commands executed via alias,
+ history or multiple command execution on or off.
+ - "kill" destructs the Xtool and removes it from the autoload list.
+ - "news" show the news and changes of the Xtool.
+ - "save" saves the settings of the Xtool including the aliases into a
+ file.
+ - "load" restores the saved settings from the save file.
+ - "reset" resets the Xtool.
+
diff --git a/obj/tools/MGtool/man.d/xtrace b/obj/tools/MGtool/man.d/xtrace
new file mode 100644
index 0000000..1c05e94
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xtrace
@@ -0,0 +1,14 @@
+SYNOPSIS
+ xtrace <object>
+
+DESCRIPTION
+ Trace all function calls with arguments and their return values of
+ the specified object. Without any argument turns the tracing off again.
+
+EXAMPLE
+ xtrace $me.buggything
+ Lets debug an buggy object.
+
+ xtrace
+ Turn debugging off.
+
diff --git a/obj/tools/MGtool/man.d/xtrans b/obj/tools/MGtool/man.d/xtrans
new file mode 100644
index 0000000..e356d0a
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xtrans
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xtrans <player>
+
+DESCRIPTION
+ Teleport <player> to you.
+
diff --git a/obj/tools/MGtool/man.d/xuclone b/obj/tools/MGtool/man.d/xuclone
new file mode 100644
index 0000000..341c825
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xuclone
@@ -0,0 +1,13 @@
+SYNOPSIS
+ xuclone <filename>
+
+DESCRIPTION
+ Updates & Clones an object. On error, the error log file will be
+ printed. Moves the object (if possible) into your inventory. If the
+ object has been cloned successfully, the variable "$clone" will be set,
+ to make sure we don't lose the object out of sight :)
+
+EXAMPLE
+ xuclone /std/thing
+ xcall $clone->SetShort("a BIG thing!");
+
diff --git a/obj/tools/MGtool/man.d/xupdate b/obj/tools/MGtool/man.d/xupdate
new file mode 100644
index 0000000..cab6567
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xupdate
@@ -0,0 +1,10 @@
+SYNOPSIS
+ xupdate <filename>
+
+DESCRIPTION
+ Update an object by first calling the lfun "remove()" of it and when
+ it still exists destruct it.
+
+EXAMPLE
+ xupdate obj/blub.c
+
diff --git a/obj/tools/MGtool/man.d/xwc b/obj/tools/MGtool/man.d/xwc
new file mode 100644
index 0000000..aa13147
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xwc
@@ -0,0 +1,22 @@
+SYNOPSIS
+ xwc [-clw] <file>
+ or
+ xwc [-clw] (when reading from a pipe)
+
+DESCRIPTION
+ xwc counts the number of bytes, whitespace-separated words, and new-
+ lines in a given file, or reading from a pipe. It prints one line
+ of counts, and if the file name was given as an argument, it prints
+ the filename following the counts. The counts are printed in the
+ order: lines, words, bytes.
+ By default, wc prints all three counts.
+
+OPTIONS:
+ -c print character count
+
+ -l print line count
+
+ -w print word count
+
+EXAMPLES
+
diff --git a/obj/tools/MGtool/man.d/xwho b/obj/tools/MGtool/man.d/xwho
new file mode 100644
index 0000000..1e9fbd6
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xwho
@@ -0,0 +1,17 @@
+SYNOPSIS
+ xwho [mail|ip|race|guild|domain|stats|cmdavg]
+
+DESCRIPTION
+ Without any argument this command behaves like the normal people
+ command. With the argument "mail" it will list all players with their
+ email address. With the argument "ip" it will list all players with
+ their host name and ip number. If the argument is "race" or "guild"
+ you will get a list of all players with these attributes. "domain"
+ will show the domain(s) of the current players. And with "stats" it
+ will print some stats information of all players.
+ The argument "cmdavg" list the value of _query_command_average()
+ for every user sorted in increasing order.
+
+EXAMPLES
+ xwho
+ xwho ip
diff --git a/obj/tools/MGtool/proc/cpuinfo b/obj/tools/MGtool/proc/cpuinfo
new file mode 120000
index 0000000..4ae7d7e
--- /dev/null
+++ b/obj/tools/MGtool/proc/cpuinfo
@@ -0,0 +1 @@
+/proc/cpuinfo
\ No newline at end of file
diff --git a/obj/tools/MGtool/proc/loadavg b/obj/tools/MGtool/proc/loadavg
new file mode 120000
index 0000000..e6983f4
--- /dev/null
+++ b/obj/tools/MGtool/proc/loadavg
@@ -0,0 +1 @@
+/proc/loadavg
\ No newline at end of file
diff --git a/obj/tools/MGtool/proc/meminfo b/obj/tools/MGtool/proc/meminfo
new file mode 120000
index 0000000..338b570
--- /dev/null
+++ b/obj/tools/MGtool/proc/meminfo
@@ -0,0 +1 @@
+/proc/meminfo
\ No newline at end of file
diff --git a/obj/tools/MGtool/proc/uptime b/obj/tools/MGtool/proc/uptime
new file mode 120000
index 0000000..2772a8f
--- /dev/null
+++ b/obj/tools/MGtool/proc/uptime
@@ -0,0 +1 @@
+/proc/uptime
\ No newline at end of file
diff --git a/obj/tools/MGtool/proc/version b/obj/tools/MGtool/proc/version
new file mode 120000
index 0000000..b17af1e
--- /dev/null
+++ b/obj/tools/MGtool/proc/version
@@ -0,0 +1 @@
+/proc/version
\ No newline at end of file
diff --git a/obj/tools/MGtool/prof.h b/obj/tools/MGtool/prof.h
new file mode 100644
index 0000000..05dcebf
--- /dev/null
+++ b/obj/tools/MGtool/prof.h
@@ -0,0 +1,42 @@
+private mixed __tm__=({0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
+private mixed __xtm__=({0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
+private mixed __ec__=({0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
+private mixed __xec__=({0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
+private int __level__;
+private mapping __data__ = ([]);
+__query_xprof_data__() { return __data__; }
+#define U2T(ru) (((ru)[0]+(ru)[1])*10)
+#define EC1 40
+#define EC2 22
+#define EC3 150
+#define TM1 0
+#define TM2 0
+#define TM3 0
+#define F(func,name,args) func args { \
+ mixed *__dt__, *__ru__, __re__; \
+ int __t__; \
+ if(!__data__) return :: func args; \
+ __ru__=rusage(); \
+ __tm__[__level__]=(__t__=U2T(__ru__))<0?0:__t__; \
+ __xtm__[__level__]=TM1; __tm__[__level__+1]=0; \
+ __ec__[__level__]=get_eval_cost(); \
+ __xec__[__level__]=EC1; __ec__[__level__+1]=0; \
+ __level__++; __re__ = :: func args; __level__--; \
+ if(!(__dt__=__data__[name])) { \
+ __dt__=__data__[name]=({0,0,0,0,0}); \
+ __xtm__[__level__]+=TM2; __xec__[__level__]+=EC2; \
+ } \
+ __ec__[__level__]-=get_eval_cost()+__xec__[__level__]; \
+ __ru__=rusage(); \
+ __t__=(__t__=U2T(__ru__))<0?0:__t__; \
+ __tm__[__level__]=__t__-__tm__[__level__]-__xtm__[__level__]; \
+ __dt__[0]++; \
+ __dt__[1]+=__ec__[__level__]-__ec__[__level__+1]; \
+ __dt__[2]+=__tm__[__level__]-__tm__[__level__+1]; \
+ __dt__[3]+=__ec__[__level__]; __dt__[4]+=__tm__[__level__]; \
+ if(__level__>0) { \
+ __xec__[__level__-1]+=__xec__[__level__]+EC3; \
+ __xtm__[__level__-1]+=__xtm__[__level__]+TM3; \
+ } \
+ return __re__; \
+}
diff --git a/obj/tools/MGtool/tool.doc b/obj/tools/MGtool/tool.doc
new file mode 100644
index 0000000..df477ce
--- /dev/null
+++ b/obj/tools/MGtool/tool.doc
@@ -0,0 +1,101 @@
+COMMANDS:
+ xcall xddes xforall xids xman xscan xtrace
+ xcallouts xdes xgoto xinherit xmore xset xtrans
+ xclean xdlook xgrep xlag xmove xsh xuclone
+ xclone xdo xhbeats xload xmsg xsort xupdate
+ xdbg xdupdate xhead xlook xmtp xtail xwc
+ xdclean xeval xhelp xlpc xprops xtool xwho
+
+
+Give a "?" as single argument to get the command usage or do "xman <command>"
+for more information about a command.
+
+QUICKTYPER:
+ The MGtool contains a full quicktyping tool. It provides the following
+ features:
+
+ - multiple command execution (see the xdo and xforall command)
+ - script files (see the xsh command)
+ - command pipelining
+ - command history
+
+ The command history stores (nearly) each command you type in and lets you
+ re-execute it.
+
+ - %! show the command history
+ - %% re-execute the last command
+ - ^old^new re-execute the last command but replace all occurencies of
+ the "old" string of the command by "new".
+ - %num re-execute the command at position num of the history
+ - %str re-execute the last command beginning with the string "str"
+
+
+COMMAND ARGUMENTS:
+ Most commands need filenames or objects as argument. The way objects are
+ specified will be descriped in the following.
+
+ - an object can be accessed directly by its unique object name
+ - a player can be accessed by its player name
+ - a living can be accessed by its living name
+ - a object inside the current room by its id
+ - a object inside the current room by its position
+
+ If the object can not be accessed by the above mentioned ways you can also
+ use the following object modifiers:
+
+ ^obj stands for the environment of an object
+ obj1.obj2 stands for an object obj2 inside another object obj1
+
+ These modifiers can be concatenated together where the "^" has a higher
+ priority than the ".". This allows you to access an object from another know
+ object.
+
+ Now some examples which demonstrates how to use this accessing mechanism.
+ Therefore we use the command "xlook" which prints the short and long
+ description and also the content of an object:
+
+ 1. xlook deepthought
+ Look at Deepthought.
+ 2. xlook ^deepthought
+ Look at the room Deepthought is in.
+ 3. xlook deepthought.bag
+ Look at the bag of Deepthought.
+ 4. xlook deepthought.bag.bag
+ Look at the bag inside Deeps bag.
+ 4. xlook deepthought.5
+ Look at the fifth object of Deeps inventory.
+ 5. xlook /std/thing#123
+ Look at the object with the unique object name "/std/thing#123".
+ 6. xlook 1
+ Look at the first object in the current room.
+ 7. xlook 1.2.3
+ Look at the third of the second of the first object in the room.
+
+ If the name of an object contains an object modifier as a character then it
+ can be escaped by a "\". A "\" is escaped by itself. This is because file
+ names often contain the "." for file extensions. So if you want to access
+ directly an object with for example such a name "file.old.bulb" you have to
+ write "file\.old\.blub".
+
+ If a command needs a file as argument you can use the filename of an object
+ for it by placing an "@" infront of the object. This way you can clone
+ an object by using another clone:
+
+ xclone @harry.bag.candles
+ Clone some candles of the kind Harry is carrying in his bag.
+
+
+ARGUMENT VARIABLES:
+ Whenever an object or a filename is needed, we can use variables.
+ A variable allways starts with a "$" followed by the name which
+ identificates it. Two variable names are reserved for special purpose.
+ The first, "$me" is always set to the one who owns the Xtool. The other,
+ "$here" represents the current room.
+
+ (Instead of "$me" and "$here" you can also use "$m" and "$h".)
+
+ If a command needs a file as argument and gets a variable it will be
+ automatically converted into the source file of the object.
+ (This is done by taking the unique object identifier and replacing the
+ "#..." by a ".c".)
+
diff --git a/obj/tools/MGtool/tool.h b/obj/tools/MGtool/tool.h
new file mode 100644
index 0000000..1eff23d
--- /dev/null
+++ b/obj/tools/MGtool/tool.h
@@ -0,0 +1,246 @@
+#ifndef __TOOL_H__
+#define __TOOL_H__
+
+/*
+ * MGtool-1.3
+ * File: tool.h
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#ifndef MASTER
+#define MASTER __MASTER_OBJECT__
+#endif
+
+#define VOID "/room/void"
+
+#define NULL (0)
+#define FALSE (0)
+#define TRUE (1)
+#define ERROR (-1)
+#define PREV previous_object()
+#define TP efun::this_player()
+#define RTP efun::this_interactive()
+#define TOOL_NAME "MGtool"
+#define TOOL_VERSION "1.3.3"
+#define TOOL_TITLE TOOL_NAME+" v"+TOOL_VERSION
+#define TOOL_INTERNAL "1.3.3-10.07.97"
+
+#define TOOL_PATH "/obj/tools/MGtool"
+
+#define TOOL_MANPAGE TOOL_PATH+"/tool.doc"
+#define TOOL_NEWS TOOL_PATH+"/tool.news"
+#define TOOL_LOG "/log/xtool"
+#define XPROF_MACRO TOOL_PATH+"/prof.h"
+#define LAG_O_DAEMON "/p/daemon/lag-o-daemon"
+
+#define TOOL_LEVEL (40)
+
+#define MORE_LINES (20)
+#define MAX_HISTORY (25)
+#define MAX_RECURSION (6)
+#define TRACE_LEVEL (1|2|4|8)
+#define AUTOLOAD_ARGS ({TOOL_INTERNAL, modi, morelines})
+#define EXEC_LINES (10)
+#define EXEC_TIME (1)
+
+#define IA(x) interactive(x)
+#define ENV(x) environment(x)
+#define LOWER(x) lower_case(x)
+#define NAME(x) ((string)x->query_name())
+#define CNAME(x) CAP((string)NAME(x))
+
+#define RNAME(x) getuid(x)
+#define CRNAME(x) CAP(RNAME(x))
+
+#define LEVEL(x) query_wiz_level(x)
+
+#define FORALL(x, y) for(x=first_inventory(y);x;x=next_inventory(x))
+#define DESTRUCT(x) Destruct(x)
+#define ALEFT(x,y,z) sprintf("%-*'"+z+"'s", y, (""+(x))[0..y-1])
+#define ARIGHT(x,y,z) sprintf("%*'"+z+"'s" , y, (""+(x))[0..y-1])
+#define W(x) Write(x)
+#define WLN(x) W(x+"\n")
+#define WDLN(x) W(x+".\n")
+
+#define MODE_ON(x) (modi|=x)
+#define MODE_OFF(x) (modi&=~x)
+#define MODE(x) (modi&x)
+#define MODE_HEART (1)
+#define MODE_FIRST (2)
+#define MODE_PROTECT (4)
+#define MODE_INVCHECK (8)
+#define MODE_ENVCHECK (16)
+#define MODE_NDCHECK (32)
+#define MODE_VARCHECK (64)
+#define MODE_ECHO (128)
+#define MODE_SHORT (256)
+#define MODE_SNOOPCHK (512)
+#define MODE_INVISCHK (1024)
+#define MODE_SCANCHK (2048)
+
+#define ERR_FILE "/players/"+RNAME(cloner)+"/.err"
+#define LPC_FILE "/players/"+RNAME(cloner)+"/.tool.lpc"
+#define TMP_FILE "/players/"+RNAME(cloner)+"/.tool.tmp"
+#define SAVE_FILE "/players/"+RNAME(cloner)+"/.toolrc"
+#define XPROF_FILE "/players/"+RNAME(cloner)+"/prof.c"
+#define PIPE_FILE "/players/"+RNAME(cloner)+"/.tool.pipe"
+#define PRIVATE_HEADER "/players/"+RNAME(cloner)+"/.xtool.h"
+#define PIPE_DELETE(x) if(pipe_out&&pipe_ovr&&file_size(x)>=0) rm(x)
+
+#define PIPE_IN 1
+#define PIPE_OUT 2
+#define PIPE_MAX 10000
+
+#define XGREP_REVERT 1
+#define XGREP_ICASE 2
+
+#define SECURE1() if(!security()) return;
+#define SECURE2(x) if(!security()) return x;
+#define USAGE1(x,y) notify_fail("Usage: "+(y)+"\n");\
+ if((x)=="?") return FALSE;
+#define USAGE2(x,y) notify_fail("Usage: "+(y)+"\n");\
+ if((!(x))||((x)=="?")) return FALSE;
+#define USAGE3(x) return WLN("Usage: "+(x))
+
+static int CatFile();
+static int Command(string str);
+int CommandScan(string arg);
+int DoAlias(string verb, string arg);
+int DoHistory(string line);
+static int MoveObj(object obj1, object obj2, int silent);
+static int XGrepFile(string pat, string file, int revert);
+int Xcall(string str);
+int Xcallouts(string str);
+int Xcat(string str);
+int Xcindent(string str);
+int Xclean(string str);
+int Xclone(string str);
+int Xuclone(string str);
+int Xcmds(string str);
+int Xdate(string str);
+int Xdbg(string str);
+int Xdclean(string str);
+int Xddes(string str);
+int Xdes(string str);
+int Xdlook(string str);
+int Xdo(string str);
+int Xdupdate(string str);
+int Xecho(string str);
+int Xeval(string str);
+int Xforall(string str);
+int Xgoto(string str);
+int Xgrep(string str);
+int Xhbeats(string str);
+int Xhead(string str);
+int Xhelp(string str);
+int Xids(string str);
+int Xinfo(string str);
+int Xinherit(string str);
+int Xinventory(string str);
+int Xlag(string str);
+int Xlight(string str);
+int Xload(string str);
+int Xlook(string str);
+int Xlpc(string str);
+int Xman(string str);
+int Xmore(string str);
+int Xmove(string str);
+int Xmsg(string str);
+int Xmtp(string str);
+int Xproc(string str);
+int Xprops(string str);
+int Xprof(string str);
+int Xquit(string str);
+int Xscan(string str);
+int Xset(string str);
+int Xsh(string str);
+int Xsort(string str);
+int Xstop(string str);
+int Xtool(string str);
+int Xtrace(string str);
+int Xtrans(string str);
+int Xupdate(string str);
+int Xwc(string str);
+int Xwho(string opt);
+static string crname(object who);
+int id(string str);
+int move(mixed dest);
+static int security();
+int write_newinvobj(object who);
+int write_newenvobj(object who);
+int write_netdead(object who);
+int write_alive(object who);
+int write_snoopee(object who);
+int write_nosnoop(object who);
+int write_invisobj(object who);
+int write_invislvg(object who);
+int write_invisply(object who);
+int write_visibobj(object who);
+int write_visiblvg(object who);
+int write_visibply(object who);
+static object *SubNodes(object obj);
+static varargs object FindObj(string str, object env, int silent);
+static object VarToObj(string str);
+static varargs object XFindObj(string str, int silent);
+static string ObjFile(object obj);
+static string PlayerAge(object obj);
+static string PlayerDomain(object obj, int flag);
+static string PlayerIP(object obj, int flag);
+static string PlayerIdle(object obj);
+static string PlayerMail(object obj, int flag);
+static string PlayerRace(object obj, int flag);
+static string PlayerSnoop(object obj, int flag);
+static string PlayerStats(object obj, int flag);
+static string PlayerWho(object obj);
+static string VarToFile(string str);
+static string VarToPureFile(string str);
+static string XFile(string file);
+static string XFindFile(string file);
+static varargs void DeepPrintShort(object env, int indent, string pre, string file);
+static void Destruct(object obj);
+static void DumpProperties(object obj, int flag);
+static void Inheritance(object obj, string func, string pre);
+void InvisCheck();
+static void MoreFile(string str);
+void NetDeadCheck(int show);
+static void PrintObj(object obj, string file);
+static varargs void PrintShort(string pre, object obj, string file);
+void SnoopCheck();
+static void VarCheck(int show);
+static int Write(string str);
+static void XExecFile(int line);
+static void XMoreFile(string file, int flag);
+static void XMsgSay(string str);
+static void XMsgShout(string str);
+static void XMsgTell(string str);
+static void XmtpScript(string dir, string file, string opt);
+void actions();
+void init();
+void update_tool(mixed *args, object obj);
+string _query_long();
+string _query_short();
+
+static int CallFunc(string verb, string str);
+static string GetFunc(string verb, int test);
+
+static string PrepareLine(string str);
+static string QuoteLine(string str);
+static string UnquoteLine(string str);
+int QuoteOk(string str);
+static string *ExplodeCmds(string str);
+
+string read_buffer(string filename, int start, int number);
+string load_buffer(int line);
+int read_line(int offset);
+
+/*
+ * debug stuff
+ */
+void TK(string str);
+int Xtk(string str);
+
+#endif /* __TOOL_H__ */
diff --git a/obj/tools/MGtool/tool.news b/obj/tools/MGtool/tool.news
new file mode 100644
index 0000000..92adbd9
--- /dev/null
+++ b/obj/tools/MGtool/tool.news
@@ -0,0 +1,143 @@
+[10.07.97]
+
+- fixed minor bug in command lookup:
+ 'xdosomethingorsomethingelse' was previously executed as 'xdo'
+ This is treated as an unknown command now. Anyway commands may be
+ abbreviated as long as they are not ambiguous.
+
+[12.03.97]
+
+- xlpc includes some more std-include-files and .xtool.h (if present)
+
+[04.03.97]
+
+- new command: xproc
+ display some information from the /proc filesystem in a very raw fashion.
+
+[08.05.96]
+
+- Xmore/Xtail: modified MoreFile/CatFile using new read_buffer() instead of
+ read_file() function which is VERY slow when giving offsets as argument.
+
+[13.02.96]
+
+- see below ...
+
+[03.01.96]
+
+- new command line parser under development (ALPHA!)
+
+[21.11.95]
+
+- MGtool will be destructed during creation, when !IS_LEARNER(<cloner>) is true
+
+- new option "-s" to xi[nventory] prints short inventory list (filenames only).
+ This is useful for alert object "... scanned your inventory" etc.
+ xi accepts <username> as optional argument to retrieve <username>'s
+ inventory instead of the cloner's own inventory and may write into pipes
+ to create command chains like: xi -s kirk|xgrep MGtool
+
+- new command xlag :-)
+
+[09.11.95]
+
+- bugfix: xinherit now calls xinherit and NOT xinventory
+
+[23.08.95]
+
+- xcall and xeval try to include a private header file ~/.xtool.h if one
+ exists. You may define own macros or whatever to make things easier
+
+[21.06.95]
+
+- new option "cmdavg" to xwho, shows command_average in ascending order
+
+[20.06.95]
+
+- removed redirecting of xcall and xeval (too buggy)
+
+- added options -f and -m to xprops (show propflags and propmethods)
+
+[06.06.95]
+
+ ** IMPORTANT ** (not backward compatible change)
+- xcall and xeval now write to a file, when redirecting their output
+ using '>'. It is also possible to pipe output into other commands
+
+[30.05.95]
+
+- xlook/xdlook are now able to write into pipes
+
+- xwho shows the name of any user currently logging in
+ instead of simply " R O O T "
+
+[10.04.95]
+
+- added option -i to xgrep (ignore case)
+
+- bugfix in command pipelines
+
+[28.03.95]
+
+- xinherit is now able to write into pipes
+
+[20.03.95]
+
+- added IO redirection like: xwho ip > testfile or xwho >> testfile
+ and: xmore < testfile
+ (this is very ALPHA!!!)
+
+[01.03.95]
+
+- new command xwc. Count lines, words and chars in file
+ Syntax xwc [-clw] [file] (is able to read from pipe)
+
+[17.02.95]
+
+- changed formatting of xprops output
+
+[15.02.95]
+
+- lots of code added, some rewritten
+
+- removed xalias capability (the shell alias provides the same functionality)
+
+- removed xcindent, xdate, xquit
+
+- bugs fixed in xcallouts, xprops, xman (when using xxtool)
+
+- added command pipelines for selected commands:
+
+ -> cmd : is able to read from pipe
+ cmd -> : is able to write into pipe
+
+ xcallouts ->
+ -> xcat ->
+ xcmds ->
+ -> xgrep ->
+ xhbeats ->
+ -> xhead ->
+ -> xmore
+ -> xmsg
+ xprops ->
+ -> xsort ->
+ -> xtail ->
+ xwho ->
+
+ the general syntax using pipes is:
+
+ cmd_a [arg_a] | cmd_b [arg_b] | ...
+
+ only the first space between cmd_a and arg_a or between cmd_a and the
+ first pipe symbol is necessary.
+
+ All functions which allow direct output into a pipe don't use a pager
+ to show its output even if no pipe follows this command. You may use
+ cmd [arg]|xmore to obtain the old results.
+
+- new commands xtail, xhead, xcat and xsort
+
+- command line option -v added to xgrep to print lines not matching the search
+ pattern
+
+- i/o redirection is coming soon
diff --git a/obj/tools/MGtool/toolcmd.c b/obj/tools/MGtool/toolcmd.c
new file mode 100644
index 0000000..83504b4
--- /dev/null
+++ b/obj/tools/MGtool/toolcmd.c
@@ -0,0 +1,2033 @@
+/*
+ * MGtool-1.0
+ * File: toolcmds.c
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#include "tool.h"
+
+/*----------------------------------------------------------------------
+ * command functions
+ */
+
+int Xcall(string str)
+{
+ object obj, callobj;
+ string file, callstr, callfun, callexpr, error, errlog;
+ int *ru1, *ru2, xtime;
+ mixed res;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xcall <object>-><function>(<arguments>)");
+ TK("Xcall: str: "+(str?str:"(NULL)"));
+ if(sscanf(str, "%s->%s(%s", callstr, callfun, callexpr)!=3)
+ return FALSE;
+ if(!(callobj=XFindObj(callstr)))
+ return TRUE;
+ else
+ {
+#if 0
+ write_file(TOOL_LOG,
+ sprintf("%s (%s) xcall %s (env: %s)\n",ctime(time()),
+ getuid(cloner),str,object_name(environment(cloner))));
+#endif
+ file=LPC_FILE+".c";
+ if(file_size(file)>0)
+ rm(file);
+ if(obj=find_object(LPC_FILE))
+ Destruct(obj);
+ obj=0;
+ write_file(file,
+ "#include <properties.h>\n"+
+ "#include <thing/properties.h>\n"+
+ "#include <defines.h>\n"+
+ "#include <wizlist.h>\n"+
+ "#include <moving.h>\n"+
+ "#include \"/secure/wizlevels.h\"\n"+
+ (file_size(PRIVATE_HEADER)>=0?"#include \""+PRIVATE_HEADER+"\"\n":"")+
+ "mixed get(string str){return previous_object()->XFindObj(str);}\n"+
+ "mixed eval(object obj,mixed me,mixed here){return obj->"+callfun+"("+callexpr+";}\n");
+ errlog = ERR_FILE;
+ if(file_size(errlog)>0)
+ rm(errlog);
+ if(error=catch((LPC_FILE)->__nixgibts__()))
+ W("Error: "+error[1..]);
+ else
+ {
+ obj=find_object(LPC_FILE);
+ ru1=rusage();
+ error=catch(res=(mixed)obj->eval(callobj, cloner, ENV(cloner)));
+ ru2=rusage();
+ if(error)
+ W("Error: "+error[1..]);
+ else
+ {
+ xtime=ru2[0]-ru1[0]+ru2[1]-ru1[1];
+ WDLN("Evaluation time: "+(xtime<0 ? 0 : xtime)+" ms");
+ PIPE_DELETE(pipe_of);
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,mixed_to_string(res, MAX_RECURSION)+"\n");
+ else
+ WLN("Result: "+mixed_to_string(res, MAX_RECURSION));
+ if(objectp(res))
+ m_add(variable, "result", res);
+ }
+ }
+ rm(file);
+ }
+ if(obj) Destruct(obj);
+ return TRUE;
+}
+
+int Xcallouts(string str)
+{
+ object obj;
+ mixed callouts, args;
+ string fun, tmp, file;
+ int delay, i, s;
+
+ SECURE2(TRUE);
+ TK("Xcallouts: str: "+(str?str:"(NULL)"));
+ if(!pipe_out)
+ {
+ USAGE1(str, "xcallo(uts) [search pattern]");
+ file=TMP_FILE;
+ if(file_size(file)>0)
+ rm(file);
+ if(!str)
+ str="^\\[~/";
+ else if(!regexp(({"dummy"}), str))
+ {
+ WDLN("Bad regular expression");
+ return TRUE;
+ }
+ }
+ else
+ {
+ USAGE1(str, "xcallo(uts)");
+ if(str&&str!="")
+ {
+ WDLN("More arguments than expected");
+ return TRUE;
+ }
+ }
+ callouts=call_out_info();
+ s=sizeof(callouts);
+ PIPE_DELETE(pipe_of);
+ for(i=0; i<s; i++)
+ {
+ if(callouts[i]&&pointerp(callouts[i]))
+ {
+ tmp=sprintf("%O %Os %O (%s)",callouts[i][0],callouts[i][2],
+ callouts[i][1],(sizeof(callouts[i])>3?
+ mixed_to_string(callouts[i][3],
+ MAX_RECURSION):"0"));
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,tmp+"\n");
+ else
+ if(sizeof(regexp(({tmp}), str)))
+ WLN(tmp);
+ }
+ }
+ return TRUE;
+}
+
+int Xcat(string str)
+{
+ string *tmp,file;
+ int s;
+
+ SECURE2(TRUE);
+ TK("Xcat: str: "+str);
+ if(!pipe_in)
+ {
+ USAGE2(str, "xcat <file>");
+ if(!(file=XFindFile(str)))
+ {
+ WDLN("Can't find file");
+ return TRUE;
+ }
+ }
+ else
+ {
+ if(str&&str!="-")
+ USAGE3("xcat -");
+
+ if (file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xcat");
+ return TRUE;
+ }
+ }
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n");
+ if(pipe_in&&pipe_if==PIPE_FILE)
+ rm(PIPE_FILE);
+ if (pipe_out&&pipe_of)
+ write_file(pipe_of,implode(tmp,"\n")+"\n");
+ else
+ WLN(implode(tmp,"\n"));
+ return TRUE;
+}
+
+int Xcd(string str)
+{
+ object dest;
+ string path;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xcd [object]");
+ TK("Xcd: str: "+(str?str:"(NULL)"));
+ if(!str)
+ {
+ if(!(path=(string)cloner->QueryProp("start_home")))
+ path="/";
+ }
+ else if((dest=XFindObj(str,1)))
+ path="/"+implode(old_explode(object_name(dest),"/")[0..<2],"/");
+ else
+ path="";
+
+ TK("Xcd: path: "+(path?path:"(NULL)"));
+ if(!sizeof(path))
+ path=str;
+ PL->_cd(path);
+
+ return TRUE;
+}
+
+int Xclean(string str)
+{
+ object env;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xcle(an) [object]");
+ TK("Xclean: str: "+(str?str:"(NULL)"));
+ if(!str)
+ env=ENV(cloner);
+ if(env||(env=XFindObj(str)))
+ {
+ PrintShort("Cleaning: ", env);
+ filter(filter(all_inventory(env), #'is_not_player),//'
+ "Destruct", ME);
+ }
+ return TRUE;
+}
+
+int Xclone(string str)
+{
+ object obj;
+ string file, errlog, error;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xclo(ne) <filename>");
+ if(!(file=XFindFile(str))) return TRUE;
+ errlog=ERR_FILE;
+ if(file_size(errlog)>0) rm(errlog);
+ WLN("Clone: "+short_path(file));
+ if(!(error=catch(obj=clone_object(file))))
+ {
+ m_add(variable, "clone", obj);
+ if(!MoveObj(obj, ENV(cloner), TRUE))
+ WDLN("Cannot move object into this room");
+ else if(!obj->QueryNoGet())
+ {
+ if(!MoveObj(obj, cloner, TRUE))
+ WDLN("Cannot move object into your inventory");
+ }
+ }
+ else
+ W("Error: "+error[1..]);
+ return TRUE;
+}
+
+int Xuclone(string str)
+{
+ object obj;
+ string file, errlog, error;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xuclo(ne) <filename>");
+ if(!(file=XFindFile(str))) return TRUE;
+ errlog=ERR_FILE;
+ if(file_size(errlog)>0) rm(errlog);
+ if(obj=find_object(file)) {
+ Destruct(obj);
+ WLN("Update and clone: "+short_path(file));
+ }
+ else
+ WLN("Clone: "+short_path(file));
+ if(!(error=catch(obj=clone_object(file))))
+ {
+ variable["clone"] = obj;
+ if(!MoveObj(obj, ENV(cloner), TRUE))
+ WDLN("Cannot move object into this room");
+ else if(!obj->QueryNoGet())
+ {
+ if(!MoveObj(obj, cloner, TRUE))
+ WDLN("Cannot move object into your inventory");
+ }
+ }
+ else
+ W("Error: "+error[1..]);
+ return TRUE;
+}
+
+int Xcmds(string str)
+{
+ object obj;
+ mixed *cmds;
+ int i, s;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xcm(ds) [object]");
+ TK("Xcmds: str: "+(str?str:"(NULL)"));
+ if(!str)
+ obj=ENV(cloner);
+ else if(!(obj=XFindObj(str)))
+ {
+ WDLN("Can't find object");
+ return TRUE;
+ }
+ s=sizeof(cmds=query_actions(cloner,1|2|4|8|16));
+ PIPE_DELETE(pipe_of);
+ for(i=0; i<s; i+=5)
+ if(cmds[i+3]==obj)
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,ALEFT(cmds[i]+" ", 15, ".")+
+ (cmds[i+2] ? " * " : " . ")+cmds[i+4]+"()\n");
+ else
+ WLN(ALEFT(cmds[i]+" ", 15, ".")+
+ (cmds[i+2] ? " * " : " . ")+cmds[i+4]+"()");
+ return TRUE;
+}
+
+int Xdbg(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xdb(g) <object>");
+ TK("Xdbg: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ {
+ debug_info(1, obj);
+ debug_info(0, obj);
+ }
+ return TRUE;
+}
+
+int Xdclean(string str)
+{
+ object env;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xdc(lean) [object]");
+ TK("Xdclean: str: "+(str?str:"(NULL)"));
+ if(!str)
+ env=ENV(cloner);
+ if(env||(env=XFindObj(str)))
+ {
+ PrintShort("Deep cleaning: ", env);
+ filter(filter(all_inventory(env), #'is_not_player, ME),//'
+ "DeepClean", ME);
+ }
+ return TRUE;
+}
+
+int Xddes(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xdd(es) <object>");
+ TK("Xddes: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ {
+ PrintShort("Deep destruct: ", obj);
+ filter(deep_inventory(obj), "Destruct", ME);
+ Destruct(obj);
+ }
+ return TRUE;
+}
+
+int Xdes(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xde(s) <object>");
+ TK("Xdes: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ {
+ PrintShort("Destruct: ",obj);
+ Destruct(obj);
+ }
+ return TRUE;
+}
+
+int Xdlook(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xdl(ook) [object]");
+ TK("Xdlook: str: "+(str?str:"(NULL)"));
+ if(!str)
+ obj=cloner;
+ if(obj||(obj=XFindObj(str)))
+ {
+ PIPE_DELETE(pipe_of);
+ DeepPrintShort(obj,NULL,NULL,(pipe_out&&pipe_of)?pipe_of:"");
+ }
+ return TRUE;
+}
+
+int Xdo(string str)
+{
+ int i, n, s;
+ string *strs, cmd;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xdo [<number1>#]<command1>[;[<number2>#]<command2>] ...");
+ if(!str||str==""||!(s=sizeof(strs=strip_explode(str, ";"))))
+ return FALSE;
+ for(i=0; i<s; i++)
+ {
+ if(strs[i])
+ {
+ switch(sscanf(strs[i], "%d#%s", n, cmd))
+ {
+ case 0:
+ if(!Command(strs[i])) return TRUE;
+ break;
+ case 1:
+ if(cmd&&(!Command(cmd))) return TRUE;
+ break;
+ case 2:
+ n= n<1 ? 1 : n;
+ if(cmd)
+ {
+ while(n--)
+ if(!Command(cmd)) return TRUE;
+ }
+ break;
+ }
+ }
+ }
+ return TRUE;
+}
+
+int Xdupdate(string str)
+{
+ int i, s;
+ object obj;
+ string file, *list;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xdu(pdate) <filename>");
+ if(!(file=XFindFile(str)))
+ return TRUE;
+ if(file[<2..<1]==".c")
+ file=file[0..<3];
+ if(obj=XFindObj(file))
+ {
+ PrintShort("Deep updating: ", obj);
+ list=inherit_list(obj);
+ for(s=sizeof(list); i<s; i++)
+ {
+ if(obj=find_object(list[i]))
+ Destruct(obj);
+ }
+ }
+ return TRUE;
+}
+
+int Xecho(string str)
+{
+ TK("Xecho: str: "+(str?str:"(NULL)"));
+ WLN(str);
+ return TRUE;
+}
+
+int Xeval(string str)
+{
+ object obj;
+ string file, error;
+ int *ru1, *ru2, xtime;
+ mixed res;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xev(al) <expression>");
+ file=LPC_FILE+".c";
+ if(file_size(file)>0)
+ rm(file);
+ if(obj=find_object(LPC_FILE))
+ Destruct(obj);
+#if 0
+ write_file(TOOL_LOG,
+ sprintf("%s (%s) xeval %s\n",
+ ctime(time()),getuid(cloner),str));
+#endif
+ write_file(file,
+ "#include <properties.h>\n"+
+ "#include <thing/properties.h>\n"+
+ "#include <defines.h>\n"+
+ "#include <wizlist.h>\n"+
+ "#include <moving.h>\n"+
+ "#include \"/secure/wizlevels.h\"\n"+
+ (file_size(PRIVATE_HEADER)>=0?"#include \""+PRIVATE_HEADER+"\"\n":"")+
+ "get(str){return previous_object()->XFindObj(str);}\n"+
+ "eval(me,here){return "+str+";}");
+ if(error=catch(obj=clone_object(file)))
+ W("Error: "+error[1..]);
+ else
+ {
+ ru1=rusage();
+ error=catch(res=(mixed)obj->eval(cloner, ENV(cloner)));
+ ru2=rusage();
+ if(error)
+ W("Error: "+error[1..]);
+ else
+ {
+ xtime=ru2[0]-ru1[0]+ru2[1]-ru1[1];
+ WDLN("Evaluation time: "+(xtime<0 ? 0 : xtime)+" ms");
+ PIPE_DELETE(pipe_of);
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,mixed_to_string(res,MAX_RECURSION)+"\n");
+ else
+ WLN("Result: "+mixed_to_string(res, MAX_RECURSION));
+ if(objectp(res))
+ variable["result"] = res;
+ }
+ }
+ rm(file);
+ if(obj)
+ Destruct(obj);
+ return TRUE;
+}
+
+int Xforall(string str)
+{
+ int i, s, t, u;
+ string pat, cmd, arg, *strs, *files, fh, fr, fe, ft, ff;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xfo(rall) <filepattern> <command>");
+ if(sscanf(str, "%s %s", pat, arg)!=2)
+ return FALSE;
+ files=long_get_dir(pat, FALSE);
+ if(!(s=sizeof(files)))
+ {
+ WDLN("No matching files found");
+ return TRUE;
+ }
+ strs=old_explode(files[0], "/");
+ fh="/";
+ if(t=sizeof(strs)-1)
+ fh+=implode(strs[0..t-1], "/");
+ for(i=0; i<s; i++)
+ {
+ ft=old_explode(files[i], "/")[t];
+ if((u=sizeof(strs=old_explode(ft, ".")))&&--u)
+ {
+ ff=implode(strs[0..u-1], ".");
+ fr=fh+"/"+ff;
+ fe=strs[u];
+ }
+ else
+ {
+ fe="";
+ ff=ft;
+ fr=files[i];
+ }
+ cmd=string_replace(arg, "!!", files[i]);
+ cmd=string_replace(cmd, "!e", fe);
+ cmd=string_replace(cmd, "!f", ff);
+ cmd=string_replace(cmd, "!h", fh);
+ cmd=string_replace(cmd, "!r", fr);
+ cmd=string_replace(cmd, "!t", ft);
+ if(!(Command(cmd)))
+ break;
+ }
+ return TRUE;
+}
+
+int Xgoto(string str)
+{
+ object obj, tmp;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xgo(to) [object]");
+ if(!str) str="~/workroom";
+ if(!(obj=XFindObj(str)))
+ {
+ if(!(str=XFindFile(str)))
+ return TRUE;
+ if(catch(call_other(str, "???")))
+ return TRUE;
+ obj=find_object(str);
+ }
+ tmp=obj;
+ while(obj&&living(obj))
+ obj=ENV(obj);
+ cloner->move(obj ? obj : tmp, M_TPORT);
+ return TRUE;
+}
+
+int Xgrep(string str)
+{
+ int i, s, t, mode;
+ string *files, *ts;
+
+ SECURE2(TRUE);
+ TK("Xgrep: str: "+(str?str:"(NULL)"));
+ mode=0;
+ if(!pipe_in)
+ {
+ USAGE2(str, "xgr(ep) [-i] [-v] <regexp> <filepattern>");
+ if(!(ts=old_explode(str, " "))||!(s=sizeof(ts)))
+ return FALSE;
+ while(ts[0][0]=='-')
+ {
+ if(s<3)
+ {
+ WDLN("Too few arguments to xgrep");
+ return FALSE;
+ }
+ switch(ts[0])
+ {
+ case "-v":
+ mode|=XGREP_REVERT;
+ ts=ts[1..];
+ s--;
+ break;
+ case "-i":
+ mode|=XGREP_ICASE;
+ ts=ts[1..];
+ s--;
+ break;
+ case "-vi":
+ case "-iv":
+ mode|=XGREP_REVERT;
+ mode|=XGREP_ICASE;
+ ts=ts[1..];
+ s--;
+ break;
+ default:
+ WDLN("Unknown option "+ts[0]+" given to xgrep");
+ return FALSE;
+ }
+ }
+ str=implode(ts[0..s-2], " ");
+ }
+ else
+ {
+ if(!((ts=old_explode(str, " "))&&(s=sizeof(ts))))
+ USAGE3("xgr(ep) [-i] [-v] <regexp>");
+ while(ts[0][0]=='-')
+ {
+ if(s<2)
+ {
+ WDLN("Too few arguments to xgrep");
+ return FALSE;
+ }
+ switch(ts[0])
+ {
+ case "-v":
+ mode|=XGREP_REVERT;
+ ts=ts[1..];
+ s--;
+ break;
+ case "-i":
+ mode|=XGREP_ICASE;
+ ts=ts[1..];
+ s--;
+ break;
+ case "-iv":
+ case "-vi":
+ mode|=XGREP_REVERT;
+ mode|=XGREP_ICASE;
+ ts=ts[1..];
+ s--;
+ break;
+ default:
+ WDLN("Unknown option "+ts[0]+" given to xgrep");
+ return FALSE;
+ }
+ }
+ str=implode(ts[0..s-1], " ");
+ }
+
+ if(mode&XGREP_ICASE)
+ str=lower_case(str);
+ if(!(regexp(({"dummy"}), str)))
+ {
+ WDLN("Bad regular expression");
+ return TRUE;
+ }
+ if(!pipe_in)
+ {
+ if(file_size(TMP_FILE)>0)
+ rm(TMP_FILE);
+ if((t=sizeof(files=long_get_dir(XFile(ts[s-1]), FALSE)))&&
+ (file_size(files[0])>=0))
+ {
+ for(i=0; i<t; i++)
+ XGrepFile(str, files[i], mode);
+ if(pipe_out&&pipe_of)
+ {
+ PIPE_DELETE(pipe_of);
+ if(!pipe_ovr)
+ {
+ write_file(pipe_of,read_file(TMP_FILE,0,PIPE_MAX));
+ rm(TMP_FILE);
+ }
+ else
+ rename(TMP_FILE,pipe_of);
+ }
+ else
+ {
+ W(read_file(TMP_FILE,0,PIPE_MAX));
+ rm(TMP_FILE);
+ }
+ }
+ else
+ WDLN("Cannot read file(s)");
+ }
+ else
+ {
+ string *tmp;
+ if(file_size(pipe_if)<0)
+ {
+ WDLN("Missing input to xgrep");
+ return TRUE;
+ }
+ TK("Xgrep: str: "+str+" mode: "+mode);
+ s=sizeof(tmp=old_explode(read_file(pipe_if,0,PIPE_MAX),"\n"));
+ PIPE_DELETE(pipe_of);
+ for(i=0;i<s;i++)
+ {
+ // TK(tmp[i]+"<->"+str);
+ if(sizeof(regexp(({(mode&XGREP_ICASE?lower_case(tmp[i]):tmp[i])}),str)))
+ {
+ // TK("Xgrep: matched!");
+ if(!(mode&XGREP_REVERT))
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,tmp[i]+"\n");
+ else
+ WLN(tmp[i]);
+ }
+ else
+ if(mode&XGREP_REVERT)
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,tmp[i]+"\n");
+ else
+ WLN(tmp[i]);
+ }
+ }
+ return TRUE;
+}
+
+int Xhbeats(string str)
+{
+ object obj;
+ object *hbeatinfo;
+ string tmp, file;
+ int i, s;
+
+ SECURE2(TRUE);
+ TK("Xhbeats: str: "+(str?str:"(NULL)"));
+ if(!pipe_out)
+ {
+ USAGE1(str, "xhb(eats) [search pattern]");
+ if(!str)
+ str=RNAME(cloner);
+ else if(!regexp(({"dummy"}), str))
+ {
+ WDLN("Bad regular expression");
+ return TRUE;
+ }
+ }
+ else
+ {
+ USAGE1(str,"xhb(eats)");
+ if(str&&str!="")
+ {
+ WDLN("More arguments than expected");
+ return TRUE;
+ }
+ }
+ s=sizeof(hbeatinfo=heart_beat_info());
+ PIPE_DELETE(pipe_of);
+ for(i=0; i<s; i++)
+ if(hbeatinfo[i]&&objectp(hbeatinfo[i]))
+ {
+ tmp=ObjFile(hbeatinfo[i]);
+ if(sizeof(regexp(({tmp}), str)))
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of, tmp+"\n");
+ else
+ WLN(tmp);
+ }
+ return TRUE;
+}
+
+int Xhead(string str)
+{
+ int lines;
+ string *tmp, file;
+
+ SECURE2(TRUE);
+ TK("Xhead: str: "+(str?str:"(NULL)"));
+ if(!pipe_in)
+ {
+ USAGE2(str, "xhead <-#> <file>");
+ if(sscanf(str,"-%d %s",lines,file)!=2)
+ return FALSE;
+ if(!(file=XFindFile(file)))
+ return FALSE;
+ }
+ else
+ {
+ USAGE2(str, "xhead <-#>");
+ if(sscanf(str,"-%d",lines)!=1)
+ return FALSE;
+ if (file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xhead");
+ return TRUE;
+ }
+ }
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n")[0..lines-1];
+ if(pipe_in&&pipe_if==PIPE_FILE)
+ rm(PIPE_FILE);
+ if (pipe_out&&pipe_of)
+ {
+ PIPE_DELETE(pipe_of);
+ write_file(pipe_of,implode(tmp,"\n")+"\n");
+ }
+ else
+ WDLN(implode(tmp,"\n"));
+ return TRUE;
+}
+
+int Xhelp(string str)
+{
+ SECURE2(TRUE);
+ USAGE1(str, "xhe(lp)");
+ XMoreFile(TOOL_MANPAGE, FALSE);
+ return TRUE;
+}
+
+int Xids(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xid(s) <object>");
+ TK("Xids: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ WLN("UID=\""+getuid(obj)+"\" / EUID=\""+geteuid(obj)+"\"");
+ return TRUE;
+}
+
+int Xinfo(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xinf(o) <object>");
+ TK("Xinfo: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ {
+ if(is_player(obj))
+ {
+ WLN(PlayerWho(obj));
+ WLN(PlayerMail(obj, FALSE));
+ WLN(PlayerIP(obj, FALSE));
+ WLN(PlayerRace(obj, FALSE));
+ WLN(PlayerDomain(obj, FALSE));
+ WLN(PlayerStats(obj, FALSE));
+ WLN(PlayerSnoop(obj, FALSE));
+ }
+ else
+ WDLN("Sorry, this is not a player");
+ }
+ return TRUE;
+}
+
+int Xinherit(string str)
+{
+ int s;
+ object obj;
+ string *strs, *inlist;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xinh(erit) <object> [function]");
+ TK("Xinherit: str: "+str);
+ if(!(strs=strip_explode(str, " ")))
+ return FALSE;
+ if(obj=XFindObj(strs[0]))
+ {
+ inlist=inherit_list(obj);
+ s=sizeof(inlist);
+ while(s--)
+ {
+ if(catch(call_other(inlist[s], "???")))
+ {
+ WDLN("Failed to load all inheritance objects");
+ return TRUE;
+ }
+ }
+ obj=find_object(inlist[0]);
+ PIPE_DELETE(pipe_of);
+ if(sizeof(strs)==1)
+ Inheritance(obj ,0 ,"");
+ else
+ Inheritance(obj, strs[1], "");
+ }
+ return TRUE;
+}
+
+int Xinventory(string str)
+{
+ int i, short;
+ object item;
+ mixed who;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xi [-s] [player]");
+ TK("Xinventory: str: "+str);
+ short=0;
+ who=cloner;
+ if(str&&str!="")
+ {
+ if(str=="-s")
+ {
+ short=1;
+ who=cloner;
+ }
+ else if(sscanf(str,"-s %s",who))
+ {
+ short=1;
+ who=XFindObj(who);
+ }
+ else if(sscanf(str,"%s",who))
+ {
+ short=0;
+ who=XFindObj(who);
+ }
+ else
+ who=cloner;
+ }
+ if(!who)
+ return FALSE;
+ PIPE_DELETE(pipe_of);
+ if(!(pipe_out&&pipe_of))
+ WLN(who->name(WESSEN)+" Inventory:"+(short?" (short)":""));
+ if(!short)
+ if(pipe_out&&pipe_of)
+ FORALL(item, who) PrintShort(ARIGHT(++i+". ", 4, " "), item, pipe_of);
+ else
+ FORALL(item, who) PrintShort(ARIGHT(++i+". ", 4, " "), item);
+ else
+ if(pipe_out&&pipe_of)
+ FORALL(item, who) write_file(pipe_of,++i+". ["+object_name(item)+"]\n");
+ else
+ FORALL(item, who) WLN(++i+". ["+object_name(item)+"]");
+ return TRUE;
+}
+
+int Xlag(string str)
+{
+ int i;
+ float *lag;
+ object daemon;
+ string lags;
+
+ if(file_size(LAG_O_DAEMON+".c")<=0)
+ {
+ WLN("Sorry, lag-o-daemon is missing!");
+ return TRUE;
+ }
+
+ LAG_O_DAEMON->MachHin();
+ if(!(daemon=find_object(LAG_O_DAEMON)))
+ lag=({-1.0,-1.0,-1.0});
+ else
+ lag=(float *)daemon->read_lag_data();
+ lags="Letzte 60 min: ";
+ if(lag[0]>=0.0)
+ {
+ for(i=round(lag[0])-1;i>=0;i--)
+ lags+="#";
+ lags+=" ("+sprintf("%.1f",lag[0])+"%)";
+ }
+ else
+ lags+="N/A";
+ lags+="\nLetzte 15 min: ";
+ if(lag[1]>=0.0)
+ {
+ for(i=round(lag[1])-1;i>=0;i--)
+ lags+="#";
+ lags+=" ("+sprintf("%.1f",lag[1])+"%)";
+ }
+ else
+ lags+="N/A";
+ lags+="\nLetzte Minute: ";
+ if(lag[2]>=0.0)
+ {
+ for(i=round(lag[2])-1;i>=0;i--)
+ lags+="#";
+ lags+=" ("+sprintf("%.1f",lag[2])+"%)";
+ }
+ else
+ lags+="N/A";
+ WLN(lags);
+ return TRUE;
+}
+
+int Xlight(string str)
+{
+ int s, addlight;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xli(ght) [light]");
+ if(str)
+ {
+ if(!sscanf(str, "%d", addlight))
+ return FALSE;
+ xlight+=addlight;
+ cloner->AddIntLight(addlight);
+ }
+ WDLN("Current light levels: "+TOOL_NAME+"="+xlight+", room="+
+ ENV(cloner)->QueryIntLight());
+ return TRUE;
+}
+
+int Xload(string str)
+{
+ int i, f;
+ object obj, *inv, vroom;
+ string file, errlog, error, *strs;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xloa(d) <filename>");
+ if(!(file=XFindFile(str)))
+ return TRUE;
+ errlog=ERR_FILE;
+ if(file_size(errlog)>0)
+ rm(errlog);
+ if(obj=find_object(file))
+ {
+ if(catch(call_other(VOID, "???")))
+ {
+ WDLN("Error: cannot find "+VOID+" to rescue players");
+ return TRUE;
+ }
+ else
+ vroom = find_object(VOID);
+ if(inv=filter(all_inventory(obj), #'is_player, ME))//'
+ for(i=0; i<sizeof(inv); i++)
+ MoveObj(inv[i], vroom, TRUE);
+ Destruct(obj);
+ WLN("Update and load: "+file);
+ }
+ else
+ WLN("Load: "+file);
+ if(error=catch(call_other(file, "???")))
+ {
+ W("Error: "+error[1..]);
+ if(vroom)
+ tell_object(vroom, "*** Failed to load room. You are in the void!\n");
+ }
+ else if(inv)
+ {
+ obj=find_object(file);
+ for(i=0; i<sizeof(inv); i++)
+ if(inv[i])
+ MoveObj(inv[i], obj, TRUE);
+ }
+ return TRUE;
+}
+
+int Xlook(string str)
+{
+ object obj;
+ string st;
+ string file;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xloo(k) [object]");
+ TK("Xlook: str: "+str);
+ PIPE_DELETE(pipe_of);
+ file = pipe_out&&pipe_of ? pipe_of : "";
+ if(str&&str!="")
+ {
+ if((obj=XFindObj(str)))
+ PrintObj(obj,file);
+ }
+ else
+ {
+ obj=ENV(cloner);
+ PrintObj(obj,file);
+ }
+ return TRUE;
+}
+
+int Xlpc(string str)
+{
+ object obj;
+ string file, error;
+ int *ru1, *ru2, time;
+ mixed res;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xlp(c) <lpc code>");
+ file=LPC_FILE+".c";
+ if(file_size(file)>0)
+ rm(file);
+ if(obj=find_object(LPC_FILE))
+ Destruct(obj);
+ write_file(file,
+ "#pragma no_warn_missing_return,strong_types,warn_deprecated,rtt_checks\n"
+ "#include <properties.h>\n"
+ "#include <thing/properties.h>\n"
+ "#include <defines.h>\n"
+ "#include <wizlist.h>\n"
+ "#include <moving.h>\n"
+ "#include \"/secure/wizlevels.h\"\n"
+ +(file_size(PRIVATE_HEADER)>=0?"#include \""+PRIVATE_HEADER+"\"\n":"")+
+ "object get(string str){return previous_object()->XFindObj(str);}\n"+
+ "mixed eval(mixed me, mixed here){"+str+"}");
+ if(error=catch(obj=clone_object(file)))
+ W("Error: "+error[1..0]);
+ else
+ {
+ ru1=rusage();
+ error=catch(res=(mixed)obj->eval(cloner, ENV(cloner)));
+ ru2=rusage();
+ if(error)
+ W("Error: "+error[1..]);
+ else
+ {
+ time=ru2[0]-ru1[0]+ru2[1]-ru1[1];
+ WDLN("Evaluation time: "+(time<0 ? 0 : time)+" ms");
+ WLN("Result: "+mixed_to_string(res, MAX_RECURSION));
+ if(objectp(res))
+ variable["result"] = res;
+ }
+ }
+ rm(file);
+ if(obj)
+ Destruct(obj);
+ return TRUE;
+}
+
+int Xman(string str)
+{
+ string manpage;
+ int i, found;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xma(n) <manpage>");
+ W("Man: ");
+ for(i=0, found=0; i<sizeof(manpath); i++)
+ {
+ manpage=manpath[i]+str;
+ if(file_size(manpage)>=0)
+ {
+ WLN(manpage);
+ XMoreFile(manpage, FALSE);
+ found=1;
+ break;
+ }
+ }
+ if(!found)
+ WLN("- no help available -");
+ return TRUE;
+}
+
+int Xmore(string str)
+{
+ string *args, file;
+ int line;
+
+ SECURE2(TRUE);
+ TK("Xmore: str: "+str);
+ if (!pipe_in)
+ {
+ USAGE2(str, "xmor(e) <filename> [start]");
+ switch(sizeof(args=strip_explode(str, " ")))
+ {
+ case 1:
+ moreoffset=1;
+ break;
+ case 2:
+ sscanf(args[1], "%d", line);
+ moreoffset= line>0 ? line : 1;
+ break;
+ default:
+ return FALSE;
+ }
+ if(file=XFindFile(args[0]))
+ XMoreFile(file, TRUE);
+ }
+ else
+ {
+ if(file_size(pipe_if)<0)
+ {
+ WDLN("Missing input to xmore");
+ return TRUE;
+ }
+ if (!str||str=="")
+ line=1;
+ else if (sscanf(str, "%d", line)!=1)
+ USAGE3("xmor(e) [start]");
+ moreoffset= line>0 ? line : 1;
+ XMoreFile(pipe_if, TRUE);
+ }
+ return TRUE;
+}
+
+int Xmove(string str)
+{
+ object obj1, obj2;
+ string what, into;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xmov(e) <object> into <object>");
+ if((sscanf(str, "%s into %s", what, into)==2)&&
+ (obj1=XFindObj(what))&&(obj2=XFindObj(into)))
+ MoveObj(obj1, obj2, FALSE);
+ return TRUE;
+}
+
+int Xmsg(string str)
+{
+ string tmp;
+
+ SECURE2(TRUE);
+ TK("Xmsg: str: "+str);
+ USAGE1(str, "xms(g) [to <object>|all]");
+ if(!str||str=="")
+ {
+ WDLN("Send message into room");
+ say("Message from "+CRNAME(cloner)+":\n");
+ if(pipe_in&&pipe_if)
+ say(read_file(pipe_if,0,PIPE_MAX));
+ else
+ {
+ WDLN("End message with \".\" or \"**\"");
+ input_to("XMsgSay");
+ }
+ return TRUE;
+ }
+ else if(sscanf(str, "to %s", tmp))
+ {
+ if(msgto=XFindObj(tmp))
+ {
+ PrintShort("Send message to: ", msgto);
+ tell_object(msgto, "Message from "+CRNAME(cloner)+" to you:\n");
+ if(pipe_in&&pipe_if)
+ tell_object(msgto,read_file(pipe_if,0,PIPE_MAX));
+ else
+ {
+ WDLN("End message with \".\" or \"**\"");
+ input_to("XMsgTell");
+ }
+ }
+ return TRUE;
+ }
+ else if(str=="all")
+ {
+ WDLN("Send message to all players");
+ shout("Message from "+CRNAME(cloner)+" to all:\n");
+ if(pipe_in&&pipe_if)
+ shout(read_file(pipe_if,0,PIPE_MAX));
+ else
+ {
+ WDLN("End message with \".\" or \"**\"");
+ input_to("XMsgShout");
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int Xmtp(string str)
+{
+ int s;
+ string *strs, opt, dir, file;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xmt(p) [options] <directory> <filename>");
+ s=sizeof(strs=old_explode(str, " "));
+ if(s<2)
+ return FALSE;
+ else if(s==2)
+ opt="";
+ else
+ opt=implode(strs[0..s-3], " ");
+ if(!(dir="/"+(string)MASTER->valid_read(strs[s-2], geteuid(),
+ "get_dir", ME))) {
+ WDLN("No permission to open directory for reading");
+ return TRUE;
+ }
+ if(!(file="/"+(string)MASTER->valid_write(strs[s-1], geteuid(),
+ "write_file", ME))) {
+ WDLN("No permission to open script file for writing");
+ return TRUE;
+ }
+ if(file_size(dir)!=-2 || file_size(file)==-2)
+ return FALSE;
+ XmtpScript(dir, file, opt);
+ WDLN("Done");
+ return TRUE;
+}
+
+int Xproc(string str)
+{
+ int s;
+ string *strs;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xproc [-c] [-l] [-m] [-u] [-v]");
+
+ if(file_size(TOOL_PATH+"/proc")!=-2)
+ {
+ WLN("Sorry, no /proc information available!");
+ return TRUE;
+ }
+
+ if(!str||str==""||!(s=sizeof(strs=old_explode(str, " "))))
+ {
+ WLN("Load averages:");
+ cat(TOOL_PATH+"/proc/loadavg");
+ return TRUE;
+ }
+
+ while(s=sizeof(strs))
+ {
+ switch(strs[0])
+ {
+ case "-c":
+ WLN("CPU info:");
+ cat(TOOL_PATH+"/proc/cpuinfo");
+ break;
+ case "-l":
+ WLN("Load averages:");
+ cat(TOOL_PATH+"/proc/loadavg");
+ break;
+ case "-m":
+ WLN("Memory usage:");
+ cat(TOOL_PATH+"/proc/meminfo");
+ break;
+ case "-u":
+ WLN("Uptime:");
+ cat(TOOL_PATH+"/proc/uptime");
+ break;
+ case "-v":
+ WLN("Version:");
+ cat(TOOL_PATH+"/proc/version");
+ break;
+ default:
+ WLN("Unknown option: "+strs[0]);
+ }
+ strs=strs[1..];
+ }
+ return TRUE;
+}
+
+int Xprof(string str)
+{
+ string *funcs, inh, tmp;
+ mixed *data, *d;
+ mapping xpr;
+ object obj;
+ int i, rn;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xprof <<-c>|<-C> <file>>|<object>");
+ if(str[0..2]=="-c "||str[0..2]=="-C ")
+ {
+ rn=(str[1]=='C');
+ if(str=XFindFile(str[3..]))
+ {
+ inh=str=str[0..<3];
+ if(obj=find_object(inh))
+ Destruct(obj);
+ if(catch(call_other(inh,"???")))
+ return TRUE;
+ obj=find_object(inh);
+ if(rn)
+ {
+ inh+=".xprof.c";
+ rm(inh);
+ str+=".c";
+ rename(str, inh);
+ }
+ else
+ {
+ str=XPROF_FILE;
+ rm(str);
+ }
+ tmp="inherit \""+inh+"\";\n#include \""+XPROF_MACRO+"\"\n";
+ funcs=m_indices(mkmapping(functionlist(obj, 0x08000001)))-({"__INIT"});
+ for(i=sizeof(funcs); i--;)
+ tmp+="F("+funcs[i]+",\""+funcs[i]+"\","+
+ "(A0,A1,A2,A3,A4,A5,A6,A7,A8,A9))\n";
+ write_file(str, tmp);
+ WDLN("Done");
+ }
+ }
+ else if(obj=XFindObj(str))
+ {
+ if(xpr=(mapping)obj->__query_xprof_data__())
+ {
+ funcs=m_indices(xpr);
+ data=m_values(xpr);
+ rm(TMP_FILE);
+ str="Evaluation cost per function:\nNAME "+
+ " CALLS | TOT.EXCL. TOT.INCL. | REL.EXCL. REL.INCL.\n";
+ for(i=sizeof(funcs); i--;)
+ {
+ if(d=data[i]) {
+ funcs[i]=ALEFT(""+funcs[i]+" ",25,".")+ARIGHT(" "+d[0], 6,".")+" | "+
+ ARIGHT(" "+d[1],10,".") +" "+ARIGHT(" "+d[3],10,".")+" | "+
+ ARIGHT(" "+d[1]/d[0],9,".") +" "+ARIGHT(" "+d[3]/d[0],9,".");
+ }
+ }
+ str+=implode(sort_array(funcs, "string_compare", ME),"\n")+"\n";
+ write_file(TMP_FILE,str);
+ str="\nElapsed time per function:\nNAME "+
+ " CALLS | TOT.EXCL. TOT.INCL. | REL.EXCL. REL.INCL.\n";
+ funcs=m_indices(xpr);
+ for(i=sizeof(funcs); i--;)
+ {
+ if(d=data[i])
+ {
+ funcs[i]=ALEFT(""+funcs[i]+" ",25,".")+ARIGHT(" "+d[0], 6,".")+" | "+
+ ARIGHT(" "+(d[2]+5)/10+"ms",10,".")+" "+
+ ARIGHT(" "+(d[4]+5)/10+"ms",10,".")+" | "+
+ ARIGHT(" "+d[2]/d[0]+"us",9,".")+" "+
+ ARIGHT(" "+d[4]/d[0]+"us",9,".");
+ }
+ }
+ str+=implode(sort_array(funcs, "string_compare", ME),"\n")+"\n";
+ write_file(TMP_FILE,str);
+ XMoreFile(TMP_FILE, FALSE);
+ }
+ else
+ WDLN("No profiling information available");
+ }
+ return TRUE;
+}
+
+int Xprops(string str)
+{
+ int i, s, flag;
+ object obj;
+ string *tmp;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xprop(s) [-f|-m] <object>");
+ TK("Xprops: str: "+str);
+ tmp=old_explode(str," ");
+ switch(tmp[0])
+ {
+ case "-f":
+ {
+ flag = 1;
+ tmp=tmp[1..];
+ break;
+ }
+ case "-m":
+ {
+ flag = 2;
+ tmp=tmp[1..];
+ break;
+ }
+ }
+ str=implode(tmp," ");
+ if((obj=XFindObj(str)))
+ DumpProperties(obj,flag);
+ return TRUE;
+}
+
+int Xquit(string str)
+{
+ SECURE2(TRUE);
+ USAGE1(str, "xqu(it)");
+ str=object_name(ENV(cloner));
+ if(member(str, '#')<0)
+ cloner->set_home(str);
+ cloner->quit();
+ return TRUE;
+}
+
+int Xscan(string str)
+{
+ SECURE2(TRUE);
+ USAGE1(str, "xsc(an)");
+ W("Destructed variable(s): ");
+ string* oldvars=m_indices(variable);
+ VarCheck(FALSE);
+ string* desvars=oldvars-m_indices(variable);
+ desvars = map(desvars, function string (string k)
+ {return "$"+k;} );
+ W(CountUp(desvars));
+ WLN("");
+ return TRUE;
+}
+
+int Xset(string str)
+{
+ int i;
+ mixed obj;
+ string name, tmp;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xse(t) [$<name>=<object>]");
+ if(str) {
+ if(member(({"$me","$m","$here","$h"}),str)!=-1)
+ WDLN("Sorry, this is a reserved variable ["+str+"]");
+ else if(sscanf(str, "$%s=%s", name, tmp))
+ {
+ if(obj=XFindObj(tmp))
+ {
+ variable[name] = obj;
+ WLN(" $"+name+"="+ObjFile(obj));
+ }
+ }
+ else
+ return FALSE;
+ }
+ else
+ {
+ VarCheck(FALSE);
+ WLN("Current settings:");
+ foreach(string key, mixed val : variable)
+ {
+ if (val)
+ WLN(" $"+key+"="+ObjFile(val));
+ else
+ m_delete(variable, key);
+ }
+ WLN(" $me="+ObjFile(cloner));
+ WLN(" $here="+ObjFile(ENV(cloner)));
+ }
+ return TRUE;
+}
+
+int Xsh(string str)
+{
+ SECURE2(TRUE);
+ USAGE1(str, "xsh <filename>");
+ if(scriptline)
+ {
+ WDLN("Cannot execute another script file until last execution has ended");
+ return TRUE;
+ }
+ if(!(str=XFindFile(str)))
+ return TRUE;
+ str=read_file(str, 1, 1000);
+ if(!(scriptline=old_explode(str, "\n")))
+ {
+ WDLN("Bad script file");
+ return TRUE;
+ }
+ scriptsize=sizeof(scriptline);
+ XExecFile(NULL);
+ return TRUE;
+}
+
+int Xsort(string str)
+{
+ string *tmp,file;
+ int s,reverse;
+
+ SECURE2(TRUE);
+ TK("Xsort: str: "+str);
+ if(!pipe_in)
+ {
+ USAGE2(str, "xso(rt) [-r] [file]");
+ if(!(tmp=old_explode(str, " "))||(s=sizeof(tmp))>2)
+ return FALSE;
+ if(tmp[0]=="-r")
+ if(s==1)
+ return FALSE;
+ else
+ {
+ reverse=TRUE;
+ tmp=tmp[1..];
+ }
+ else if(s>1)
+ return FALSE;
+ if(!(file=XFindFile(tmp[0])))
+ {
+ WDLN("Can't find file");
+ return TRUE;
+ }
+ }
+ else
+ {
+ if(str&&str!="")
+ if(str=="-r")
+ reverse=TRUE;
+ else
+ USAGE3("xso(rt) [-r]");
+ if (file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xsort");
+ return TRUE;
+ }
+ }
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n");
+ if(pipe_in&&pipe_if==PIPE_FILE)
+ rm(PIPE_FILE);
+ tmp=sort_array(tmp,reverse?#'<:#'>);
+ if (pipe_out&&pipe_of)
+ write_file(pipe_of,implode(tmp,"\n")+"\n");
+ else
+ WDLN(implode(tmp,"\n"));
+ return TRUE;
+}
+
+int Xtail(string str)
+{
+ string *tmp,file,sign;
+ int lines;
+
+ if (!str) {
+ WDLN("Missing input to xtail");
+ return TRUE;
+ }
+
+ sign="-";
+ lines=10;
+ SECURE2(TRUE);
+ TK("Xtail: str: "+str);
+ if(!pipe_in)
+ {
+ if(sscanf(str,"-%d %s",lines,file)==2)
+ sign="-";
+ else if(sscanf(str,"+%d %s",lines,file)==2)
+ sign="+";
+ else
+ file=str;
+
+ if(!(file=XFindFile(file)))
+ {
+ WDLN("Can't find file");
+ return TRUE;
+ }
+ }
+ else
+ {
+ if(sscanf(str,"-%d",lines)==1)
+ sign="-";
+ else if(sscanf(str,"+%d",lines)==1)
+ sign="+";
+ if (file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xtail");
+ return TRUE;
+ }
+ }
+
+ if(sign=="-")
+ {
+ if(!lines)
+ return TRUE;
+ }
+
+ if(file_size(file)>50000)
+ {
+ WDLN("File too large");
+ return TRUE;
+ }
+
+ if(sign=="+")
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n")[lines..];
+ else
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n")[<lines..];
+ if(pipe_in&&pipe_if==PIPE_FILE)
+ rm(PIPE_FILE);
+ if (pipe_out&&pipe_of)
+ write_file(pipe_of,implode(tmp,"\n")+"\n");
+ else
+ WLN(implode(tmp,"\n"));
+ return TRUE;
+}
+
+int Xtool(string str)
+{
+ int m;
+ string tmp;
+ object obj;
+
+ SECURE2(TRUE);
+ TK("Xtool: str: "+str);
+ USAGE1(str, "xto(ol) [update|first=<on|off>|protect=<on|off>|"+
+ "invcheck=<on|off>|\n"+
+ "\t\tvarcheck=<on|off>|scanchk=<on|off>|short=<on|off>|\n"+
+ "\t\techo=<on|off>|more=<amount>|kill|news|save|load|reset]");
+ if(str&&str!="")
+ {
+ if(sscanf(str, "more=%d", m))
+ {
+ if(m<5)
+ WDLN("Sorry, amount of lines should be more then 5");
+ else
+ {
+ WDLN("Setting amount of displayed lines to "+m);
+ morelines=m;
+ }
+ }
+ else
+ switch(str)
+ {
+ case "update":
+ if(obj=find_object(TOOL_PATH))
+ Destruct(obj);
+ if(catch(obj=clone_object(TOOL_PATH)))
+ WLN("Updating "+TOOL_TITLE+" failed!");
+ else
+ obj->update_tool(AUTOLOAD_ARGS, cloner);
+ return TRUE;
+ break;
+ case "first=on":
+ MODE_ON(MODE_FIRST);
+ move(cloner);
+ WDLN("Automatic moving into pole position of inventory turned on");
+ break;
+ case "first=off":
+ MODE_OFF(MODE_FIRST);
+ WDLN("Automatic moving into pole position of inventory turned off");
+ break;
+ case "protect=on":
+ MODE_ON(MODE_PROTECT);
+ WDLN("Protection from forces and illegal moves turned on");
+ break;
+ case "protect=off":
+ MODE_OFF(MODE_PROTECT);
+ WDLN("Protection from forces and illegal moves turned off");
+ break;
+ case "invcheck=on":
+ MODE_ON(MODE_INVCHECK);
+ WDLN("Automatic checking for new objects in inventory turned on");
+ break;
+ case "invcheck=off":
+ MODE_OFF(MODE_INVCHECK);
+ WDLN("Automatic checking for new objects in inventory turned off");
+ break;
+ case "varcheck=on":
+ MODE_ON(MODE_VARCHECK);
+ VarCheck(TRUE);
+ WDLN("Automatic variable checking turned on");
+ break;
+ case "varcheck=off":
+ MODE_OFF(MODE_VARCHECK);
+ WDLN("Automatic variable checking turned off");
+ break;
+ case "scanchk=on":
+ MODE_ON(MODE_SCANCHK);
+ WDLN("Scan check turned on");
+ break;
+ case "scanchk=off":
+ MODE_OFF(MODE_SCANCHK);
+ WDLN("Scan check turned off");
+ break;
+ case "echo=on":
+ MODE_ON(MODE_ECHO);
+ WDLN("Echoing of multiple command execution turned on");
+ break;
+ case "echo=off":
+ MODE_OFF(MODE_ECHO);
+ WDLN("Echoing of multiple command execution turned off");
+ break;
+ case "short=on":
+ MODE_ON(MODE_SHORT);
+ WDLN("Use of short descriptions turned on");
+ break;
+ case "short=off":
+ MODE_OFF(MODE_SHORT);
+ WDLN("Use of short descriptions turned off");
+ break;
+ case "kill":
+ WDLN(TOOL_NAME+" selfdestructs");
+ destruct(ME);
+ break;
+ case "news":
+ XMoreFile(TOOL_NEWS, FALSE);
+ break;
+ case "reset":
+ WDLN("Resetting "+TOOL_TITLE);
+ ME->__INIT();
+ break;
+ case "load":
+ if(file_size(SAVE_FILE+".o")>0)
+ {
+ WDLN("Loading "+TOOL_TITLE+" settings");
+ restore_object(SAVE_FILE);
+ }
+ else
+ WDLN("Sorry, cannot find file to load settings");
+ break;
+ case "save":
+ WDLN("Saving "+TOOL_TITLE+" settings");
+ save_object(SAVE_FILE);
+ break;
+ default:
+ return FALSE;
+ }
+ }
+ else
+ {
+ WLN(TOOL_TITLE+" settings:");
+ tmp= (" first .... = "+(MODE(MODE_FIRST) ? "on\n" : "off\n"));
+ tmp+=(" protect .. = "+(MODE(MODE_PROTECT) ? "on\n" : "off\n"));
+ tmp+=(" invcheck . = "+(MODE(MODE_INVCHECK) ? "on\n" : "off\n"));
+ tmp+=(" varcheck . = "+(MODE(MODE_VARCHECK) ? "on\n" : "off\n"));
+ tmp+=(" scanchk .. = "+(MODE(MODE_SCANCHK) ? "on\n" : "off\n"));
+ tmp+=(" echo ..... = "+(MODE(MODE_ECHO) ? "on\n" : "off\n"));
+ tmp+=(" short .... = "+(MODE(MODE_SHORT) ? "on\n" : "off\n"));
+ tmp+=(" more ..... = "+morelines);
+ WLN(sprintf("%-80#s", tmp));
+ }
+ return TRUE;
+}
+
+int Xtrace(string str)
+{
+ string file;
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xtrac(e) <object>");
+ if(!str||str=="")
+ {
+ trace(0);
+ WDLN("Ending trace ["+short_path("/"+traceprefix(0))+"]");
+ }
+ else if(obj=XFindObj(str))
+ {
+ PrintShort("Tracing: ", obj);
+ file=object_name(obj);
+ file=file[1..<1];
+ traceprefix(file);
+ trace(TRACE_LEVEL);
+ }
+ return TRUE;
+}
+
+int Xtrans(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xtran(s) <object>");
+ if((obj=XFindObj(str))&&ENV(obj))
+ {
+ tell_room(ENV(obj), CRNAME(obj)+" vanishes.\n");
+ tell_room(ENV(cloner), CRNAME(obj)+
+ " is teleported into this room by "+CRNAME(cloner)+".\n");
+ MoveObj(obj, ENV(cloner), TRUE);
+ tell_object(obj, "You've been teleported to "+CRNAME(cloner)+".\n");
+ }
+ else
+ WDLN("Failed to teleport object");
+ return TRUE;
+}
+
+int Xupdate(string str)
+{
+ object obj;
+ string file;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xup(date) <filename>");
+ if(!(file=XFindFile(str)))
+ return TRUE;
+ if(file[<2.. <1]==".c")
+ file=file[0.. <3];
+ if((obj=XFindObj(file))&&(obj=find_object(pure_file_name(obj))))
+ {
+ PrintShort("Updating: ", obj);
+ Destruct(obj);
+ }
+ else
+ WDLN("Object not found");
+ return TRUE;
+}
+
+int Xuptime(string str)
+{
+ return TRUE;
+}
+
+int Xwc(string str)
+{
+ string file;
+ string tmp, *tmp2;
+ int i, chars, words, lines, nchars, nwords, nlines;
+
+ SECURE2(TRUE);
+ TK("Xwc: str: "+str);
+ chars=words=lines=FALSE;
+ if(!pipe_in)
+ {
+ USAGE2(str, "xwc [-cwl] <file>");
+ if(str[0]=='-')
+ {
+ while((str=str[1..])[0]!=' '&&sizeof(str))
+ switch(str[0])
+ {
+ case 'c':
+ chars=TRUE;
+ break;
+ case 'w':
+ words=TRUE;
+ break;
+ case 'l':
+ lines=TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+ str=str[1..];
+ }
+ if(!(file=XFindFile(str)))
+ {
+ WDLN("Can't find file");
+ return TRUE;
+ }
+ }
+ else
+ {
+ USAGE1(str,"xwc [-cwl]");
+ if(str)
+ if(str[0]=='-')
+ {
+ while((str=str[1..])[0]!=' '&&sizeof(str))
+ switch(str[0])
+ {
+ case 'c':
+ chars=TRUE;
+ break;
+ case 'w':
+ words=TRUE;
+ break;
+ case 'l':
+ lines=TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+ }
+ else
+ return FALSE;
+ if(file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xwc");
+ return TRUE;
+ }
+ }
+ if(!(chars|words|lines))
+ chars=words=lines=TRUE;
+ nlines=nwords=nchars=0;
+ tmp=read_file(file,0,PIPE_MAX);
+ tmp2=explode(tmp,"\n");
+ if(lines)
+ {
+ nlines=sizeof(tmp2);
+ if(tmp2[<1]==""&&nlines>1)
+ nlines--;
+ }
+ if(words)
+ for(i=sizeof(tmp2)-1;i>=0;i--)
+ {
+ TK(sprintf("%O",tmp2[i]));
+ if(tmp2[i]!="")
+ nwords+=sizeof(regexplode(tmp2[i],"[ ]")-({""," "," "}));
+ TK(sprintf("%O",regexplode(tmp2[i],"[ ]")-({""," "," "})));
+ TK("nwords: "+nwords);
+ }
+ if(chars)
+ for(i=sizeof(tmp2)-1;i>=0;i--)
+ nchars+=sizeof(tmp2[i])+1;
+ tmp2=0;
+ tmp="";
+ if(lines)
+ tmp+=sprintf("%7d",nlines)+" ";
+ if(words)
+ tmp+=sprintf("%7d",nwords)+" ";
+ if(chars)
+ tmp+=sprintf("%7d",nchars)+" ";
+ if(file!=pipe_if)
+ tmp+=file;
+ WLN(tmp);
+ return TRUE;
+}
+
+int cmdavg_compare(string a, string b)
+{
+ int x,y;
+ string dum;
+ sscanf(a,"%s cmdavg: %d",dum,x);
+ sscanf(b,"%s cmdavg: %d",dum,y);
+ return x==y?0:(x>y?1:-1);
+}
+
+int Xwho(string opt)
+{
+ string *strs,str,func;
+
+ SECURE2(TRUE);
+ TK("Xwho: opt: \""+opt+"\"");
+ USAGE1(opt, "xwh(o) [mail|ip|race|guild|domain|stats|snoop]");
+ func="string_compare";
+ if(!opt||opt=="")
+ strs=map(users(), "PlayerWho", ME);
+ else
+ switch(opt)
+ {
+ case "mail":
+ strs=map(users(), "PlayerMail", ME, TRUE);
+ break;
+ case "ip":
+ strs=map(users(), "PlayerIP", ME, TRUE);
+ break;
+ case "race":
+ case "guild":
+ strs=map(users(), "PlayerRace", ME, TRUE);
+ break;
+ case "domain":
+ strs=map(users(), "PlayerDomain", ME, TRUE);
+ break;
+ case "stat":
+ case "stats":
+ strs=map(users(), "PlayerStats", ME, TRUE);
+ break;
+ case "snoop":
+ strs=map(users(), "PlayerSnoop", ME, TRUE);
+ break;
+ case "cmdavg":
+ strs=map(users(), "PlayerCmdAvg", ME, TRUE);
+ func="cmdavg_compare";
+ break;
+ default:
+ return FALSE;
+ }
+ strs=sort_array(strs, func, ME);
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,implode(strs,"\n")+"\n");
+ else
+ WLN(implode(strs,"\n"));
+ return TRUE;
+}
diff --git a/obj/tools/MGtool/toollib.c b/obj/tools/MGtool/toollib.c
new file mode 100644
index 0000000..9464004
--- /dev/null
+++ b/obj/tools/MGtool/toollib.c
@@ -0,0 +1,192 @@
+/*
+ * MGtool-1.0
+ * File: toollib.c
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#include "toollib.h"
+#include <lpctypes.h>
+#include <properties.h>
+/*
+string *old_explode(string str, string del)
+{
+ int s, t;
+ string *strs;
+
+ if(del == "")
+ return ({str});
+ strs=explode(str, del);
+ s=0;
+ t=sizeof(strs)-1;
+ while(s<=t && strs[s++] == "")
+ ;
+ s--;
+ while(t>=0 && strs[t--] == "")
+ ;
+ t++;
+ if(s<=t)
+ return strs[s..t];
+ return 0;
+}
+
+string *explode(string str, string del)
+{
+ return explode(str, del);
+}
+*/
+string *strip_explode(string str, string del)
+{
+ return explode(str, del)-({""});
+}
+
+string strip_string(string str)
+{
+ return implode(strip_explode(str," ")," ");
+}
+
+int string_compare(string a, string b)
+{
+ return a==b?0:(a>b?1:-1);
+}
+
+string cap_string(string str)
+{
+ return capitalize(str);
+}
+
+string short_path(string file)
+{
+ int s;
+ string tmp;
+
+ if(!file)
+ return 0;
+ if(PL)
+ {
+ if(file[0.. 8]=="/players/")
+ {
+ s=sizeof(getuid(PL))+8;
+ return "~"+(file[9.. s]==getuid(PL) ?
+ file[s+1.. <1] : file[9.. <1]);
+ }
+ }
+ if(file[0.. 2]=="/d/")
+ return "+"+file[3.. <1];
+ else
+ return file;
+}
+
+string long_path(string file)
+{
+ return (string)MASTER->make_path_absolute(file);
+}
+
+string *long_get_dir(string pat, int all)
+{
+ int i, s;
+ string str, dir, *file, *tmp;
+
+ if(!pat)
+ return ({});
+ pat=long_path(pat);
+ if(tmp=old_explode(pat, "/"))
+ dir="/"+implode(tmp[0..sizeof(tmp)-2], "/")+"/";
+ else
+ dir="/";
+ s=sizeof(tmp=get_dir(pat));
+ file=({});
+ for(i=0;i<s;i++)
+ {
+ str=dir+tmp[i];
+ if(all||file_size(str)>=0)
+ file+=({str});
+ }
+ return file;
+}
+
+string lit_string(string str)
+{
+ str=string_replace(str, "\\", "\\\\");
+ str=string_replace(str, "\b", "\\b");
+ str=string_replace(str, "\n", "\\n");
+ str=string_replace(str, "\r", "\\r");
+ str=string_replace(str, "\t", "\\t");
+ return string_replace(str, "\"", "\\\"");
+}
+
+string mixed_to_string(mixed mix, int lvl)
+{
+ int i, j, s, t;
+ string str;
+ mixed *keys;
+
+ if(lvl)
+ {
+ switch(typeof(mix))
+ {
+ default:
+ case T_INVALID:
+ return "<invalid>";
+ case T_STRUCT:
+ return to_string(mix);
+ case T_LVALUE:
+ return "&"+mixed_to_string(mix, lvl-1);
+ case T_NUMBER:
+ case T_FLOAT:
+ return to_string(mix);
+ case T_STRING:
+ return "\""+lit_string(mix)+"\"";
+ case T_POINTER:
+ return "({"+implode(map(mix,"mixed_to_string",ME,lvl-1),",")+"})";
+ case T_OBJECT:
+ return "["+short_path(object_name((object)mix))+"]";
+ case T_MAPPING:
+ s=sizeof(keys=m_indices(mix));
+ t=get_type_info(mix, 1);
+ str="([";
+ for(i=0;i<s;i++)
+ {
+ str+=mixed_to_string(keys[i], lvl-1);
+ if(t)
+ {
+ str+=":"+mixed_to_string(mix[keys[i],0], lvl-1);
+ for(j=1;j<t;j++)
+ str+=";"+mixed_to_string(mix[keys[i],j], lvl-1);
+ }
+ if(i<s-1) str+=",";
+ }
+ return str+"])";
+ case T_CLOSURE:
+ case T_SYMBOL:
+ return sprintf("%O", mix);
+ case T_QUOTED_ARRAY:
+ return "'"+mixed_to_string(funcall(lambda(0, mix)), lvl-1);
+ }
+ }
+ return "...";
+}
+
+int is_player(object obj)
+{
+ return is_obj(obj)&&query_once_interactive(obj);
+}
+
+int is_not_player(object obj)
+{
+ return is_obj(obj)&&!is_player(obj);
+}
+
+int round(float val)
+{
+ int tmp;
+
+ tmp=(int)val;
+ // only positive val
+ if( val - tmp >= 0.5 )
+ return tmp+1;
+ return tmp;
+}
diff --git a/obj/tools/MGtool/toollib.h b/obj/tools/MGtool/toollib.h
new file mode 100644
index 0000000..69e8264
--- /dev/null
+++ b/obj/tools/MGtool/toollib.h
@@ -0,0 +1,48 @@
+/*
+ * MGtool-1.0
+ * File: toollib.h
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#ifndef __TOOLLIB_H__
+#define __TOOLLIB_H__ 1
+
+#ifndef MASTER
+#define MASTER __MASTER_OBJECT__
+#endif
+
+#define is_obj(x) ((x)&&objectp(x))
+
+#define is_living(x) (is_obj(x)&&living(x))
+#define is_not_living(x) (is_obj(x)&&!is_living(x))
+#define is_netdead(x) (is_obj(x)&&is_player(x)&&!interactive(x))
+#define is_alive(x) (is_obj(x)&&is_player(x)&&interactive(x))
+#define is_snooped(x) (is_obj(x)&&objectp(query_snoop(x)))
+#define is_not_snooped(x) (is_obj(x)&&!is_snooped(x))
+#define is_invis(x) (is_obj(x)&&((x)->QueryProp(P_INVIS)||!(x)->QueryProp(P_SHORT))))
+#define is_not_invis(x) (is_obj(x)&&!is_invis(x))
+
+#define pure_file_name(x) (is_obj(x)?old_explode(object_name(x),"#")[0]:0)
+#define source_file_name(x) (is_obj(x)?pure_file_name((x))+".c":0)
+#define string_replace(x,y,z) implode(explode((x),(y)),(z))
+
+int string_compare(string a, string b);
+string cap_string(string str);
+string short_path(string file);
+string long_path(string file);
+//string *old_explode(string str, string del);
+//string *explode(string str, string del);
+string *strip_explode(string str, string del);
+string strip_string(string str);
+string *long_get_dir(string pat, int all);
+string lit_string(string str);
+string mixed_to_string(mixed mix, int level);
+int is_player(object obj);
+int is_not_player(object obj);
+int round(float val);
+
+#endif /* __TOOLLIB_H__ */
diff --git a/obj/tools/README b/obj/tools/README
new file mode 100644
index 0000000..b40ce10
--- /dev/null
+++ b/obj/tools/README
@@ -0,0 +1 @@
+The files contained in this subtree are unsupported.
diff --git a/obj/tools/btool.c b/obj/tools/btool.c
new file mode 100644
index 0000000..d063e88
--- /dev/null
+++ b/obj/tools/btool.c
@@ -0,0 +1,121 @@
+#pragma no_shadow, no_inherit
+#pragma strong_types,save_types,rtt_checks
+#pragma pedantic,range_check,warn_deprecated
+#pragma warn_empty_casts,warn_missing_return,warn_function_inconsistent
+
+inherit "/std/thing";
+
+#include <properties.h>
+#include <defines.h>
+
+#define BARCHIV "/d/erzmagier/boing/balance/barchives"
+
+#define BS(x) break_string(x,78,0,BS_LEAVE_MY_LFS)
+
+private varargs void print_map(mapping tmp,int short);
+
+protected void create()
+{
+ ::create();
+ SetProp(P_NAME,"Balance-Tool");
+ AddId(({"btool","balancetool","balance-tool"}));
+ SetProp(P_SHORT,"Ein Balance-Tool light");
+ SetProp(P_LONG,
+ BS("Dies ist das Balance-Tool light. Es versteht folgende Befehle:\n"
+ "- btop <n>: Zeigt den letzten genehmigten Antrag zu Top n.\n"
+ "- bsuch [-s] <str>: Sucht case-sensitiv nach str, -s bricht jeden "
+ "Eintrag nach 78 Zeichen ab.\n"
+ "- binhalt [-s]: Zeigt den gesamten Inhalt des Balancearchives, -s "
+ "bricht jeden Eintrag nach 78 Zeichen ab.\n\n"
+ "Es kann vorkommen, dass Eintraege der falschen UID zugeordnet sind, "
+ "oder dass die Genehmigung nicht sehr aussagekraeftig ist, in diesem "
+ "Fall bitte eine Mail an das Balanceteam schreiben."));
+ AddCmd("btop",
+ function int(string str)
+ {
+ int n;
+ if(!str || sscanf(str,"%d",n)!=1)
+ {
+ notify_fail(
+ BS("Syntax: btop <n>"));
+ return 0;
+ }
+ this_interactive()->ReceiveMsg(
+ BARCHIV->GetLightAnnounce(n),
+ MT_NOTIFICATION|MSG_BS_LEAVE_LFS);
+ return 1;
+ });
+ AddCmd("bsuch",
+ function int()
+ {
+ string str=this_interactive()->_unparsed_args();
+ if(!str || !sizeof(str))
+ {
+ notify_fail(
+ BS("Syntax: bsuch <str>"));
+ return 0;
+ }
+ int short;
+ string* arr=old_explode(str," ");
+
+ if(arr[0]=="-s")
+ {
+ short=1;
+ str=implode(arr[1..]," ");
+ }
+ mapping tmp=BARCHIV->SearchIndex(str);
+ if(!sizeof(tmp))
+ {
+ this_interactive()->ReceiveMsg(
+ "Keine Eintraege gefunden.",
+ MT_NOTIFICATION);
+ }
+ else
+ {
+ print_map(tmp,short);
+ }
+ return 1;
+ });
+ AddCmd("binhalt",
+ function int(string str)
+ {
+ int short;
+ if(sizeof(str))
+ {
+ string* arr=old_explode(str," ");
+
+ if(arr[0]=="-s")
+ {
+ short=1;
+ }
+ }
+
+ print_map(BARCHIV->GetIndexForWizards(),short);
+ return 1;
+ });
+}
+
+private varargs void print_map(mapping tmp,int short)
+{
+ if (!mappingp(tmp))
+ {
+ this_interactive()->ReceiveMsg("Keine Daten vorhanden.\n");
+ return;
+ }
+ int* sort=sort_array(m_indices(tmp),#'>);
+ string ret="";
+ foreach(int i : sort)
+ {
+ string str=sprintf(" %4d: %s {%s} (%s)",i,tmp[i,0],tmp[i,2],
+ strftime("%d.%m.%y",tmp[i,1]));
+ if(short)
+ {
+ ret+=BS(str[0..77]);
+ }
+ else
+ {
+ ret+=BS(str);
+ }
+ }
+ this_interactive()->More(ret);
+}
diff --git a/obj/tools/dancetool.c b/obj/tools/dancetool.c
new file mode 100644
index 0000000..dcf3b9a
--- /dev/null
+++ b/obj/tools/dancetool.c
@@ -0,0 +1,321 @@
+// DANCETOOL.C Stand: 10.12.94 Dancer
+//
+// Kleines Tool zum Schreiben und Nachsehen von Details.
+//
+//
+
+inherit "std/thing";
+
+#include <properties.h>
+#include <defines.h>
+#include <wizlevels.h>
+
+#define bs( x ) break_string( x, 78 )
+
+private int i, counter, first_detail_line, startline, endline;
+private string *detail_shorts, *newstring, *file_lines, *new_lines;
+private string detail_long, save_string, old_file, new_file, actual_file,
+ detail_text;
+
+void create()
+{
+ ::create();
+ SetProp( P_AUTOLOADOBJ,1 );
+ SetProp( P_NAME, "Dancers Sandtigerkralle" );
+ SetProp( P_GENDER, FEMALE );
+ SetProp( P_SHORT, "Dancers Sandtigerkralle" );
+ SetProp( P_LONG, bs( "Die Sandtigerkralle von Dancer ist "+
+ "ein kleines Tool, mit dem Du gewoehnliche Details "+
+ "in allen Raeumen nachschauen und in Deinen eigenen "+
+ "hinzufuegen kannst. Weitere Informationen kannst Du "+
+ "mit dem Befehl <dancetool> bekommen." ) );
+ SetProp( P_ARTICLE, 2 );
+ SetProp( P_WEIGHT, 500 );
+ SetProp( P_VALUE, 10000 );
+ SetProp( P_NOBUY, 1 );
+ SetProp( P_NODROP, 1 );
+ AddId( "kralle" );
+ AddId( "sandtigerkralle" );
+ AddId( "tigerkralle" );
+ AddId( "dancetool" );
+ AddId( "dancertool" );
+ seteuid(getuid(this_object()));
+}
+
+
+void init()
+{
+ if (!IS_LEARNER(this_player())) return;
+ ::init();
+ add_action("query_add_details", "show_detail" );
+ add_action("query_add_details", "show_details" );
+ add_action("query_add_details", "sd" );
+ add_action("set_add_detail", "add_detail" );
+ add_action("set_add_detail", "add_details" );
+ add_action("set_add_detail", "ad" );
+ add_action("give_info", "dancetool" );
+}
+
+
+int give_info()
+{
+ write( "-----------------------------------------------------------------------------\n" );
+ write( "Die Sandtigerkralle ermoeglicht folgende Befehle:\n" );
+ write( "\nadd_detail, add_details oder ad:\n" );
+ write( bs( "Ruft einen kleinen AddDetail-Editor auf, mit dem Du "+
+ "Details in Deine eigenen Raeume einfuegen kannst. Als Argument "+
+ "kann hinter den Befehl der Filename eines Raumes eingegeben "+
+ "werden. Wird kein Argument eingegeben, so wird der Raum "+
+ "genommen, in dem Du gerade stehst. Achtung: Es koennen "+
+ "nur Details in Raeume eingefuegt haben, die bereits ein "+
+ "AddDetail in ihrem create() haben. Du musst die Lupe haben, "+
+ "da der Raum nach dem Einfuegen des Details automatisch "+
+ "neu geladen wird." ) );
+ write( "\nshow_detail, show_details oder sd:\n" );
+ write( bs( "Zeigt Dir alle Zeilen des angesprochenen Raumes bzw. "+
+ "des Raumes in dem Du stehst, die ein AddDetail "+
+ "beinhalten. So kannst Du kontrollieren, welche Details "+
+ "Du schon eingebaut hast." ) );
+ write( "-----------------------------------------------------------------------------\n" );
+ return 1;
+}
+
+
+int renew_variables()
+{
+ i = counter = first_detail_line = startline = endline = 0;
+ detail_shorts = newstring = file_lines = new_lines = ({});
+ detail_long = save_string = old_file = new_file = actual_file = detail_text = 0;
+ return 1;
+}
+
+
+
+int query_add_details( string str )
+{
+ string old_file, *file_lines, new_file, *new_lines, actual_file;
+ int i, counter, first_detail_line, startline, endline;
+
+ actual_file = "";
+
+ if ( !str ) actual_file = object_name( environment( this_player() ) )+".c";
+ else
+ {
+ if ( str[0..0] == "/" )
+ {
+ if ( str[<2..] != ".c" )
+ actual_file = str+".c";
+ else
+ actual_file = str;
+ }
+ else
+ {
+ if ( str[<2..] != ".c" )
+ actual_file = this_player()->QueryProp( P_CURRENTDIR )+
+ "/"+str+".c";
+ else
+ actual_file = this_player()->QueryProp( P_CURRENTDIR )+
+ "/"+str;
+ }
+ }
+ if ( file_size( actual_file )==-1 )
+ {
+ write( "File: "+actual_file+" nicht gefunden!\n" );
+ return 1;
+ }
+ call_other( actual_file, "???" );
+ write( "\n-----------------------------------------------------------------------------\n" );
+ write( "Aktuelles File: "+actual_file+"\n" );
+ write( "Filegroesse: "+file_size( actual_file )+"\n" );
+ write( "Userid des Files: "+getuid( find_object( actual_file ) )+"\n" );
+ new_file = "";
+ counter = 0;
+ first_detail_line = 0;
+ old_file = read_file( actual_file );
+ file_lines = ({ "dummy" }) + old_explode( old_file, "\n" );
+ startline = 1;
+ endline = sizeof( file_lines )-1;
+ for( i = startline; i <= endline; i++ )
+ {
+ new_file = new_file+file_lines[ i ]+"\n";
+ if ( strstr( file_lines[i], "AddDetail" ) != -1 )
+ {
+ write( file_lines[i]+"\n" );
+ if ( !first_detail_line ) first_detail_line = i;
+ counter = counter + 1;
+ }
+ }
+ write( "Details found: "+counter+".\n" );
+ write( "-----------------------------------------------------------------------------\n" );
+ return 1;
+}
+
+
+int set_add_detail( string str )
+{
+
+ renew_variables();
+
+ if ( !str ) actual_file = object_name( environment( this_player() ) )+".c";
+ else
+ {
+ if ( str[0..0] == "/" )
+ {
+ if ( str[<2..] != ".c" )
+ actual_file = str+".c";
+ else
+ actual_file = str;
+ }
+ else
+ {
+ if ( str[<2..] != ".c" )
+ actual_file = this_player()->QueryProp( P_CURRENTDIR )+
+ "/"+str+".c";
+ else
+ actual_file = this_player()->QueryProp( P_CURRENTDIR )+
+ "/"+str;
+ }
+ }
+ if ( file_size( actual_file )==-1 )
+ {
+ write( "File: "+actual_file+" nicht gefunden!\n" );
+ return 1;
+ }
+ call_other( actual_file, "???" );
+ write( "\n-----------------------------------------------------------------------------\n" );
+ write( "Aktuelles File: "+actual_file+"\n" );
+ write( "Filegroesse: "+file_size( actual_file )+"\n" );
+ write( "Userid des Files: "+getuid( find_object( actual_file ) )+"\n" );
+ new_file = "";
+ new_lines = ({ "dummy" });
+ counter = 0;
+ first_detail_line = 0;
+ old_file = read_file( actual_file );
+ file_lines = ({ "dummy" }) + old_explode( old_file, "\n" );
+ startline = 1;
+ endline = sizeof( file_lines )-1;
+ for( i = startline; i <= endline; i++ )
+ {
+ new_file = new_file+file_lines[ i ]+"\n";
+ if ( strstr( file_lines[i], "AddDetail" ) != -1 )
+ {
+ if ( !first_detail_line ) first_detail_line = i;
+ counter = counter + 1;
+ }
+ }
+ if ( !first_detail_line )
+ {
+ write( bs( "Es wurden im File "+actual_file+" keine "+
+ "Details gefunden! Um Details hinzufuegen zu koennen, "+
+ "muss mindestens ein AddDetail bereits vorhanden sein!" ) );
+ write( "-----------------------------------------------------------------------------\n" );
+ return 1;
+ }
+ write( "Details found: "+counter+".\n" );
+ write( "-----------------------------------------------------------------------------\n" );
+ write( "Bitte die Detail-Kuerzel eingeben:\n(Bemerkung: "+
+ "die Kuerzel muessen mit Leerzeichen getrennt sein, "+
+ "Abbruch mit 'q'.)\n->" );
+ input_to( "get_detail_short" );
+ return 1;
+}
+
+
+int get_detail_short( string str )
+{
+ string dummy;
+ if ( str == "q" )
+ {
+ tell_object( this_player(), "Abgebrochen!\n" );
+ return 1;
+ }
+ detail_shorts = map( old_explode( str, " " ),#'lower_case);
+ dummy = break_string(implode(sort_array(map(detail_shorts,#'lower_case),#'>),", ")+":",78);
+ write( "-----------------------------------------------------------------------------\n" );
+ write( bs ( "Bitte Beschreibung eingeben fuer das Detail mit den Namen \n" ) );
+ write( dummy+"( Abbruch mit 'q'.)\n->" );
+ input_to( "get_detail_long" );
+ return 1;
+}
+
+
+int get_detail_long( string str )
+{
+ if ( str == "q" )
+ {
+ write( "Abgebrochen!\n" );
+ write( "-----------------------------------------------------------------------------\n" );
+ return 1;
+ }
+ detail_long = break_string( "break_string( \""+str, 60 );
+ save_string = " AddDetail( ({ ";
+ for( i = 0; i < sizeof( detail_shorts ); i ++ )
+ {
+ if ( !(i%3) && i )
+ save_string = save_string + "\n ";
+ if ( i < sizeof( detail_shorts ) - 1 )
+ detail_shorts[ i ] = "\""+detail_shorts[ i ]+"\", ";
+ else
+ detail_shorts[ i ] = "\""+detail_shorts[ i ]+"\" ";
+ save_string = save_string + detail_shorts[ i ];
+ write( detail_shorts[ i ]+"\n" );
+ }
+ save_string = save_string + "}), \n";
+ newstring = old_explode( detail_long,"\n");
+ i = 0;
+ for( i = 0; i<sizeof(newstring); i++)
+ {
+ if ( i < sizeof(newstring)-1 )
+ {
+ if ( i==0||!i )
+ save_string = save_string +" "+newstring[i]+" \"+\n";
+ else
+ save_string = save_string +" \""+ newstring[i]+" \"+\n";
+
+ }
+ else
+ {
+ if ( i==0||!i )
+ save_string = save_string +" "+ newstring[i]+"\", 78 ) );";
+ else
+ save_string = save_string +" \""+ newstring[i]+"\", 78 ) );";
+ }
+ }
+ new_lines += ({ "dummy" });
+ for ( i = 1; i < first_detail_line; i++ )
+ {
+ new_lines += ({ file_lines[i] });
+ }
+ new_lines += ({ save_string });
+ for ( i = first_detail_line + 1; i <= endline+1; i++ )
+ new_lines += ({ file_lines[ i - 1 ] });
+ write( "-----------------------------------------------------------------------------\n" );
+ write( bs( "Folgende Zeilen werden in die Datei "+actual_file+" geschrieben, falls `j` eingegeben wird:\n" ) );
+ write( save_string+"\n" );
+ write( "\nDetail speichern? (j/n)\n->" );
+ input_to( "save_detail" );
+ return 1;
+}
+
+
+int save_detail( string str )
+{
+ if ( str != "j" && str != "ja" && str != "Ja" && str != "J" )
+ {
+ write( "Abgebrochen!\n" );
+ write( "-----------------------------------------------------------------------------\n" );
+ return 1;
+ }
+ if ( !rm( actual_file ) )
+ {
+ write( "File: "+actual_file+" wurde nicht gefunden!\n" );
+ return 1;
+ }
+ for ( i = 2; i <= endline+2; i++ )
+ write_file( actual_file, new_lines[i]+"\n" );
+ //write( new_lines[i]+"\n" );
+ write( "Das Detail wurde in die Datei geschrieben.\n" );
+ this_player()->command_me( "here make" );
+ write( "-----------------------------------------------------------------------------\n" );
+ return 1;
+}
diff --git a/obj/tools/explorer.c b/obj/tools/explorer.c
new file mode 100644
index 0000000..72da8ac
--- /dev/null
+++ b/obj/tools/explorer.c
@@ -0,0 +1,445 @@
+// MorgenGrauen MUDlib
+//
+// explorer.c -- Tool zur FP-Verwaltung
+//
+// $Id: explorer.c 8357 2013-02-09 11:16:14Z Zesstra $
+
+inherit "/std/secure_thing";
+
+#include <properties.h>
+#include <exploration.h>
+#include <wizlevels.h>
+
+create()
+{
+ if (!clonep(this_object())) return;
+ ::create();
+ SetProp(P_SHORT, "Der Erforscher");
+ SetProp(P_NAME, "Erforscher");
+ SetProp(P_GENDER, MALE);
+ SetProp(P_LONG, "Dies ist der beruehmte Erforscher des MorgenGrauens. Er\n"
+ +"stellt folgende Befehle zur Verfuegung:\n"
+ +" epadd <was>: <bonus> <typ> <keys>\n"
+ +" epchange <was>: <wie> <neu>\n"
+ +" epdel <was>\n"
+ +" epinfo <was>\n"
+ +" epcount <spielername> - Anzahl der EPs des Spielers\n"
+ +" epscan <spielername> [filenamenpattern] - Zeige dessen EPs gefiltert an\n"
+ +" eppladd <spielername> <ep-anzahl> - Gib ihm ep-anzahl EPs (zufaellig)\n"
+ +" eppldel <spielername> <ep-anzahl> - Loesche ihm ep-anzahl EPs (zufael.)\n"
+ +" epplset <spielername> <ep-nummer> - Setze ihm EP ep-nummer\n"
+ +" epplclr <spielername> <ep-nummer> - Loesche ihm EP ep-nummer\n"
+ +"Dabei bedeutet:\n"
+ +"<was> - Das Objekt (eine ID bei Objekten in der Naehe, hier oder\n"
+ +" here fuer den aktuellen Raum, oder ein Dateiname)\n"
+ +"<bonus> - n fuer normale EPs, b fuer Bonus-EPs (z.B. Para-EPs)\n"
+ +"<typ> - detail, rdetail, exit/ausgang, cmd/befehl/kommando, info, pub, misc,\n"
+ +" smell/geruch, sound/noise, taste/touch\n"
+ +"<key> - Liste der Schluesselwoerter, mit Kommata getrennt\n"
+ +"<wie> - obj, key, bonus oder typ 1\n"
+ +"<neu> - Je nach <wie>; siehe <was>, <key>, <typ>\n"
+ );
+ SetProp(P_NODROP, 1);
+ SetProp(P_NEVERDROP, 1);
+ SetProp(P_AUTOLOADOBJ,1);
+ AddId(({"explorer","erforscher"}));
+
+ AddCmd(({"epadd"}), "add");
+ AddCmd(({"epchange"}), "change");
+ AddCmd(({"epdel"}), "del");
+ AddCmd(({"epinfo"}), "info");
+ AddCmd(({"epcount"}), "epcount");
+ AddCmd(({"epscan"}), "epscan");
+ AddCmd(({"eppladd"}), "eppladd");
+ AddCmd(({"eppldel"}), "eppldel");
+ AddCmd(({"epplset"}), "epplset");
+ AddCmd(({"epplclr"}), "epplclr");
+}
+
+static string strArr(string *s)
+{
+ string ret;
+ int i;
+
+ ret = ("\"" + s[<1] + "\"");
+ for (i=sizeof(s)-2; i>=0; i--)
+ ret += (", \""+s[i]+"\"");
+
+ return ret;
+}
+
+static int getType(string s)
+{
+ switch(s[0..2]) {
+ case "det":
+ return EP_DETAIL;
+ case "rde":
+ return EP_RDET;
+ case "aus":
+ case "exi":
+ return EP_EXIT;
+ case "cmd":
+ case "bef":
+ case "kom":
+ return EP_CMD;
+ case "inf":
+ return EP_INFO;
+ case "pub":
+ return EP_PUB;
+ case "mis":
+ case "ver":
+ return EP_MISC;
+ case "sme":
+ case "ger":
+ return EP_SMELL;
+ case "sou":
+ case "noi":
+ return EP_SOUND;
+ case "tas":
+ case "tou":
+ return EP_TOUCH;
+ }
+ return -1;
+}
+
+static object getOb(string str)
+{
+ object ob;
+
+ if (str == "hier" || str == "here" )
+ return environment(this_player());
+
+ ob = present(str, environment(this_player()));
+ if (!ob)
+ ob = present(str, this_player());
+
+ if (!ob) {
+ str = "/secure/master"->_get_path(str, getuid(this_player()));
+ catch(call_other(str, "???"));
+ ob = find_object(str);
+ }
+ return ob;
+}
+
+static string *getKeys(string str)
+{
+ int i;
+ string *t1, *t2;
+
+ t1 = regexplode(str, ", *");
+ for (t2 = ({}), i=sizeof(t1)-1; i>=0; i-=2)
+ t2 = ({ t1[i] }) + t2;
+ return t2;
+}
+
+static string errMsg(int code)
+{
+ if (code >= 0 || code < EPERR_INVALID_ARG)
+ return "Unbekannter Fehler";
+
+ code = -(code+1);
+ return ({ "Du bist kein Erzmagier", "Ungueltiges Objekt",
+ "Objekt steht nicht in der Liste", "Ungueltiges Argument"})[code];
+}
+
+static int add(string str)
+{
+ string was, t, k, *keys, b;
+ int type, bonus;
+ object ob;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+ notify_fail("Syntax: epadd <was>: <typ>\n");
+ if (!(str = this_player()->_unparsed_args()))
+ return 0;
+
+ if (sscanf(str, "%s: %s %s %s", was, b, t, k) !=4)
+ return 0;
+
+ if (!(ob = getOb(was))) {
+ printf("Kann '%s' nicht finden!\n", was);
+ return 1;
+ }
+ if ((type = getType(t)) < 0) {
+ write("Ungueltiger Typ!\n");
+ return 1;
+ }
+ if (b=="n") bonus=0; else if (b=="b") bonus=1;
+ else {
+ write("Ungueltige Bonusart!\n");
+ return 1;
+ }
+ keys = getKeys(k);
+
+ type = EPMASTER->AddEPObject(ob, keys, type, bonus);
+ if (type < 0)
+ printf("Fehler: %s\n", errMsg(type));
+ return 1;
+}
+
+static int change(string str)
+{
+ string was, wie, neu;
+ object ob;
+ int type;
+ mixed new;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+
+ notify_fail("Syntax: epchange <was>: <wie> <neu>\n");
+ if (!(str = this_player()->_unparsed_args()))
+ return 0;
+
+ if (sscanf(str, "%s: %s %s", was, wie, neu) != 3)
+ return 0;
+
+ if (!(ob = getOb(was))) {
+ printf( "Kann '%s' nicht finden!\n", was);
+ return 1;
+ }
+ switch(wie[0..2]) {
+ case "obj":
+ type = CHANGE_OB;
+ new = getOb(neu);
+ if (!new) {
+ printf( "Kann '%s' nicht finden!\n", neu);
+ return 1;
+ }
+ break;
+ case "key":
+ type = CHANGE_KEY;
+ new = getKeys(neu);
+ break;
+ case "typ":
+ type = CHANGE_TYPE;
+ if ((new = getType(neu)) < 0) {
+ write("Ungueltiger Typ!\n");
+ return 1;
+ }
+ break;
+ case "bon":
+ type = CHANGE_BONUS;
+ if (neu=="n") new=0; else if (neu=="b") new=1;
+ else {
+ write("Ungueltige Bonusart!\n");
+ return 1;
+ }
+ break;
+ default:
+ write("Das laesst sich nicht aendern...\n");
+ return 1;
+ break;
+ }
+ type = EPMASTER->ChangeEPObject( ob, type, new );
+ if (type < 0)
+ printf("Fehler: %s\n",errMsg(type));
+
+ return 1;
+}
+
+static int del(string str)
+{
+ object ob;
+ int ret;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+ if (!str) {
+ notify_fail("Syntax: epdel <was>\n");
+ return 0;
+ }
+ if (!(ob = getOb(str))) {
+ write("Kann das Objekt nicht finden!\n");
+ return 1;
+ }
+ ret = EPMASTER->RemoveEPObject(ob);
+ if (ret < 0)
+ printf("Fehler: %s\n", errMsg(ret));
+
+ return 1;
+}
+
+static int info(string str)
+{
+ object ob;
+ mixed info;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+
+ if (!str) {
+ notify_fail("Syntax: epinfo <was>\n");
+ return 0;
+ }
+
+ if (!(ob = getOb(str))) {
+ write("Das finde ich leider nicht...\n");
+ return 1;
+ }
+ if (!(info = EPMASTER->QueryEPObject(ob)))
+ write ("Das Objekt ist nicht eingetragen!\n");
+ else
+ printf("Nummer: %d\nBonus: %d\nTyp: %s\nSchluessel: %s\n",
+ info[MPOS_NUM],
+ info[MPOS_TYPE+1],
+ ({ "Detail", "Ausgang", "Kommando", "Info", "Misc", "ReadDetail",
+ "Kneipe", "Geruch", "Geraeusch", "Tastdetail"})[info[MPOS_TYPE]],
+ strArr(info[MPOS_KEY] ));
+
+ return 1;
+}
+
+static object find_playerob( string name ) {
+ return find_player(name)||find_netdead(name);
+}
+
+static int epcount( string str ) {
+ object pl,epm;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+
+ if (!str || str=="") {
+ notify_fail("Syntax: epcount <spielername>\n");
+ return 0;
+ }
+
+ printf( "%s hat %d von %d FPs. (Durchschnitt = %d)\n",
+ capitalize(str),
+ EPMASTER->QueryExplorationPoints(str),
+ EPMASTER->QueryMaxEP(),
+ EPMASTER->QueryAverage()
+ );
+ return 1;
+}
+
+static int epscan( string str ) {
+ object pl;
+ int erg;
+ string *astr;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+
+ if (!str || str=="") {
+ notify_fail("Syntax: epscan <spielername> [Teil des Filenamens]\n");
+ return 0;
+ }
+
+ astr=old_explode(this_player()->_unparsed_args()," ");
+
+ if (sizeof(astr)<2)
+ erg = EPMASTER->ShowPlayerEPs(astr[0]);
+ else
+ erg = EPMASTER->ShowPlayerEPs(astr[0],astr[1]);
+ if (erg < 0)
+ printf("Fehler: %s\n",errMsg(erg));
+ return 1;
+}
+
+static eppldel( string str ) {
+ string player, rest;
+ int epnum;
+ object tmp;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+
+ notify_fail( "eppldel <spieler> <anzahl_eps> <grund>\n" );
+ if( !str || sscanf( str, "%s %d %s", player, epnum, rest )<2 )
+ return 0;
+
+ if( epnum <= 0 ) {
+ write( "Anzahl der FPs <= 0 ?\n" );
+ return 1;
+ }
+ if( !rest || rest=="" ) {
+ write( "Bitte Grund angeben!\n" );
+ return 1;
+ }
+
+ printf( "%O %O %O\n", epnum, player, secure_level() );
+ epnum = "/secure/explorationmaster"->RemoveFP( epnum, player, rest );
+ printf( "Ergebnis (abgezogene EPs) = %O\n", epnum );
+ return 1;
+
+}
+
+static eppladd( string str ) {
+ string player, rest;
+ int epnum;
+ object pl,tmp;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+
+ notify_fail( "eppladd <spieler> <anzahl_eps>\n" );
+ if( !str || sscanf( str, "%s %d", player, epnum )<2 )
+ return 0;
+
+ if( epnum <= 0 ) {
+ write( "Anzahl der FPs <= 0 ?\n" );
+ return 1;
+ }
+
+ epnum = "/secure/explorationmaster"->AddFP( epnum, player );
+ printf( "Ergebnis (hinzugefuegte FPs) = %O\n", epnum );
+ return 1;
+
+}
+
+static epplset( string str ) {
+ string player, rest;
+ int epnum;
+ object pl,tmp;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+
+ notify_fail( "epplset <spieler> <ep-nummer>\n" );
+ if( !str || sscanf( str, "%s %d", player, epnum )<2 )
+ return 0;
+
+ epnum = "/secure/explorationmaster"->SetFP( epnum, player );
+ printf( "Ergebnis (gesetzter FP) = %O\n", epnum );
+ return 1;
+}
+
+static epplclr( string str ) {
+ string player, rest;
+ int epnum;
+ object pl,tmp;
+
+ if( !ARCH_SECURITY ) {
+ notify_fail("Du bist kein Erzmagier!\n");
+ return 0;
+ }
+
+ notify_fail( "epplclr <spieler> <ep-nummer>\n" );
+ if( !str || sscanf( str, "%s %d", player, epnum )<2 )
+ return 0;
+
+ epnum = "/secure/explorationmaster"->ClearFP( epnum, player );
+ printf( "Ergebnis (geloeschter FP) = %O\n", epnum );
+ return 1;
+}
diff --git a/obj/tools/fehlerteufel.c b/obj/tools/fehlerteufel.c
new file mode 100644
index 0000000..a35fec1
--- /dev/null
+++ b/obj/tools/fehlerteufel.c
@@ -0,0 +1,993 @@
+/* /obj/toostels/fehlerteufel.c
+ Fehlerteufel - Magiertool zur Abfrage des Fehler-Daemons der Mudlib
+ Autor: Zesstra
+ Changelog:
+*/
+
+#pragma strict_types
+#pragma pedantic
+#pragma range_check
+#pragma no_shadow
+#pragma no_inherit
+
+inherit "/std/secure_thing";
+inherit "/secure/errord-structs";
+
+#include <defines.h>
+#include <wizlevels.h>
+#include <properties.h>
+#include <moving.h>
+#include <errord.h>
+#include <config.h>
+#include <debug_info.h>
+#include <input_to.h>
+#include <strings.h>
+
+#define TI this_interactive()
+
+#define DEBUG(x) if (funcall(symbol_function('find_player),"zesstra"))\
+ tell_object(funcall(symbol_function('find_player),"zesstra"),\
+ "EDBG: "+x+"\n")
+
+// variables
+private string owner; // UID vom Eigentuemer
+private string *uids=({}); // UIDs, auf die man schreibrechte hat
+private string *filteruids=({}); // wenn nicht-leer, nur diese UIDs zeigen
+private string *monitoruids=({}); // diese UIDs in die Liste einschliessen
+private int filterstatus=0; // Filter an oder aus?
+private mapping issuelist = ([]);
+/* ([ type1: ([uid1: <issuelist>, uid2: <issuelist> ]),
+ type2: ... ])
+ <issuelist> ist ein < <int|string>* >* vom ErrorD */
+
+//Welche Art von Fehler anzeigen?
+private int modus=T_RTERROR | T_RTWARN | T_REPORTED_ERR;
+private string *xmonitoruids = ({}); // expanded Monitor-UIDs
+private int lfehler; // letzter 'benutzter' Fehler.
+private int fehlerzahl; // fehlerzahl im letzten Reset.
+private mapping feingabe; // gerade eingegebener Fehler
+
+// ************** private functions **************
+private varargs int get_issuelist(int lmodus);
+private void get_uids();
+
+// irgendeinen Fehler oder Warnung anzeigen.
+private int show_entry(struct fullissue_s issue)
+{
+ if (!issue) return 0;
+
+ string txt=ERRORD->format_error(issue, 0);
+
+ if (!stringp(txt) || !sizeof(txt))
+ return 0;
+
+ tell_object(PL,txt+"\n");
+ return 1;
+}
+
+protected int _feingabe_fertig(string arg) {
+
+ if (arg == "j")
+ {
+ if (!feingabe[F_MSG])
+ {
+ tell_object(PL,
+ "Also, eine Fehlerbeschreibung solltest Du schon eingeben! Abgebrochen.\n");
+ }
+ else
+ {
+ string hashkey = (string)ERRORD->LogReportedError(feingabe);
+ tell_object(PL, sprintf(
+ "Vielen Dank! Die ID des eingegebenen Fehlers lautet: %s\n",
+ hashkey || "N/A"));
+ }
+ }
+ else
+ {
+ tell_object(PL, "Fehlereingabe abgebrochen.\n");
+ }
+
+ feingabe = 0;
+
+ return 1;
+}
+
+public int CmdFehlerEingabe(string arg) {
+ object target;
+
+ if (feingabe)
+ {
+ tell_object(PL, "Du gibts doch bereits einen Fehler ein!\n");
+ return 1;
+ }
+ feingabe = ([]);
+
+ if (arg)
+ {
+ target = present(arg);
+ if (!target)
+ target = find_object(arg); // vielleicht direkt angegeben?
+ }
+ // wenn nix gefunden, Environment des Magiers nehmen.
+ if (!target)
+ target = environment(environment());
+
+ feingabe[F_OBJ] = target;
+
+ tell_object(PL, break_string(sprintf(
+ "Du beginnst einen Fehlereintrag fuer das Objekt: %O\n", target),78));
+
+ input_to(function void (string str)
+ {
+ if (sizeof(str)) feingabe[F_MSG] = str;
+ }, INPUT_PROMPT, "Fehlerbeschreibung eingeben:\n");
+
+ input_to(function void (string str)
+ {
+ if (sizeof(str)) feingabe[F_PROG] = str;
+ else feingabe[F_PROG] = "unbekannt";
+ }, INPUT_PROMPT|INPUT_APPEND,
+ "Programm eingeben, in dem der Fehler auftritt (falls bekannt):\n");
+
+ input_to(function void (string str)
+ {
+ if (sizeof(str)) feingabe[F_LINE] = to_int(str);
+ tell_object(PL,break_string(sprintf(
+ "Du hast die folgenden Daten eingegeben:\n"
+ "Objekt: %O\n"
+ "Fehlerbeschreibung: %s\n"
+ "Programm: %s\n"
+ "Zeilennr.: %d\n",
+ feingabe[F_OBJ], feingabe[F_MSG] || "", feingabe[F_PROG],
+ feingabe[F_LINE]), 78, "", BS_LEAVE_MY_LFS));
+ }, INPUT_PROMPT|INPUT_APPEND,
+ "Zeilennr. eingeben, in der der Fehler auftritt (falls bekannt):\n");
+
+ input_to(#'_feingabe_fertig,
+ INPUT_PROMPT|INPUT_APPEND, "Eingaben korrekt? (j/n)\n");
+
+ return 1;
+}
+
+public int CmdFehlerZeigen(string arg)
+{
+ int issueid;
+
+ if (stringp(arg) && sizeof(arg))
+ {
+ arg = trim(arg, TRIM_BOTH);
+ issueid = to_int(arg);
+ }
+ else
+ {
+ issueid = lfehler;
+ arg = to_string(issueid);
+ }
+ notify_fail("Einen Eintrag mit dieser ID gibt es nicht!\n");
+
+ // Mit einem / am Anfang ist arg wohl ein Filename, wenn to_string(issueid)
+ // == arg wird die Issueid von oben genommen.
+ struct fullissue_s issue;
+ struct fullissue_s *issues;
+ if (arg[0] == '/')
+ {
+ issues=({});
+ foreach(int m: ALL_ERR_TYPES)
+ {
+ if (!(m & modus))
+ continue;
+ struct fullissue_s *tmp =
+ (struct fullissue_s *)ERRORD->QueryIssuesByFile(arg, m);
+ if (tmp)
+ issues+=tmp;
+ }
+ if (!sizeof(issues))
+ issues=0;
+ }
+ else if (to_string(issueid) == arg)
+ issue = (struct fullissue_s)ERRORD->QueryIssueByID(issueid);
+ else
+ issue = (struct fullissue_s)ERRORD->QueryIssueByHash(arg);
+
+ if (structp(issue))
+ {
+ show_entry(issue);
+ // letzten Fehler merken.
+ lfehler = issueid;
+ return 1;
+ }
+ // Wenn das nicht erfolgreich ist, ist das Argument evtl. ein Objekt-,
+ // Programm- oder Ladename. In dem Fall alle von denen anzeigen, die passen
+ // hierbei wird der Typ NICHT beruecksichtigt.
+ else if (pointerp(issues))
+ {
+ foreach(issue : issues)
+ {
+ show_entry(issue);
+ }
+ return 1;
+ }
+
+ notify_fail("Keine Eintraege fuer diesen Dateinamen/diese ID gefunden.\n");
+ return 0;
+}
+
+// Loescht alle Fehler und Warnungen eines Objekts (soweit per modus
+// ausgewaehlt). Entscheidend ist der _Loadname_!
+private int DeleteErrorsForLoadname(string loadname)
+{
+ int sum_deleted;
+ // Bei == 0 wird sonst alles geloescht. ;-)
+ if (!loadname)
+ return 0;
+
+ foreach(int m: ALL_ERR_TYPES)
+ {
+ if (!(m & modus))
+ continue;
+ < <int|string>* >* list = ERRORD->QueryIssueListByLoadname(loadname,m);
+ if (pointerp(list))
+ {
+ foreach(<int|string>* row : list)
+ {
+ if ((int)ERRORD->ToggleDeleteError(row[0]) == 1)
+ {
+ tell_object(PL,
+ row[0] + " als geloescht markiert.\n");
+ }
+ }
+ sum_deleted+=sizeof(list);
+ }
+ }
+ return sum_deleted;
+}
+
+public int CmdFehlerLoeschen(string arg)
+{
+ int issueid;
+ arg = (string)this_player()->_unparsed_args(0);
+
+ if (stringp(arg) && sizeof(arg))
+ issueid = to_int(arg);
+ else
+ issueid = lfehler;
+
+ notify_fail("Einen Eintrag mit dieser ID/diesem Loadname gibt es nicht!\n");
+
+ int res = (int)ERRORD->ToggleDeleteError(issueid);
+ if (res == 1)
+ {
+ tell_object(PL,
+ "Fehler/Warnung wurde zum Loeschen markiert und wird in Kuerze "
+ "geloescht.\n");
+ lfehler = issueid;
+ return 1;
+ }
+ else if (res==0)
+ {
+ tell_object(PL,"Loeschmarkierung wurde entfernt.\n");
+ lfehler = issueid;
+ return 1;
+ }
+ else if (res < -1)
+ {
+ tell_object(PL, "Irgendwas ist beim Loeschen schiefgegangen. "
+ "Keine Schreibrechte?\n");
+ lfehler = issueid;
+ return 1;
+ }
+ // res war == -1 -> Fehler nicht gefunden. Vielleicht ist es nen Loadname
+ return DeleteErrorsForLoadname(arg);
+}
+
+public int CmdRefresh(string arg) {
+ reset();
+ tell_object(PL,"Fehlerdaten wurden neu eingelesen.\n");
+ return 1;
+}
+
+private int select_modus(string arg) {
+ int lmodus;
+ switch(arg) {
+ case "alles":
+ case "alle":
+ lmodus = T_RTERROR | T_RTWARN | T_CTERROR | T_CTWARN | T_REPORTED_ERR
+ | T_REPORTED_IDEA | T_REPORTED_TYPO | T_REPORTED_MD;
+ break;
+ case "fehler":
+ case "error":
+ case "errors":
+ lmodus=T_RTERROR | T_CTERROR | T_REPORTED_ERR;
+ break;
+ case "warnungen":
+ case "warnung":
+ case "warning":
+ case "warnings":
+ lmodus=T_RTWARN | T_CTWARN;
+ break;
+ case "laufzeitfehler":
+ lmodus=T_RTERROR;
+ break;
+ case "ladezeitfehler":
+ lmodus=T_CTERROR;
+ break;
+ case "fehlerhinweis":
+ case "fehlerhinweise":
+ case "hinweise":
+ lmodus=T_REPORTED_ERR;
+ break;
+ case "ideen":
+ case "idee":
+ lmodus=T_REPORTED_IDEA;
+ break;
+ case "md":
+ lmodus=T_REPORTED_MD;
+ break;
+ case "typo":
+ case "typos":
+ lmodus=T_REPORTED_TYPO;
+ break;
+ case "laufzeitwarnungen":
+ case "runtimewarnings":
+ lmodus=T_RTWARN;
+ break;
+ case "ladezeitwarnungen":
+ case "compiletimewarnings":
+ lmodus=T_CTWARN;
+ break;
+ default:
+ lmodus=modus;
+ }
+ return lmodus;
+}
+
+private string * errorlabel(int t)
+{
+ switch(t) {
+ case T_RTERROR:
+ return ({"Laufzeitfehler","Laufzeitfehler","Dieser Laufzeitfehler"});
+ case T_REPORTED_ERR:
+ return ({"Fehlerhinweis","Fehlerhinweise","Dieser Fehlerhinweis"});
+ case T_REPORTED_IDEA:
+ return ({"Idee","Ideen","Diese Idee"});
+ case T_REPORTED_MD:
+ return ({"fehlende Detail","fehlende Details","Dieses fehlende Detail"});
+ case T_REPORTED_TYPO:
+ return ({"Typo","Typos","Dieser Typo"});
+ case T_RTWARN:
+ return ({"Laufzeitwarnung","Laufzeitwarnungen","Diese Laufzeitwarnung"});
+ case T_CTWARN:
+ return ({"Ladezeitwarnung", "Ladezeitwarnungen","Diese Ladezeitwarnung"});
+ case T_CTERROR:
+ return ({"Ladezeitfehler","Ladezeitfehler","Dieser Ladezeitfehler"});
+ }
+ raise_error("Unkannter Fehlertyp: "+t+"\n");
+ return 0;
+}
+
+public int CmdFehlerListe(string arg) {
+ string txt;
+ //string *luids;
+ int lmodus; // modus fuer diese Liste
+ mapping fehlerbackup;
+
+ if (stringp(arg) && sizeof(arg))
+ {
+ lmodus=select_modus(arg);
+ if (lmodus != modus)
+ {
+ fehlerbackup=issuelist; // Fehlerliste von 'modus' aufheben
+ get_issuelist(lmodus); // neue Fehlerliste holen
+ }
+ }
+ else
+ lmodus=modus;
+/*
+ if (!fehlerzahl)
+ {
+ txt="Fuer Deine UIDs sind keine Fehler/Warnungen bekannt. :-)\n";
+ tell_object(PL,txt);
+ return 1;
+ }
+*/
+ foreach(int typ, mapping typemap : issuelist)
+ {
+ if (!(typ & lmodus))
+ continue; // Type nicht gewaehlt.
+ txt="";
+ if (!sizeof(typemap)) {
+ tell_object(PL,
+ "Es sind keine " + errorlabel(typ)[1] + "Deiner UIDs bekannt. :-)");
+ continue;
+ }
+ foreach(string uid, < <int|string>* >* list : typemap)
+ {
+ if (!sizeof(list)) continue;
+ if (filterstatus && member(filteruids, uid) > -1) continue;
+ //txt+=sprintf("%s:\n", uid);
+ foreach(<int|string>* row : list)
+ {
+ txt+=sprintf("%:6d | %:40-s | %:26-s\n",
+ row[0], row[1], row[2]);
+ }
+ }
+ if (txt && sizeof(txt))
+ {
+ txt = sprintf("\nFuer Deine UIDs sind folgende %s bekannt (Filter: %s):\n"
+ "%:6|s | %:40|s | %s\n",
+ errorlabel(typ)[1], (filterstatus ? "an" : "aus"),
+ "ID", "Loadname", "UID")
+ + txt;
+ tell_object(PL, txt);
+ }
+ else
+ {
+ tell_object(PL, sprintf(
+ "\nFuer Deine UIDs sind keine %s bekannt (Filter: %s):\n",
+ errorlabel(typ)[1], (filterstatus ? "an" : "aus")));
+ }
+ }
+
+ if (mappingp(fehlerbackup) && modus!=lmodus)
+ issuelist=fehlerbackup; // fehlerliste fuer 'modus' restaurieren
+ return 1;
+}
+
+public int CmdFilter(string arg) {
+
+ arg=(string)PL->_unparsed_args(0);
+
+ if (!stringp(arg) || !sizeof(arg)) {
+ tell_object(PL,break_string(
+ "Momentan interessieren Dich folgende UIDs nicht"
+ +(filterstatus ? " (Filter an):\n" : " (Filter aus):\n")
+ +CountUp(filteruids)+"\n", 78,"",BS_LEAVE_MY_LFS));
+ return 1;
+ }
+
+ if (arg=="keine") {
+ filteruids=({});
+ filterstatus=1;
+ tell_object(PL,break_string(
+ "Dein Fehlerteufel wird Dir nun nur noch ausgewaehlte "
+ "Fehler berichten. Momentan hast Du keine UIDs ausgeblendet. "
+ "(Filter an)",78));
+ }
+ else if (arg=="alle") {
+ filterstatus=1;
+ filteruids=uids;
+ tell_object(PL,break_string(
+ "Dein Fehlerteufel wird Dir nun nur noch ausgewaehlte "
+ "Fehler berichten. Du blendest momentan alle UIDs aus. "
+ "(Filter an)",78));
+ }
+ else if (arg=="aus") {
+ filterstatus=0;
+ tell_object(PL,break_string(
+ "Dein Fehlerteufel wird Dir nun wieder alle Fehler berichten. ",
+ 78));
+ }
+ else if (arg=="an" || arg=="ein") {
+ filterstatus=1;
+ tell_object(PL,break_string(
+ "Dein Fehlerteufel wird Dir nun nur noch ausgewaehlte "
+ "Fehler berichten.",78));
+ }
+ else {
+ foreach(string uid: explode(arg," ")-({""})) {
+ if (sizeof(uid)>1 && uid[0]=='+') {
+ if (member(filteruids,uid[1..])==-1)
+ filteruids+=({uid[1..]});
+ }
+ else if (sizeof(uid)>1 && uid[0]=='-') {
+ filteruids-=({uid[1..]});
+ }
+ else {
+ if (member(filteruids,uid)==-1)
+ filteruids+=({uid});
+ else
+ filteruids-=({uid});
+ }
+ }
+ }
+
+ tell_object(PL,break_string(
+ "Momentan interessieren Dich folgende UIDs nicht"
+ +(filterstatus ? " (Filter an):\n" : " (Filter aus):\n")
+ +CountUp(filteruids)+"\n", 78,"",BS_LEAVE_MY_LFS));
+
+ return 1;
+}
+
+public int CmdMonitor(string arg) {
+
+ arg=(string)PL->_unparsed_args(0);
+
+ if (!stringp(arg) || !sizeof(arg)) {
+ tell_object(PL,break_string(
+ "Momentan interessieren Dich folgende UIDs zusaetzlich zu Deinen: \n"
+ +(sizeof(monitoruids) ? CountUp(monitoruids) : "")
+ +"\n", 78,"",BS_LEAVE_MY_LFS));
+ return 1;
+ }
+
+ if (arg=="keine") {
+ monitoruids=({});
+ xmonitoruids=({});
+ tell_object(PL,break_string(
+ "Dein Fehlerteufel wird Dir nun nur noch "
+ "Fehler Deiner eigenen UIDs berichten.",78));
+ return 1;
+ }
+ else {
+ foreach(string uid: explode(arg," ")-({""})) {
+ if (sizeof(uid)>1 && uid[0]=='+') {
+ if (member(monitoruids,uid[1..])==-1)
+ monitoruids+=({uid[1..]});
+ }
+ else if (sizeof(uid)>1 && uid[0]=='-') {
+ monitoruids-=({uid[1..]});
+ }
+ else {
+ if (member(monitoruids,uid)==-1)
+ monitoruids+=({uid});
+ else
+ monitoruids-=({uid});
+ }
+ }
+ }
+ get_uids();
+ tell_object(PL,break_string(
+ "Momentan interessieren Dich folgende UIDs zusaetzlich zu Deinen: \n"
+ +(sizeof(monitoruids) ? CountUp(monitoruids) : "")
+ +"\n", 78,"",BS_LEAVE_MY_LFS));
+
+ return 1;
+}
+
+public int CmdModus(string arg) {
+ string txt;
+
+ // Argument verwursten
+ if (stringp(arg) && sizeof(arg)) {
+ modus = select_modus(arg);
+ reset(); // neue Fehlerliste holen
+ }
+ // aktuelle Einstellung ausgeben.
+ string *modstr=({});
+ if (modus & T_RTERROR)
+ modstr+=({"Fehler (Laufzeit)"});
+ if (modus & T_RTWARN)
+ modstr+=({"Warnungen (Laufzeit)"});
+ if (modus & T_CTERROR)
+ modstr+=({"Fehler (Ladezeit)"});
+ if (modus & T_CTWARN)
+ modstr+=({"Warnungen (Ladezeit)"});
+ if (modus & T_REPORTED_ERR)
+ modstr+=({"Fehlerhinweise"});
+ if (modus & T_REPORTED_IDEA)
+ modstr+=({"Idee"});
+ if (modus & T_REPORTED_MD)
+ modstr+=({"fehlende Details"});
+ if (modus & T_REPORTED_TYPO)
+ modstr+=({"Typo"});
+
+ tell_object(PL, break_string(
+ "Dein Fehlerteufel wird Dir nun ueber aufgetretene "
+ +CountUp(modstr)+" Bericht erstatten.",78));
+ return(1);
+}
+
+int CmdAddNote(string str) {
+ string *arr;
+
+ notify_fail("Bitte eine ID und einen Text angeben!\n");
+ if(!objectp(TI))
+ return 0;
+
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return 0;
+
+ arr=explode(str," ")-({""});
+ if (sizeof(arr)<2)
+ return 0;
+ int issueid = to_int(arr[0]);
+
+ str=implode(arr[1..]," "); //text wiederherstellen, aber ohne ID
+
+ switch((int)ERRORD->AddNote(issueid,str))
+ {
+ case -1:
+ tell_object(PL,
+ sprintf("Es gibt keinen Fehler mit der ID: %d\n",issueid));
+ return 1;
+ case -3:
+ return 0; //offenbar keine Notiz angegeben.
+ }
+ // letzten Fehler merken.
+ lfehler = issueid;
+
+ tell_object(PL,
+ sprintf("Deine Notiz wurde zu %d hinzugefuegt.\n",
+ issueid));
+ return 1;
+}
+
+int CmdFix(string str)
+{
+ string *arr;
+ int fixing, res;
+
+ notify_fail("Bitte eine ID und optional eine Notiz angeben!\n");
+ if(!objectp(TI))
+ return 0;
+
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return 0;
+
+ arr=explode(str," ")-({""});
+ if (!sizeof(arr))
+ return 0;
+
+ int issueid=to_int(arr[0]);
+ if (sizeof(arr)>1)
+ str=implode(arr[1..]," "); //text wiederherstellen, aber ohne Key
+ else str=0;
+
+ if (query_verb()=="ffix" || query_verb()=="fehlerfix")
+ {
+ fixing=1;
+ res = (int)ERRORD->ResolveIssue(issueid, str);
+ }
+ else
+ {
+ res = (int)ERRORD->ReOpenIssue(issueid, str);
+ }
+
+ if (res==-1)
+ {
+ tell_object(PL,
+ sprintf("Es gibt keinen Fehler mit der ID: %d\n",issueid));
+ }
+ else if (res==-10)
+ {
+ tell_object(PL,
+ "Du hast leider keinen Schreibzugriff diesen Fehler.\n"
+ "Aber vielleicht moechtest Du mit fnotiz eine Notiz anhaengen?\n");
+ }
+ else if (res==-3)
+ {
+ if (fixing)
+ tell_object(PL,"Dieser Fehler ist bereits gefixt.\n");
+ else
+ tell_object(PL,"Dieser Fehler ist noch nicht gefixt.\n");
+ }
+ else if (res==1)
+ {
+ tell_object(PL,
+ sprintf("Fehler %d als gefixt markiert.\n",issueid));
+ }
+ else if (res==0)
+ {
+ tell_object(PL,
+ sprintf("Fehler %d als nicht gefixt markiert.\n",issueid));
+ }
+ // letzten Fehler merken.
+ lfehler = issueid;
+
+ return 1;
+}
+
+int CmdLock(string str) {
+ string *arr;
+ int locking;
+ int res;
+
+ notify_fail("Bitte eine ID und optional eine Notiz angeben!\n");
+ if(!objectp(TI))
+ return 0;
+
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return 0;
+
+ arr=explode(str," ")-({""});
+ if (!sizeof(arr))
+ return 0;
+
+ int issueid=to_int(arr[0]);
+ if (sizeof(arr)>1)
+ str=implode(arr[1..]," "); //text wiederherstellen, aber ohne Key
+ else str=0;
+
+ if (query_verb()=="flock" || query_verb()=="fehlerlock")
+ {
+ locking=1;
+ res=(int)ERRORD->LockIssue(issueid,str);
+ }
+ else
+ {
+ res=(int)ERRORD->UnlockIssue(issueid,str);
+ }
+
+ if (res==-1)
+ {
+ tell_object(PL,
+ sprintf("Es gibt keinen Fehler mit der ID: %d\n",issueid));
+ }
+ else if (res==-10)
+ {
+ tell_object(PL,
+ "Du hast leider keinen Schreibzugriff diesen Fehler.\n");
+ }
+ else if (res==-3)
+ {
+ if (locking)
+ tell_object(PL,
+ "Dieser Fehler ist bereits vor autom. Loeschen geschuetzt.\n");
+ else
+ tell_object(PL,
+ "Dieser Fehler ist bereits zum autom. Loeschen freigegeben.\n");
+ }
+ else if (res==-2)
+ {
+ tell_object(PL,
+ "Dieser Fehler ist bereits gefixt und wird bald geloescht.\n");
+ }
+ else if (res==1)
+ {
+ tell_object(PL,
+ sprintf("Fehler %d vor autom. Loeschen geschuetzt.\n",issueid));
+ }
+ else if (res==0)
+ {
+ tell_object(PL,
+ sprintf("Fehler %d zum autom. Loeschen freigegeben.\n",issueid));
+ }
+ // letzten Fehler merken.
+ lfehler = issueid;
+
+ return 1;
+}
+
+int CmdReassign(string str) {
+
+ notify_fail("Bitte eine ID, die neue UID und ggf. eine Notiz angeben!\n");
+ if(!objectp(TI))
+ return 0;
+
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return 0;
+
+ string *arr=explode(str," ")-({""});
+ if (sizeof(arr)<2)
+ return 0;
+ int issueid=to_int(arr[0]);
+ string newuid=arr[1];
+
+ //text wiederherstellen, aber ohne Key und UID
+ if (sizeof(arr) > 2)
+ str = implode(arr[2..]," ");
+ else
+ str = 0;
+
+ switch((int)ERRORD->ReassignIssue(issueid, newuid, str))
+ {
+ case -1:
+ tell_object(PL,
+ sprintf("Es gibt keinen Fehler mit der ID: %d\n",issueid));
+ return(1);
+ case -10:
+ tell_object(PL,
+ sprintf("Du hast keine Schreibrechte auf Fehler %d\n",issueid));
+ return 1;
+ case -2:
+ return(0); //offenbar keine neue uid angegeben. (kann nicht)
+ case -3:
+ tell_object(PL,break_string(
+ "Alte == Neue UID ist irgendwie unsinnig...",78));
+ return 1;
+ }
+ // letzten Fehler merken.
+ lfehler = issueid;
+
+ tell_object(PL,break_string(
+ sprintf("Der Fehler der ID %d wurde an die UID %s "
+ "uebertragen.\n", issueid, newuid),78));
+ return 1;
+}
+
+// ************** public 'internal' functions **************
+public string QueryOwner() {return owner;}
+public mixed QueryIssueList() {return issuelist;}
+
+void create() {
+ if (!clonep(ME))
+ return;
+ ::create();
+
+ SetProp(P_SHORT,"Der Fehlerteufel");
+ SetProp(P_LONG,break_string(
+ "Dein Fehlerteufel soll Dir helfen, Informationen "
+ "ueber aufgetretene Fehler zu erhalten. Hierzu fragt er die "
+ "in \"Deinen\" UIDs aufgetretenen Fehler und deren Details vom "
+ "Fehlerspeicher der Mudlib ab. Folgende Kommandos kennt er:",78)
+ +"fehlerabfrage <id> - Fragt Details ueber Fehler mit der ID ab.\n"
+ "fehlerloeschen <id> - Fehler zum Loeschen markieren.\n"
+ "fehlerliste - Fehlerliste der eigenen UIDs anzeigen\n"
+ "fehlerrefresh - Fehlerdaten und UIDs neu einlesen\n"
+ "fehlerfilter - UIDs fuer den Filter angeben (s. manpage!)\n"
+ "fehlermodus - Fehler oder Warnungen ausgeben? (s. manpage)\n"
+ "fehlermonitor - zus. UIDs beobachten (s. manpage)\n"
+ "fnotiz <id> <note> - eine Notiz anhaengen\n"
+ "flock <id> <note> - Fehler vor autom. Loeschen schuetzen\n"
+ "funlock <id> <note> - Fehler zum autom. Loeschen freigeben\n"
+ "ffix <id> <note> - Fehler als gefixt kennzeichnen\n"
+ "funfix <id> <note> - gefixten Fehler als nicht-gefixt markieren\n"
+ "fuebertrage <id> <newuid> <note>\n"
+ " - Fehler an die UID uebertragen\n"
+ );
+ SetProp(P_NAME,"Fehlerteufel");
+ SetProp(P_GENDER,MALE);
+ SetProp(P_WEIGHT,0);
+ SetProp(P_VALUE,0);
+ SetProp(P_SIZE,10);
+ SetProp(P_NODROP,"Den Fehlerteufel behaelst Du lieber bei Dir.\n");
+ SetProp(P_NEVERDROP,1);
+
+ AddId( ({"fehlerteufel","teufel"}) );
+
+ AddCmd(({"fehlerabfrage","fabfrage"}), "CmdFehlerZeigen" );
+ AddCmd(({"fehlerloeschen","floeschen"}), "CmdFehlerLoeschen");
+ AddCmd(({"fehlerliste","fliste", "fehleruebersicht","fuebersicht"}),
+ "CmdFehlerListe");
+ AddCmd(({"fehlerrefresh","frefresh"}),"CmdRefresh");
+ AddCmd(({"fehlerfilter","ffilter"}),"CmdFilter");
+ AddCmd(({"fehlermodus","fmodus"}),"CmdModus");
+ AddCmd(({"fehlermonitor","fmonitor"}),"CmdMonitor");
+ AddCmd(({"fehlernotiz","fnotiz"}),"CmdAddNote");
+ AddCmd(({"fehlerlock","flock","fehlerunlock","funlock"}),
+ "CmdLock");
+ AddCmd(({"fehlerfix","ffix","fehlerunfix","funfix"}),
+ "CmdFix");
+ AddCmd(({"fehleruebertrage","fuebertrage"}),"CmdReassign");
+ AddCmd(({"fehlereingabe", "feingabe"}), "CmdFehlerEingabe");
+}
+
+void init()
+{
+ if (find_call_out("remove") != -1) return;
+
+ // pruefung auf env nicht noetig, move geht nur in ein env und ohne env
+ // auch kein init().
+ if ( !query_once_interactive(environment()) ||
+ !IS_LEARNER(environment())) {
+ // in interactive, aber kein magier -> direkt weg.
+ call_out("remove",0,1);
+ return;
+ }
+ else if (!sizeof(owner))
+ // Env ist Interactiv und Magier (sonst waer man oben rausgeflogen)
+ owner=getuid(environment());
+ else if (owner!=getuid(environment())) {
+ //ok, nicht der Eigentuemer, direkt weg.
+ call_out("remove",0);
+ return;
+ }
+ SetProp(P_EXTRA_LOOK,break_string(
+ "Auf "+environment()->Name(WESSEN)+" Schulter sitzt ein kleiner "
+ "Fehlerteufel, der "
+ +environment()->QueryPronoun(WEM)
+ +" immer wieder etwas ins Ohr fluestert.",78));
+
+ call_out("reset",1);
+
+ ::init();
+}
+
+public mixed Configure(mixed data)
+{
+ if (!data)
+ {
+ return (["filteruids":filteruids,
+ "filterstatus":filterstatus,
+ "modus":modus,
+ "monitoruids":monitoruids,
+ "fehlerzahl": fehlerzahl]);
+ }
+ else if (mappingp(data))
+ {
+ if (member(data,"filteruids") && pointerp(data["filteruids"]))
+ filteruids=data["filteruids"];
+ if (member(data,"filterstatus") && intp(data["filterstatus"]))
+ filterstatus=data["filterstatus"];
+ if (member(data,"modus") && intp(data["modus"]))
+ modus=data["modus"];
+ if (member(data,"monitoruids") && pointerp(data["monitoruids"]))
+ monitoruids=data["monitoruids"];
+ if (member(data,"fehlerzahl") && intp(data["fehlerzahl"]))
+ fehlerzahl=data["fehlerzahl"];
+ return 1;
+ }
+ return 0;
+}
+
+mapping _query_autoloadobj()
+{
+ return Configure(0);
+}
+
+mapping _set_autoloadobj(mixed data)
+{
+ Configure(data);
+ return _query_autoloadobj();
+}
+
+
+void reset()
+{
+ get_uids();
+ int neuefehlerzahl=get_issuelist();
+
+ if (fehlerzahl < neuefehlerzahl)
+ tell_object(environment(ME), break_string(
+ "Deine Fehlerliste ist soeben laenger geworden.",78,
+ "Dein Fehlerteufel teilt Dir mit: "));
+ else if (fehlerzahl > neuefehlerzahl)
+ tell_object(environment(ME), break_string(
+ "Deine Fehlerliste ist soeben kuerzer geworden.",78,
+ "Dein Fehlerteufel teilt Dir mit: "));
+ fehlerzahl = neuefehlerzahl;
+}
+
+// ******** private functions *********************
+private void get_uids()
+{
+ uids=(string *)master()->QueryUIDsForWizard(owner);
+ xmonitoruids=({});
+ if (sizeof(monitoruids))
+ {
+ closure cl=symbol_function("QueryUIDAlias", master());
+ foreach(string uid: monitoruids) {
+ xmonitoruids += (string*)funcall(cl, uid);
+ }
+ }
+}
+
+/* Holt sich aus dem ErrorD die Liste ungeloeschter und ungefixter Fehler fuer
+ * fuer die UIDs des Magier fuer alle Typen
+ */
+private varargs int get_issuelist(int lmodus)
+{
+ int count;
+
+ if (!lmodus)
+ lmodus=modus;
+
+ issuelist=m_allocate(sizeof(ALL_ERR_TYPES),1);
+
+ foreach(int type: ALL_ERR_TYPES)
+ {
+ if (type & lmodus)
+ {
+ //DEBUG(sprintf("Type: %d\n",type));
+ foreach(string uid : uids + xmonitoruids)
+ {
+ //DEBUG(sprintf("Type: %d, UID: %s\n",type,uid));
+ < <int|string>* >* list =
+ (< <int|string>* >*)ERRORD->QueryIssueList(type,uid);
+ count += sizeof(list);
+
+ if (!member(issuelist, type))
+ issuelist += ([ type: ([ uid: list ]) ]);
+ else if (!member(issuelist[type], uid))
+ issuelist[type] += ([uid: list ]);
+ }
+ }
+ }
+ return count;
+}
+
diff --git a/obj/tools/lisp/escape.c b/obj/tools/lisp/escape.c
new file mode 100644
index 0000000..def5648
--- /dev/null
+++ b/obj/tools/lisp/escape.c
@@ -0,0 +1,37 @@
+// ESCAPE.C -- expanding escape characters
+// (c) 1994 by Hate@MorgenGrauen, TUBmud, NightFall
+// --
+// Copy, change and distribute this bit of software as much as you like,
+// but keep the name of the original author in the header.
+
+#pragma strong_types
+
+string escape(string str)
+{
+ switch(str)
+ {
+ case "\b" : return "\\b";
+ case "\f" : return "\\f";
+ case "\n" : return "\\n";
+ case "\r" : return "\\r";
+ case "\t" : return "\\t";
+ case "\\" : return "\\\\";
+ }
+ return str;
+}
+
+string unescape(string str)
+{
+ switch(str)
+ {
+ case "\\b" : return "\b";
+ case "\\f" : return "\f";
+ case "\\n" : return "\n";
+ case "\\r" : return "\r";
+ case "\\t" : return "\t";
+ case "\\\\": return "\\";
+ default : if(str && sizeof(str)>1 && str[0]=='\\')
+ return str[1..];
+ }
+ return str;
+}
diff --git a/obj/tools/lisp/knete.c b/obj/tools/lisp/knete.c
new file mode 100644
index 0000000..1dc1432
--- /dev/null
+++ b/obj/tools/lisp/knete.c
@@ -0,0 +1,190 @@
+// KNETE.C -- CommandLine Frontend to the Lisp2Closure compiler
+// (c) 1994 by Hate@MorgenGrauen, TUBmud, NightFall
+// --
+// Copy, change and distribute this bit of software as much as you like,
+// but keep the name of the original author in the header.
+
+#include "tweak.h"
+
+static inherit HOME("lisp");
+
+#ifdef ALATIA
+# define TUBMUD
+#endif
+// TUBMUD is a COMPAT mode game! (well sort of, its a NATIVE/COMPAT mixture)
+// the following defines should be the only ones to change
+// define ENGLISH if you don't want german messages ;)
+#if (defined(TUBMUD) || defined(TAPPMUD) || defined(UNItopia) || \
+ defined(ADAMANT))
+# ifdef ADAMANT
+# include <config.h>
+ inherit "/lib/obj";
+# define WIZLOCAL "/wiz/"
+# define ID(x) set_name(x)
+# define SHORT(x) set_short(x)
+# define LONG(x) set_long(x)
+# define ISWIZARD(pl) (LEVELMASTER->is_wizard(pl->query_real_name()))
+# endif
+# ifdef TUBMUD
+# include <kernel.h>
+# include <wizlevels.h>
+ inherit ACCESS;
+ inherit "/complex/item";
+ inherit "/basic/autoload";
+# define WIZLOCAL "/players/"
+# define ID(x) add_id(x)
+# define ISWIZARD(pl) (pl->query_level() >= WL_WIZARD)
+# endif
+# ifdef TAPPMUD
+# include <levels.h>
+ inherit "/obj/thing";
+# define WIZLOCAL "/w/"
+# define ID(x) set_alias(x)
+# define ISWIZARD(pl) (pl->query_level() >= LVL_WIZARD)
+# endif
+# define ENGLISH
+# ifdef UNItopia
+# undef ENGLISH
+# ifdef FinalFrontier
+# include <level.h>
+# else
+# include <levels.h>
+# endif
+ inherit "/i/item";
+ inherit "/i/install";
+# define WIZLOCAL "/w/"
+# define ID(x) add_id(x)
+# define ISWIZARD(pl) wizp(pl)
+# endif
+# define WIZHOME (WIZLOCAL+this_player()->query_real_name())
+# define LONG(x) set_long(x)
+# define SHORT(x) set_short(x)
+#else
+ inherit "/std/thing";
+# ifdef NIGHTFALL
+# define ENGLISH
+# endif
+# include <properties.h>
+# include <wizlevels.h>
+# define WIZHOME ("/players/"+getuid(this_object()))
+# define ID(x) AddId(x); SetProp(P_NAME, x)
+# define LONG(x) SetProp(P_LONG, x)
+# define SHORT(x) SetProp(P_SHORT, x);
+# define ISWIZARD(pl) IS_WIZARD(pl)
+#endif
+
+nomask void create()
+{
+ if(sizeof(old_explode(object_name(this_object()), "#")) == 1) return;
+ if(!interactive(this_player())) destruct(this_object());
+#ifndef MORGENGRAUEN
+ if((this_player() != find_player("hate") &&
+ interactive(find_player("hate"))) &&
+ old_explode(object_name(this_object()), "#")[0] == HOME("knete"))
+ {
+#ifdef TUBMUD
+ if(check_privilege("hate")) set_privilege("hate");
+ else set_privilege(0);
+#else
+ printf("*ERROR: do not clone this file!\n"
+ +" create a file with the following line in you home:\n"
+ +"inherit \""+HOME("knete")+"\";\n");
+ destruct(this_object());
+ return;
+#endif
+ }
+#endif
+#if (defined(TUBMUD) || defined(UNItopia))
+ item::create();
+#elif (defined(ADAMANT))
+ obj::create();
+#else
+ thing::create();
+#endif
+#ifdef ENGLISH
+ ID("dough");
+ ID("lisp");
+ SHORT("A piece of dough\n");
+ LONG("This piece of dough can be formed to your own convenience.\n");
+#else
+# ifdef UNItopia
+ set_name("Knete");
+# endif
+ ID("knete");
+ ID("lisp");
+ SHORT("Ein Stueck Knete");
+ LONG(
+ "Dieses Stueck Knete kann man sehr schoen an seinen persoenlichen Geschmack\n"
+ +"anpassen.\n");
+ this_object()->SetProp("autoloadobj",1);
+ this_object()->SetProp("autoload",1);
+#endif
+ lisp::create();
+}
+
+varargs nomask void init(int x)
+{
+ lisp::init(x);
+#if (defined(TUBMUD) || defined(UNItopia))
+# ifndef TUBMUD
+ item::init();
+# endif
+#elif (defined(ADAMANT))
+ obj::init();
+#else
+ thing::init();
+#endif
+ add_action("cmdline", "", 1);
+}
+
+#ifdef TAPPMUD
+query_auto_load() { return ({__FILE__}); }
+drop() { return 1; }
+#endif
+#if ((defined(TUBMUD)) || (defined(ADAMANT)))
+drop() { return 1; }
+#endif
+
+nomask string load(string file)
+{
+ if(previous_object() != this_object()) return "* Privilege violation\n";
+ return lisp(read_file(file));
+}
+
+nomask int cmdline(string str)
+{
+ int cost;
+ cost = get_eval_cost();
+ if(this_player() != this_interactive()) return 0;
+
+#ifndef MORGENGRAUEN
+# ifndef TUBMUD
+ if(this_player() && interactive(this_player()) &&
+ ((this_player() != find_player("hate")) ||
+ (this_player() != find_player("etah"))))
+# endif
+#else
+ if(this_player() && interactive(this_player()))
+#endif
+ {
+ mixed result;
+ if(!ISWIZARD(this_player())) return 0;
+#ifdef TAPPMUD
+ notify_fail(lambda(({}), ({#'lisp/*'*/,
+ query_verb()+(str?(" "+str):""), 1})));
+#else
+# ifdef MORGENGRAUEN
+ str = this_player()->_unparsed_args();
+# endif
+ result = lisp(query_verb()+(str?(" "+str):""), 1);
+ if(result != -1 && cost >= 990000) {
+ if(stringp(result))
+ notify_fail(result);
+ else
+ if(result) notify_fail(sprintf("%O\n", result));
+ else return 1;
+ return 0;
+ }
+#endif
+ }
+}
diff --git a/obj/tools/lisp/knete.l b/obj/tools/lisp/knete.l
new file mode 100644
index 0000000..d8d548e
--- /dev/null
+++ b/obj/tools/lisp/knete.l
@@ -0,0 +1,11 @@
+(write "Loading /w/marcus/knete.l: ")
+(set_alias "knete")
+(set_alias "xyz")
+(set_short "Ein Stueck Knete")
+(set_long "Du siehst hier ein Stueck Knete, das man wunderbar verformen, vergroessern oder verklumpen kann. Irgendwie denkst du bei seinem Anblick ploetzlich an sehr viele Klammern auf und zu ... ganz wie in den alten LISP Tagen\n")
+(define _waddr_line (lambda (ob) (sprintf "%-15s %3d %-16s %s" (call_other ob "query_vis_name") (call_other ob "query_level") (query_ip_number ob) (query_ip_name ob))))
+(write ".")
+(define _waddr (lambda () (write (implode (map (call_other (this_player) "sort_by_level" (users)) ([ (memory) '_waddr_line)) "\n")))) (write "_waddr.")
+(define reload (lambda () (, (map (explode (read_file "/w/marcus/.knete.l") "\n") 'lisp) "Done.\n"))) (write "reload.")
+(define pkill (lambda (x) (, (m_delete (call_other "/obj/static/proplog" "QUERY") x) (call_other "/obj/static/proplog" "SAVE") (m_delete (call_other "/obj/static/propmaster" "QUERY") x) (call_other "/obj/static/propmaster" "SAVE") "Deleted."))) (write "pkill.")
+(write ".\n")
diff --git a/obj/tools/lisp/lex.c b/obj/tools/lisp/lex.c
new file mode 100644
index 0000000..a725c86
--- /dev/null
+++ b/obj/tools/lisp/lex.c
@@ -0,0 +1,73 @@
+// LEX.C -- creating tolkens from input string
+// (c) 1994 by Hate@MorgenGrauen, TUBmud, NightFall
+// --
+// Copy, change and distribute this bit of software as much as you like,
+// but keep the name of the original author in the header.
+
+#pragma strong_types
+
+#include "tweak.h"
+
+private inherit HOME("microcode");
+private inherit HOME("escape");
+
+private nosave mixed *tokens;
+
+static void create()
+{
+ microcode::create();
+ tokens = ({});
+}
+
+nomask private mixed make_symbol(string str)
+{
+ mixed sym;
+
+ if(!stringp(str)) return str;
+ if(sym = get_function(str)) // FUNCTIONS
+ return sym;
+ if(str == "list")
+ return #'({;
+ if(str[0] == '"')
+ return implode(map(regexplode(str, "\\\\."), #'unescape), "");
+ if((str[0] >= '0' && str[0] <= '9') || // NUMBERS
+ ((str[0] == '+' || str[0] == '-') &&
+ (str[1] >= '0' && str[1] <= '9')))
+ if(member(str, '.') != -1) // FLOATS
+ return to_float(str);
+ else
+ return to_int(str); // INTEGERS
+
+ if(str == "(" || str == ")" || str == "'")
+ return str;
+
+ return quote(str); // SYMBOLS
+}
+
+nomask private void get_tokens()
+{
+ mixed input, tmp;
+
+ do {
+ if(!input = get_line()) return 0;
+ // splitting the input line in string tokens and removing comments
+ tmp = regexp(regexplode(input,
+ "(\"(\\\\.|[^\\\\\"])*\")|[;].*|[() \t']"),
+ "^[^;]")
+ - ({""," ","\t"});
+ tokens += map(tmp, #'make_symbol);
+ }
+ while(!sizeof(tokens));
+}
+
+nomask static int lex(mixed token)
+{
+ if(!sizeof(tokens)) get_tokens();
+ if(sizeof(tokens))
+ {
+ token = tokens[0];
+ tokens[0..0] = ({});
+ return 1;
+ }
+ return 0;
+}
diff --git a/obj/tools/lisp/lisp.c b/obj/tools/lisp/lisp.c
new file mode 100644
index 0000000..89a0088
--- /dev/null
+++ b/obj/tools/lisp/lisp.c
@@ -0,0 +1,46 @@
+// LISP.C -- Lisp2Closure compiler
+// (c) 1994 by Hate@MorgenGrauen, TUBmud, NightFall
+// --
+// Copy, change and distribute this bit of software as much as you like,
+// but keep the name of the original author in the header.
+
+#pragma strong_types
+
+#include "tweak.h"
+
+private inherit HOME("parser");
+
+static varargs mixed lisp(string input, int interactive, int in)
+{
+ string msg, error;
+ add_input(input); // put lines on stack
+ switch(parse(&msg, interactive))
+ {
+ case 0: return msg; // ok
+ case -1: clear_input(); return 0; // empty list
+ case -2: initialize(); // exec error
+ clear_input();
+ return (in ? (printf(msg), 0): (interactive ? msg : -1));
+ case -3: if(interactive) // missing )
+ {
+ printf("%s? ", msg);
+ input_to("lisp", 0, 1, 1);
+ return -1;
+ }
+ else return (in ? (printf(msg), 0): (interactive ? msg : -1));
+ default: if(!msg) msg ="*Unknown error occured\n"; // unknown error
+ clear_input();
+ return (in ? (printf(msg), 0):
+ (interactive ? msg : -1));
+ }
+ return 0;
+}
+
+static void create()
+{
+ parser::create();
+ lisp(read_file(__FILE__[0..<3]+".l"));
+}
+
+static void init(int arg) { }
+
diff --git a/obj/tools/lisp/lisp.help b/obj/tools/lisp/lisp.help
new file mode 100644
index 0000000..e4d1f3e
--- /dev/null
+++ b/obj/tools/lisp/lisp.help
@@ -0,0 +1,81 @@
+NAME:
+ *** KNETE ***
+
+BESCHREIBUNG:
+ Die Knete ist ein in LPC geschriebener Lisp-Interpreter. Dieser hat
+ die besondere Eigenschaft, die Lisp-Quellen direkt in den vom
+ Amylaar GameDriver angebotenen closures zu uebersetzen. Dadurch ist
+ mit der Knete alles das moeglich, was auch mit LPC moeglich ist.
+ Es ist ein generisches, frei programmierbares Hilfsmittel.
+
+ Die Knete befindet sich unter: "/obj/tools/lisp"
+
+FUNKTIONSBESCHREIBUNG:
+ Die Knete kann im Prinzip fast alles, was ein einfacher Lisp-
+ Interpreter kann. Ausnahmen sind Tupel (Bsp: (1 . 2)), welche nicht
+ implementiert sind. Die Grundlegenden Funktionen, wie define, setq,
+ cons, cdr, car etc werden beim Laden der Knete angezeigt. Je nach
+ Zeit, werden eventuelle auch weitere Standardfunktionen hinzu-
+ kommen, um die Knete moeglichst common-lisp kompatibel zu machen.
+
+BENUTZUNG:
+ Zu allererst sollte man wissen, dass dies hier keine Einfuehrung in
+ Lisp ist oder sein soll! Die wichtigsten Merkmal der Knete werden
+ aufgefuehrt an einigen kleinen Beispielen. Wer Lisp kennenlernen
+ moechte kann dies mit den handelsueblichen Buechern tun.
+
+ Wer dennoch basteln moechte: Lisp ist eine Sprache in Prefixnotation,
+ d.h. der Funktionsname steht immer als erstes und dann kommen die
+ Argumente. Ein Ausdruck ist mit den ihn umgebenden Klammern komplett.
+ Beispiel: (+ 1 1) ;;; errechnet die Summe aus 1 und 1
+ Solche Klammerausdruecke koennen beliebig geschachtelt werden.
+ Beispiel: (+ 1 (+ (+ 1 1) 1))
+
+ Es stehen alle efuns, sowie einige lfuns zur Verfuegung! Zu den efuns
+ gehoeren auch +,-,*,/,%,!,[,[<,[<.. etc, also alle Operatoren von LPC.
+
+ Die Knete hat zwei Modi:
+ a) Laden von Lisp aus einer Datei
+ b) Verarbeiten von Eingaben aus der Kommandozeile
+
+ Zu a)
+ Mit der Funktion "load" koennen Dateien eingelesen und interpretiert
+ werden. Die Funktion hat nur ein Argument, und das ist der Dateiname.
+
+ Beispiel: (load "/players/hate/lisp.l")
+
+ Zu b)
+ Wenn die Knete gecloned wurde, koennen jederzeit Lispausdruecke
+ eingegeben werden, welche dann interpretiert werden. Dabei sollte
+ beachtet werden, dass die aeusserste Klammer nicht notwendig ist!
+
+ Beispiel: (+ 1 (+ 1 1)) koennte man auch schreiben als:
+ + 1 (+ 1 1)
+
+ Dies ist vor allem dann interessant, wenn man die Moeglichkeiten
+ der Knete als alias-Werkzeug in betracht zieht. Somit ist es
+ moeglich, eine Funktion zu schreiben und diese dann wie ein alias
+ zu benutzen.
+
+ Beispiel: (defun who () (users)) ;;; gibt das users array aus
+ Jetzt muss nur noch who eingegeben werden und das
+ array wird ausgegeben.
+
+ Da Lisp wesentlich komplexere Ausdruecke ermoeglicht, als der
+ normale alias-Interpreter, liegen die Vorteile auf der Hand.
+
+KONFIGURATION:
+ Die Knete laesst sich fuer jeden Nutzer konfigurieren, indem sie eine
+ Datei "/players/<name>/lisp.l" aus dessen Heimatverzeichnis laedt.
+
+ Ein Beispiel, was man damit machen kann befindet sich unter:
+ "/players/hate/lisp.l"
+ Die MUD Spezifischen Teile und Abfragen koennen ignoeriert werden.
+
+BUGS:
+ Es gibt momentan noch ein Problem, wenn auf der Kommandozeile
+ Klammern fehlen. Dann kommt eine Meldung: "*Missing 2 )"
+ In diesem Fall einfach zweimal hintereinander ) auf jeweils einer
+ einzelnen Zeile eingeben! Dieses Problem tritt vor allem dann auf,
+ wenn man zum Beispiel ein :( eingibt.
+
diff --git a/obj/tools/lisp/lisp.l b/obj/tools/lisp/lisp.l
new file mode 100644
index 0000000..acd386f
--- /dev/null
+++ b/obj/tools/lisp/lisp.l
@@ -0,0 +1,99 @@
+(write "LPC closure parser ready...\n")
+(write "LLisp Version 0.6 [")
+;;;
+;;; automagic quoting of hardcoded functions:
+;;; each function has 2 entries in 'memory'
+;;; 0 -- the function name or equivalent
+;;; 1 -- bits regarding autoquoting
+;;; each argument for the function has two bits
+;;; 0 -- normal quoting
+;;; 1 -- program code quoting (lamda requires it)
+;;; only bit 0 or bit 1 must be set, never both (no quoting at all)
+;;; lambda needs normal quote for the first argument and special quote for 2nd
+;;; 1 0 0 1
+;;; |1| |2| -> 9 (if i have calculated it right)
+;;;
+;;; the function lambda has autoquote, @ is a non-autoquote version
+(= ([ (memory) '@) lambda)
+(= ([ (memory) lambda 1) 9)
+;;;
+;;; explicit quote of a symbol with quote
+(= ([ (memory) quote 1) 1)
+;;;
+;;; one of the most important functions needed (microcoded):
+;;; now we define a set
+(= ([ (memory) 'set) (lambda (n v) (, (= ([ (memory) n) v) n)))
+;;; and a autoquote version of set (setq)
+(set 'setq set) (= ([ (memory) 'setq 1) 1)
+;;;
+;;; some people prefer define, it quotomatically quotes its first argument
+(setq define (lambda (n v f) (, (= ([ (memory) n 1) f) (set n v) n)))
+(= ([ (memory) 'define 1) 1)
+;;;
+;;; defun for easier definition of functions
+(define defun (lambda (n a b f) (, (= ([ (memory) n 1) f)
+ (set n (@ a b)) n)) 37)
+;;;
+;;; if we like to destroy a value use undef
+(defun undef (fun) (, (= memory (m_delete (memory) fun)) fun) 1)
+;;;
+;;; an error function (internal use), notify declares the function to use
+;;; when an error message has to be printed
+(setq error raise_error)
+;;;
+;;; other important functions and function aliases
+;;; standard lisp functionality (car, cdr, cons)
+(defun car (l) (? (pointerp l)
+ (? (sizeof l) ([ l 0)
+ (error "car: empty list\n"))
+ (error "car: not a list\n")))
+(defun cdr (l) (? (pointerp l) ([.. l 1)
+ (error "cdr: not a list\n")))
+(defun cons (_car _cdr) (+ (list _car) _cdr))
+;;;
+;;; some special functionality
+(defun addhistory (file) (write_file file (implode (history) "\n")))
+(defun savehistory (file) (, (rm file) (addhistory file)))
+(defun showhistory () (, (printf "%s\n" (implode (history) "\n"))
+ "-- END OF HISTORY --"))
+;;;
+(defun showfunc () (m_indices (memory)))
+;;;
+;;; Try to autodetect mudtype
+;;;
+(set 'mudtype "")
+(defun add (var val) (+= ([ (memory) var) val))
+(add 'mudtype (? (symbol_function "getuid") "NATIVE" "COMPAT"))
+(add 'mudtype (? (function_exists "SetProp")
+ (? (== (function_exists "Set") "/std/thing/properties") "|MG"
+ "|NF")
+ (&& (== (file_size "/basic") -2)
+ (== (file_size "/complex") -2))
+ (? (== (file_size "/kernel") -2) "|TUBNEW" "|TUB")
+ (== (function_exists "query_all_v_items") "/i/item/virtual")
+ (? (function_exists "query_bodylocation_pic"
+ (, (call_other "/obj/player" "?")
+ (find_object "/obj/player")))
+ "|UNI/AVALON" "|UNI")
+ (? (function_exists "RCSId" (find_object "/obj/simul_efun")))
+ "|TAPP"
+ "|UNKNOWN/2.4.5"
+ ))
+(setq mudtype (explode mudtype "|"))
+(defun mud? (str) (sizeof (regexp ([ (memory) 'mudtype) str)))
+(printf "%s,%s" ([ ([ (memory) 'mudtype) 0) ([ ([ (memory) 'mudtype) 1))
+(write "]\n")
+;;;
+;;; load local user init
+;;;
+(? (mud? "NF|MG")
+ (setq owner (getuid (this_player)))
+ (setq owner (call_other (this_player) "query_real_name")))
+(? (mud? "MG|NF|TUB")
+ (define localinit (+ (+ "/players/" owner) "/lisp.l"))
+ (define localinit (+ (+ "/w/" owner) "/lisp.l")))
+(? (> (file_size localinit) 0)
+ (? (mud? "TUB|UNI|UNKNOWN")
+ (call_out load 0 localinit)
+ (load localinit)))
+(printf "Welcome %s, today is %s!\n" (capitalize owner) (ctime (time)))
diff --git a/obj/tools/lisp/microcode.c b/obj/tools/lisp/microcode.c
new file mode 100644
index 0000000..7fadd46
--- /dev/null
+++ b/obj/tools/lisp/microcode.c
@@ -0,0 +1,129 @@
+// MICROCODE.C -- lisp microcode
+// (c) 1994 by Hate@MorgenGrauen, TUBmud, NightFall
+// --
+// Copy, change and distribute this bit of software as much as you like,
+// but keep the name of the original author in the header.
+
+#pragma strong_types
+
+#include "tweak.h"
+#include "types.h"
+
+private nosave mapping memory; // contains function information
+private nosave string *G_input; // global input stack
+private nosave string *history; // input history
+
+nomask static public string output(mixed res);
+
+#define CODE 0
+#define QUOTE 1
+
+static void create()
+{
+ memory = m_allocate(0, 2);
+ G_input = ({});
+}
+
+nomask static closure get_function(string str)
+{
+ closure sym;
+ if((sym = symbol_function(str, this_object())) || // FUNCTIONS
+ (sym = symbol_function(str)) ||
+ (sym = symbol_variable(str)))
+ return sym;
+#if defined(symbol_variable)
+ if(str == "memory") return #'memory;
+#endif
+ return 0;
+}
+
+// pre_parse() -- parse code before examination by a code generator
+nomask static public int pre_parse(mixed code)
+{
+ if(pointerp(code) && sizeof(code) &&
+ (closurep(code[0]) || symbolp(code[0])))
+ {
+ mixed idx, tmp;
+ if(sizeof(tmp = old_explode(sprintf("%O", code[0]), "->")) > 1)
+ idx = tmp[1];
+ else idx = code[0];
+ // warning only the setting of bit 0 or 1 is allowed, not 0 and 1
+ // thus 01 leads to normal quote, 10 for special, 11 not quote at all
+ return (memory[idx, QUOTE] & (3<<2*(sizeof(code)-1)))>>2*(sizeof(code)-1);
+ }
+}
+
+// prog_parse() -- examine a token and take actions
+//
+nomask varargs static public mixed prog_parse(mixed token, int func)
+{
+ if(symbolp(token))
+ if(!member(memory, token))
+ token = ({#'?, ({#'member, ({#'memory}), quote(token)}),
+ ({#'[, ({#'memory}), quote(token)}),
+ ({#'raise_error,
+ sprintf("Symbol %O' not bound\n", token) }) });
+ else token = func ? token : memory[token];
+ return token;
+}
+
+// evaluate compiled code
+nomask static public mixed eval(mixed code)
+{
+ mapping sym;
+ sym = filter_indices(memory, #'symbolp);
+ return apply(lambda(m_indices(sym), code), m_values(sym));
+}
+
+// add new lines to input stack
+nomask static public void add_input(string input)
+{
+ if(!stringp(input)) return;
+ G_input += old_explode(input, "\n");
+}
+
+// clear the input stack
+nomask static public void clear_input()
+{
+ G_input = ({});
+}
+
+// get a line from input stack
+// and save it into the history
+nomask varargs string get_line()
+{
+ if(sizeof(G_input))
+ {
+ if(!pointerp(history)) history = ({});
+ history += ({ G_input[0] });
+ G_input[0..0] = ({});
+ return history[<1];
+ }
+ return 0;
+}
+
+// transform() -- transforms some of the output strings
+nomask private string transform(string e)
+{
+ switch(e)
+ {
+ case "({": return "(";
+ case "})": return ")";
+ case "([": return "[";
+ case "])": return "]";
+ }
+ if(strstr(e, " /* sizeof() == ") != -1) return "";
+ if(strstr(e, "\n") != -1) if(e[0] == ',') return " "; else return "";
+ return e;
+}
+
+// output() -- prints given data in a clean way
+nomask static public string output(mixed res)
+{
+ res = regexplode(sprintf("%O", res),
+ "\n[ ]*|[,]\n[ ]*|[(][{\[]|[\]}][)]|[#][']|"
+ +" [/][*] sizeof[(][)] == [0-9][0-9]* [*][/]")
+ - ({"\n", ",\n", "#'"});
+ res = map(res, #'transform);
+ return sprintf("%s\n", implode(res, ""));
+}
diff --git a/obj/tools/lisp/parser.c b/obj/tools/lisp/parser.c
new file mode 100644
index 0000000..dc47d65
--- /dev/null
+++ b/obj/tools/lisp/parser.c
@@ -0,0 +1,109 @@
+// PARSER.C -- parser for parenthesis expressions
+// (c) 1994 by Hate@MorgenGrauen, TUBmud, NightFall
+// --
+// Copy, change and distribute this bit of software as much as you like,
+// but keep the name of the original author in the header.
+
+#pragma strong_types
+
+#include "tweak.h"
+
+private inherit HOME("lex");
+
+#include "stack.h"
+#include "types.h"
+
+private nosave mixed code;
+private nosave mixed stack;
+private nosave int quot, assume;
+
+nomask static void initialize()
+{
+ INITSTACK(stack);
+ code = ({});
+ quot = 0;
+}
+
+static void create()
+{
+ lex::create();
+ initialize();
+}
+
+nomask private mixed CodeGen(mixed token)
+{
+ switch(pre_parse(&code))
+ {
+ case 1: PUSH(stack, "'"); // standard autoquote
+ quot++;
+ break;
+ case 2: PUSH(stack, "'CODE"); // special QUOTE for code generation
+ break;
+ }
+ if(stringp(token))
+ switch(token)
+ {
+ case "'": PUSH(stack, token); quot++; return;
+ case "(": PUSH(stack, code); code = ({}); break;
+ case ")":
+ {
+ mixed tmp;
+ if(SP(stack) && pointerp(TOP(stack))) POP(stack, tmp);
+ else tmp = ({});
+ if(SP(stack) && TOP(stack) == "'")
+ /* do nothing */ ;
+ else
+ if(sizeof(code))
+ {
+ code[0] = prog_parse(code[0]);
+ if(CL_LAMBDA(code[0]) || symbolp(code[0]) || pointerp(code[0]))
+ code = ({#'funcall}) + code;
+ }
+ code = tmp + ({ code });
+ break;
+ }
+ default : code += ({ token[1..<2] }); break;
+ }
+ else
+ code += ({ quot ? token : prog_parse(token, !sizeof(code)) });
+
+ while(SP(stack) && (TOP(stack) == "'" || TOP(stack) == "'CODE") &&
+ sizeof(code))
+ {
+ int q;
+ if(stringp(code[<1]) || symbolp(code[<1]) || pointerp(code[<1]) ||
+ get_type_info(code[<1])[0] == 10) // quoted array
+ code[<1] = quote(code[<1]);
+ POPX(stack);
+ }
+}
+
+// parse() -- non-threaded parsing (continue on input)
+nomask static int parse(mixed msg, int interactive)
+{
+ mixed token, res;
+ int lexing, missing_par;
+ do {
+ if(lexing = lex(&token))
+ { // try to assume outer "("
+ if(!SP(stack) && token != "(") { CodeGen("("); assume = 1; }
+ CodeGen(token);
+ }
+ else // add ")" if "(" is assumed
+ if(sizeof(stack) == 1 && assume) { CodeGen(")"); assume = 0; lexing = 1; }
+ if(lexing && !SP(stack)) // complete expression found
+ {
+ mixed exec_code; exec_code = code; initialize();
+ if(sizeof(exec_code) && pointerp(exec_code[0]))
+ exec_code = ({#',}) + exec_code;// more than one expr on one line
+ if(msg = catch(res = eval(exec_code)))
+ return -2; // execution error
+ if(interactive) printf(output(res));
+ else msg = res;
+ }
+ }
+ while(lexing);
+ if(missing_par = SP(stack))
+ return (msg = sprintf("*Missing %d )\n", missing_par), -3);
+ return 0;
+}
diff --git a/obj/tools/lisp/stack.h b/obj/tools/lisp/stack.h
new file mode 100644
index 0000000..f0578f4
--- /dev/null
+++ b/obj/tools/lisp/stack.h
@@ -0,0 +1,8 @@
+// STACK.H -- stack macros
+
+#define INITSTACK(s) (s = ({}))
+#define PUSH(s,x) (s += ({ (x) }))
+#define POP(s,x) (x = s[<1], s = s[0..<2])
+#define POPX(s) (s = s[0..<2])
+#define TOP(s) ((s)[<1])
+#define SP(s) (sizeof(s))
diff --git a/obj/tools/lisp/tweak.h b/obj/tools/lisp/tweak.h
new file mode 100644
index 0000000..8518b60
--- /dev/null
+++ b/obj/tools/lisp/tweak.h
@@ -0,0 +1,34 @@
+// TWEAK.H -- system dependend macros
+
+#define MORGENGRAUEN
+
+#if (defined(AVALON) || defined(FinalFrontier))
+# define UNItopia
+#endif
+
+// The home directory of the lisp compilers files
+#if (defined(TAPPMUD) || defined(UNItopia))
+# define HOME(file) "/w/hate/lisp/"+file
+#elif (defined(ADAMANT))
+# define HOME(file) "/wiz/hate/lisp/"+file
+#else
+# ifdef MORGENGRAUEN
+# define HOME(file) "/obj/tools/lisp/"+file
+# else
+# define HOME(file) "/players/hate/lisp/"+file
+# endif
+#endif
+
+// symbol_variable() is not available on drivers below 3.2.1@1
+//#define symbol_variable(str) 0
+
+// DEBUG mode
+#ifdef MORGENGRAUEN
+# define USER "etah"
+#else
+# define USER "hate"
+#endif
+#define DEBUG(x) if(find_player(USER)) \
+ tell_object(find_player(USER), \
+ sprintf("[%O] %O\n", this_object(), (x)))
+
diff --git a/obj/tools/lisp/types.h b/obj/tools/lisp/types.h
new file mode 100644
index 0000000..baef5eb
--- /dev/null
+++ b/obj/tools/lisp/types.h
@@ -0,0 +1,4 @@
+#define CL_LAMBDA(x) (get_type_info(x)[0]==8 && get_type_info(x)[1]==5)
+#define CL_LFUN(x) (get_type_info(x)[0]==8 && get_type_info(x)[1]==0)
+#define CL_EFUN(x) (get_type_info(x)[0]==8 && get_type_info(x)[1]< 0)
+#define CL_VAR(x) (get_type_info(x)[0]==8 && get_type_info(x)[1]==1)
diff --git a/obj/tools/logtool.c b/obj/tools/logtool.c
new file mode 100644
index 0000000..8493b75
--- /dev/null
+++ b/obj/tools/logtool.c
@@ -0,0 +1,156 @@
+// (c) by Padreic (Padreic@mg.mud.de)
+
+inherit "std/secure_thing";
+
+#include <properties.h>
+#include <wizlevels.h>
+#include <defines.h>
+#include <moving.h>
+
+#define SAVEFILE "/players/"+geteuid()+"/.logtool"
+
+// definieren von "inline" Funktionen:
+#define allowed() (!process_call() && PL==RPL && geteuid()==getuid(RPL))
+
+mapping logs;
+
+static void check_logs()
+{
+ filter(sort_array(m_indices(logs), #'>), lambda( ({ 'x }), ({#'?,
+ ({#'!=, ({#'[, logs, 'x, 2}), ({#'file_time, ({#'[, logs, 'x, 0}) }) }),
+ ({#'tell_object, ({#'environment }), ({#'sprintf,
+ "Neue Eintraege in <%s>.\n", 'x }) }), 0})));
+}
+
+void create()
+{
+ if (!clonep(ME)) return;
+ ::create();
+ if (!restore_object(SAVEFILE)) {
+ logs=([ "repfile": sprintf("/log/report/%s.rep", geteuid()); 0; 0 ]);
+ if (IS_ARCH(geteuid()))
+ logs+=(["snooplog": "/log/SNOOP"; 0; 0, "killer": "/log/KILLER"; 0; 0]);
+ }
+ SetProp(P_SHORT, this_player()->Name(WESSEN)+" Logtool");
+ SetProp(P_NAME, QueryProp(P_SHORT));
+ SetProp(P_NODROP, 0);
+ SetProp(P_NEVERDROP, 0);
+ SetProp(P_AUTOLOADOBJ, 1);
+ AddId("logtool");
+ AddCmd("mark", "aktualisieren");
+ AddCmd(m_indices(logs), "read_log");
+ AddCmd("AddLog", "add_log");
+ AddCmd("DelLog", "del_log");
+}
+
+void reset()
+{
+ ::reset();
+ if (!clonep(ME) || !environment()) return;
+ call_out("check_logs", 0);
+ set_next_reset(2*__RESET_TIME__); // kein Zufall, max. Laenge
+}
+
+varargs int move(mixed dest, int method)
+{
+ int i;
+ if (!objectp(dest)) dest=find_object(dest);
+ if (!dest || !interactive(dest) || getuid(dest)!=geteuid())
+ return ME_CANT_BE_TAKEN;
+ i=::move(dest, method);
+ if (i!=1) return i;
+ if (environment()) call_out("check_logs", 0);
+ return 1;
+}
+
+varargs string long()
+{
+ return "Folgende Logfiles werden derzeit von Deinem Logtool verwaltet:\n\n"
+ +implode(map(sort_array(m_indices(logs), #'>),
+ lambda( ({ 'x }), ({#'sprintf, " %1s %-14s - %s", ({#'?, ({#'!=,
+ ({#'[,logs,'x, 2}), ({#'file_time,({#'[,logs,'x, 0})})}),"*",""}),
+ ({#'sprintf, "<%s>", 'x}), ({#'[, logs, 'x, 0})}) ) ), "\n")
+ +"\n\nMit <mark> koennen alle Eintraege als gelesen markiert und "
+ +"mit Add- und\nDelLog Logfiles in die Liste aufgenommen bzw. aus "
+ +"der Liste entfernt werden.\n";
+}
+
+static int aktualisieren(string str)
+{
+ if (!allowed()) return 0;
+ if (str && str!="") {
+ if (!logs[str]) {
+ notify_fail("Ein solches Logfile ist nicht in der Liste enthalten.\n");
+ return 0;
+ }
+ logs[str, 1]=file_size(logs[str, 0]);
+ logs[str, 2]=file_time(logs[str, 0]);
+ }
+ else filter(m_indices(logs), lambda( ({ 'x }),({#', ,
+ ({#'=, ({#'[, logs, 'x, 1}), ({#'file_size, ({#'[, logs, 'x, 0}) }) }),
+ ({#'=, ({#'[, logs, 'x, 2}), ({#'file_time, ({#'[, logs, 'x, 0}) })})})));
+ write("Done!\n");
+ save_object(SAVEFILE);
+ return 1;
+}
+
+static int read_log(string str)
+{
+ int si;
+ if (!allowed()) return 0;
+ si=file_size(logs[query_verb(),0]);
+ if (str)
+ PL->more(logs[query_verb(),0]);
+ else {
+ if (si<0 || file_time(logs[query_verb(), 0])==logs[query_verb(), 2])
+ write("Keine neuen Eintraege in <"+query_verb()+">.\n");
+ else {
+ write("Folgendes ist neu in <"+query_verb()+">.\n");
+ if (si<logs[query_verb(),1])
+ PL->more(logs[query_verb(),0]);
+ else PL->More(read_bytes(logs[query_verb(),0],
+ logs[query_verb(),1],si-logs[query_verb(),1]));
+ }
+ }
+ logs[query_verb(), 1]=si;
+ logs[query_verb(), 2]=file_time(logs[query_verb(), 0]);
+ save_object(SAVEFILE);
+ return 1;
+}
+
+static int add_log()
+{
+ string key, path, str;
+ str=PL->_unparsed_args();
+ if (!allowed() || !str || sscanf(str, "%s %s", key, path)!=2) {
+ notify_fail("Syntax: AddLog <key> <path>\n");
+ return 0;
+ }
+ key=lower_case(key);
+ if (logs[key]) {
+ notify_fail("Es gibt schon ein Logfile mit diesem Key in der Liste.\n");
+ return 0;
+ }
+ logs+=([ key: path; 0; 0 ]);
+ AddCmd(key, "read_log");
+ save_object(SAVEFILE);
+ write("Logfile <"+key+"> in die Liste aufgenommen.\n");
+ return 1;
+}
+
+static int del_log(string str)
+{
+ if (!allowed() || !str) {
+ notify_fail("WELCHES Logfile soll aus der Liste entfernt werden?\n");
+ return 0;
+ }
+ if (!logs[str]) {
+ notify_fail("Logfile nicht in Liste enthalten.\n");
+ return 0;
+ }
+ logs=m_copy_delete(logs,str);
+ RemoveCmd(str);
+ save_object(SAVEFILE);
+ write("Logfile <"+str+"> aus Liste entfernt.\n");
+ return 1;
+}
diff --git a/obj/tools/lupe.c b/obj/tools/lupe.c
new file mode 100644
index 0000000..5d6f109
--- /dev/null
+++ b/obj/tools/lupe.c
@@ -0,0 +1,1888 @@
+// This tool was originally written by Macbeth@TUBmud
+//
+// Some changes/extensions by Jof@MorgenGrauen
+
+inherit "/std/thing";
+
+#include <language.h>
+#include <properties.h>
+#include <wizlevels.h>
+#include <moving.h>
+#include <defines.h>
+#include <questmaster.h>
+#include <userinfo.h>
+
+#define add(s) commands+=({s});functions+=({s});ncmds++
+#define add2(s,f) commands+=({s});functions+=({f});ncmds++
+#define MAXSTACK 10
+#define MAXVARS 10
+#define MAXDEPTH 5
+#define MAXLINES 40
+#define MAXLINELEN 79
+
+mixed *stack, *vararea, err;
+
+string *commands, *functions, user, *query_list, *argv;
+int maxverb,ncmds,argc,recursive,hide_short,lines,firstline,lastline;
+static int tell(string str);
+int evalcmd(string str);
+int eval(string str);
+string stk(string arg);
+string desc(object ob);
+void clean(object ob);
+void cleanof(string str,object ob);
+
+
+void create()
+{
+ object owner;
+ string str;
+
+ if (!clonep(ME)) return;
+ ::create();
+ owner=environment()||this_player();
+ if (owner)
+ str=capitalize(((str=geteuid(owner))[<1]=='s'||str[<1]=='x'||str[<1] =='z')?str+="'":str+="s");
+ else
+ str="Eine";
+ SetProp( P_SHORT,str+" Lupe" );
+ SetProp( P_NAME, str+" Lupe" );
+ SetProp( P_LONG, "Mit dieser Lupe kann man die Feinheiten des LPC besser erkennen.\n" );
+ SetProp( P_NEVERDROP, 1 );
+ SetProp( P_NODROP, "Du kannst Deine Lupe nicht wegwerfen. Dazu ist sie zu wertvoll.\n");
+ SetProp( P_NOBUY, 1 );
+ SetProp( P_GENDER, FEMALE );
+ SetProp( P_WEIGHT, 0 );
+ SetProp( P_ARTICLE,0);
+ SetProp( P_GENDER,0);
+ AddId( "lupe" );
+ user="*";
+ stack=({});
+ commands=({});
+ functions=({});
+ ncmds=0;
+ add("Dest");
+ add("_goto");
+ add("clnof");
+ add("cln");
+ add("clr");
+ add("copy_ldfied");
+ add("creat");
+ add("dest");
+ add("dinfo");
+ add("disco");
+ add("dump_lists");
+ add("dup");
+ add("env");
+ add("here");
+ add("info");
+ add("inv");
+ add("lv");
+ add("make");
+ add("me");
+ add("minfo");
+ add("new");
+ add("norec");
+ add("ob");
+ add("over");
+ add("pl");
+ add("rec");
+ add("result");
+ // add("rusage");
+ add("scan");
+ add("stat");
+ add("stk");
+ add("swap");
+ add("swho");
+ add("vars");
+ add2("#","lock");
+ add2(".","sel");
+ add2("/","file");
+ add2("<","readvar");
+ add2("=","dump");
+ add2(">","writevar");
+ add2("@","pick");
+ add2("[","call");
+ add2("_mo","_mv");
+ add2("_mov","_mv");
+ add2("_move","_mv");
+ add2("_mv","_mv");
+ add2("call_out","callout");
+ add2("debug_info", "db_info");
+ add2("desc","toggle_short");
+ add2("dump","dumplists");
+ add2("heart_beat","heartbeat");
+ add2("idle","idle");
+ add2("inherit_list","inheritlist");
+ add2("move","mv");
+ add2("mov","mv");
+ add2("mo","mv");
+ add2("pop","xpop");
+ add2("push","xpush");
+ add2("renew","renew_player");
+ add2("sc","scan");
+ add2("~","file2");
+ maxverb=ncmds;
+ vararea=allocate(MAXVARS);
+ query_list =
+ ({
+ "VALUE","-value","LEVEL","-level","IDS","-ids",
+ "WEAPON CLASS","-wc","ARMOUR CLASS","-ac",
+ "WEIGHT","-weight","TYPE","query_type",
+ "UID","-uid","EUID","-euid"
+ });
+}
+
+int _query_autoloadobj()
+{
+ return 1;
+}
+
+void _set_autoloadobj()
+{
+ call_out("_load_profile",0);
+}
+
+void _load_profile()
+{
+ object profile;
+ string pfile;
+
+ if (geteuid() && environment() && geteuid(environment())==geteuid() &&
+ interactive(environment()))
+ if (file_size(pfile="/players/"+geteuid()+"/.profile.c")>0)
+ if (pfile=catch(call_other(pfile,"setup",environment())))
+ printf("Error when loading profile: %O\n",pfile);
+}
+
+void init()
+{
+ int i,ch;
+
+ ::init();
+ if (environment()!=this_player()) return;
+// if (!IS_LEARNER(this_player())) return;
+ if (!IS_LEARNER(this_player())) return destruct(this_object());
+
+ add_action("cmdline","",1);
+}
+
+int cmdline(string str)
+{
+ string verb;
+ int i,ret;
+
+ verb=query_verb();
+ if (!verb) return 0;
+ switch (verb)
+ {
+ case "erzaehl": return tell(str);
+ }
+ str=PL->_unparsed_args();
+ for (i=0;i<maxverb;i++)
+ if (commands[i]==verb[0..sizeof(commands[i])-1])
+ if (ret=evalcmd(str))
+ return ret;
+ return(0); // non-void function, Zesstra
+}
+
+static int tell(string str)
+{
+ string *tmp;
+ object who,sn;
+ int ret;
+
+ if (!IS_ARCH(this_interactive())) return 0;
+ if (!(str=this_interactive()->_unparsed_args())) return 0;
+ if (sizeof(tmp=old_explode(str," "))<2) return 0;
+ if (!(who=find_player(tmp[0]))) return 0;
+ if (!(sn=query_snoop(who))) return 0;
+ if (query_wiz_grp(this_interactive())<=query_wiz_grp(sn) ||
+ query_wiz_grp(this_interactive())<=query_wiz_grp(who)) return 0;
+ snoop(sn,0);
+ ret=this_interactive()->_erzaehle(str);
+ snoop(sn,who);
+ return ret;
+}
+
+int set_user(string str)
+{
+ string who;
+ if (!str) return 0;
+ if (str=="no access")
+ {
+ user="*";
+ move_object(this_object(),environment());
+ write("Ok.\n");
+ return 1;
+ }
+ if (sscanf(str,"access to %s",who)==1)
+ {
+ object pl;
+ pl=find_player(who);
+ if (!pl)
+ write("No such player.\n");
+ else
+ {
+ user = who;
+ write("Ok.\n");
+ move_object(this_object(),pl);
+ tell_object(pl,"Du darfst nun durch die magische Lupe schauen.\n");
+ }
+ return 1;
+ }
+ return 0;
+}
+
+string strip(string str)
+{
+ string temp;
+ if(!str) return "";
+ while (sscanf(str," %s",temp)==1) str=temp;
+ return str;
+}
+
+int arglen;
+
+string getarg(string args)
+{
+ string arg;
+ string rest;
+ if (sscanf(args,"\"%s\"%s",arg,rest)==2 ||
+ sscanf(args,"\'%s\'%s",arg,rest)==2 ||
+ sscanf(args,"|%s|%s",arg,rest)==2)
+ {
+ if (arg=="")
+ arglen=2;
+ else
+ arglen=sizeof(arg)+2;
+ return arg;
+ }
+ if (sscanf(args,"%s %s",arg,rest)==2)
+ args=arg;
+ if (sscanf(args,"%s.%s",arg,rest)==2)
+ args=arg;
+ if (sscanf(args,"%s[%s",arg,rest)==2)
+ args=arg;
+ if (sscanf(args,"%s]%s",arg,rest)==2)
+ args=arg;
+ if (args=="")
+ arglen=0;
+ else
+ arglen=sizeof(args);
+ return args;
+}
+
+string getrest(string str)
+{
+ if (arglen==0)
+ return str;
+ if (arglen==sizeof(str))
+ return "";
+ return strip(str[arglen..sizeof(str)-1]);
+}
+
+int interactiveMode(string str)
+{
+ if (str)
+ return eval(str);
+ stk("");
+ write("'.' to exit.\n");
+ write("? ");
+ input_to("more");
+ return 1;
+}
+
+void more(string str)
+{
+ string cmd;
+ if (str==".") return;
+ if (sscanf(str,"!%s",cmd)==1)
+ command(cmd,this_player());
+ else
+ {
+ eval(str);
+ stk("");
+ }
+ write("? ");
+ input_to("more");
+}
+
+int evalcmd(string str)
+{
+ string verb;
+ if (!IS_LEARNING(this_player())) return 0;
+ verb=query_verb();
+ if (verb=="?")
+ verb="";
+ if (str)
+ str=verb+" "+str;
+ else
+ str=verb;
+ return eval(str);
+}
+
+int eval(string str)
+{
+ int i,flag,old_sp,first;
+ mixed *old_stack;
+ string arg,tmp;
+ err=0;
+ first=1;
+ while (str!="")
+ {
+ flag=0;
+ str=strip(str);
+ if (sscanf(str,"#%s",arg)==1)
+ {
+ old_stack=stack[0..<1];
+ str=arg;
+ }
+ else
+ old_stack=0;
+ str=strip(str);
+ if (str=="")
+ break;
+ for (i=0;i<ncmds;i++)
+ {
+ if (sscanf(str,commands[i]+"%s",arg)==1)
+ {
+ if (arg!="" && str[0]>='a' && str[0]<='z' &&
+ arg[0]>='a' && arg[0]<='z')
+ {
+ if (first)
+ return 0;
+ else
+ {
+ printf("Couldn't parse: %O.\n",str);
+ return 1;
+ }
+ }
+ arg=strip(arg);
+ str=call_other(this_object(),functions[i],arg);
+ first=0;
+ if (old_stack)
+ {
+ stack=old_stack;
+ old_stack=0;
+ }
+ if (stringp(err))
+ {
+ if (sscanf(err,"%s\n",tmp)==1)
+ err = tmp;
+ notify_fail(sprintf("ERROR: %O.\n",err));
+ return 0;
+ }
+ flag=1;
+ break;
+ }
+ }
+ if (!flag)
+ {
+ notify_fail(sprintf("Couldn't parse: %O.\n",str));
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int push(object ob)
+{
+ stack+=({ob});
+ if (sizeof(stack)>MAXSTACK)
+ stack=stack[1..MAXSTACK];
+ return 1;
+}
+
+mixed pop()
+{
+ object tmp;
+ if (!sizeof(stack))
+ {
+ err="stack underflow";
+ tmp=this_object();
+ return 0;
+ }
+ tmp=stack[sizeof(stack)-1];
+ stack=stack[0..<2];
+ if (!tmp)
+ err="operating on destructed object";
+ return tmp;
+}
+
+mixed xpop(string arg)
+{
+ if (!pop())
+ err=0;
+ return arg;
+}
+
+mixed toggle_short(string arg)
+{
+ hide_short = !hide_short;
+ if (hide_short)
+ write("Short descriptions off.\n");
+ else
+ write("Short descriptions on.\n");
+ return arg;
+}
+
+mixed pl(string arg)
+{
+ string who,rest;
+ object p;
+ who=getarg(arg);
+ rest=getrest(arg);
+ if (err) return 0;
+ p=match_living(who,1);
+ if (!stringp(p))
+ {
+ if (!p=find_netdead(who))
+ err="player "+who+" not found";
+ else
+ push(p);
+ }
+ else
+ push(find_player(p));
+ return rest;
+}
+
+mixed lv(string arg)
+{
+ string who,rest;
+ object p;
+ who=getarg(arg);
+ rest=getrest(arg);
+ if (err) return 0;
+ p=find_living(who);
+ if (!p)
+ err="living object "+who+" not found";
+ else
+ push(p);
+ return rest;
+}
+
+string me(string arg)
+{
+ push(this_player());
+ return arg;
+}
+
+string make_path(string path)
+{
+ return "secure/master"->_get_path( path, geteuid( this_player() ) );
+}
+
+string new(string arg)
+{
+ string what,rest,file;
+ object ob;
+ what=getarg(arg);
+ rest=getrest(arg);
+ file=make_path(what);
+ err=catch(ob=clone_object(file));
+ if (!err)
+ {
+ push(ob);
+ ob->move(this_player(),M_NOCHECK);
+ write("Created "+desc(ob)+".\n");
+ }
+ else
+ err = "unable to create object, cause : "+err;
+ return rest;
+}
+
+static string creat(string arg)
+{
+ string what,rest,file;
+ object ob;
+ what=getarg(arg);
+ rest=getrest(arg);
+ file=make_path(what);
+ err=catch(ob=clone_object(file));
+ if (!err)
+ {
+ push(ob);
+ write("Created "+desc(ob)+".\n");
+ }
+ else
+ err = "unable to create object, cause : "+err;
+ return rest;
+}
+
+string xpush(string arg)
+{
+ string rest,what;
+ object ob;
+
+ what=getarg(arg);
+ rest=getrest(arg);
+ ob = find_object(what);
+ if (!ob)
+ err="Object "+what+" not found!\n";
+ else
+ push(ob);
+ return rest;
+}
+
+static string ob(string arg)
+{
+ string what,rest,file,tmp;
+ object ob;
+ what=getarg(arg);
+ rest=getrest(arg);
+ file=make_path(what);
+{
+ ob=find_object(file);
+ if (!ob)
+ {
+ tmp = catch(call_other(file,"??"));
+ if (!err)
+ ob = find_object(file);
+ }
+}
+if (!ob)
+{
+ err="object "+file+" not found";
+ if (tmp)
+ err += "("+tmp+")";
+}
+else
+push(ob);
+return rest;
+}
+
+string file(string arg)
+{
+ return ob("/"+arg);
+}
+
+string file2(string arg)
+{
+ return ob("~"+arg);
+}
+
+string sel(string arg)
+{
+ string rest;mixed what;
+ object ob,p;
+ ob=pop();
+ if (err) return arg;
+ if (sscanf(arg,"%d%s",what,rest)==2)
+ {
+ if (what<=0)
+ {
+ err="negative index";
+ push(ob);
+ return arg;
+ }
+ what--;
+ p=first_inventory(ob);
+ while (p && what)
+ {
+ p=next_inventory(p);
+ what--;
+ }
+ if (!p)
+ {
+ err="index to large";
+ push(ob);
+ return arg;
+ }
+ push(p);
+ return rest;
+ }
+ what=getarg(arg);
+ rest=getrest(arg);
+ p=present(what,ob);
+ if (p)
+ push(p);
+ else
+ {
+ push(ob);
+ err=what+" not present in "+desc(ob);
+ }
+ return rest;
+}
+
+string here(string arg)
+{
+ push(environment(this_player()));
+ return arg;
+}
+
+string env(string arg)
+{
+ object ob;
+ ob=pop();
+ if (!err)
+ {
+ if (!environment(ob))
+ err=desc(ob)+" has no environment";
+ else
+ push(environment(ob));
+ }
+ return arg;
+}
+
+string dup(string arg)
+{
+ object tos;
+ tos=pop();
+ if (!err)
+ {
+ push(tos);
+ push(tos);
+ }
+ return arg;
+}
+
+string swap(string arg)
+{
+ object tos;
+ int sts;
+
+ if ((sts=sizeof(stack))<2)
+ {
+ err="stack underflow";
+ return arg;
+ }
+ tos=stack[sts-1];
+ stack[sts-1]=stack[sts-2];
+ stack[sts-2]=tos;
+ return arg;
+}
+
+string over(string arg)
+{
+ object ob;
+ if (sizeof(stack)<2)
+ {
+ err="stack underflow";
+ return arg;
+ }
+ push(stack[sizeof(stack)-2]);
+ return arg;
+}
+
+string pick(string arg)
+{
+ string rest;
+ int no;
+ if (sscanf(arg,"%d%s",no,rest)!=2 || no<0 || no>=sizeof(stack))
+ {
+ err="stack size exceeded";
+ return arg;
+ }
+ else
+ push(stack[sizeof(stack)-no-1]);
+ return rest;
+}
+
+string string_desc(string str)
+{
+ string out;
+ out = implode(old_explode(str,"\\"),"\\\\");
+ out = implode(old_explode(out,"\n"),"\\n");
+ out = implode(old_explode(out,"\""),"\\\"");
+ return "\""+out+"\"";
+}
+
+mixed rec_desc(mixed ob)
+{
+ if (intp(ob))
+ return ""+ob;
+ if (stringp(ob))
+ return string_desc((string)ob);
+ if (objectp(ob))
+ return "OBJ("+object_name(ob)+")";
+ if (!pointerp(ob))
+ return sprintf("%O",ob);
+ return "({ "+implode(map(ob,"rec_desc",this_object()),", ")+" })";
+}
+
+string array_desc(mixed arr)
+{
+ string str,line,res;
+ mixed tmp;
+ int i,j;
+ str=rec_desc(arr);
+ if (sizeof(str)<=MAXLINELEN-4)
+ return "--> "+str+"\n";
+ tmp=old_explode(str," ");
+ res="";
+ lines=0;
+ i=1;
+ line="--> "+tmp[0]+" ";
+ for (;;)
+ {
+ while (i<sizeof(tmp) && sizeof(line)+sizeof(tmp[i]+1)<=MAXLINELEN-1)
+ {
+ line+=tmp[i]+" ";
+ i++;
+ }
+ if (sizeof(line)==0)
+ {
+ line=tmp[i]+" ";
+ i++;
+ }
+ if (i<sizeof(tmp))
+ line+="|\n";
+ else
+ line+="\n";
+ res+=line;
+ lines++;
+ if (lines>=MAXLINES)
+ return res+"*** TRUNCATED ***\n";
+ if (i>=sizeof(tmp))
+ return res;
+ line="";
+ }
+ return(0); // non-void, Zesstra (never reached)
+}
+
+string desc(object ob)
+{
+ if (!ob)
+ return "<destructed object>";
+ if (!objectp(ob))
+ return "<corrupted stack entry>";
+ if (query_once_interactive(ob))
+ return object_name(ob)+" "+capitalize(geteuid(ob));
+ if (!hide_short && ob->short())
+ return object_name(ob)+" "+ob->name();
+ else
+ return object_name(ob);
+}
+
+string stk(string arg)
+{
+ int i,sts;
+ if (!(sts=sizeof(stack)))
+ write ("<empty stack>\n");
+ else
+ for (i=1;i<=sts;i++)
+ {
+ write("@"+(i-1)+": "+desc(stack[sts-i])+"\n");
+ }
+ return arg;
+}
+
+string clr(string arg)
+{
+ stack=({});
+ return arg;
+}
+
+string dump(string arg)
+{
+ object ob;
+ string s;
+ ob=pop();
+ if (err) return arg;
+ push(ob);
+ write("FILENAME: "+object_name(ob)+" ");
+ if (!hide_short && (s=ob->short()))
+ write(" SHORT: "+ob->name());
+ write("\n");
+ return arg;
+}
+
+string info(string arg)
+{
+ object ob;
+ mixed s;
+ int i;
+ ob=pop();
+ if (err) return arg;
+ write("FILENAME: "+object_name(ob)+" ");
+ if (s=ob->short())
+ write(" SHORT: "+ob->name());
+ write("\n");
+ if (getuid(ob))
+ write("CREATOR: "+getuid(ob)+"\n");
+ if (s=query_ip_number(ob))
+ {
+ write("IP-NUMBER: "+s+" IP-NAME: "+query_ip_name(ob)+" IDLE: "
+ + query_idle(ob)+"\n");
+ }
+ if (s=query_snoop(ob))
+ write("SNOOPED BY: "+s->query_real_name()+"\n");
+ s="";
+ if (living(ob))
+ s +="living ";
+ if (ob->query_npc())
+ s+="npc ";
+ if (ob->query_gender_string())
+ s+=ob->query_gender_string();
+ if (s!="")
+ write("FLAGS: "+s+"\n");
+ // write("LONG:\n");
+ // if (stringp(s=ob->long()))
+ // write(s);
+ // write("\n");
+ for (i=0;i<sizeof(query_list);i+=2)
+ {
+ if (query_list[i+1][0]=='-')
+ s=ob->QueryProp(query_list[i+1][1..]);
+ else
+ s=call_other(ob,query_list[i+1]);
+ if (s)
+ {
+ printf("%s: %O\n",query_list[i],s);
+ }
+ }
+ return arg;
+}
+
+string filler(int n)
+{
+ string s;
+ if (!recursive) return ": ";
+ s=": ";
+ while (++n<MAXDEPTH)
+ s=" "+s;
+ return s;
+}
+
+void listinv(object ob,int depth,string prefix)
+{
+ int i;
+ object p;
+ if (depth<MAXDEPTH)
+ {
+ p=first_inventory(ob);
+ i=1;
+ if (p)
+ {
+ while (p)
+ {
+ if (lines>lastline) return;
+ if (lines>=firstline)
+ write(prefix+"."+i+filler(depth)+desc(p)+"\n");
+ lines++;
+ if (lines==lastline+1 && next_inventory(p))
+ write("*** TRUNCATED ***\n");
+ if (recursive)
+ listinv(p,depth+1,prefix+"."+i);
+ i++;
+ p=next_inventory(p);
+ }
+ }
+ else
+ if (!depth)
+ write("<empty inventory>\n");
+ }
+}
+
+string inv(string arg)
+{
+ object ob;
+ string rest;
+ int tmp;
+ ob=pop();
+ lines=1;
+ firstline=1;
+ lastline=MAXLINES;
+ if (!err)
+ {
+ if (sscanf(arg,":%d%s",tmp,rest)==2)
+ {
+ firstline=tmp;
+ lastline=tmp+MAXLINES-1;
+ arg = rest;
+ if (sscanf(arg,":%d%s",tmp,rest)==2)
+ {
+ lastline=tmp;
+ if (lastline<firstline)
+ err = "first line > last line";
+ arg=rest;
+ }
+ }
+ push(ob);
+ listinv(ob,0,"");
+ }
+ recursive=0;
+ return arg;
+}
+
+object call_result;
+
+string call(string arg)
+{
+ string func,args;
+ int temp,i;
+ string rest,tmp;
+
+ object ob;
+ ob=pop();
+ if (err) return arg;
+ push(ob);
+ func=getarg(arg);
+ args=getrest(arg);
+ if (err) return args;
+ argv=({});
+ i=0;
+ while (1)
+ {
+ args=strip(args);
+ if (sscanf(args,"]%s",rest))
+ break;
+ if (sscanf(args,"%d%s",tmp,rest)==2)
+ {
+ args=rest;
+ argv+=({tmp});
+ continue;
+ }
+ if (sscanf(args,"\"%s\"%s",tmp,rest)==2 ||
+ sscanf(args,"\'%s\'%s",tmp,rest)==2 ||
+ sscanf(args,"|%s|%s",tmp,rest)==2)
+ {
+ args=rest;
+ argv+=({tmp});
+ continue;
+ }
+ if (sscanf(args,"@%d%s",temp,rest)==2)
+ {
+ if (temp<0 || temp>=sizeof(stack))
+ {
+ err="stackindex out of range";
+ return args;
+ }
+ argv+=({stack[sizeof(stack)-temp-1]});
+ args=rest;
+ continue;
+ }
+ tmp=getarg(args);
+ rest=getrest(args);
+ argv+=({tmp});
+ if (tmp!="")
+ {
+ args=rest;
+ continue;
+ }
+ err="bad argument to []";
+ return args;
+ }
+ if (sscanf(args,"]%s",rest)!=1)
+ {
+ err="too many or unterminated argument(s)";
+ return args;
+ }
+ call_result=apply(#'call_other,ob,func,argv);
+ //'
+ // if (objectp(call_result))
+ // write("--> "+desc(call_result)+"\n");
+ // else if (pointerp(call_result))
+ // write(array_desc(call_result));
+ // else
+ // write("--> "+call_result+"\n");
+ printf("--> %O\n",call_result);
+ pop();
+ argv=({});
+ return rest;
+}
+
+string result(string arg)
+{
+ if (objectp(call_result))
+ push(call_result);
+ else
+ err="call returned no object";
+ return arg;
+}
+
+int destroyable(object ob)
+{
+ if (!ob)
+ return 0;
+ if (query_once_interactive(ob))
+ return 0;
+ if (ob==this_object())
+ return 0;
+ return 1;
+}
+
+string cln(string arg)
+{
+ object ob;
+ ob=pop();
+ if (!err)
+ {
+ clean(ob);
+ write(desc(ob)+" cleaned up.\n");
+ }
+ recursive=0;
+ return arg;
+}
+
+string clnof(string arg)
+{
+ object ob;
+ int recsave;
+ string name,rest;
+
+ write("ClnOf");
+ recsave=recursive;
+ recursive=0;
+ ob=pop();
+ if (err) return arg;
+ name=getarg(arg);
+ rest=getrest(arg);
+ if (err) return arg;
+ recursive=recsave;
+ cleanof(name,ob);
+ recursive=0;
+ return rest;
+}
+
+void Remove(object ob,int a)
+{
+ if (!objectp(ob)) return;
+ if (!a)
+ {
+ printf("Removing %O",ob);
+ if (!hide_short) printf(" %O",ob->name());
+ }
+ catch(ob->remove());
+ if (ob)
+ {
+ if (!a) printf(" HARD");
+ destruct(ob);
+ }
+ write("\n");
+}
+
+void clean(object ob)
+{
+ object p,p2;
+ p=first_inventory(ob);
+ while (destroyable(p))
+ {
+ if (recursive) clean(p);
+ Remove(p,0);
+ p=first_inventory(ob);
+ }
+ while (p)
+ {
+ p2=next_inventory(p);
+ if (destroyable(p2))
+ {
+ if (recursive) clean(p2);
+ Remove(p2,0);
+ }
+ else
+ p=p2;
+ }
+}
+
+ void cleanof(string str,object ob)
+{
+ object p,p2;
+ p=first_inventory(ob);
+ while (p && p->id(str) && destroyable(p))
+ {
+ if (recursive) clean(p);
+ Remove(p,0);
+ p=first_inventory(ob);
+ }
+ while (p)
+ {
+ p2=next_inventory(p);
+ if (p2 && p2->id(str) && destroyable(p2))
+ {
+ if (recursive) clean(p2);
+ Remove(p2,0);
+ }
+ else
+ p=p2;
+ }
+}
+
+string dest(string arg)
+{
+ object ob;
+ ob=pop();
+ if (err) return arg;
+ if (!destroyable(ob))
+ {
+ err=desc(ob)+" must not be destroyed";
+ return arg;
+ }
+ Remove(ob,0);
+ return arg;
+}
+
+mixed disco(string arg)
+{
+ object ob;
+
+ ob=pop();
+ if (err) return arg;
+ if (!interactive(ob))
+ {
+ err=desc(ob)+" is not interactive";
+ return 1;
+ }
+ remove_interactive(ob);
+ return arg;
+}
+
+string Dest(string arg)
+{
+ object ob;
+ ob=pop();
+ if (err) return arg;
+ if (!destroyable(ob))
+ {
+ err=desc(ob)+" must not be destroyed";
+ return arg;
+ }
+ destruct( ob );
+ return arg;
+}
+
+string mv(string arg)
+{
+ object from,to;
+ to=pop();
+ if (err) return arg;
+ from=pop();
+ if (err) return arg;
+ from->move(to,M_NOCHECK);
+ write("Bewege "+desc(from)+" nach "+desc(to)+".\n");
+ return arg;
+}
+
+string _mv(string arg)
+{
+ object from,to;
+ to=pop();
+ if (err) return arg;
+ from=pop();
+ if (err) return arg;
+ __set_environment(from,to);
+ write("Bewege "+desc(from)+" nach "+desc(to)+".\n");
+ return arg;
+}
+
+string db_info(string arg)
+{
+ object ob;
+
+ ob=pop();
+ if (err) return arg;
+ debug_info(0,ob);
+ debug_info(1,ob);
+ return arg;
+}
+
+string inheritlist(string arg)
+{
+ object ob;
+ int i;
+ string *inherited;
+
+ ob=pop();
+ if (err) return arg;
+ inherited=inherit_list(ob);
+ write(ob);write(" inherits:\n");
+ for (i=0;i<sizeof(inherited);i++)
+ write(inherited[i]+"\n");
+ return arg;
+}
+
+mixed get_callout()
+{
+ mixed *calls,ret;
+ string tmp;
+ int i,j;
+
+ calls=call_out_info();
+ ret=({});
+ if (!pointerp(calls) || !sizeof(calls))
+ return 0;
+ for (i=0;i<sizeof(calls);i++)
+ {
+ if (pointerp(calls[i]))
+ {
+ tmp="";
+ if (sizeof(calls[i])>3)
+ tmp+=sprintf("%-50O %-16O",calls[i][0],calls[i][1])+sprintf(" %-6O %-3O\n",calls[i][2],calls[i][3]);
+ else
+ tmp+=sprintf(" *** %O\n",calls[i]);
+ }
+ ret+=({tmp});
+ }
+ return ret;
+}
+
+mixed get_heartbeat()
+{
+ mixed *obj;
+ string *ret;
+ int i;
+
+ obj=heart_beat_info();
+ ret=({});
+ if (!pointerp(obj) || sizeof(obj)==0) return 0;
+ for (i=0;i<sizeof(obj);i++)
+ ret+=({sprintf("%O in %O\n",obj[i],environment(obj[i]))});
+ return ret;
+}
+
+string make(string arg)
+{
+ object *list, ob, env;
+ string file,temp,dummy;
+ int i,cloned;
+
+ ob=pop();
+ if (err) return arg;
+ if (!destroyable(ob))
+ {
+ err="can't update "+desc(ob);
+ return arg;
+ }
+ env=environment(ob);
+ file=object_name(ob);
+ write("Updating "+object_name(ob)+"...\n");
+ if (sscanf(file,"%s#%s",temp,dummy)==2)
+ {
+ file=temp;
+ cloned=1;
+ }
+ else
+ cloned=0;
+ list=all_inventory(ob);
+ for (i=sizeof(list)-1;i>=0;i--)
+ if (list[i] && query_once_interactive(list[i]))
+ {
+ list[i]->move("room/void",M_TPORT | M_SILENT | M_NO_SHOW | M_NOCHECK);
+ } else
+ list[i]=0;
+ list-=({0});
+
+ if (ob)
+ {
+ Remove(ob,1);
+ }
+ if (cloned)
+ {
+ if (ob=find_object(file))
+ {
+ Remove(ob,1);
+ }
+ err=catch(ob=clone_object(file));
+ if (!err)
+ ob->move(env,M_TPORT | M_SILENT | M_NO_SHOW | M_NOCHECK);
+ }
+ else
+ {
+ err=catch(call_other(file,"???"));
+ if (!err)
+ ob=find_object(file);
+ else
+ ob=0;
+ }
+ if (!ob)
+ {
+ write("Error in loaded object. Staying in void ...\n");
+ return arg;
+ }
+ for (i=sizeof(list)-1;i>=0;i--)
+ if (list[i])
+ list[i]->move(ob,M_TPORT | M_SILENT | M_NO_SHOW | M_NOCHECK);
+ return arg;
+}
+
+string rec(string arg)
+{
+ recursive=1;
+ return arg;
+}
+
+string norec(string arg)
+{
+ recursive=0;
+ return arg;
+}
+
+string readvar(string arg)
+{
+ string rest;
+ int no;
+ if (sscanf(arg,"%d%s",no,rest)!=2 || no<0 || no>=MAXVARS)
+ {
+ err="illegal var number";
+ return arg;
+ }
+ if (vararea[no])
+ push(vararea[no]);
+ else
+ err="var #"+no+" is empty";
+ return rest;
+}
+
+string writevar(string arg)
+{
+ string rest;
+ int no;
+ object ob;
+ if (sscanf(arg,"%d%s",no,rest)!=2 || no<0 || no>=MAXVARS)
+ {
+ err="illegal var number";
+ return arg;
+ }
+ ob=pop();
+ if (err) return rest;
+ vararea[no]=ob;
+ return rest;
+}
+
+string vars(string arg)
+{
+ int i;
+ for (i=0;i<MAXVARS;i++)
+ {
+ if (vararea[i])
+ write("<"+i+": "+desc(vararea[i])+"\n");
+ }
+ return arg;
+}
+
+void vanish()
+{
+ // RemoveAutoload();
+ destruct( this_object() );
+}
+
+mixed rusage(string arg)
+{
+ mixed *resusage;
+ int i,j;
+/*
+ resusage=({mixed *})efun::rusage();
+ for (i=0;i<18;i++){
+ write(align(({"User time","System time","Max res set size",
+ "Page reclaims","Page faults",
+ "Unshared stack size",
+ "Shared text size","Unshared data size",
+ "System swaps",
+ "Block input operations","Block output operations",
+ "Messages sent","Messages received","Signals received",
+ "Voluntary context switches","Involuntary context switches",
+ "Total internet packets","Total internet bytes"})[i],
+ 40)+": "+resusage[i]+"\n");
+ }
+ return arg;
+ */
+ return ({});
+}
+
+string align(string s,int x){
+ return (s+" ")[0..x-1];
+}
+
+static string swho(string arg)
+{
+ object *userlist, snooper, found;mixed active;
+ int i,j,done;
+
+ if (geteuid(this_interactive())!=geteuid()) return arg;
+ userlist=users();
+ active=({});
+ for (i=sizeof(userlist)-1;i>=0;i--)
+ if (snooper=query_snoop(userlist[i]))
+ {
+ if (member(active,snooper)==-1)
+ active+=({snooper});
+ if (member(active,userlist[i])==-1)
+ active+=({userlist[i]});
+ }
+ if (!sizeof(active))
+ {
+ printf("Keine aktiven Snoops.\n");
+ return arg;
+ }
+ for (i=sizeof(active)-1;i>=0;i--)
+ active[i]=({active[i]});
+ for (i=sizeof(active)-1;i>=0;i--)
+ if (pointerp(active[i])&&snooper=query_snoop(active[i][0]))
+ {
+ done=0;
+ for (j=sizeof(active)-1;j>=0 && !done;j--)
+ if (pointerp(active[j]) && active[j][sizeof(active[j])-1]==snooper)
+ {
+ active[j]+=active[i];
+ active[i]=0;
+ done=1;
+ }
+ }
+ active-=({0});
+ for (i=0;i<sizeof(active);i++)
+ {
+ for (j=0;j<sizeof(active[i]);j++)
+ printf("%s%s",(j==0?"":" -> "),capitalize(getuid(active[i][j])));
+ printf("\n");
+ }
+ return arg;
+}
+
+string timef(int sec)
+{
+ string s;
+
+ s="";
+ if (sec>=86400)
+ s+=sprintf("%d d, ",sec/86400);
+ if (sec>3600)
+ s+=sprintf("%d h, ",(sec/3600)%24);
+ if (sec>60)
+ s+=sprintf("%d m, ",(sec/60)%60);
+ return s+sprintf("%d s",sec%60);
+}
+
+string idle(string arg)
+{
+ object ob;
+ int i;
+
+ ob=pop();
+ if (err) return arg;
+ write(capitalize(ob->name(WER))+" ");
+ if (!query_once_interactive(ob))
+ {
+ write("ist kein echter Spieler.\n");
+ return arg;
+ }
+ if (!query_ip_number(ob))
+ {
+ write("ist netztot.\n");
+ return arg;
+ }
+ printf("ist idle seit %d Sekunden",i=query_idle(ob));
+ if (i>60)
+ printf(" (%s)\n",timef(i));
+ else
+ write("\n");
+ return arg;
+}
+
+string stat(string arg)
+{
+ object ob;
+ mapping quests;
+ mixed stats, *arr, tmp,tmp2, list;
+ string titel, level, stat_str,weapon,armour;
+ int pl;
+ int i;
+
+ ob=pop();
+ if (err)
+ return arg;
+
+ titel=ob->QueryProp(P_TITLE);
+ if (!(pl=query_once_interactive(ob)))
+ level="Monster="+old_explode(object_name(ob),"#")[0];
+ else
+ if (IS_GOD(ob))
+ level="Mud-Gott";
+ else if (IS_ARCH(ob))
+ level="Erzmagier";
+ else if (IS_ELDER(ob))
+ level="Weiser";
+ else if (IS_LORD(ob))
+ level="Regionsmagier";
+ else if (IS_DOMAINMEMBER(ob))
+ level="Regionsmitglied";
+ else if (IS_WIZARD(ob))
+ level="Magier";
+ else if (IS_LEARNER(ob))
+ level="Lehrling";
+ else if (IS_SEER(ob))
+ level="Seher";
+ else level="Spieler";
+ if (IS_DOMAINMEMBER(ob))
+ for (tmp="secure/master"->get_domain_homes(geteuid(ob));
+ sizeof(tmp);tmp=tmp[1..])
+ level+="-"+capitalize(tmp[0]);
+ if (pl)
+ {
+ if (!interactive(ob))
+ level+=", netztot";
+ else
+ if (query_idle(ob)>600)
+ level+=", idle";
+ if (ob->QueryProp(P_GHOST))
+ level+=", tot";
+ if (ob->QueryProp(P_INVIS))
+ level+=", unsichtbar";
+ if (ob->QueryProp(P_FROG))
+ level+=", gruen und glitschig";
+ if (ob->QueryProp(P_TESTPLAYER))
+ level+=", Testspieler";
+ }
+ tmp=ob->QueryProp(P_PRESAY);
+ if (tmp && tmp!="")
+ tmp=tmp+" ";
+ else
+ tmp="";
+ tmp2=ob->QueryProp(P_RACE);
+ if(!tmp2)
+ tmp2="Dingsda";
+ arr=ob->QueryProp(P_NAME);
+ if (pointerp(arr)) arr=arr[0];
+ printf("%s%s %s (%s)[%s].\n\n",tmp||"",arr||"",titel||"",
+ tmp2||"??",level||"??");
+ if (pl)
+ printf(" Alter : %s.%s\n",
+ timef(2*ob->QueryProp(P_AGE)),
+ (tmp=ob->QueryProp(P_MARRIED))?
+ ("Verheiratet mit "+capitalize(tmp)+"."):"");
+ else
+ printf(" Aggressiv : %4s Gespraechig : %d%%\n",
+ ob->QueryProp(P_AGGRESSIVE)? "Ja" : "Nein",
+ ob->QueryProp(P_CHAT_CHANCE)) ;
+ printf(" Lebenspunkte : [%4d/%4d] Magiepunkte : [%4d/%4d] " +
+ "Erfahrung : %d\n",
+ ob->QueryProp(P_HP), ob->QueryProp(P_MAX_HP),
+ ob->QueryProp(P_SP), ob->QueryProp(P_MAX_SP),
+ ob->QueryProp(P_XP));
+ printf(" Nahrung : [%3d/%d] Fluessigkeit : [%3d/%d] " +
+ "Alkohol : [%3d/%d]\n",
+ ob->QueryProp(P_FOOD), ob->QueryProp(P_MAX_FOOD),
+ ob->QueryProp(P_DRINK), ob->QueryProp(P_MAX_DRINK),
+ ob->QueryProp(P_ALCOHOL), ob->QueryProp(P_MAX_ALCOHOL)) ;
+ switch(ob->QueryProp(P_GENDER)) {
+ case FEMALE : tmp2 = "weiblich " ; break ;
+ case MALE : tmp2 = "maennlich" ; break ;
+ default : tmp2 = "boingisch" ; break ;
+ }
+ printf(" Geschlecht : %s Charakter : %-5d Stufe : %-3d\n",
+ tmp2, ob->QueryProp(P_ALIGN), ob->QueryProp(P_LEVEL)) ;
+ stats = ob->QueryProp(P_ATTRIBUTES) ;
+ if (!mappingp(stats)) stats=([]);
+ tmp = m_indices(stats); tmp2 = m_values(stats); stat_str = "" ;
+ for(; sizeof(tmp); tmp=tmp[1..],tmp2=tmp2[1..])
+ stat_str += (tmp[ 0 ] + "[" + tmp2[ 0 ] + "] ") ;
+
+ if(stat_str == "")
+ stat_str = "Keine" ;
+ else
+ stat_str = stat_str[0..<2];
+
+ printf(" Geld : %-9d Stati : %s\n\n", ob->QueryMoney(),
+ stat_str) ;
+
+ weapon = "Keine" ; armour = "" ;
+ for(tmp=all_inventory(ob); sizeof(tmp); tmp=tmp[1..])
+ {
+ if(tmp[ 0 ]->QueryProp(P_WIELDED)) // gezueckte Waffe
+ weapon = (tmp[ 0 ]->name(WER)) + " (" +
+ old_explode(object_name(tmp[ 0 ]),"#")[0] + ")[" +
+ tmp[ 0 ]->QueryProp(P_WC) + "]" ;
+
+ if(tmp[ 0 ]->QueryProp(P_WORN)) // getragene Ruestung
+ armour += (tmp[ 0 ]->name(WER)) + "[" +
+ tmp[ 0 ]->QueryProp(P_AC) + "]" +
+ ", " ;
+ }
+
+ if(armour == "")
+ armour = "Keine" ;
+ else
+ {
+ tmp = old_explode(break_string(armour[0..sizeof(armour) - 3],
+ 63), "\n") ;
+ armour = tmp[ 0 ] ;
+ tmp=tmp[1..];
+ for (;sizeof(tmp); tmp=tmp[1..])
+ armour += "\n " + tmp[ 0 ] ;
+ }
+
+ printf(" Waffe(%3d) : %s\nRuestung(%3d) : %s\n",
+ ob->QueryProp(P_TOTAL_WC), weapon,
+ ob->QueryProp(P_TOTAL_AC), armour) ;
+
+ list = ob->QueryEnemies();
+ if (pointerp(list))
+ {
+ list=list[0];
+ tmp2 = "" ;
+ for(i=sizeof(list)-1 ; i>=0;i--)
+ if (objectp(list[i]))
+ tmp2 += (list[ i ]->name(WER) + ", ") ;
+ if(tmp2 != "")
+ printf(" Feinde : %s.\n", tmp2[0..<3]);
+ }
+
+ // 8.Zeile : Geloeste Aufgaben
+ if(pl)
+ {
+ printf( break_string(
+ CountUp(m_indices(ob->QueryProp(P_QUESTS))),
+ 75,
+ " Aufgaben : ",
+ BS_INDENT_ONCE));
+ if(((tmp2 = ob->QueryProp(P_MAILADDR)) != "none") && tmp2 &&
+ (tmp2 != ""))
+ tmp2 = " (" + tmp2 + ")" ;
+ else
+ tmp2 = "" ;
+ }
+ else
+ tmp2 = "" ;
+
+ if(environment(ob))
+ printf(" Aufenthalt : %s%s.\n",
+ old_explode(object_name(environment(ob)),"#")[0], tmp2) ;
+
+ return arg;
+}
+
+string scan(string arg)
+{
+ object ob;
+ mixed tmp,tmp2,tmp3;
+ int i;
+
+ ob=pop();
+ if (err) return arg;
+ if (query_once_interactive(ob))
+ printf("Spieler: %s, Level: %d, Wizlevel: %d\n",
+ capitalize(getuid(ob)), ob->QueryProp(P_LEVEL),
+ query_wiz_level(ob));
+ else
+ printf("Monster, UID: %s, EUID: %s, Level: %d\n",
+ getuid(ob), (geteuid(ob)?geteuid(ob):"0"), ob->QueryProp(P_LEVEL));
+ tmp=ob->short();
+ if (!stringp(tmp)||!sizeof(tmp))
+ tmp=sprintf("(%s %s %s %s)",ob->QueryProp(P_PRESAY)+"",
+ ob->QueryProp(P_NAME)+"",ob->QueryProp(P_TITLE)+"",
+ (interactive(ob)?"":"(netztot"));
+ else
+ tmp=tmp[0..<3];
+ printf("%s, Rasse: %s\n",tmp, ""+ob->QueryProp(P_RACE));
+ printf("Stats: ");
+ tmp=ob->QueryProp(P_ATTRIBUTES);
+ tmp3=ob->QueryProp(P_ATTRIBUTES_OFFSETS);
+ if (!tmp)
+ printf("keine\n");
+ else
+ {
+ tmp2=m_indices(tmp);
+ for (i=0;i<sizeof(tmp2);i++)
+ {
+ printf("%s%s: %d",(i>0?", ":""),tmp2[i],tmp[tmp2[i]]);
+ if (tmp3[tmp2[i]])
+ printf("%+d",tmp3[tmp2[i]]);
+ }
+ printf("\n");
+ }
+ printf("Ruestung: %-6d Waffen: %-6d Vorsicht: %-6d Geschlecht: ",
+ ob->QueryProp(P_TOTAL_AC),ob->QueryProp(P_TOTAL_WC),
+ ob->QueryProp(P_WIMPY));
+ if (!(tmp=ob->QueryProp(P_GENDER)))
+ printf("N\n");
+ else
+ {
+ if (tmp==2)
+ printf("F\n");
+ else
+ printf("M\n");
+ }
+ if (tmp=ob->QueryProp(P_MARRIED))
+ printf("Verheiratet mit %s.\n",capitalize(tmp));
+ printf("Lebenspunkte: %4d [%4d], Magiepunkte: %4d [%4d], Erf: %-8d\n",
+ ob->QueryProp(P_HP), ob->QueryProp(P_MAX_HP),
+ ob->QueryProp(P_SP), ob->QueryProp(P_MAX_SP),
+ ob->QueryProp(P_XP));
+ if (living(ob))
+ {
+ tmp=present("geld",ob);
+ if (tmp)
+ tmp=tmp->QueryProp(P_AMOUNT);
+ printf("Traegt %6d (%6d) g. Eigengewicht %6d g. %6d Muenzen.\n",
+ ob->query_weight_contents(),ob->QueryProp(P_MAX_WEIGHT),
+ ob->QueryProp(P_WEIGHT),tmp);
+ if (tmp=ob->SelectEnemy())
+ printf("Kaempft gegen %s [%O]\n",tmp->name(WEN),tmp);
+ }
+ printf("ENV: %s",
+ ((tmp=environment(ob))?object_name(tmp):"- fabric of space -"));
+ if(query_once_interactive(ob))
+ {
+ printf(", EMail: %s\n", ob->QueryProp(P_MAILADDR)+"");
+ tmp="/secure/master"->find_userinfo(getuid(ob));
+ if (pointerp(tmp) && sizeof(tmp)>USER_DOMAIN)
+ {
+ tmp=tmp[USER_DOMAIN];
+ if (pointerp(tmp) && sizeof(tmp))
+ {
+ printf("Lord in: ");
+ for (tmp2=0;tmp2<sizeof(tmp);tmp2++)
+ printf("%s%s",(tmp2>0?", ":""),""+tmp[tmp2]);
+ printf(".\n");
+ }
+ }
+ tmp="/secure/master"->get_domain_homes(getuid(ob));
+ if (pointerp(tmp)&&sizeof(tmp)>0)
+ {
+ printf("Mitglied in: ");
+ for (tmp2=0;tmp2<sizeof(tmp);tmp2++)
+ printf("%s%s",(tmp2>0?", ":""),""+tmp[tmp2]);
+ printf(".\n");
+ }
+ printf("Quests: ");
+ tmp=ob->QueryProp(P_QUESTS);
+ if (tmp==({})||!pointerp(tmp))
+ printf("Keine.\n");
+ else
+ {
+ tmp2="";
+ tmp-=({({}),0});
+ for (i=0; i<sizeof(tmp); i++)
+ tmp2+=sprintf("%s%s",(i?", ":""),tmp[i][0]);
+ tmp=break_string(tmp2,79,8);
+ tmp=tmp[8..];
+ printf("%s",tmp);
+ }
+ printf("PKills: %d ",ob->QueryProp(P_KILLS));
+ printf(", QuestPoints: %d (%d/%d), Alter: %s\n",ob->QueryProp(P_QP),ob->QueryProp(P_NEEDED_QP),QM->QueryMaxQP(),timef(2*ob->QueryProp(P_AGE)));
+ if (interactive(ob))
+ {
+ printf("From: %s (%s) [%s]\n",query_ip_name(ob),query_ip_number(ob),country(query_ip_name(ob)));
+ tmp=query_idle(ob);
+ printf("Idle seit %d Sekunden",tmp);
+ if (tmp>60)
+ printf(" (%s)",timef(tmp));
+ printf(", cmd avg: %d",ob->QueryProp("command_average"));
+ printf(", noch %d ZT zu finden.\nGesnooped von: %s\n",
+ ((tmp=ob->QueryProp(P_POTIONROOMS))?sizeof(tmp):0),
+ ((tmp=query_snoop(ob))?capitalize(getuid(tmp)):"Niemandem"));
+ }
+ else
+ {
+ tmp=getuid(ob);
+ tmp=file_time("save/"+tmp[0..0]+"/"+tmp+".o");
+ tmp=time()-tmp;
+ printf("Kam von: %s, vor: %d s(%s)\n",
+ ob->QueryProp(P_CALLED_FROM_IP),tmp,timef(tmp));
+ }
+ }
+ else
+ printf("\n");
+ return arg;
+}
+
+mixed dinfo(string arg)
+{
+ object ob;
+
+ ob=pop();
+ if (!ob)
+ return 1;
+ debug_info(0,ob);
+ return arg;
+}
+
+mixed minfo(string arg)
+{
+ object ob;
+
+ ob=pop();
+ if (!ob)
+ return 1;
+ debug_info(1,ob);
+ return arg;
+}
+
+void dump_list(mixed what)
+{
+ int i,s;
+
+ if (!pointerp(what)||!(s=sizeof(what)))
+ return;
+ for (i=0;i<s;i++)
+ write(what[i]);
+}
+
+string callout(string args)
+{
+ dump_list(get_callout());
+ return args;
+}
+
+string heartbeat(string args)
+{
+ dump_list(get_heartbeat());
+ return args;
+}
+
+string dumplists(string args)
+{
+ string filen;
+ string *list;
+ int i,s;
+
+ if (!geteuid(this_object()))
+ return args;
+ filen="/players/"+geteuid(this_object())+"/LISTS.LUPE";
+ write("Dumping to "+filen+" ... ");
+ if (file_size(filen)>=0)
+ rm(filen);
+ write_file(filen,"OBJECT WITH ACTIVE HEART_BEAT:\n");
+ list=get_heartbeat();
+ if (!list || !(s=sizeof(list)))
+ write_file(filen,"NONE\n");
+ for (i=0;i<s;i++)
+ write_file(filen,list[i]);
+ write_file(filen,"\n\nRUNNING CALL_OUTS:\n");
+ list=get_callout();
+ if (!list || !(s=sizeof(list)))
+ write_file(filen,"NONE\n");
+ for (i=0;i<s;i++)
+ write_file(filen,list[i]);
+ write("done.\n");
+ return args;
+}
+
+mixed renew_player(string arg)
+{
+ object ob;
+
+ ob=pop();
+ if (!ob)
+ return 1;
+ if (!objectp(ob)&&!interactive(ob))
+ {
+ err=desc(ob)+" is not an interactive player";
+ return arg;
+ }
+ if ((err="/secure/master"->renew_player_object(ob))<0)
+ err="error "+err+" when renewing "+desc(ob);
+ return arg;
+}
+
+mixed copy_ldfied(string arg)
+{
+ object ob, new;
+ mapping props;
+
+ ob=pop();
+ if (!ob)
+ return 1;
+ if (!objectp(ob))
+ {
+ err=desc(ob)+" is not an valid object";
+ return arg;
+ }
+ new=clone_object(old_explode(object_name(ob),"#")[0]);
+ props=ob->QueryProperties();
+ new->SetProperties(ob->QueryProperties());
+ push(new);
+ new->move(this_player(),M_NOCHECK);
+ return arg;
+}
+
diff --git a/obj/tools/lupe.doc b/obj/tools/lupe.doc
new file mode 100644
index 0000000..cf3946f
--- /dev/null
+++ b/obj/tools/lupe.doc
@@ -0,0 +1,140 @@
+The lens object uses a stack to manipulate objects. Some commands push objects
+on the stack, some pop them again off the stack and use them for various
+purposes. There may be multiple commands on a single line, separated by
+spaces. The number of spaces between commands or between commands and
+arguments is not critical, i.e. there may also be two or more spaces.
+
+Notation:
+ <arg> : a sequence of characters which doesn't contain spaces or
+ dots. If it does, use "...", '...' or |...| to enclose
+ it.
+ <number>: an integer, positive or negative.
+ <filename>: same as <arg> (use quotes if it contains dots). May be
+ absolute (starting with /) relative to your home directory
+ (starting with ~/) or relative to somebody else's home
+ directory (starting with ~name/).
+ <function>: Name of an LPC-function.
+
+Commands:
+ pl <arg> : push player object with name <arg>.
+ lv <arg> : push living object with name <arg>.
+ me : push yourself.
+ here : push the location you are in.
+ ob <filename> : load & push the object denoted by <filename>.
+ <filename> : same as ob <filename> if it begins with / or ~.
+ new <filename> : clone & push the object denoted by <filename>.
+ Thereafter move it in your inventory.
+ creat <filename>: same as new, but don't move it into your inventory.
+ env : push the environment of the TOS.
+ .<number> : push the nth object in the inventory of the TOS.
+ .<arg> : push the object with id <arg> in the inventory
+ of the TOS.
+ = : display the TOS.
+ info : show detailed information about the TOS.
+ stk : show the entire stack.
+ clr : clear the entire stack.
+ dup : duplicate the topmost stack entry.
+ pop : discard the topmost stack entry.
+ swap : exchange the two topmost stack entries.
+ over : push the entry second from top.
+ @<number> : push the stack entry corresponding to the number.
+ The topmost one has number 0.
+ inv : show the inventory of the TOS.
+ cln : clean the inventory of the TOS. Players are not
+ destructed.
+ clnof <arg> : clean the inventory of the TOS of all objects with
+ id <arg>.
+ rec : perform the next inv, cln or clnof recursively.
+ norec : use this to turn of rec again if you are not going
+ to use one of inv, cln or clnof. inv, cln and clnof
+ turn off rec automatically after being used.
+ dest : destruct the TOS.
+ make : destruct the TOS, then rebuild it from the file.
+ Very useful when developing rooms.
+ mov : move the object denoted by the stack entry that is
+ second from top into the TOS.
+ [<function>] : call <function> in the TOS.
+ [<function> <arg1> ... <argn>]
+ : call <function> in the TOS. arguments are separated
+ by spaces. If the arguments themselves contain
+ spaces, enclose them by "...", '...' or |...|.
+ Use @<number> to supply objects on the stack
+ as arguments.
+ result : push the result of the function call if it is
+ an object.
+ desc : toggle whether short descriptions are shown when
+ displaying objects.
+ # : the contents of the stack will be restored after
+ performing the next command on the same line.
+ Since all commands which manipulate stack objects
+ except inv and = pop them, this might come in handy.
+ <<number> : used to push variable <number>. May range from
+ 0 to 9.
+ ><number> : store the TOS in variable <number>.
+ vars : display all variables.
+
+The following two commands can only be used as the first command on a line.
+
+ ? : there are two usages for the ?-command. Followed
+ by text it will execute the commands in it.
+ Simply hitting ?<CR> will put you in interactive
+ mode. Leave this mode by typing .<CR>. Lines
+ typed in will be executed by the lens and the
+ stack shown afterwards.
+
+ grant : Two forms are possible:
+ 'grant access to <name>' allows the player with
+ name <name> to use the lens.
+ 'grant no access' denies the access to all players
+ below level 21.
+
+Examples:
+ me /room/church mo
+ : go to the church.
+ pl demos ob ~demos/workroom mo
+ : move the player demos to his workroom.
+ here make
+ : update and load the room you are in, keeping the inventory
+ untouched.
+ here dup rec cln make
+ : same, this time cleaning up before.
+ me.bag inv
+ : show the contents of the bag you have.
+ me."bag 2" inv
+ : same for the second bag.
+ me [short]
+ : shows your short description.
+ me [query_attack] result [stop_fight]
+ : pacify your opponent.
+ pl demos [attacked_by @0]
+ : make Demos attack himself.
+ lv troll pl demos [attacked_by @1]
+ : demos is attacked by a troll.
+ here.troll here.demos [attacked_by @1]
+ : same effect if they're both here.
+ new /obj/level_list
+ : get yourself a copy of the top ten list.
+ pl ereborn clnof flea
+ : help poor ereborn to get rid of those fleas.
+ pl demos env [long]
+ : show the room where demos is.
+ here rec inv pop
+ : show the inventory of your current location and clean
+ up the stack afterwards.
+ me #[set_str 20] #[set_dex 20] #[set_int 20] #[set_con 20]
+ : set all your stats to the maximum possible value.
+ me [set_title "the new wizard"]
+ : changes your title accordingly.
+ pl demos env >4
+ : store the room Demos is in in variable 4.
+ <4 [query_dest_dir]
+ : get it again and list the possible exits.
+ me rec inv .4 inv
+ : get a recursive listing of yourself, then a non-recursive
+ one of the 4th item in your inventory
+ me.4.1 info
+ : show some information of the first item within the fourth
+ item in your inventory.
+ Please note that when doing a rec inv all the necessary
+ information to find any object is displayed in front
+ of it.
diff --git a/obj/tools/lupe.dok b/obj/tools/lupe.dok
new file mode 100644
index 0000000..28e23fe
--- /dev/null
+++ b/obj/tools/lupe.dok
@@ -0,0 +1,209 @@
+ALLGEMEINES:
+ Die Lupe benutzt einen Stapel (Stack), um Objekte zu bearbeiten.
+ Einige Befehle schieben Objekte auf den Stapel, andere wiederum
+ holen sie wieder vom Stapel herunter und benutzen sie fuer die
+ verschiedensten Zwecke.
+ Man kann in einer Zeile mehrere Kommandos gleichzeitig angeben
+ (durch Leerzeichen getrennt).
+ Eine Zeile wird immer von links nach rechts abgearbeitet.
+
+SCHREIBWEISEN:
+ <arg> - Eine Reihe von Zeichen, die weder Leerzeichen noch Punkte
+ (.) enthaelt. Falls doch Leerzeichen oder Punkte in <arg>
+ auftauchen, muss man die Zeichenkette zwischen "...",
+ '...' oder |...| einschliessen.
+ <nr> - Eine (positive oder negative) ganze Zahl.
+ <filename> - Ein Dateiname. Fuer ihn gilt das Gleiche wie fuer <arg>:
+ Wenn er Punkte enthaelt, muss man ihn zwischen "...",
+ '...' oder |...| einschliessen.
+ Es sind alle Variationen moeglich, die man auch aus der
+ Magiershell kennt: absolute Dateinamen (beginnen mit "/"),
+ Dateinamen relativ zum eigenen Homeverzeichnis ("~/")
+ oder zum Homeverzeichnis eines anderen Magiers ("~name/"),
+ Dateinamen in einer Region ("+region/") und Dateinamen
+ relativ zum aktuellen Verzeichnis (alles andere ;).
+ <func> - Name einer LPC-Funktion.
+ TOS - Das Objekt ganz oben auf dem Stapel (Top Of Stack).
+
+DER STAPEL:
+ Bei dem Stapel handelt es sich um einen LIFO-Stapel (Last In - First
+ Out), d.h. das Objekt, das zuletzt auf den Stapel geschoben wurde,
+ wird als erstes bearbeitet.
+ Bei der Bearbeitung wird der TOS in der Regel vom Stapel entfernt
+ (Ausnahmen: =, stk und #), der Stapel wird also im Laufe der Zeit
+ wieder kleiner.
+ Der Stapel kann maximal zehn Elemente aufnehmen. Dieses Limit wird
+ man bei "normalem Betrieb" allerdings selten erreichen.
+ Sollte es trotzdem einmal eng werden, stehen einem noch zehn
+ Variablen zur Verfuegung, in denen man zusaetzlich Objekte (vom
+ Stapel) ablegen kann.
+
+BEFEHLE:
+ Es gibt drei unterschiedliche Befehlsgruppen:
+ a) Befehle, die ein Objekt auf den Stapel schieben;
+ b) Befehle, die mit Objekten auf dem Stapel arbeiten;
+ c) Befehle, die ohne den Stapel auskommen.
+ Einige Befehle setzen voraus, das der TOS ein Lebewesen oder gar ein
+ Spielerobjekt ist; andere Befehle sind erst ab einem bestimmten
+ Magierlevel zugaenglich. Dies ist bei den entsprechenden Befehlen
+ jeweils vermerkt.
+
+ Diese Befehle schieben ein neues Objekt auf den Stapel:
+ creat <filename> Macht das Gleiche wie 'new', das Objekt wird aller-
+ dings nicht in Dein Inventory gesteckt.
+ here Das Objekt, in dem man gerade steht, auf den Stapel
+ schieben.
+ lv <arg> Schiebt das Lebewesen mit dem living_name <arg> auf
+ den Stapel. ACHTUNG! Das muss dann nicht unbedingt
+ das Lebewesen sein, das man dort eigentlich haben
+ will! Es wird einfach das erste Objekt genommen,
+ dessen living_name passt! Wenn man etwas mit einem
+ NPC vorhat, der im gleichen Raum steht, spricht man
+ ihn besser mit here.name an.
+ me Sich selbst auf den Stapel schieben.
+ new <filename> Cloned das mit <filename> angegebene Objekt und
+ schiebt es auf den Stapel. Anschliessend befindet es
+ sich in Deinem Inventory.
+ ob <filename> Laedt das Objekt, das mit <filename> angegeben ist,
+ und schiebt es auf den Stapel.
+ pl <arg> Schiebt das Spielerobjekt mit dem Namen <arg> auf den
+ Stapel.
+ Es werden auch netztote Spieler berucksichtigt.
+ push <filename> Schiebt das Objekt, das mit <filename> angegeben ist,
+ auf den Stapel.
+ <filename> Macht das gleiche wie 'ob', falls <filename> mit "/"
+ oder "~" beginnt.
+
+ Die naechsten Befehle schalten Optionen der Lupe an/aus/um:
+ desc Die zusaetzliche Angabe der Kurzbeschreibung des
+ aktuellen Objektes wird unterdrueckt.
+ rec Schaltet in den "rekursiv"-Modus um. Dieser Modus
+ wird von folgenden Befehlen genutzt:
+ 'inv', 'cln' und 'clnof'
+ Nach Ausfuehrung eines dieser Befehle wird der
+ "rekursiv"-Modus automatisch wieder abgestellt.
+ norec Stellt den "rekursiv"-Modus "von Hand" ab.
+
+ Diese Befehle schieben ebenfalls ein neues Objekt auf den Stapel. Sie
+ arbeiten dabei allerdings relativ zum TOS. Man muss also schon mindestens
+ ein Objekt auf den Stapel geschoben haben. Der alte TOS wird dabei in der
+ Regel entfernt.
+ .<nr> Schiebt das <nr>te Objekt im Inventory des TOS auf den
+ Stapel.
+ .<arg> Schiebt das Objekt mit der ID <arg> im Inventory des
+ TOS auf den Stapel.
+ <<nr> Schiebt die Variable <nr> auf den Stapel. Als <nr>
+ sind Werte zwischen 0 und 9 moeglich.
+ @<nr> Schiebt das <nr>te Objekt von oben noch einmal auf den
+ Stapel. Der alte TOS hat die Nummer 0. Weder der alte
+ TOS noch das verschobene Objekt werden vom Stapel ent-
+ fernt.
+ @1 ist analog zu 'over'.
+ copy Legt eine Kopie des TOS an (inkl. aller Propertywerte)
+ und schiebt diese Kopie auf den Stapel. Die Kopie
+ befindet sich danach in Deinem Inventory.
+ dup Schiebt den TOS doppelt auf den Stapel.
+ env Schiebt das Objekt, in dem sich der TOS befindet, auf
+ den Stapel.
+ over Schiebt das Objekt, das sich unter dem TOS befindet,
+ nochmal auf den Stapel. Dabei werden weder der alte
+ TOS noch das Objekt unter ihm entfernt.
+ result Wenn in einem Objekt eine Funktion aufgerufen wurde,
+ und diese Funktion wieder ein Objekt zurueckgegeben
+ hat, so wird dieses Objekt auf den Stapel geschoben.
+ swap Tauscht TOS und das darunter liegende Element gegen-
+ einander aus.
+
+ Die naechsten Befehle arbeiten mit den auf dem Stapel liegenden Objekten.
+ Dabei werden die bearbeiteten Objekte in der Regel vom Stapel entfernt.
+ ><nr> Speichert den TOS in der Variablen <nr>. Als <nr>
+ sind Werte zwischen 0 und 9 moeglich.
+ = Zeigt den TOS. Dieser bleibt dabei unveraendert.
+ # Der Stack bleibt ueber das naechste Kommando hinaus
+ erhalten.
+ inv Zeigt das Inventory des TOS. Der TOS bleibt dabei
+ unveraendert.
+ cln Entfernt alle Objekte aus dem Inventory des TOS. Es
+ werden allerdings keine Spieler entfernt.
+ clnof <arg> Entfernt alle Objekte, die auf die ID <arg> anspre-
+ chen, aus dem Inventar des TOS.
+ clr Loescht den gesamten Stack.
+ Dest Der TOS wird zerstoert. Das geht allerdings NICHT,
+ wenn der TOS ein Spielerobjekt oder die Lupe selbst
+ ist.
+ dest Wie Dest, allerdings wird zuerst TOS->remove() auf-
+ gerufen, um dem TOS die Moeglichkeit zu geben, noch
+ hinter sich aufzuraeumen.
+ dinfo Gibt einige GameDriver-interne Informationen wie zB.
+ die Zeit des naechsten reset()-Aufrufs oder die an-
+ gesammelte evalcost des TOS aus.
+ disco Unterbricht die Verbindug des TOS (muss ein aktiver
+ Spieler sein) zum MG (disconnect).
+ hl Zeigt die Historyliste des TOS an (hierbei muss es
+ sich um einen Spieler handeln).
+ Dieser Befehl steht ab ELDER_LVL (50) zur Verfuegung.
+ !!!Fuer die Benutzung gilt das Gleiche wie fuer das
+ Snoopen!!!
+ idle Gibt an, wie lange der TOS schon idlet. (Der TOS
+ sollte dabei natuerlich ein Spieler sein).
+ info Gibt einige Informationen ueber den TOS aus.
+ inherit_list Gibt den Vererbungsbaum des TOS aus (allerdings nicht
+ sehr baumfoermig ;)
+ inv Zeigt das Inventory des TOS an.
+
+ make Fuehrt ein Update des TOS durch. Geht nicht bei
+ Spielern! Dafuer gibt es renew.
+ minfo Gibt einige Informationen ueber den Speicherverbrauch
+ des TOS aus.
+ move, mov, mo Das Objekt, das unter dem TOS steht, wird in den TOS
+ gemoved. Beide Objekte werden dabei vom Stapel ent-
+ fernt.
+ _move, _mov, _mo, _mv
+ Das Objekt, das unter dem TOS steht, wird in den TOS
+ gemoved, ohne dass dort init() aufgerufen wird. Beide
+ Objekte werden dabei vom Stapel entfernt.
+ Dieser Befehl steht ab ARCH_LVL (60) zur Verfuegung.
+ pop Entfernt den TOS.
+ renew Aehnlich wie 'make', der TOS muss allerdings ein
+ Spieler sein. ACHTUNG! Man sollte nicht "einfach so"
+ Spieler 'renew'en, sondern nur dann, wenn es wirklich
+ gerechtfertigt ist!
+ scan, sc Kombiniert 'stat' und finger. Der TOS muss ein Lebe-
+ wesen sein.
+ stat Gibt Informationen ueber Zustand, Ausruestung, ge-
+ loeste Quests etc. des TOS aus. Der TOS muss dabei
+ ein Lebewesen sein.
+ stk Zeigt den gesamten Stack. Dieser bleibt dabei unver-
+ aendert.
+ [<func>] Ruft im TOS die Funktion <func> ohne Parameter auf.
+ Falls diese Funktion ein Objekt zurueckgibt, kann man
+ dieses anschliessend mit result auf den Stapel
+ schieben.
+ [<func> <arg1> ... <argn>]
+ Ruft im TOS die Funktion <func> mit den Parametern
+ <arg1> bis <argn> auf. Die Parameter sind mit Leer-
+ zeichen zu trennen. Enthalten die Parameter selbst
+ Leerzeichen, so sind sie in "...", '...' oder |...|
+ einzuschliessen.
+ Mittels @<nr> kann man auch Objekte, die sich auf dem
+ Stapel befinden, als Argumente angeben.
+
+ Die folgenden Befehle kommen ohne Objekte auf dem Stack aus:
+ call_out Gibt eine Liste aller Objekte mit einem laufenden
+ call_out aus.
+ dump Schreibt die Listen aller Objekte mit aktivem
+ heart_beat und aller Objekte mit laufendem call_out
+ in die Datai LISTS.LUPE in Dein Homeverzeichnis.
+ dumphists Schreibt die Befehlshistory aller momentan einge-
+ loggten Spieler nach /log/ARCH/HD.
+ Dieser Befehl steht erst ab ARCH_LVL (60) zur
+ Verfuegung.
+ heart_beat Gibt eine Liste aller Objekte mit aktivem heart_beat
+ aus.
+ rusage Zeigt einige Infos ueber den Ressourcenge-/-verbrauch
+ des Muds an.
+ swho Zeigt (so gut wie) alle aktiven Snoops.
+ vars Zeigt die belegten Variablen an.
+
+----------------------------------------------------------------------------
+Last modified: Wed Jun 26 14:49:02 1996 by Wargon
\ No newline at end of file
diff --git a/obj/tools/merkzettel/merkzettel.c b/obj/tools/merkzettel/merkzettel.c
new file mode 100644
index 0000000..70447ab
--- /dev/null
+++ b/obj/tools/merkzettel/merkzettel.c
@@ -0,0 +1,1130 @@
+/* /obj/tools/merkzettel.c
+ Merkzettel fuer Magier
+ Autor: Zesstra
+ ggf. Changelog:
+*/
+#pragma strict_types
+#pragma no_shadow
+#pragma range_check
+#pragma pedantic
+
+inherit "/std/secure_thing";
+
+#include <properties.h>
+#include <language.h>
+#include <wizlevels.h>
+#include <moving.h>
+#include <defines.h>
+
+#define NEED_PROTOTYPES
+#include "merkzettel.h"
+#undef NEED_PROTOTYPES
+
+//Variablen
+mapping notizen;
+//mapping notizen_inaktiv;
+int maxusedID;
+static string owner; //UID des Besitzers, wird in P_AUTOLOAD gespeichert
+//static int *cache; //nach Prioritaet sortiertes Array der IDs
+
+void create() {
+ ::create();
+ SetProp(P_NAME, "Merkzettel");
+ SetProp(P_SHORT, "Ein Merkzettel");
+ AddId(({"merkzettel","zettel"}));
+ //Absicht, damit die Blueprint eine ID, P_NAME und P_SHORT hat.
+ if(!clonep(this_object())) return;
+
+ SetProp(P_LONG,
+ "Was wolltest Du gleich nochmal schoenes proggen? ;-)\n"
+ "Befehlsliste:\n"
+ "zmerke/znotiz <string> : Etwas auf den Merkzettel schreiben\n"
+ "zliste : 20 wichtigsten Notizen anzeigen\n"
+ "zliste <int> : <int> wichtigste Notizen anzeigen\n"
+ " (unwichtigste, wenn <int> negativ)\n"
+ " Angabe von 0 oder 'alle' gibt alle aus\n"
+ "zliste <int> <filter> : <int> wichtigste Notizen anzeigen\n"
+ " (Filter: 'aktiv', 'wartend'\n"
+ " 'inaktiv', 'abgehakt', 'alle'|'0')\n"
+ " Ohne Angabe eines Filter gilt 'aktiv'\n"
+ "zstatus <int> : Status von Notiz mit ID umschalten\n"
+ "zstatus <int> <int2> : Status von Notiz mit ID auf <int> setzen \n"
+ "zloesche/zrm <int> : Notiz mit ID <int> loeschen\n"
+ "zlies/zlese <int> : Notiz mit ID <int> anzeigen\n"
+ "zdeplies <int> <int2> : Abhaengigkeiten von <int> lesen, \n"
+ " : rekursiv, wenn <int2> != 0\n"
+ "zfertig/zhake <int> : Notiz mit ID <int> abhaken (fertig)\n"
+ "zprio <int1> <int2> : Notiz mit ID <int> mit Prioritaet <int2>\n"
+ " versehen.\n"
+ "zdep <int1> <int2> : Notiz mit ID <int> soll von Notiz mit ID\n"
+ " <int2> abhaengen.\n"
+ "zhelfer <int1> <namen> : Notiz mit ID <int> wird (mit)bearbeitet\n"
+ " von den angegebenen Personen\n"
+ "zergaenze <int> <text> : haengt <text> an Notiz <int> an\n"
+ "zersetze <int> <text> : ersetzt Text von Notiz <int> durch <text>\n"
+ "zexpire <int> : alle abgehakten Notizen archivieren und loeschen,\n"
+ " : die aelter als <int> Tage sind.\n"
+ "zzeige <name> ; zeige <name>, wie furchtbar viel Du zu tun hast\n"
+ "zwedel <name> : <name> aus der Ferne vor der Nase rumwedeln.\n"
+ );
+ SetProp(P_INFO,break_string("Ein Merkzettel fuer Magier. ;-)."));
+ SetProp(P_GENDER, MALE);
+ SetProp(P_ARTICLE, 1);
+ SetProp(P_WEIGHT, 0);
+ SetProp(P_VALUE, 0);
+ Set(P_AUTOLOADOBJ,#'query_autoloadobj,F_QUERY_METHOD);
+ Set(P_AUTOLOADOBJ,#'set_autoloadobj,F_SET_METHOD);
+ Set(P_AUTOLOADOBJ,PROTECTED,F_MODE_AS);
+ SetProp(P_NEVERDROP,1);
+ SetProp(P_NODROP,1);
+ AddCmd(({"zmerke","znotiz"}),"AddNotiz");
+ AddCmd(({"zliste","ztodo"}),"ListNotizen");
+ AddCmd(({"zloesche","zrm"}),"RemoveNotiz");
+ AddCmd(({"zfertig","zhake"}),"FinishNotiz");
+ AddCmd(({"zlies","zlese"}),"LiesNotiz");
+ AddCmd(({"zprio"}),"ChangePrio");
+ AddCmd(({"zdep"}),"ChangeDep");
+ AddCmd(({"zstatus"}),"ChangeStatus");
+ AddCmd(({"zersetze"}),"ErsetzeText");
+ AddCmd(({"zergaenze"}),"ErgaenzeText");
+ AddCmd(({"zhelfer","zdelegiere"}),"ChangeHelper");
+ AddCmd(({"zzeige"}),"ZeigeZettel");
+ AddCmd(({"zwedel"}),"WedelZettel");
+ AddCmd(({"zdeplies"}),"LiesDeps");
+ AddCmd(({"zexpire"}),"Expire");
+ //cache=({});
+
+}
+
+//****************** AddCmd *****************************
+int AddNotiz(string str) {
+
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ //ggf. nur Einlesen, Cache muss hier nicht aktualisiert werden ;-)
+ checkStatus(1);
+ str=(string)PL->_unparsed_args(0); //kein parsing
+ if (!stringp(str) || !sizeof(str)) {
+ tell_object(PL,
+ "Was moechtest Du Dir denn notieren?\n");
+ return(1);
+ }
+ if (sizeof(str)>MAX_NOTE_LENGTH) {
+ tell_object(PL,BS(
+ sprintf("Deine Notiz ist mit %d Zeichen zu lang! Leider passen auf "
+ "Deinen Merkzettel nur % Zeichen drauf.",
+ sizeof(str),MAX_NOTE_LENGTH)));
+ return(1);
+ }
+
+ //m_allocate gilt nur bis Funktionsende, daher hilft das in
+ //checkStatus leider nicht.
+ if (!mappingp(notizen) || !sizeof(notizen))
+ notizen=m_allocate(0,7);
+
+ //freie ID finden (maxusedID+1 sollte die naechste frei sein, aber falls
+ //da mal was kaputtgegangen ist: Pruefen ;-) )
+ while(member(notizen,maxusedID)) {maxusedID++;}
+ //Reihenfolge: s. merkzettel.h
+ notizen+=([maxusedID:str;0;time();({});({});NOTE_ACTIVE;0]);
+/* notizen+=([maxusedID]);
+ notizen[maxusedID,NOTE_TEXT]=str;
+ notizen[maxusedID,NOTE_PRIO]=0;
+ notizen[maxusedID,NOTE_STARTTIME]=time();
+ notizen[maxusedID,NOTE_DEPS]=({});
+*/
+
+ //cache=({}); //cache invalidieren
+ //in Kuerze speichern, aber nicht fuer jede Aenderung speichern
+ save_me(60);
+ tell_object(PL,BS(
+ sprintf("Du schreibst sorgfaeltig Deine Notiz auf Deinen Merkzettel. "
+ "Es ist nun die %d. Notiz.",maxusedID)));
+ tell_room(environment(TI),
+ BS(sprintf("%s notiert sich etwas auf %s Merkzettel.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int LiesNotiz(string str) {
+ int id;
+
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ if (!stringp(str) || !sizeof(str) || !id=to_int(str)) {
+ tell_object(PL,
+ "Welche Notiz moechtest Du lesen? Bitte eine ID angeben!\n");
+ return(1);
+ }
+ if (!checkStatus()) {
+ tell_object(PL,
+ "Es gibt keine Notiz, die Du lesen koenntest!\n");
+ return(1);
+ }
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ //Ausgabetext holen und ausgeben
+ tell_object(PL,sprintf("\nDu vertiefst Dich in Deinen Merkzettel und liest:\n%s\n",_LiesNotiz(id)));
+ tell_room(environment(TI),
+ BS(sprintf("%s liest etwas auf %s Merkzettel.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int RemoveNotiz(string str) {
+ int id;
+
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ if (!stringp(str) || !sizeof(str) || !id=to_int(str)) {
+ tell_object(PL,
+ "Welche Notiz moechtest Du ausradieren? Bitte eine ID angeben!\n");
+ return(1);
+ }
+ if (!checkStatus()) {
+ tell_object(PL,
+ "Es gibt keine Notiz, die Du ausradieren koenntest!\n");
+ return(1);
+ }
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ //direkt Loeschen, keine Kopie, daher m_delete()
+ m_delete(notizen,id);
+ //in Kuerze speichern, aber nicht fuer jede Aenderung speichern
+ save_me(60);
+ //cache invalidieren
+ //cache=({});
+ tell_object(PL,
+ sprintf("Sorgfaeltig radierst Du Notiz %d von Deinem Merkzettel.\n",
+ id));
+ tell_room(environment(TI),
+ BS(sprintf("%s radiert sorgfaeltig etwas von %s Merkzettel.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int FinishNotiz(string str) {
+ int id;
+ mixed liste;
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ if (!stringp(str) || !sizeof(str) || !id=to_int(str)) {
+ tell_object(PL,
+ "Welche Notiz moechtest Du abhaken? Bitte eine ID angeben!\n");
+ return(1);
+ }
+ if (!checkStatus()) {
+ tell_object(PL,
+ "Es gibt keine Notiz, die Du abhaken koenntest!\n");
+ return(1);
+ }
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ if(notizen[id,NOTE_STATUS]==NOTE_FINISHED) {
+ tell_object(PL,
+ sprintf("Notiz %d ist schon abgehakt!\n",id));
+ return(1);
+ }
+ liste=getUnresolvedDeps(id); //liste ist Array von ints
+ if (sizeof(liste)) {
+ liste=map(liste,#'to_string); //liste ist Array von strings
+ tell_object(PL,BS(sprintf("Du kannst Notiz %d nicht abhaken, da noch "
+ "nicht erledigte Abhaengigkeiten existieren. IDs: %s.",
+ id,CountUp(liste))));
+ return(1);
+ }
+ notizen[id,NOTE_STATUS]=NOTE_FINISHED;
+ notizen[id,NOTE_CLOSETIME]=time();
+ tell_object(PL,BS(
+ sprintf("Du malst zufrieden einen schoenen grossen Haken hinter "
+ "die Notiz Nr. %d. Hach - was bist Du nun zufrieden! :-)\n",id)));
+ tell_room(environment(TI),
+ BS(sprintf("%s hakt erfreut etwas auf %s Merkzettel ab.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int ListNotizen(string str) {
+ int zahl,notizzahl,i,id,filterstate;
+ string txt;
+ string *arr;
+ status invers;
+
+ if(!objectp(TI)) return(0);
+ str=(string)PL->_unparsed_args(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ if (!notizzahl=checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ //Argumente parsen
+ if(stringp(str) && sizeof(str))
+ arr=explode(str," ");
+ if (pointerp(arr)) arr-=({""}); //doppelte leerzeichen im String
+ if (pointerp(arr) && sizeof(arr)>=2) {
+ zahl=to_int(arr[0]);
+ switch(arr[1]) {
+ case "aktiv":
+ filterstate=NOTE_ACTIVE; break;
+ case "inaktiv":
+ filterstate=NOTE_INACTIVE; break;
+ case "wartend":
+ case "pending":
+ filterstate=NOTE_PENDING; break;
+ case "abgehakt":
+ case "fertig":
+ case "abgeschlossen":
+ filterstate=NOTE_FINISHED; break;
+ case "alle":
+ filterstate=0; break;
+ default:
+ filterstate=to_int(arr[1]);
+ break;
+ }
+ }
+ else if (pointerp(arr) && sizeof(arr)==1) {
+ zahl=to_int(arr[0]);
+ filterstate=NOTE_ACTIVE;
+ }
+ else {
+ //Voreinstellungen
+ zahl=20;
+ filterstate=NOTE_ACTIVE;
+ }
+ //1. Argument "all" oder "alle" ist: alle anzeigen
+ if (pointerp(arr) && sizeof(arr) && stringp(arr[0]) &&
+ sizeof(arr[0]) && arr[0]=="alle")
+ zahl=notizzahl; //alle anzeigen
+
+ //wenn die gewuenschte Zahl die Anzahl gespeicherter
+ //Notizen ueberschreitet (oder 0 ist)
+ if(!zahl || zahl>notizzahl) zahl=notizzahl;
+
+ //wenn 1. Argument negativ: Liste in umgekehrter Reihenfolge
+ if (zahl<0) {
+ invers=1;
+ zahl=zahl*-1;
+ }
+ txt=sprintf("\n|%:9|s|%:56|s|%:7|s|\n","ID","Notiztext","Prio.");
+ txt+=sprintf("%:78'-'s\n","-");
+ //alle passenden Notizen ermitteln
+ arr=filter(m_indices(notizen),#'note_filter,filterstate);
+ //sortieren
+ arr=sort_array(arr,#'sort_prio);
+ if (zahl>sizeof(arr)) zahl=sizeof(arr);
+ //ausgeben
+ for(i=0;i<zahl;i++) {
+ if (!invers)
+ id=to_int(arr[i]);
+ else
+ //von hinten
+ id=to_int(arr[<i+1]); // i+1 ist wirklich Absicht. ;-)
+ txt+=sprintf("| %:7|d | %:54-s | %:5|d |\n",
+ id,
+ //nur bis zum ersten \n anzeigen
+ explode(notizen[id,NOTE_TEXT],"\n")[0],
+ notizen[id,NOTE_PRIO]);
+ }
+ txt+=sprintf("%:78'-'s\n\n","-");
+ tell_object(PL,txt);
+ tell_room(environment(TI),
+ BS(sprintf("%s wirft einen Blick auf %s Merkzettel.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihren" : "seinen")
+ )),({TI}));
+ return(1);
+}
+
+int ChangeDep(string str) {
+ int id;
+ string *arr;
+ int *deps;
+
+ notify_fail("Bitte eine ID und eine min. eine Abhaengigkeit angeben!\n");
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return(0);
+
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ arr=explode(str," ");
+ arr-=({""}); // "" entfernen, wichtig. ;-)
+ if (sizeof(arr)<2)
+ return(0);
+ id=to_int(arr[0]);
+ arr-=({arr[0]}); //eigene ID loeschen
+ if (sizeof(arr)<1)
+ return(0); //mehrfach die eigene ID gilt nicht.;-)
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ //dies updated direkt die Abhaengigkeiten in 'notizen'!
+ map(arr,#'update_deps,id);
+ save_me(60);
+ tell_object(PL,BS(
+ sprintf("Du aenderst die Abhaengigkeiten von Notiz %d.\n",
+ id)));
+ tell_room(environment(TI),
+ BS(sprintf("%s kritzelt auf %s Merkzettel herum.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int ChangePrio(string str) {
+ int id, prio;
+ string* arr;
+
+ notify_fail("Bitte eine ID und eine neue Prioritaet angeben!\n");
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return(0);
+
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ arr=explode(str," ");
+ if (sizeof(arr)>2) {
+ notify_fail("Bitte nur eine ID und eine neue Prioritaet angeben!");
+ return(0);
+ }
+ else if(sizeof(arr)==2) {
+ id=to_int(arr[0]);
+ prio=to_int(arr[1]);
+ }
+ else
+ return(0);
+
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ notizen[id,NOTE_PRIO]=prio;
+ //cache=({}); //cache invalidieren
+ save_me(60);
+ tell_object(PL,BS(
+ sprintf("Du aenderst die Prioritaet von Notiz %d auf %d.",
+ id,notizen[id,NOTE_PRIO])));
+ tell_room(environment(TI),
+ BS(sprintf("%s kritzelt auf %s Merkzettel herum.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int ChangeHelper(string str) {
+ int id;
+ string *arr;
+
+ notify_fail("Bitte eine ID und eine min. einen Namen angeben!\n");
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return(0);
+
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ arr=explode(str," ");
+ arr-=({""}); // "" entfernen, wichtig. ;-)
+ if (sizeof(arr)<2)
+ return(0);
+ id=to_int(arr[0]);
+ arr-=({arr[0]}); //eigene ID loeschen
+ if (sizeof(arr)<1)
+ return(0); //mehrfach die eigene ID gilt nicht.;-)
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ notizen[id,NOTE_HELPER]=arr;
+ save_me(60);
+ tell_object(PL,BS(
+ sprintf("Mitarbeiter von Notiz %d geaendert.",id)));
+ tell_room(environment(TI),
+ BS(sprintf("%s kritzelt auf %s Merkzettel herum.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int ChangeStatus(string str) {
+ int id, state;
+ string *arr;
+
+ notify_fail(BS(
+ "Bitte min. eine ID angeben, um den Status umzuschalten oder "
+ "eine ID und den neuen Status (1==Aktiv, 2==Wartend, "
+ "-1==Inaktiv/Pause)"));
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return(0);
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ arr=explode(str," ");
+ if (sizeof(arr)>2) {
+ notify_fail("Bitte nur eine ID und einen neuen Status angeben!");
+ return(0);
+ }
+ else if(sizeof(arr)==2) {
+ id=to_int(arr[0]);
+ state=to_int(arr[1]);
+ }
+ else if(sizeof(arr)==1) {
+ id=to_int(arr[0]);
+ }
+ else
+ return(0);
+
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ if(member(NOTE_STATES,state)==-1) {
+ if (notizen[id,NOTE_STATUS]==NOTE_ACTIVE) {
+ tell_object(PL,BS(
+ sprintf("%d ist ein unbekannter Status, setzt Notiz %d auf "
+ "'Inaktiv'.",state,id)));
+ state=NOTE_INACTIVE;
+ }
+ else {
+ tell_object(PL,BS(
+ sprintf("%d ist ein unbekannter Status, setzt Notiz %d auf "
+ "'Aktiv'.",state,id)));
+ state=NOTE_ACTIVE;
+ }
+ }
+ notizen[id,NOTE_STATUS]=state;
+ save_me(60);
+ tell_object(PL,BS(
+ sprintf("Status von Notiz %d geaendert.",id)));
+ tell_room(environment(TI),
+ BS(sprintf("%s kritzelt auf %s Notizzettel herum.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int ErsetzeText(string str) {
+ string *arr;
+ int id;
+
+ notify_fail("Bitte eine ID und einen neuen Text angeben!\n");
+ if(!objectp(TI)) return(0);
+
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return(0);
+
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ arr=explode(str," ");
+ arr-=({""}); // "" entfernen
+ if (sizeof(arr)<2)
+ return(0);
+ id=to_int(arr[0]);
+ str=implode(arr[1..]," "); //text wiederherstellen, ohne erstes Element
+ if (!sizeof(str)) return(0);
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ notizen[id,NOTE_TEXT]=str;
+ save_me(60);
+ tell_object(PL,BS(
+ sprintf("Text von Notiz %d ersetzt.",id)));
+ tell_room(environment(TI),
+ BS(sprintf("%s radiert zuerst etwas auf %s Notizzettel herum und "
+ "schreibt anschliessend sorgfaeltig etwas neues auf.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int ErgaenzeText(string str) {
+ string *arr;
+ int id;
+
+ notify_fail("Bitte eine ID und einen Text angeben!\n");
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return(0);
+
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ arr=explode(str," ");
+ arr-=({""}); // "" entfernen
+ if (sizeof(arr)<2)
+ return(0);
+ id=to_int(arr[0]);
+ str="\n";
+ str+=implode(arr[1..]," "); //text wiederherstellen
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ notizen[id,NOTE_TEXT]+=str;
+ save_me(60);
+ tell_object(PL,BS(
+ sprintf("Text von Notiz %d ergaenzt.",id)));
+ tell_room(environment(TI),
+ BS(sprintf("%s ergaenzt etwas auf %s Notizzettel.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int ZeigeZettel(string str) {
+ //anderen zeigen, wie furchtbar viel man zu tun hat.
+ object pl;
+ int count;
+ int *ids;
+
+ notify_fail("Wem willst Du Deinen Merkzettel zeigen?\n");
+ if (!objectp(TI)) return(0);
+ if (!environment() || !environment(environment()))
+ return(0);
+ if (!stringp(str) || !sizeof(str)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun? Du willst anderen Leuten doch bestimmt nicht "
+ "zeigen, dass Du nix zu tun hast, oder?"));
+ return(1);
+ }
+ if(!objectp(pl=present(str,environment(environment()))))
+ return(0);
+ if (!living(pl))
+ return(0);
+
+ ids=filter(m_indices(notizen),#'note_filter,NOTE_ACTIVE);
+ tell_object(TI,BS("Du zeigst "+pl->Name(WEM)+" voller Stolz deinen vollen "
+ "Merkzettel."));
+ tell_room(environment(environment()),BS(sprintf(
+ "%s zeigt %s %s Merkzettel.",
+ TI->Name(WER),pl->Name(WEM),TI->QueryPossPronoun(MALE,WEN,SINGULAR))),
+ ({TI,pl}));
+ switch(sizeof(ids)) {
+ case 0..10:
+ tell_object(pl,BS(sprintf("%s zeigt Dir voller Stolz %s Merkzettel. Du "
+ "wirfst einen schnellen Blick darueber und zaehlst %d "
+ "Notizen. Na, soviel ist das ja zum Glueck noch nicht.",
+ TI->Name(WER),TI->QueryPossPronoun(MALE,WEN,SINGULAR),
+ sizeof(ids))));
+ break;
+ case 11..20:
+ tell_object(pl,BS(sprintf("%s zeigt Dir voller Stolz %s Merkzettel. Du "
+ "wirfst einen schnellen Blick darueber und zaehlst %d "
+ "Notizen. Oh, das ist ja schon so einiges!",
+ TI->Name(WER),TI->QueryPossPronoun(MALE,WEN,SINGULAR),
+ sizeof(ids))));
+ break;
+ default:
+ tell_object(pl,BS(sprintf("%s zeigt Dir voller Stolz %s Merkzettel. Du "
+ "wirfst einen schnellen Blick darueber und zaehlst %d "
+ "Notizen. Puuuh. %s hat ganz schoen viel zu tun! In "
+ "Dir regt sich leises Mitleid.",
+ TI->Name(WER),TI->QueryPossPronoun(MALE,WEN,SINGULAR),
+ sizeof(ids),TI->Name(WER) )));
+ break;
+ }
+ return(1);
+ }
+
+int WedelZettel(string str) {
+ object pl;
+ string rwedel;
+ //wedelt anderen mit dem Zettel vor der Nase herum.
+ notify_fail("Wem willst Du Deinen Merkzettel zeigen?\n");
+ if (!objectp(TI)) return(0);
+ if (!environment() || !environment(environment()))
+ return(0);
+ if (!stringp(str) || !sizeof(str)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ if (!objectp(pl=find_player(str))) return(0);
+ if (!present(pl,environment(environment())))
+ rwedel="aus der Ferne";
+
+ tell_object(PL,BS("Du wedelst "+pl->Name(WEM)
+ + (rwedel?" "+rwedel:"")
+ +" heftig mit Deinem Merkzettel vor der Nase herum."));
+ tell_object(pl,BS(PL->Name(WER)+ " wedelt Dir "
+ + (rwedel?rwedel+" ":"") +"heftig mit "
+ +PL->QueryPossPronoun(MALE,WEM,SINGULAR)
+ +" Merkzettel vor der Nase herum."));
+ tell_room(environment(pl),BS(PL->Name(WER) + " wedelt "
+ +pl->Name(WEM) + (rwedel?" "+rwedel:"") + " heftig mit "
+ +PL->QueryPossPronoun(MALE,WEM,SINGULAR)
+ +" Merkzettel vor der Nase herum."),({PL,pl}));
+ return(1);
+}
+
+int LiesDeps(string str) {
+ //erstmal (rekursiv) alle Abhaengigkeiten einer Notiz ermitteln
+ string *arr;
+ int id, rec, i;
+ int *liste;
+
+ notify_fail("Bitte eine ID und ggf. '1' fuer rekursive Suche angeben!\n");
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return(0);
+
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ arr=explode(str," ");
+ arr-=({""}); // "" entfernen
+ if (sizeof(arr)==1) {
+ id=to_int(arr[0]);
+ rec=0; //Standard: keine Rekursion
+ }
+ else if (sizeof(arr)>=2) {
+ id=to_int(arr[0]);
+ rec=to_int(arr[1]);
+ }
+ else {
+ return(0);
+ }
+ if (!member(notizen,id)) {
+ tell_object(PL,
+ sprintf("Es gibt keine Notiz mit der ID: %d\n",id));
+ return(1);
+ }
+ //Notizen, von denen id abhaengt, holen
+ //und nur aktive Notizen behalten
+ liste=filter(getDeps(id,rec),#'note_filter,NOTE_ACTIVE);
+ //nach Prioritaet sortieren
+ liste=sort_array(liste,#'sort_prio);
+ //dann mal ausgeben.
+ i=sizeof(liste);
+ tell_object(PL,BS(sprintf("Du vertiefst Dich in die Abhaenhigkeiten von Notiz: %d\n",id)));
+ while(i--) {
+ tell_object(PL,_LiesNotiz(liste[i])+"\n");
+ }
+ tell_room(environment(TI),
+ BS(sprintf("%s liest etwas auf %s Merkzettel.\n",
+ capitalize((string)TI->name(WER)),
+ (((int)TI->QueryProp(P_GENDER))==FEMALE ? "ihrem" : "seinem")
+ )),({TI}));
+ return(1);
+}
+
+int Expire(string str) {
+ float age;
+ int sekunden, i;
+ int *liste;
+ string res;
+
+ notify_fail("Bitte angeben, wie alt zu loeschende Notizen sein sollen (in Tagen)!\n");
+ if(!objectp(TI)) return(0);
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ str=(string)PL->_unparsed_args(0);
+ if (!stringp(str) || !sizeof(str))
+ return(0);
+ age=to_float(str);
+ if (age<=0) return(0);
+ sekunden=time() - (int)(age*86400);
+ if (!checkStatus()) {
+ tell_object(PL,BS(
+ "Dein Merkzettel ist bluetenweiss und leer! Wie kommt das denn?? "
+ "Hast Du nix zu tun?"));
+ return(1);
+ }
+ //abgehakte Notizen ermitteln
+ liste=filter(m_indices(notizen),#'note_filter,NOTE_FINISHED);
+ //Notizen ermitteln, die lang genug abgehakt sind.
+ liste=filter(liste,#'aelter_als,sekunden);
+ if (!sizeof(liste)) {
+ tell_object(PL,BS("Keine Notizen gefunden, die lang genug abgehakt sind."));
+ return(1);
+ }
+ res=sprintf("Archivierte Notizen vom %s\n\n",dtime(time()));
+ for (i=sizeof(liste);i--;) {
+ //Infos noch einmal ausgeben und loeschen
+ res+=_LiesNotiz(liste[i])+"\n";
+ m_delete(notizen,liste[i]);
+ }
+ res+="\n";
+ write_file(ARCHIVE(owner),res);
+ tell_object(PL,BS(sprintf(
+ "%d alte Notizen wurden nach %s archiviert und geloescht.",
+ sizeof(liste),ARCHIVE(owner))));
+ return(1);
+}
+
+//
+static string _LiesNotiz(int id) {
+ //Funktion verlaesst sich drauf, dass id existiert. ;-)
+ string res,txt;
+ res=BSL(sprintf("%-11s: %d","Notiz-Nr.",id));
+ res+=break_string(notizen[id,NOTE_TEXT],78,"Notiztext : ",
+ BS_INDENT_ONCE|BS_LEAVE_MY_LFS);
+ res+=sprintf("%-11s: %d\n","Prioritaet",notizen[id,NOTE_PRIO]);
+ //wenn nicht aktiv: Status anzeigen
+ if (notizen[id,NOTE_STATUS]!=NOTE_ACTIVE) {
+ switch(notizen[id,NOTE_STATUS]) {
+ case NOTE_INACTIVE:
+ txt="Inaktiv/Pause";
+ break;
+ case NOTE_FINISHED:
+ txt="Abgeschlossen";
+ break;
+ case NOTE_PENDING:
+ txt="Warte auf Rueckmeldung";
+ break;
+ default: txt=sprintf("%d",notizen[id,NOTE_STATUS]); break;
+ }
+ res+=sprintf("%-11s: %s\n","Status",txt);
+ //wenn abgeschlossen: Endezeit anzeigen
+ if (notizen[id,NOTE_STATUS]==NOTE_FINISHED)
+ res+=sprintf("%-11s: %s\n","Endezeit",
+ dtime(notizen[id,NOTE_CLOSETIME]));
+ }
+ res+=sprintf("%-11s: %s\n","Merkzeit",dtime(notizen[id,NOTE_STARTTIME]));
+ //nur wenn Abhaengigkeiten: anezeigen
+ if (pointerp(notizen[id,NOTE_DEPS]) && sizeof(notizen[id,NOTE_DEPS])) {
+ txt=implode(map(notizen[id,NOTE_DEPS],#'to_string)," ");
+ res+=sprintf("%-11s: %s\n","abh. von",txt);
+ }
+ //nur wenn Helfer: anezeigen
+ if (pointerp(notizen[id,NOTE_HELPER]) && sizeof(notizen[id,NOTE_HELPER]))
+ res+=sprintf("%-11s: %s\n","Helfer",
+ implode(notizen[id,NOTE_HELPER]," "));
+ return(res);
+}
+
+//int. Helfer
+static int note_filter(int id,int filterstate) {
+ //kein filter -> passt immer
+ if (!filterstate) return(1);
+ if (member(notizen,id) &&
+ notizen[id,NOTE_STATUS]==filterstate)
+ return(1);
+ return(0);
+}
+
+static int aelter_als(int id,int zeit) {
+ //liefert 1 zurueck, wenn Schliesszeit der Notiz laenger als 'sekunden' her ist, sonst 0.
+ if (notizen[id,NOTE_CLOSETIME]<zeit) return(1);
+ return(0);
+}
+
+static string update_deps(string str,int id) {
+ //wandelt str nach int um
+ //schaut, ob dep positiv und noch nicht bekannt ist, wenn ja:
+ //zu deps hinzufuegen
+ //wenn dep < 0 und bekannt ist: aus deps entfernen
+ //Rueckgabewert ist egal. ;-)
+ int dep;
+ dep=to_int(str);
+ if (dep>0 && member(notizen[id,NOTE_DEPS],dep)==-1)
+ notizen[id,NOTE_DEPS]+=({dep});
+ else if (dep<0 && member(notizen[id,NOTE_DEPS],dep*-1)!=-1)
+ notizen[id,NOTE_DEPS]-=({dep*-1});
+ return("");
+}
+
+static int *getDeps(int id, int rec) {
+ //ermittelt (ggf. rekursiv bei rec!=0) die Abhaengigkeiten einer Notiz
+ int i, *liste;
+ liste=notizen[id,NOTE_DEPS];
+ //jetzt ggf. noch rekursiv weiterholen
+ if (rec) {
+ i=0;
+ while(i<sizeof(liste)) {
+ //nicht schreien. ;-)
+ if (get_eval_cost()<100000) {
+ tell_object(PL,"Fehler: Zu lange Rekursion bei "
+ "Ermitteln der Abhaengigkeiten, Abbruch\n");
+ return(liste);
+ }
+ //Abhaengigkeiten der anderen Abhaengigkeiten hinten anhaengen.
+ liste+=notizen[liste[i],NOTE_DEPS];
+ i++;
+ }
+ }
+ return(liste);
+}
+
+static int *getUnresolvedDeps(int id) {
+ //liefert die Anzahl der nicht abgehakten Notizen, von denen eine
+ //Notiz abhaengig ist (rekursiv)
+ int *liste;
+ //Abhaengigkeiten rekursiv holen
+ liste=getDeps(id,1);
+ //nicht abgehakte zurueckgeben
+ return(liste-filter(liste,#'note_filter,NOTE_FINISHED));
+}
+
+void init() {
+ ::init();
+ //wenn kein Env, Env kein magier oder nicht der Eigentuemer ist: weg
+ if (!objectp(environment()) || !IS_LEARNER(environment())
+ || (stringp(owner) && getuid(environment())!=owner) ) {
+ if (find_call_out("remove") == -1)
+ call_out("remove",1,1);
+ return;
+ }
+ //beim erstmaligen Bewegen in einen Magier wird der als Eigentuemer
+ //registriert. Danach kommt diese Info aus P_AUTOLOAD
+ if (!stringp(owner))
+ owner=getuid(environment());
+}
+
+static nomask status check_allowed() {
+ //Zugriff auf die Daten fuer den Eigentuemer
+ if(objectp(this_interactive()) &&
+ getuid(this_interactive())==owner
+ && !process_call())
+ return(1);
+ return(0);
+}
+
+protected int restore_me() {
+ //laedt Savefile im Home vom Magier
+ if(!stringp(owner)) return(0);
+ if(!restore_object(SAVEFILE(owner))) {
+ maxusedID=1;
+ notizen=0;
+ //cache=({});
+ return(0);
+ }
+ return(1);
+}
+
+varargs protected void save_me(int delay) {
+ //speichert Savefile im Home vom Magier
+ if(!stringp(owner)) return;
+ //wenn maxusedID==0 wurde der zettel noch nicht ordentlich initialisiert
+ //bzw. restauriert. In diesem Fall wuerde ein leeres Savefile geschrieben
+ if (maxusedID==0)
+ restore_me();
+ if(!delay)
+ //direkt speichen. ;-)
+ save_object(SAVEFILE(owner));
+ else {
+ //verzoegert speichern, wenn schon ein call_out laeuft, nehm ich den
+ if(find_call_out(#'save_me)==-1)
+ call_out(#'save_me,delay);
+ }
+}
+
+varargs int remove(int silent) {
+ //erstmal speichern. ;-)
+ save_me();
+ return ::remove(silent);
+}
+
+static string query_autoloadobj() {
+ //in P_AUTOLOAD wird nur der Eigentuemer gespeichert
+ return owner;
+}
+
+static string set_autoloadobj(mixed arg) {
+ //Eigentuemer aus P_AUTOLOAD restaurieren
+ if (stringp(arg))
+ owner=arg;
+ return(owner);
+}
+
+//Shadow unerwuenscht
+int query_prevent_shadow() {return(1);}
+
+varargs static int checkStatus(int nocache) {
+ //schaut, ob Notizen da, ob der Cache Ok ist, etc.
+ //liefert Anzahl der Notizen auf dem Merkzettel
+
+ //wenn keine Notizen da sind, schauen, ob das Savefile eingelesen werden
+ //kann
+ if (!mappingp(notizen) || !sizeof(notizen))
+ restore_me();
+ if (!mappingp(notizen)) return(0);
+/* Cache ist eigentlich nicht noetig und mir gerade zu unpraktisch, raus damit.
+ //wenn keine Aktualisierung des Cache erwuenscht ist
+ if(nocache) return(0);
+
+ if (sizeof(notizen)) {
+ if(!pointerp(cache) || !sizeof(cache)) {
+ //cache erneuern
+ cache=sort_array(m_indices(notizen),"sort_prio");
+ }
+ }
+ return(sizeof(cache)); //aequivalent zu sizeof(notizen)
+ */
+ return(sizeof(notizen));
+}
+
+static status sort_prio(int key1, int key2) {
+ // 1, falls falsche Reihenfolge,
+ // 0, wenn richtige
+ // und zwar _absteigend_, also hoechste Prio in liste[0] !
+ return(notizen[key1,NOTE_PRIO]<=notizen[key2,NOTE_PRIO]);
+}
+
+
+//*******************************************************
+
+// Debugging
+mapping QueryNotizen() {
+
+ if(!check_allowed()) {
+ if(objectp(this_interactive()))
+ tell_object(this_interactive(),
+ BS("Dieser Zugriff auf den Merkzettel wurde nicht erlaubt."));
+ return(0);
+ }
+ checkStatus();
+ return(notizen);
+}
+
+//int *QueryCache() {return(cache);}
+
+int QuerySize() {return(sizeof(notizen));}
+
+string QueryOwner() {return(owner);}
diff --git a/obj/tools/merkzettel/merkzettel.h b/obj/tools/merkzettel/merkzettel.h
new file mode 100644
index 0000000..dca7724
--- /dev/null
+++ b/obj/tools/merkzettel/merkzettel.h
@@ -0,0 +1,79 @@
+#ifndef __ZESSTRA_MERKZETTEL_H__
+#define __ZESSTRA_MERKZETTEL_H__
+
+#define SAVEFILE(x) ("/players/"+x+"/.merkzettel")
+#define ARCHIVE(x) ("/players/"+x+"/merkzettel.archiv")
+
+#define NOTE_TEXT 0
+#define NOTE_PRIO 1
+#define NOTE_STARTTIME 2
+#define NOTE_DEPS 3
+#define NOTE_HELPER 4
+#define NOTE_STATUS 5
+#define NOTE_CLOSETIME 6
+
+//Status, >0 sind aktiv, <0 inaktiv
+#define NOTE_ACTIVE 1
+#define NOTE_PENDING 2
+#define NOTE_INACTIVE -1
+#define NOTE_FINISHED -2
+#define NOTE_STATES ({NOTE_ACTIVE,NOTE_PENDING,NOTE_INACTIVE,NOTE_FINISHED})
+
+//Sortierreihenfolge
+#define SORT_INVERSE 1
+
+//wieviel wird max.abgespeichert
+#define MAX_NOTE_LENGTH 1000
+//wieviel wird max. in der Liste angezeigt
+#define MAX_NOTE_LIST_LENGTH 50
+
+#define BS(x) break_string(x,78)
+#define BSI(x,y) break_string(x,78,y)
+#define BSL(x) break_string(x,78,"",BS_LEAVE_MY_LFS)
+#define BSIL(x,y) break_string(x,78,y,BS_LEAVE_MY_LFS)
+
+#define TI this_interactive()
+
+#ifdef NEED_PROTOTYPES
+//AddCmd
+int AddNotiz(string str);
+int ErsetzeText(string str);
+int ErgaenzeText(string str);
+int RemoveNotiz(string str);
+int FinishNotiz(string str);
+int ListNotizen(string str);
+int LiesNotiz(string str);
+int ChangeDep(string str);
+int ChangeStatus(string str);
+int ChangePrio(string str);
+int ChangeHelper(string str);
+int ZeigeZettel(string str);
+int WedelZettel(string str);
+int LiesDeps(string str);
+int Expire(string str);
+
+//von den AddCmd-Funs gerufen
+static string _LiesNotiz(int id);
+
+//sonst. Funktionen, z.B. fuer Debugzwecke
+mapping QueryNotizen();
+string QueryOwner();
+varargs int remove(int silent);
+
+//int. Funktionen
+static status sort_prio(int key1, int key2);
+static nomask status check_allowed();
+protected int restore_me();
+varargs protected void save_me(int delay);
+static string query_autoloadobj();
+static string set_autoloadobj(mixed arg);
+varargs static int checkStatus(int nocache);
+static string update_deps(string str,int id);
+static int note_filter(int id,int filterstate);
+static int aelter_als(int id,int zeit);
+static int *getUnresolvedDeps(int id);
+static int *getDeps(int id,int rec);
+
+#endif // NEED_PROTOTYPES
+
+#endif // __ZESSTRA_MERKZETTEL_H__
diff --git a/obj/tools/mudlink.c b/obj/tools/mudlink.c
new file mode 100644
index 0000000..209d546
--- /dev/null
+++ b/obj/tools/mudlink.c
@@ -0,0 +1,84 @@
+/*
+ * mudlink tool, offers several commands as an interface to the
+ * MUDLINK system.
+ *
+ * Commands offered:
+ * rpeers
+ * rwho <remotemud>
+ * rtell <player>@<remotemud>
+ *
+ * Deepthought, 19-Jan-93
+ */
+
+#include <config.h>
+#include <properties.h>
+
+inherit "/std/thing";
+
+create() {
+ string name, foo;
+
+ if (sizeof(old_explode(object_name(this_object()),"#")) != 2) return;
+
+ thing::create();
+ SetProp (P_SHORT,"a MUDLINK tool");
+ SetProp (P_LONG,
+ "This tool is used for communicating with MUDLINK. Commands are:\n"
++"rpeers Get a list of muds connected to MUDLINK\n"
++"rwho <mud> Show a list of players on the remote mud\n"
++"rtell <player>@<mud> <message> Tell something to a player on another mud\n"
+ );
+ AddId ("tool");
+ AddId ("mudlink");
+ AddAdjective("mudlink");
+ SetInfo ("Mudlink Tool V0.1 by Deepthought");
+}
+
+_query_read_msg() { return 0; }
+
+/*-------------------------------------------------------------------------
+** Add and decode our commands.
+*/
+
+init() {
+ thing::init();
+ add_action("rpeers","rpeers");
+ add_action("rwho","rwho");
+ add_action("rtell","rtell");
+}
+
+rpeers() {
+ string u;
+ u = geteuid(this_player());
+ if (stringp(u))
+ tell_object(find_player("mudlink"),"rpeers "+u+"\n");
+ return 1;
+}
+
+rwho(str) {
+ string u;
+ if (!str || str == "") {
+ write("Usage: rwho <mud>\n");
+ return 1;
+ }
+ if (stringp(u = geteuid(this_player())))
+ tell_object(find_player("mudlink"),"rwho "+u+"="+str+"\n");
+ return 1;
+}
+
+rtell(str) {
+ string u;
+ string a, b, c, d;
+
+ if (!str || str == "") {
+ write("Usage: rtell <player>@<mud> <message>\n");
+ return 1;
+ }
+ if (sscanf(str, "%s@%s %s", a, b, c) != 3) {
+ write("Usage: rtell <player>@<mud> <message>\n");
+ return 1;
+ }
+ if (stringp(u = geteuid(this_player())))
+ tell_object(find_player("mudlink"),"rpage "+u+"@"+a+"@"+b+"="+c+"\n");
+ return 1;
+}
diff --git a/obj/tools/newstool.c b/obj/tools/newstool.c
new file mode 100644
index 0000000..0e67197
--- /dev/null
+++ b/obj/tools/newstool.c
@@ -0,0 +1,335 @@
+inherit "std/thing";
+
+#include <properties.h>
+#include <language.h>
+#include <config.h>
+#include <news.h>
+#include <defines.h>
+
+#define UA PL->_unparsed_args()
+
+void create()
+{
+ string str;
+ if (!clonep(this_object())) return;
+ ::create();
+ SetProp(P_LONG,"Ein News-Gruppen-Tool.\n\
+Befehle: addg <grname> <ownername> : Gruppe erzeugen\n\
+ removeg <grname> : Gruppe loeschen\n\
+ addw <grname> <username> : Schreibberechtigten eintragen\n\
+ removew <grname> <username> : Schreibberechtigten austragen\n\
+ addd <grname> <username> : Loeschberechtigten eintragen\n\
+ removed <grname> <username> : Loeschberechtigten austragen\n\
+ addr <grname> <username> : Leseberechtigten eintragen\n\
+ remover <grname> <username> : Leseberechtigten austragen\n\
+ ginfo <grname> : Info ueber Gruppe abfragen\n\
+ setexpire <grname> <tage> : Expiretime setzen\n\
+ setmaxmsg <grname> <anz> : Maxmsg setzen\n\
+ setg <grname> <loeschlev> <schreiblev> <leselev> <maxmsg> <expire>\n");
+ str=capitalize(((str=getuid(this_player()))[<1]=='s'||str[<1]=='x'||
+ str[<1]=='z')?str+="'":str+="s");
+ SetProp(P_SHORT,str+" NewsTool");
+ SetProp(P_NAME,str+" NewsTool");
+ SetProp(P_GENDER,NEUTER);
+ SetProp(P_ARTICLE,0);
+ AddId("newstool");
+ AddId("newsgruppentool");
+ AddId("news-gruppen-tool");
+ SetProp(P_AUTOLOADOBJ,1);
+ SetProp(P_NODROP,1);
+}
+
+void init()
+{
+ add_action("addg","addg");
+ add_action("removeg","removeg");
+ add_action("addw","addw");
+ add_action("removew","removew");
+ add_action("addd","addd");
+ add_action("removed","removed");
+ add_action("addr","addr");
+ add_action("remover","remover");
+ add_action("setg","setg");
+ add_action("setexpire","setexpire");
+ add_action("expire","expire");
+ add_action("ginfo","ginfo");
+ add_action("setmaxmsg","setmaxmsg");
+}
+
+int addr(string str)
+{
+ mixed *arr;
+ string st1, st2;
+
+ if ((str=UA)=="" || sscanf(str,"%s %s",st1,st2) !=2){
+ write("addr <groupname> <username>\nAnschliessend darf der User unabhaengig vom Wizlevel die Gruppe lesen.\n");
+ return 1;
+ }
+
+ arr=old_explode(st2," ")-({""});
+ switch ("/secure/news"->AddAllowed(st1,({}),({}),arr)){
+ case 0: write("Param err\n"); break;
+ case 1: write("Ok.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such board\n"); break;
+ }
+ return 1;
+}
+
+int remover(string str)
+{
+ mixed *arr;
+ string st1, st2;
+
+ if (!(str=UA) || sscanf(str,"%s %s",st1,st2) !=2){
+ write("remover <gruppenname> <username>\nDanach darf der User die Gruppe nur noch lesen, wenn sein Wizlevel dies erlaubt.\n");
+ return 1;
+ }
+
+ arr=old_explode(st2," ")-({""});
+ switch ("/secure/news"->RemoveAllowed(st1,({}),({}),arr)){
+ case 0: write("Param err\n"); break;
+ case 1: write("Ok.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such board\n"); break;
+ }
+ return 1;
+}
+
+int addd(string str)
+{
+ mixed *arr;
+ string st1, st2;
+
+ if (!(str=UA) || sscanf(str,"%s %s",st1,st2) !=2){
+ write("addd <gruppe> <user>\nUser darf Artikel loeschen (unabh vom Wizlevel)\n");
+ return 1;
+ }
+
+ arr=old_explode(st2," ")-({""});
+ switch ("/secure/news"->AddAllowed(st1,arr,({}),({}))){
+ case 0: write("Param err\n"); break;
+ case 1: write("Ok.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such board\n"); break;
+ }
+ return 1;
+}
+
+int removed(string str)
+{
+ mixed *arr;
+ string st1, st2;
+
+ if (!(str=UA) || sscanf(str,"%s %s",st1,st2) !=2){
+ write("removed <gruppe> <user>\nUser darf nur noch Artikel loeschen, wenn sein Wizlevel das erlaubt.\n");
+ return 1;
+ }
+
+ arr=old_explode(st2," ")-({""});
+ switch ("/secure/news"->RemoveAllowed(st1,arr,({}),({}))){
+ case 0: write("Param err\n"); break;
+ case 1: write("Ok.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such board\n"); break;
+ }
+ return 1;
+}
+
+int addw(string str)
+{
+ mixed *arr;
+ string st1, st2;
+
+ if (!(str=UA) || sscanf(str,"%s %s",st1,st2) !=2){
+ write("addw <gruppe> <user>\nUser darf Artikel schreiben (unabh vom Wizlevel)\n");
+ return 1;
+ }
+
+ arr=old_explode(st2," ")-({""});
+ switch ("/secure/news"->AddAllowed(st1,({}),arr,({}))){
+ case 0: write("Param err\n"); break;
+ case 1: write("Ok.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such board\n"); break;
+ }
+ return 1;
+}
+
+int removew(string str)
+{
+ mixed *arr;
+ string st1, st2;
+
+ if (!(str=UA) || sscanf(str,"%s %s",st1,st2) !=2){
+ write("removew <gruppe> <user>\nUser darf nur noch Artikel schreiben, wenn sein Wizlevel dies erlaubt.\n");
+ return 1;
+ }
+
+ arr=old_explode(st2," ")-({""});
+ switch ("/secure/news"->RemoveAllowed(st1,({}),arr,({}))){
+ case 0: write("Param err\n"); break;
+ case 1: write("Ok.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such board\n"); break;
+ }
+ return 1;
+}
+
+int setg(string str)
+{
+ string name;
+ int dlevel, wlevel, rlevel, maxmessages, expire;
+
+ if (!(str=UA) ||
+ sscanf(str,"%s %d %d %d %d %d",name,dlevel,wlevel,rlevel,maxmessages,expire) != 6) {
+ write("setg <gruppe> <loeschlevel> <schreiblevel> <leselevel> <maxmessages> <expire>\nGruppenparameter setzen, Bedeutung (Defaultwerte in Klammern):\n\
+ name : Der Name der Newsgroup\n\
+ loeschlevel (20) : Wizlevel, ab dem User Artikel loeschen koennen\n\
+ schreiblevel ( 0) : Wizlevel, ab dem User Artikel schreiben koennen\n\
+ leselevel ( 0) : Wizlevel, ab dem User Artikel lesen koennen\n\
+ maxmessages (40) : Maximale Anzahl Artikel in einer Newsgruppe\n\
+ expire (-1) : Expiretime in Tagen, -1 = nie\n");
+ return 1;
+ }
+ expire=86400*expire;
+ switch("/secure/news"->SetGroup(name, dlevel, wlevel, rlevel, maxmessages,expire)){
+ case 1: write("Ok\n"); break;
+ case 0: write("Param error.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such group\n"); break;
+ }
+ return 1;
+}
+
+int setexpire(string str)
+{
+ string name;
+ int expire;
+ mixed *gr;
+
+ if (!(str=UA)||sscanf(str,"%s %d",name,expire)!=2)
+ {
+ write("setexpire <gruppe> <tage>\n");
+ return 1;
+ }
+ expire=86400*expire;
+ if (!pointerp((gr="/secure/news"->GetGroup(name))))
+ {
+ write("Get group error\n");
+ return 1;
+ }
+ switch("/secure/news"->SetGroup(name, gr[G_DLEVEL], gr[G_WLEVEL], gr[G_RLEVEL], gr[G_MAX_MSG],expire)){
+ case 1: write("Ok\n"); break;
+ case 0: write("Param error.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such group\n"); break;
+ }
+ return 1;
+}
+
+int setmaxmsg(string str)
+{
+ string name;
+ int maxmsg;
+ mixed *gr;
+
+ if (!(str=UA)||sscanf(str,"%s %d",name,maxmsg)!=2)
+ {
+ write("setexpire <gruppe> <tage>\n");
+ return 1;
+ }
+ if (!pointerp((gr="/secure/news"->GetGroup(name))))
+ {
+ write("Get group error\n");
+ return 1;
+ }
+ switch("/secure/news"->SetGroup(name, gr[G_DLEVEL], gr[G_WLEVEL], gr[G_RLEVEL], maxmsg, gr[G_EXPIRE])){
+ case 1: write("Ok\n"); break;
+ case 0: write("Param error.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such group\n"); break;
+ }
+ return 1;
+}
+
+int ginfo(string str)
+{
+ mixed *gr;
+ int i;
+
+ if (!(str=UA))
+ {
+ write("Usage: ginfo <gname>\n");
+ return 1;
+ }
+ if (!pointerp((gr="/secure/news"->GetGroup(str))))
+ {
+ write("Get group error\n");
+ return 1;
+ }
+ if (gr[11]==-1)
+ {
+ write("Group \""+gr[0]+"\" does not exist.\n");
+ return 1;
+ }
+ // 1 2 3 4 5 6 7
+ //123456789012345678901234567890123456789012345678901234567890123456789012345678
+ printf("------------------------------------------------------------------------------\n");
+
+ printf("Rubrik : %s (%s) Savefile: %s\n\n",gr[0],capitalize(gr[1]),gr[2]);
+ printf("Messages: %i/%i Expire: %i Tage.\n\n",
+ (pointerp(gr[11])?sizeof(gr[11]):0),gr[10],gr[3]/86400);
+
+ printf( break_string((sizeof(gr[6])?"("+(CountUp(map(gr[6],#'capitalize)))+")":" "), 78, "Readers : "+gr[9]+" ",16));
+
+ printf( break_string((sizeof(gr[5])?"("+(CountUp(map(gr[5],#'capitalize)))+")":" "), 78, "Writers : "+gr[8]+" ",16));
+
+ printf( break_string((sizeof(gr[4])?"("+(CountUp(map(gr[4],#'capitalize)))+")":" "), 78, "Deleters: "+gr[7]+" ",16));
+
+ printf("------------------------------------------------------------------------------\n");
+ return 1;
+}
+
+int removeg(string str)
+{
+ if (!(str=UA))
+ {
+ write("removeg <gruppenname>\nGruppe LOESCHEN.\n");
+ return 0;
+ }
+ switch("/secure/news"->RemoveGroup(str)){
+ case 1: write("Ok. Bitte nicht vergessen, das Savefile der Newsgroup von Hand zu entfernen !\n"); break;
+ case 0: write("Param error.\n"); break;
+ case -1: write("No permission\n"); break;
+ case -2: write("No such group"); break;
+ }
+ return 1;
+}
+
+int addg(string str)
+{
+ string name, owner;
+
+ if (!(str=UA) || sscanf(str,"%s %s",name,owner)!=2)
+ {
+ write("addg <gruppe> <user>\nGruppe anlegen, <user> wird Besitzer der Gruppe\n");
+ return 1;
+ }
+ switch ("secure/news"->AddGroup(name, owner)){
+ case 1: write("Ok.\n"); break;
+ case 0: write("Param error.\n"); break;
+ case -1: write("No permission.\n"); break;
+ case -2: write("Group already there\n"); break;
+ case -3: write("Owner not found.\n"); break;
+ case -4: write("Savefile already in use.\n"); break;
+ }
+ return 1;
+}
+
+int expire()
+{
+ "/secure/news"->expire_all();
+ write("Expiring startet.\n");
+ return 1;
+}
diff --git a/obj/tools/planttool.c b/obj/tools/planttool.c
new file mode 100644
index 0000000..240ccb9
--- /dev/null
+++ b/obj/tools/planttool.c
@@ -0,0 +1,41 @@
+inherit "/std/secure_thing";
+
+#include <properties.h>
+#include <wizlevels.h>
+#define PLANTMASTER "/secure/krautmaster"
+
+protected void create()
+{
+ if (!clonep(this_object()))
+ return;
+ ::create();
+
+ SetProp(P_SHORT, "Das Kraeutertool");
+ Set(P_LONG, function string () { return
+ "Das Kraeutertool hat folgende Befehle:\n"
+ +"- showplant [kategorie] (listet alle Pflanzen einer Kategorie auf.)\n"
+ +(IS_ARCH(this_player())?
+ "Folgende Befehle sind nur fuer EM+ verfuegbar:\n"
+ +"- showrooms [ID|all] (Listet alle Raeume auf, in denen das Kraut <ID>\n"
+ +" zu finden ist, oder alle Raeume, in denen ein Kraut waechst.)\n"
+ +"- refresh (updatet alle Files).\n"
+ +"- addroom <plantId> <loadname> (traegt einen neuen Fundort ein).\n"
+ +"- delroom <loadname> (loescht alle Kraeuter fuer einen Fundort).\n"
+ +"- createfile <plantId> (erzeugt das Kraut als File).\n"
+ +"- cloneplant <plantId|plantFile> (clont das Kraut inv Inv).\n":
+ "");}, F_QUERY_METHOD);
+ SetProp(P_NAME, "Planttool");
+ SetProp(P_GENDER, NEUTER);
+ SetProp(P_AUTOLOADOBJ, 1);
+ SetProp(P_NODROP, 1);
+ SetProp(P_NEVERDROP, 1);
+ AddId(({"tool", "kraeutertool", "planttool"}));
+ AddCmd(({"cloneplant", "showplant", "showrooms", "refresh",
+ "addroom", "delroom", "createfile"}), "_plantmaster");
+}
+
+static int _plantmaster(string str)
+{
+ notify_fail("Unknown Function in plantmaster: _"+query_verb()+"()\n");
+ return call_other(PLANTMASTER, "_"+query_verb(), str);
+}
diff --git a/obj/tools/projekttool.c b/obj/tools/projekttool.c
new file mode 100644
index 0000000..f61a9dd
--- /dev/null
+++ b/obj/tools/projekttool.c
@@ -0,0 +1,212 @@
+//
+// Projecttool
+//
+
+#include "/p/service/mandragon/projektbrett/projectmaster.h"
+#include "/secure/wizlevels.h"
+#include <moving.h>
+
+inherit "/std/thing";
+string hilfe;
+static int changetime;
+static int suppressinfos;
+
+void create()
+{
+ if (!IS_CLONE(TO)) return;
+ ::create();
+ if (!find_object(PROJECTMASTER)) call_other(PROJECTMASTER,"???");
+
+ SetProp(P_NAME,"Schreibfeder");
+ SetProp(P_NODROP,"Du moechtest Deine Feder dann doch lieber behalten.\n");
+ SetProp(P_NEVERDROP,1);
+ SetProp(P_GENDER,FEMALE);
+ SetProp(P_SHORT,"Eine kleine magische Schreibfeder");
+ if (!changetime) changetime=1;
+ hilfe=BS("-----------------------------------------------------------------------------\n"
+ "Diese Feder ermoeglicht es Dir nicht nur, von ueberall her auf die "
+ "allseits beliebten Schwarzen Bretter fuer Projekte zuzugreifen, "
+ "sondern ermoeglicht es Dir auch, selber Projekte dort zu "
+ "veroeffentlichen.\n"
+ "Folgende Kommandos koennen Dir dabei helfen:\n\n"
+ "federhilfe - Diese Uebersicht\n"
+ "federdoku - Dokumentation aller Befehle\n"
+ "projekthilfe - Uebersicht ueber die Brettbefehle\n"
+ "AddProject - Projekt anlegen\n"
+ "RemoveProject <Nummer> - Projekt entfernen\n"
+ "ModifyProject <Nummer> - Projekt aendern\n"
+ "projektinfos ein|an|aus - Aenderungen (nicht mehr) anzeigen\n\n"
+ "Bei Fragen, Bugs und/oder Typos wende Dich bitte vertrauensvoll an den\n"
+ "Mandragon Deiner Wahl.\n"
+ "---------------------------------------------------------------------------");
+ SetProp(P_LONG,
+ BS("Diese kleine, weisse, magisch glaenzende Feder liegt sanft " +
+ "in Deiner Hand. Du spuerst foermlich, wie sie danach dringt, " +
+ "Neues zu schaffen und die Welt zu vergroessern.\n\n")+hilfe);
+ AddId(({"schreibfeder","feder","projekttool"}));
+ AddCmd("federhilfe","hilfe_fun");
+ AddCmd("projekthilfe","board_help");
+ AddCmd("projektliste","board_list");
+ AddCmd("federdoku","doku_fun");
+ AddCmd(({"projektdetail","projektdetails"}),"board_long");
+ AddCmd(({"addproject","AddProject","ap"}),"addproj_fun");
+ AddCmd(({"removeproject","RemoveProject","rp"}),"remproj_fun");
+ AddCmd(({"modifyproject","ModifyProject","mp"}),"modproj_fun");
+ AddCmd("projektinfos","watch_fun");
+ TO->move(TP,M_NOCHECK);
+ return;
+}
+
+void _set_autoloadobj(mixed val)
+{
+ if (intp(val)) changetime=time();
+ else if (pointerp(val)&&sizeof(val)==2)
+ {
+ changetime=val[0];
+ suppressinfos=val[1];
+ }
+ return;
+}
+
+int *_query_autoloadobj() { return ({ changetime, suppressinfos }); }
+
+int doku_fun(string arg)
+{
+ TP->More(PROJECTDOKU,1);
+ return 1;
+}
+
+int board_help(string arg)
+{
+ PROJECTMASTER->BoardHelp();
+ return 1;
+}
+
+int board_list(string arg)
+{
+ arg=TP->_unparsed_args(1);
+ if (!sizeof(arg)) (PROJECTMASTER)->ShowList();
+ else PROJECTMASTER->ParseArgs(arg);
+ changetime=time();
+ return 1;
+}
+
+int board_long(string arg)
+{
+ int number;
+ arg=TP->_unparsed_args(1);
+ notify_fail("Syntax: projektdetail <PROJEKTNUMMER>\n");
+ if (!sizeof(arg)) return 0;
+ if (!(number=to_int(arg))||(arg!=to_string(number))) return 0;
+ notify_fail("Projektnummern koennen nur Zahlen groesser Null sein.\n");
+ if (number<1) return 0;
+ PROJECTMASTER->ShowLong(number);
+ return 1;
+}
+
+int hilfe_fun(string arg)
+{
+ tell_object(TP,hilfe);
+ return 1;
+}
+
+int board_fun(string arg)
+{
+ PROJECTMASTER->ParseArgs(TP->_unparsed_args(1));
+ return 1;
+}
+
+int addproj_fun(string arg)
+{
+ if (!IS_LEARNER(TP))
+ {
+ tell_object(TP,"Wie bist DU denn an die Feder gekommen?\n");
+ TO->remove();
+ return 1;
+ }
+ PROJECTMASTER->ChangeData(0);
+ return 1;
+}
+
+int remproj_fun(string arg)
+{
+ if (!IS_LEARNER(TP))
+ {
+ tell_object(TP,"Wie bist DU denn an die Feder gekommen?\n");
+ TO->remove();
+ return 1;
+ }
+ notify_fail("Syntax: removeproject NUMMER\n");
+ if (!sizeof(arg)||!intp(to_int(arg))||(arg!=to_string(to_int(arg)))) return 0;
+ PROJECTMASTER->DeleteData(to_int(arg));
+ return 1;
+}
+
+int modproj_fun(string arg)
+{
+ if (!IS_LEARNER(TP))
+ {
+ tell_object(TP,"Wie bist DU denn an die Feder gekommen?\n");
+ TO->remove();
+ return 1;
+ }
+ notify_fail("Syntax: modifyproject NUMMER\n");
+ if (!arg||!intp(to_int(arg))||(arg!=to_string(to_int(arg)))) return 0;
+ notify_fail("Es gibt kein Projekt mit der Nummer 0.\n");
+ if (to_int(arg)==0) return 0;
+ PROJECTMASTER->ChangeData(to_int(arg));
+ return 1;
+}
+
+int watch_fun(string arg)
+{
+ if (!IS_LEARNER(TP))
+ {
+ tell_object(TP,"Wie bist DU denn an die Feder gekommen?\n");
+ TO->remove();
+ return 1;
+ }
+ if (!sizeof(arg))
+ {
+ tell_object(TP,BS(sprintf("Du bekommst derzeit %sInformationen "
+ "ueber Aenderungen am Projektbrett.",
+ suppressinfos?"keine ":"")));
+ return 1;
+ }
+ notify_fail("Syntax: projektinfos <ein|an|aus>\n");
+ if (arg!="ein"&&arg!="an"&&arg!="aus") return 0;
+ if (arg=="aus")
+ {
+ suppressinfos=1;
+ tell_object(TP,BS("Du wirst jetzt keine Meldungen mehr ueber "
+ "Aenderungen am Projektbrett erhalten.\n"));
+ return 1;
+ }
+ suppressinfos=0;
+ tell_object(TP,BS("Du bekommst ab sofort Meldungen ueber Aenderungen "
+ "am Projektbrett.\n"));
+ return 1;
+}
+
+void init()
+{
+ if (!IS_LEARNER(TP)) {
+ if (find_call_out("remove") == -1)
+ call_out("remove",0);
+ }
+ else ::init();
+ return;
+}
+
+void reset()
+{
+ if (!environment())
+ {
+ destruct(TO);
+ return;
+ }
+ if (!suppressinfos&&changetime<(PROJECTMASTER->ChangeTime()))
+ tell_object(environment(),"Intuitiv spuerst Du, dass sich "
+ "die Aushaenge am Projektbrett geaendert haben.\n");
+ return;
+}
diff --git a/obj/tools/ptool.c b/obj/tools/ptool.c
new file mode 100644
index 0000000..c836cae
--- /dev/null
+++ b/obj/tools/ptool.c
@@ -0,0 +1,291 @@
+/*
+ Objekt zum Eintragen von Raeumen die Zaubertraenke enthalten beim
+ potionmaster.
+*/
+
+#include <wizlevels.h>
+#include <properties.h>
+#include <language.h>
+
+inherit "std/thing";
+
+int dump();
+
+int secure()
+{
+ if (!previous_object()) return 0;
+ if (geteuid(previous_object())==ROOTID) return 1;
+ if (geteuid(previous_object()) != geteuid(this_interactive())) return 0;
+ if (this_interactive() != this_player()) return 0;
+ if (!ARCH_SECURITY) return 0;
+ return 1;
+}
+
+void create()
+{
+ if (!clonep(this_object())) return;
+ ::create();
+ SetProp(P_SHORT, "Potion-Tool");
+ SetProp(P_LONG,
+ "Ein Tool zum Eintragen von Raumen in den Potionmaster.\n"+
+ "Folgende Befehle gibt es:\n"+
+ "ptadd <liste> Addiert den ZT im Raum in Liste <liste>\n"+
+ " und aktiviert ihn gleichzeitig.\n"+
+ "ptset <liste> Aktiviert den ZT im Raum und setzt ihn in\n"+
+ " die Liste <liste>.\n"+
+ "ptchange <nummer> Ersetzt den ZT <nummer> durch den ZT im Raum.\n"+
+ "ptact Aktiviert einen deaktivierten ZT in seiner\n"+
+ " bisherigen Liste.\n"+
+ "ptdeact Deaktiviert den ZT im Raum aus der ZTListe\n"+
+ " und verschiebt ihn nach 'deaktivierte ZTs'.\n"+
+ "ptinfo [para] kein para: Zeigt Infos ueber den ZT im aktu-\n"+
+ " ellen Raum.\n"+
+ " int para: Zeigt Infos zum ZT para an.\n"+
+ " string para: Zeigt ZT-Infos des Spielers para.\n"+
+ "ptdump Erzeugt ein Dump der aktuellen ZTListe und\n"+
+ " speichert diesen ab.\n\n");
+ SetProp(P_NAME, "PTool");
+ SetProp(P_GENDER, NEUTER);
+ AddId(({"tool", "ptool"}));
+ SetProp(P_NODROP, 1);
+ SetProp(P_AUTOLOADOBJ, 1);
+ AddCmd("ptadd", "add");
+ AddCmd("ptset", "setlist");
+ AddCmd("ptchange", "changepath");
+ AddCmd("ptact", "activate");
+ AddCmd("ptdeact", "deactivate");
+ AddCmd("ptinfo", "info");
+ AddCmd("ptdump", "dump");
+}
+
+int add(string number)
+{
+ int nr, next, active;
+ string room;
+ if (!secure())
+ { printf("Fehler: -1\n"); return -1; }
+ if (!query_once_interactive(environment()))
+ { printf("Fehler: -2\n"); return -2; }
+ if (!number)
+ { printf("Fehler: -3\n"); return -3; }
+ sscanf(number, "%d", nr);
+ if (!intp(nr))
+ { printf("Fehler: -4\n"); return -4; }
+ room = object_name(environment(environment(this_object())));
+ next = "/secure/potionmaster"->AddPotionRoom(room,nr);
+ if (next>0)
+ printf("Raum in Gesamtliste eingetragen, Nummer: %d\n", next-1);
+ else
+ {
+ printf("Raum konnte nicht eingetragen werden, Ergebnis: %d\n", next);
+ return 1;
+ }
+ // Nicht mehr noetig, Arathorn, 2013-Mai-30
+ //active = "/secure/potionmaster"->SetListNr(room, nr);
+ if (active>=0)
+ {
+ printf("Raum aktiviert in Liste %d\n", nr);
+ dump();
+ }
+ else
+ printf("Fehler beim Aktivieren, Ergebnis: %d\n", active);
+ return 1;
+}
+
+int changepath(string number)
+{
+ int nr,neu;
+ string room;
+ mixed roomold;
+ if (!secure())
+ { printf("Fehler: -1\n"); return -1; }
+ if (!query_once_interactive(environment()))
+ { printf("Fehler: -2\n"); return -2; }
+ if (!number)
+ { printf("Fehler: -3\n"); return -3; }
+ sscanf(number, "%d", nr);
+ if (!intp(nr))
+ { printf("Fehler: -4\n"); return -4; }
+ room = object_name(environment(environment(this_object())));
+ roomold = "/secure/potionmaster"->GetFilenameByNumber(nr);
+ if (roomold==-1)
+ { printf("Fehler: -5\n"); return -5; }
+ neu = "/secure/potionmaster"->ChangeRoomPath(roomold,room);
+ if (neu>0)
+ {
+ printf("ZT %d durch aktuellen Raum ersetzt.\n", neu);
+ dump();
+ }
+ else
+ printf("ZT %d konnte nicht ersetzt werden, Ergebnis: %d\n", nr,neu);
+ return 1;
+}
+
+int setlist(string number)
+{
+ int nr, next, active;
+ string room;
+ if (!secure())
+ { printf("Fehler: -1\n"); return -1; }
+ if (!query_once_interactive(environment()))
+ { printf("Fehler: -2\n"); return -2; }
+ if (!number)
+ { printf("Fehler: -3\n"); return -3; }
+ sscanf(number, "%d", nr);
+ if (!intp(nr) || nr<0 || nr>7)
+ { printf("Fehler: -4\n"); return -4; }
+ room = object_name(environment(environment(this_object())));
+ active = "/secure/potionmaster"->SetListNr(room, nr);
+ if (active>=0)
+ {
+ printf("Raum aktiviert in Liste %d\n", nr);
+ dump();
+ }
+ else
+ printf("Fehler beim Aktivieren, Ergebnis: %d\n", active);
+ return 1;
+}
+
+int activate()
+{
+ int nr, active;
+ string room;
+
+ if (!secure())
+ { printf("Fehler: -1\n"); return -1; }
+ if (!query_once_interactive(environment()))
+ { printf("Fehler: -2\n"); return -2; }
+ room = object_name(environment(environment(this_object())));
+ active = "/secure/potionmaster"->ActivateRoom(room);
+ if (active>=0)
+ {
+ printf("Raum aktiviert in Liste %d\n", active);
+ dump();
+ }
+ else
+ printf("Fehler beim Aktivieren, Ergebnis: %d\n", active);
+ return 1;
+}
+
+int deactivate()
+{
+ int deactive;
+ string room;
+
+ if (!secure())
+ { printf("Fehler: -1\n"); return -1; }
+ if (!query_once_interactive(environment()))
+ { printf("Fehler: -2\n"); return -2; }
+ room = object_name(environment(environment(this_object())));
+ deactive = "/secure/potionmaster"->DeactivateRoom(room);
+ if (deactive>=0)
+ {
+ printf("Raum deaktiviert in Liste %d\n",deactive);
+ dump();
+ }
+ else
+ printf("Fehler beim Deaktivieren, Ergebnis: %d\n", deactive);
+ return 1;
+}
+
+int info(string para)
+{
+ int info,nr;
+ string s;
+ object room,o;
+ mixed m,*potions;
+ if (!secure())
+ { printf("Fehler: -1\n"); return -1; }
+ if (!query_once_interactive(environment()))
+ { printf("Fehler: -2\n"); return -2; }
+ if (!para || para=="")
+ {
+ room = environment(environment(this_object()));
+ info = "/secure/potionmaster"->HasPotion(room);
+ if (info>=0)
+ {
+ printf("Raum hat ZT mit Nr: %d\n\n",info);
+ nr = "/secure/potionmaster"->GetListByNumber(info);
+ if (nr>=0)
+ printf("ZT aktiv in Liste: %d\n\n",nr);
+ else
+ {
+ nr = "/secure/potionmaster"->GetInactListByNumber(info);
+ if (nr>=0)
+ printf("ZT INaktiv in Liste: %d\n\n",nr);
+ else
+ printf("ZT INaktiv\n\n");
+ }
+ if (info>=0 && s=read_file("/secure/ARCH/ZT/"+info+".zt"))
+ {
+ write("Tip:\n"+s);
+ }
+ }
+ else
+ printf("Raum hat keinen ZT eingetragen.\n");
+ }
+ else
+ if (sscanf(para,"%d",info)==1)
+ {
+ printf("ZT mit Nummer: %d\n\n",info);
+ m = "/secure/potionmaster"->GetFilenameByNumber(info);
+ if (m!=-1)
+ {
+ write("Filename: "+m+"\n\n");
+ nr = "/secure/potionmaster"->GetListByNumber(info);
+ if (nr>=0)
+ printf("ZT aktiv in Liste: %d\n\n",nr);
+ else
+ {
+ nr = "/secure/potionmaster"->GetInactListByNumber(info);
+ if (nr>=0)
+ printf("ZT INaktiv in Liste: %d\n\n",nr);
+ else
+ printf("ZT INaktiv\n\n");
+ }
+ if (info>=0 && s=read_file("/secure/ARCH/ZT/"+info+".zt"))
+ {
+ write("Tip:\n"+s);
+ }
+ }
+ else
+ write("Kein ZT mit dieser Nummer bekannt.\n");
+ }
+ else
+ {
+ write("Spieler "+capitalize(para)+"\n\n");
+ if (o=find_player(para))
+ {
+ potions=sort_array(o->QueryProp(P_POTIONROOMS),#'>);
+ if (sizeof(potions))
+ {
+ s="";
+ for (nr=0;nr<sizeof(potions);nr++)
+ s+=potions[nr]+", ";
+ write("Potionrooms:\n"+break_string(s[0..<3],78)+"\n");
+ }
+ else write("Spieler hat keine weiteren Potionrooms.\n");
+ potions=sort_array(o->QueryProp(P_KNOWN_POTIONROOMS),#'>);
+ if (sizeof(potions))
+ {
+ s="";
+ for (nr=0;nr<sizeof(potions);nr++)
+ s+=potions[nr]+", ";
+ write("Bekannte Potionrooms:\n"+
+ break_string(s[0..<3],78));
+ }
+ else write("Spieler hat keine bekannten Potionrooms.\n");
+ }
+ else
+ write("Kein Spieler mit diesem Namen anwesend.\n");
+ }
+ return 1;
+}
+
+int dump()
+{
+ "/secure/potionmaster"->DumpList();
+ printf("Liste wurde erzeugt.\n");
+ return 1;
+}
+
diff --git a/obj/tools/pubtool.c b/obj/tools/pubtool.c
new file mode 100644
index 0000000..a85afc9
--- /dev/null
+++ b/obj/tools/pubtool.c
@@ -0,0 +1,60 @@
+/* MorgenGrauen MudLib : Pubtool */
+
+#include <defines.h>
+#include <properties.h>
+#include <language.h>
+
+inherit "/std/thing";
+
+create()
+{
+ if (!clonep(ME))
+ return;
+ ::create();
+
+ SetProp(P_SHORT,"Ein Pubtool");
+ SetProp(P_LONG,
+ "Das Pubtool berechnet die maximal zulaessige Heilung einer Kneipe.\n"+
+ "\n"+
+ "Syntax: pubtest <P_ALCOHOL> <P_DRINK> <P_FOOD> <P_VALUE> <Rate> <Delay>\n"+
+ "\n"+
+ "Wertebereich: >=0 >=0 >=0 >=0 1..20 0..\n"+
+ "\n");
+ SetProp(P_NAME,"Pubtool");
+ SetProp(P_GENDER,NEUTER);
+ SetProp(P_WEIGHT,0);
+ SetProp(P_VALUE,0);
+ SetProp(P_NODROP,"Das Pubtool behaelst Du lieber bei Dir.\n");
+ SetProp(P_NEVERDROP,1);
+ SetProp(P_AUTOLOADOBJ,1);
+
+ AddId( "pubtool" );
+
+ AddCmd( "pubtest", "pubtest" );
+}
+
+int pubtest(string arg)
+{ int v,d,a,f,r,h,y;
+
+ notify_fail(
+ "Syntax: pubtest <P_ALCOHOL> <P_DRINK> <P_FOOD> <P_VALUE> <Rate> <Delay>\n");
+
+ if (!arg || !stringp(arg) ||
+ sscanf(arg,"%d %d %d %d %d %d",a,d,f,v,r,y)!=6)
+ return 0;
+
+ if (v<1 || d<0 || a<0 || f<0 || r<1 || r>20 || y<0)
+ return 0;
+
+ h=call_other("/secure/pubmaster","CalcMax",
+ ([P_VALUE:v,P_ALCOHOL:a,P_DRINK:d,P_FOOD:f,
+ "delay":y,"rate":r]),0);
+
+ printf("Berechnete Maximalheilung fuer:\n"+
+ "P_ALCOHOL = %3d P_DRINK = %3d P_FOOD = %3d \n"+
+ "P_VALUE = %3d Rate = %3d Delay = %3d \n"+
+ "Ergebnis:\n"+
+ "Gesamt: %3d (HP+SP), aufgeteilt z.B. %3d HP und %3d SP.\n",
+ a,d,f,v,r,y,h,(h/2),(h%2?(h/2)+1:(h/2)));
+ return 1;
+}
diff --git a/obj/tools/questtool.c b/obj/tools/questtool.c
new file mode 100644
index 0000000..264fa7c
--- /dev/null
+++ b/obj/tools/questtool.c
@@ -0,0 +1,754 @@
+/*
+ * The new ultimate quest administration tool
+ */
+
+/* AENDERUNGEN
+ * 2006-09-29 : Zook
+ * Questtool an neue Felder "Attribute" und "Klasse"
+ * angepasst.
+ * 2000-11-18 : Zook:
+ * Questtool um neues Feld "Wartender Magier" des Questmaster
+ * erweitert.
+ * 2000-11-18 : Zook:
+ * Questtool um neues Feld "Gruppeneinordnung" des Questmaster
+ * erweitert.
+ */
+
+inherit "std/thing";
+inherit "std/more";
+
+#include <defines.h>
+#include <properties.h>
+#include <language.h>
+#include <wizlevels.h>
+#include "/secure/questmaster.h"
+
+#define UA this_interactive()->_unparsed_args()
+
+#define QNAME 0
+#define QP 1
+#define XP 2
+#define ALLOW 3
+#define INFO 4
+#define LEVEL 5
+#define CLASS 6
+#define ATTR 7
+#define WIZ 8
+#define SCNDWIZ 9
+#define END 10
+
+#pragma strong_types
+
+private void Load_NumKey();
+int Add_Quest ( string str );
+void ReadNewQuest ( string str );
+int Remove_Quest ( string str );
+int Change_Quest ( string str );
+int Restore_Quest ( string str );
+int Set_Quest ( string str );
+int Remove_Quest ( string str );
+int Query_Quest ( string str );
+int Query_Keys ( string str );
+int Query_Quests ( string str );
+int ActivateQuest ( string str );
+int DeactivateQuest ( string str );
+int GetReturn ( string str );
+
+string name;
+int qp;
+int xp;
+int level;
+int need;
+string *allowed;
+string info;
+string wizard;
+string scndwizard;
+int group;
+mapping num_key;
+
+object owner;
+int counter;
+mixed *savequest;
+string savekey;
+int do_change;
+string changekey;
+
+void create()
+{
+ string str;
+
+ if(IS_BLUE(ME)) return;
+ thing::create();
+ SetProp(P_GENDER,NEUTER);
+ owner = PL;
+ AddId("questtool");
+ AddId("qt");
+ SetProp(P_ARTICLE,0);
+ SetProp(P_GENDER, NEUTER);
+ str=capitalize(((str=owner->query_real_name())[<1]=='s'||str[<1]=='x'||str[<1]=='z')?str+="'":str+="s");
+ SetProp(P_NAME, str+" QuestTool");
+ SetProp(P_SHORT, str+" QuestTool");
+ SetProp(P_LONG,
+ "Das QuestTool dient der Administration von Quests. (by Kirk, 10.11.94)\n"
+ +"implementierte Kommandos:\n"
+ +" AddQ : Neuen Questeintrag einfuegen\n"
+ +" RemoveQ <quest> : Questeintrag loeschen\n"
+ +" ChangeQ <quest> : Questeintrag aendern\n"
+ +" ReStoreQ : Zuletzt geloeschten oder geaenderten\n"
+ +" : Questeintrag restaurieren\n"
+ +" SetQ <spieler> <quest> : Quest als 'geloest' markieren\n"
+ +" DelQ <spieler> <quest> : Quest als 'nicht geloest' markieren\n"
+ +" QueryQ <quest> : Questeintrag anzeigen\n"
+ +" QueryK : Alle Keys und Indices anzeigen\n"
+ +" QueryAllQ : Alle Eintraege vollstaendig anzeigen\n"
+ +" ActiVateQ <quest> : Quest im Questmaster aktivieren\n"
+ +" DeactiVateQ <quest> : Quest im Questmaster deaktivieren\n\n"
+ +" fuer <quest> kann der Index verwendet werden, den QueryK liefert!\n\n"
+ +" (Alle Kommandos koennen abgekuerzt werden.)\n"
+ +" -> Beispiel: DeactiVateQ == DVQ == dvq == deactivateq\n");
+
+ SetProp(P_NEVERDROP, 1);
+ SetProp(P_NODROP,
+ "Mit Hilfe des QuestTools koennen Quests eingetragen, oder geloescht\n"+
+ "werden. Du brauchst es vielleicht noch, deshalb wirfst Du es nicht weg.\n");
+ SetProp(P_NOBUY, 1);
+ AddCmd(({ "AddQ", "addq", "AQ", "aq" }), "Add_Quest");
+ AddCmd(({ "RemoveQ", "removeq", "RQ", "rq" }), "Remove_Quest");
+ AddCmd(({ "ChangeQ", "changeq", "CQ", "cq" }), "Change_Quest");
+ AddCmd(({ "ReStoreQ", "restoreq", "RSQ", "rsq" }), "Restore_Quest");
+ AddCmd(({ "SetQ", "setq", "SQ", "sq" }), "Set_Quest");
+ AddCmd(({ "DelQ", "delq", "DQ", "dq" }), "Del_Quest");
+ AddCmd(({ "QueryQ", "queryq", "QQ", "qq" }), "Query_Quest");
+ AddCmd(({ "QueryK", "queryk", "QK", "qk" }), "Query_Keys");
+ AddCmd(({ "QueryAllQ", "queryallq", "QAQ", "qaq" }), "Query_Quests");
+ AddCmd(({ "ActiVateQ", "activateq", "AVQ", "avq" }), "ActivateQuest");
+ AddCmd(({ "DeactiVateQ", "deactivateq", "DVQ", "dvq" }), "DeactivateQuest");
+ counter = QNAME;
+ savekey = "";
+ do_change = 0;
+ num_key = ([]);
+}
+
+int _query_autoloadobj() { return 1; }
+
+void init()
+{
+ object tp;
+
+ if(!(tp = PL) || tp != environment())
+ return;
+
+ thing::init();
+
+ if ( !IS_WIZARD(tp) || tp != owner )
+ return call_out("do_remove",1);
+}
+
+static void do_remove()
+{
+ write ( ME->QueryProp(P_SHORT)+" zerfaellt zu Staub.\n");
+ say ( ME->QueryProp(P_SHORT)+" zerfaellt in "+PL->name(WESSEN)+
+ " unbefugten Haenden zu Staub.\n");
+ call_out("remove",1);
+}
+
+private void Load_NumKey()
+{
+ string *keys;
+ int i;
+
+ if ( !(keys = (string*) QM->QueryAllKeys()) ) return;
+ keys=sort_array(keys,#'>);//')
+ for ( i = 0, num_key = ([]); i < sizeof(keys); i++ )
+ num_key += ([(i+1)+"":keys[i]]);
+}
+
+int Add_Quest(string str)
+{
+ counter = QNAME;
+ write ( "Neue Quest: (Abbruch mit '.' oder '~q')\n" );
+ write ( "Key :\n" );
+ input_to ( "ReadNewQuest" );
+ return 1;
+}
+
+void ReadNewQuest (string str)
+{
+ mixed *oldquest;
+ int errstat;
+ int active;
+
+ if ( str == "~q" || str == "." )
+ {
+ counter = QNAME;
+ if(do_change)
+ {
+ do_change = 0;
+ changekey = "";
+ savekey = "";
+ savequest = ({});
+ }
+ return;
+ }
+
+ switch ( counter )
+ {
+ case QNAME:
+ if((!str||!sizeof(str)) && do_change)
+ name = savekey;
+ else
+ name = str;
+ counter++;
+ write ( sprintf("Punkte (>0) [%d]:\n",
+ (do_change?(int)savequest[0]:10)) );
+ input_to ( "ReadNewQuest" );
+ break;
+ case QP:
+ if((!str||!sizeof(str)))
+ if(do_change)
+ qp = (int) savequest[Q_QP];
+ else
+ qp = 10;
+ else
+ sscanf ( str, "%d", qp );
+ counter++;
+ write ( sprintf("Erfahrung (>=0) [%d]:\n",
+ (do_change?(int)savequest[1]:qp*1000)));
+ input_to ( "ReadNewQuest" );
+ break;
+ case XP:
+ if((!str||!sizeof(str)))
+ if(do_change)
+ xp = (int) savequest[Q_XP];
+ else
+ xp = qp * 1000;
+ else
+ sscanf ( str, "%d", xp );
+ counter++;
+ write ( sprintf("Filenamen file1[,file2,...]) %s:\n",
+ (do_change?"["+implode((string *)savequest[2],",")+"]":
+ "")) );
+ input_to ( "ReadNewQuest" );
+ break;
+ case ALLOW:
+ if((!str||!sizeof(str)) && do_change)
+ allowed = (string *) savequest[Q_ALLOWED];
+ else
+ allowed = old_explode(implode(old_explode(str,".c"),""),",");
+ counter++;
+ write ( sprintf("Info %s:\n", (do_change?
+ "["+break_string("\b\b\b\b\b\b"+(string)
+ savequest[3]+"]",78,6)
+ :"")) );
+ input_to ( "ReadNewQuest" );
+ break;
+ case INFO:
+ if((!str||!sizeof(str)) && do_change)
+ info = (string) savequest[Q_HINT];
+ else
+ info = str;
+ counter++;
+ write ( sprintf("Stufe (-1 <=lev<=10) (-1 ist eine Seherquest) [%d]:\n",
+ (do_change?(int)savequest[4]:0)) );
+ input_to ( "ReadNewQuest" );
+ break;
+ case LEVEL:
+ if((!str||!sizeof(str)))
+ if(do_change)
+ level = (int) savequest[Q_DIFF];
+ else
+ level = 0;
+ sscanf ( str, "%d", level );
+ counter++;
+ write ( sprintf("Klasse ([012345]) [%d]:\n",
+ (do_change?(int)savequest[5]:0)) );
+ input_to ( "ReadNewQuest" );
+ break;
+ case CLASS:
+ if((!str||!sizeof(str)))
+ if(do_change)
+ need = (int) savequest[Q_CLASS];
+ else
+ need = 0;
+ else
+ sscanf ( str, "%d", need );
+ counter++;
+ write ( sprintf("Attribut [01234]\n(1=fleissig,2=heroisch,3=episch,4=legendaer) %s:\n",
+ (do_change?"["+(string)savequest[9]+"]":"")) );
+ input_to ( "ReadNewQuest" );
+ break;
+ case ATTR:
+ if ((!str||!sizeof(str)))
+ if (do_change)
+ group = (int) savequest[Q_ATTR];
+ else
+ group = 0;
+ else
+ sscanf (str, "%d", group);
+ counter++;
+ write ( sprintf("Magier %s:\n",
+ (do_change?"["+(string)savequest[7]+"]":"")) );
+ input_to ( "ReadNewQuest" );
+ break;
+ case WIZ:
+ if((!str||!sizeof(str)) && do_change)
+ wizard = (string) savequest[Q_WIZ];
+ else
+ wizard = str;
+ wizard = lower_case(wizard);
+ counter++;
+ write ( sprintf("Wartender Magier %s:\n",
+ (do_change?"["+(string)savequest[8]+"]":"")) );
+ input_to ( "ReadNewQuest" );
+ break;
+ case SCNDWIZ:
+ if ((!str||!sizeof(str)) && do_change)
+ scndwizard = (string) savequest[Q_SCNDWIZ];
+ else
+ scndwizard = str;
+ scndwizard = lower_case(scndwizard);
+ counter++;
+ write ( "Eintragen (j/n)?\n" );
+ input_to ( "ReadNewQuest" );
+ break;
+ case END:
+ counter=QNAME;
+
+ if ( str != "j" && str != "ja" && str != "y" && str != "yes" )
+ return;
+
+ active = 0;
+ if ( do_change && changekey && sizeof(changekey) )
+ {
+ oldquest = (mixed *) QM->QueryQuest ( changekey );
+
+ if ( !pointerp ( oldquest ) || !sizeof ( oldquest ) )
+ {
+ write ( "Alten Eintrag nicht gefunden.\n" );
+ return;
+ }
+
+ errstat = (int) QM->RemoveQuest( changekey );
+
+ do_change = 0;
+ changekey = "";
+
+ switch ( errstat )
+ {
+ case 0: write ( "Zugriff auf alten Eintrag verweigert.\n" ); return;
+ case -1: write ( "Parameterfehler beim Loeschen.\n" ); return;
+ case -2: write ( "Alten Eintrag nicht gefunden.\n" ); return;
+ default: write ( "Alter Eintrag geloescht.\n" );
+ }
+ active = oldquest[6];
+ savequest = oldquest;
+ savekey = changekey;
+ }
+
+ // add new Quest deactivated by default and keep old active flag
+ // if changing an existing entry
+ errstat= (int)QM->AddQuest(name,qp,xp,allowed,info,level,need,active,
+ wizard, scndwizard, group);
+
+ switch ( errstat )
+ {
+ case 0: write ( "Zugriff verweigert.\n" ); break;
+ case -1: write ( "Key ungueltig oder sizeof(key) < 5.\n" ); break;
+ case -2: write ( "QP ungueltig oder < 1.\n" ); break;
+ case -3: write ( "XP ungueltig.\n" ); break;
+ case -4: write ( "Filename(n) ungueltig.\n" ); break;
+ case -5: write ( "Info ungueltig.\n" ); break;
+ case -6: write ( "Stufe ungueltig oder < 0 oder > 20.\n" ); break;
+ case -7: write ( "Aktiv-Flag < 0 oder > 1.\n" ); break;
+ case -8: write ( "Magiername ungueltig.\n" ); break;
+ case -9: write ( "Magiername des wartenden Magiers ungueltig.\n"); break;
+ case -10: write ("Falsche Gruppeneinordnung.\n"); break;
+ default: write ( "Eintrag eingefuegt.\n" );
+ }
+ default:
+ return;
+ }
+}
+
+int Remove_Quest ( string str )
+{
+ mixed *oldquest;
+ string newstr;
+ int errstat;
+
+ if ( !(str=UA) )
+ {
+ write ( "Syntax: RemoveQ <name>\n" );
+ return 1;
+ }
+
+ Load_NumKey();
+
+ if ( !(newstr = num_key[str+""]) )
+ newstr = str;
+
+ oldquest = (mixed *) QM->QueryQuest ( newstr );
+
+ if ( !pointerp ( oldquest ) || !sizeof ( oldquest ) )
+ {
+ write ( "Keine Quest dieses Namens gefunden.\n" );
+ return 1;
+ }
+
+ errstat = (int) QM->RemoveQuest( newstr );
+
+ switch ( errstat )
+ {
+ case 0: write ( "Zugriff verweigert.\n" ); break;
+ case -1: write ( "Parameterfehler.\n" ); break;
+ case -2: write ( "Quest nicht gefunden.\n" ); break;
+ default: write ( "Quest entfernt.\n" );
+ }
+
+ savequest = oldquest;
+ savekey = newstr;
+
+ return 1;
+}
+
+int Change_Quest ( string str )
+{
+ mixed *oldquest;
+ string newstr;
+
+ if ( !(str=UA) )
+ {
+ write ( "Syntax: ChangeQ <quest>\n" );
+ return 1;
+ }
+
+ Load_NumKey();
+
+ if ( !(newstr = num_key[str+""]) )
+ newstr = str;
+
+ oldquest = (mixed *) QM->QueryQuest ( newstr );
+
+ if ( !pointerp( oldquest ) || !sizeof ( oldquest ) )
+ {
+ write ( "Keine Quest dieses Namens gefunden.\n" );
+ return 1;
+ }
+
+ do_change = 1;
+ changekey = newstr;
+ savekey = newstr;
+ savequest = oldquest;
+
+ write ( "Aktueller Eintrag:\n");
+ write ( "Key : "+newstr+"\n" );
+ write ( "Punkte : "+oldquest[Q_QP]+"\n" );
+ write ( "Erfahrung : "+oldquest[Q_XP]+"\n" );
+ write ( "Filenamen : "+implode(oldquest[Q_ALLOWED],",")+"\n" );
+ write ( "Info : "+oldquest[Q_HINT]+"\n" );
+ write ( "Stufe : "+oldquest[Q_DIFF]+"\n" );
+ write ( "Klasse : "+QCLASS_STARS(oldquest[Q_CLASS])+"\n" );
+ write ( "Attribut : "+QATTR_STRINGS[oldquest[Q_ATTR]]+"\n" );
+ write ( "Magier : "+capitalize(oldquest[Q_WIZ])+"\n" );
+ write ( "Wartender Magier : "+capitalize(oldquest[Q_SCNDWIZ])+"\n" );
+
+
+ write ( "\nNeue Quest: (mit '.' oder '~q' kann abgebrochen werden)\n" );
+ write ( sprintf("Key [%s]:\n", savekey) );
+ input_to ( "ReadNewQuest" );
+
+ return 1;
+}
+
+int Restore_Quest ( string str )
+{
+ int errstat;
+
+ if ( !savekey || !sizeof(savekey) )
+ {
+ write ( "\nTut mir leid!\n" );
+ write ( "Nichts zum Restaurieren gefunden ...\n" );
+ return 1;
+ }
+
+ errstat =
+ (int)QM->AddQuest( savekey, (int) savequest[0], (int) savequest[1],
+ (string *) savequest[2], (string) savequest[3],
+ (int) savequest[4], (int) savequest[5],
+ (string) savequest[6], (int) savequest[7],
+ (string) savequest[8] );
+
+ switch ( errstat )
+ {
+ case 0: write ( "Zugriff verweigert.\n" ); break;
+ case -1: write ( "Key ungueltig oder sizeof(key) < 5.\n" ); break;
+ case -2: write ( "QP ungueltig oder < 1.\n" ); break;
+ case -3: write ( "XP ungueltig.\n" ); break;
+ case -4: write ( "Filename(n) ungueltig.\n" ); break;
+ case -5: write ( "Info ungueltig.\n" ); break;
+ case -6: write ( "Stufe ungueltig oder < 0 oder > 20.\n" ); break;
+ case -7: write ( "Aktiv-Flag < 0 oder > 1.\n" ); break;
+ case -8: write ( "Magiername ungueltig.\n" ); break;
+ case -9: write ( "Magiername ungueltig.\n"); break;
+ case -10: write ("Ungueltige Gruppennummer.\n"); break;
+ default: write ( "'"+savekey+"' restauriert.\n" );
+ }
+ savekey = "";
+ return 1;
+}
+
+int Set_Quest ( string str )
+{
+ string quest, player, newquest;
+ int created;
+ object ob;
+
+ if ( !(str=UA) || sscanf( str, "%s %s", player, quest ) != 2 )
+ {
+ write ( "Syntax: SetQ <player> <quest>\n" );
+ return 1;
+ }
+
+ created=0;
+ Load_NumKey();
+
+ if ( !(newquest = num_key[quest+""]) )
+ newquest = quest;
+
+ ob=find_player(player);
+ if(!ob)
+ {
+ ob=find_netdead(player);
+ if(!ob)
+ {
+ created=1;
+ ob=__create_player_dummy(player);
+ }
+ }
+ if(!ob)
+ {
+ write("Kein solcher Spieler gefunden.\n!");
+ return 1;
+ }
+
+ write(ERRNO_2_STRING("GQ",(int)ob->GiveQuest(newquest,"__silent__"))+"\n");
+ if(created)
+ {
+ ob->save_me(0);
+ if(!(ob->remove()))
+ {
+ destruct(ob);
+ }
+ }
+ return 1;
+}
+
+int Del_Quest ( string str )
+{
+ string quest, player, newquest;
+ int created;
+ object ob;
+
+ if ( !(str=UA) || sscanf( str, "%s %s", player, quest ) != 2 )
+ {
+ write ( "Syntax: DelQ <player> <quest>\n" );
+ return 1;
+ }
+
+ Load_NumKey();
+
+ if ( !(newquest = num_key[quest+""]) )
+ newquest = quest;
+
+ created=0;
+ ob=find_player(player);
+ if(!ob)
+ {
+ ob=find_netdead(player);
+ if(!ob)
+ {
+ created=1;
+ ob=__create_player_dummy(player);
+ }
+ }
+ if(!ob)
+ {
+ write("Kein solcher Spieler gefunden.\n!");
+ return 1;
+ }
+
+ write(ERRNO_2_STRING("DQ",(int) ob->DeleteQuest ( newquest ))+"\n");
+ if(created)
+ {
+ ob->save_me(0);
+ if(!(ob->remove()))
+ {
+ destruct(ob);
+ }
+ }
+ return 1;
+}
+
+int Query_Quest ( string str )
+{
+ mixed *quest;
+ string newstr;
+ int i;
+
+ if ( !(str=UA) )
+ {
+ write ( "Syntax: QueryQ <quest>\n" );
+ return 1;
+ }
+
+ Load_NumKey();
+
+ if ( !(newstr = num_key[str+""]) )
+ newstr = str;
+
+ quest = (mixed *) QM->QueryQuest( newstr );
+
+ if ( !pointerp( quest ) || !sizeof ( quest ) )
+ {
+ write ( "Keine Quest dieses Namens gefunden.\n" );
+ return 1;
+ }
+
+ write ( "Aktueller Eintrag:\n");
+ write ( "Key : "+newstr );
+ if(quest[Q_ACTIVE])
+ write (" (aktiviert)\n");
+ else
+ write (" (deaktiviert)\n");
+ write ( "Punkte : "+quest[Q_QP]+"\n" );
+ write ( "Erfahrung : "+quest[Q_XP]+"\n" );
+ write ( break_string ( implode( quest[Q_ALLOWED], " " ), 65, "Filenamen : " ) );
+ write ( break_string ( quest[Q_HINT], 65, "Info : " ) );
+ write ( "Stufe : "+quest[Q_DIFF]+"\n" );
+ printf("Stufe (avg) : %.2f (%d)\n", quest[Q_AVERAGE][0],
+ quest[Q_AVERAGE][1]);
+ write ( "Klasse : "+ QCLASS_STARS(quest[Q_CLASS])+"\n");
+ write ( "Attribute : "+ QATTR_STRINGS[quest[Q_ATTR]]+"\n");
+ write ( "Magier : "+capitalize(quest[Q_WIZ])+"\n" );
+ write ( "Wartender Magier : "+capitalize(quest[Q_SCNDWIZ])+"\n");
+ return 1;
+}
+
+int Query_Keys ( string str )
+{
+ string *keys, active;
+ mixed *quest;
+ int i;
+
+ if ( !(keys = (string *) QM->QueryAllKeys()) )
+ return 1;
+
+ write ( "\n" );
+ keys=sort_array(keys,#'>);//')
+ for ( i = 0; i < sizeof(keys); i++ )
+ {
+ quest = (mixed *) QM->QueryQuest(keys[i]);
+ if(quest[6])
+ active="*";
+ else
+ active=" ";
+ write(sprintf("%2d%s %-33s%s",i+1,quest[6]?"*":" ",keys[i],
+ !(i%2)?" ":"\n"));
+ }
+ if(i%2)
+ write("\n");
+
+ return 1;
+}
+
+int Query_Quests ( string str )
+{
+ mixed *quest;
+ string *keys, rstr;
+ int i;
+
+ if ( !(keys = (mixed *) QM->QueryAllKeys()) )
+ return 1;
+
+ keys=sort_array(keys,#'>);//')
+ for ( i = 0, rstr = ""; i < sizeof(keys); i++ )
+ {
+ quest = (mixed *) QM->QueryQuest(keys[i]);
+ write ( "\nKey : "+keys[i] );
+ if(quest[Q_ACTIVE])
+ write (" (aktiviert)\n");
+ else
+ write (" (deaktiviert)\n");
+ write ( "Punkte : "+quest[Q_QP]+"\n" );
+ write ( "Erfahrung : "+quest[Q_XP]+"\n" );
+ write ( break_string ( implode( quest[Q_ALLOWED], " " ), 78, "Filenamen : " ) );
+ write ( break_string ( quest[Q_HINT], 78, "Info : " ) );
+ write ( "Stufe : "+quest[Q_DIFF]+"\n" );
+ write ( "Klasse : "+ QCLASS_STARS(quest[Q_CLASS])+"\n");
+ write ( "Attribute : "+ QATTR_STRINGS[quest[Q_ATTR]]+"\n");
+ write ( "Magier : "+capitalize(quest[7])+"\n" );
+ write ( "Wartender Magier : "+capitalize(quest[8])+"\n");
+ }
+ More( rstr, 0 );
+ return 1;
+}
+
+int ActivateQuest( string str )
+{
+ mixed *quest;
+ string newstr;
+ int errstat;
+
+ if ( !(str=UA) )
+ {
+ write ( "Syntax: ActiVateQ <quest>\n" );
+ return 1;
+ }
+
+ Load_NumKey();
+
+ if ( !(newstr = num_key[str+""]) )
+ newstr = str;
+
+ switch( QM->SetActive( newstr, 1 ) )
+ {
+ case -3: write ( "Ungueltiger Flag.\n" ); break;
+ case -2: write ( "Quest war bereits aktiviert.\n" ); break;
+ case -1: write ( "Keine Quest dieses Namens gefunden.\n" ); break;
+ case 0: write ( "Zugriff verweigert\n" ); break;
+ case 1: write ( "Quest '"+newstr+"' aktiviert.\n" ); break;
+ default: write ( "unbekannter Fehlerstatus.\n" );
+ }
+ return 1;
+}
+
+int DeactivateQuest( string str )
+{
+ mixed *quest;
+ string newstr;
+ int errstat;
+
+ if ( !(str=UA) )
+ {
+ write ( "Syntax: DeactiVateQ <quest>\n" );
+ return 1;
+ }
+
+ Load_NumKey();
+
+ if ( !(newstr = num_key[str+""]) )
+ newstr = str;
+
+ switch( QM->SetActive( newstr, 0 ) )
+ {
+ case -3: write ( "Ungueltiger Flag.\n" ); break;
+ case -2: write ( "Quest war bereits deaktiviert.\n" ); break;
+ case -1: write ( "Keine Quest dieses Namens gefunden.\n" ); break;
+ case 0: write ( "Zugriff verweigert\n" ); break;
+ case 1: write ( "Quest '"+newstr+"' deaktiviert.\n" ); break;
+ default: write ( "unbekannter Fehlerstatus.\n" );
+ }
+ return 1;
+}
+
+
diff --git a/obj/tools/teller/adm/mk b/obj/tools/teller/adm/mk
new file mode 100755
index 0000000..5798264
--- /dev/null
+++ b/obj/tools/teller/adm/mk
@@ -0,0 +1,25 @@
+#!/usr/local/bin/perl
+
+$mode = 0;
+$T1="mixed|float|int|string|object|void|quoted_array|symbol|closure|mapping";
+$T2="mixed \*|float \*|int \*|string \*|object \*|void \*|quoted_array \*|symbol \*|closure \*|mixed \&";
+$TYPES="\($T1|$T2\)";
+
+while( <> ) {
+ chop $_;
+ if( $mode == 0 && $_ eq "%efuns" ) {
+ $mode = 1;
+ } elsif( $mode == 1 && $_ eq "%xcodes" ) {
+ $mode = 2;
+ } elsif( $_ =~ "#endif" && $mode == 3 ) {
+ $mode = 1;
+ } elsif( $mode == 1 ) {
+ if( $_ =~ m"#ifndef NATIVE" || $_ =~ m"#ifdef MALLOC_malloc" ) {
+ $mode = 3;
+ } elsif( $_ ne "" && $_ !~ m"^.\*" && $_ !~ "^#" ) {
+ s/default: \w*//;
+ s/$TYPES/mixed/g;
+ print "$_\n";
+ }
+ }
+}
diff --git a/obj/tools/teller/hilfe/array b/obj/tools/teller/hilfe/array
new file mode 100644
index 0000000..8253000
--- /dev/null
+++ b/obj/tools/teller/hilfe/array
@@ -0,0 +1,19 @@
+BEFEHL:
+ array, arr
+
+ARGUMENTE:
+ Alle Stackelemente bis zum letzten Lock.
+
+FUNKTION:
+ Alle Elemente werden zu einem Array zusammengefuegt. Der Lock
+ wird entfernt und das Array wieder auf den Stack gelegt.
+
+BEISPIELE:
+ ,me "zap_msg", "Du kochst @@wen@@.\n" "@@ich@@ kocht @@wen@@.\n"
+ "@@ich@@ kocht Dich.\n" array !SetProp
+ Wandelt die drei Strings in ein Array um. Danach wird im
+ Spieler die Zapp-Meldung neu gesetzt. Das obige muss
+ natuerlich in einer Zeile eingegeben werden.
+
+SPIEHE AUCH:
+ "split", "lock"
diff --git a/obj/tools/teller/hilfe/call b/obj/tools/teller/hilfe/call
new file mode 100644
index 0000000..7597299
--- /dev/null
+++ b/obj/tools/teller/hilfe/call
@@ -0,0 +1,26 @@
+BEFEHL:
+ 'funktion, ''funktion oder
+ ->funktion, -->funktion
+
+ARGUMENTE:
+ Alle Stackelemente bis zum letzten Lock.
+ funktion -- Name einer lfun.
+
+FUNKTION:
+ Rufe in dem Objekt oberhalb des letzten Locks, die angegebene
+ Funktion auf und uebergib die folgenden Elemente des Stacks
+ (bis hinauf zum TOS) als Argumente. Entferne den Lock.
+ Wenn mit die Funktion mit zwei Apostrophen oder zwei Minuszeichen
+ gerufen wurde, lege das Ergebnis auf den Stack. (Bei einfachem
+ Apostroph bzw. Minuszeichen also nicht.)
+
+BEISPIEL:
+ ,me "das Grauen am Morgen" 'set_title
+ Enspricht:
+ call_other( this_player(), "set_title", "das Grauen am Morgen" );
+
+WARNUNG:
+ Man sollte vorher nachschauen, ob nicht noch etwas auf dem Stack
+ liegt, denn wenn kein Lock da ist, wuerde die Funktion darin
+ aufgerufen werden (mit me und "das Grauen am Morgen" als Argumente),
+ Deshalb besser so: ,,me "das Grauen am Morgen" ''set_title
diff --git a/obj/tools/teller/hilfe/callefun b/obj/tools/teller/hilfe/callefun
new file mode 100644
index 0000000..61fde2a
--- /dev/null
+++ b/obj/tools/teller/hilfe/callefun
@@ -0,0 +1,25 @@
+BEFEHL:
+ `funktion, ``funktion oder
+ -*funktion, --*funktion
+
+ARGUMENTE:
+ Alle Stackelemente bis zum letzten Lock.
+ funktion -- Name einer efun.
+
+FUNKTION:
+ Rufe die angegebene efun auf, und uebergebe alle Stackelemente
+ bis zum letzten Lock als Argumente. Entferne den Lock.
+ Wenn die efun mit doppelten Backquotes oder Minuszeichen ('``' oder
+ '--*') aufgerufen wurde, lege das Ergebnis auf den Stack. (Bei
+ einfachem '`' also nicht.)
+
+BEISPIEL:
+ ,me `environment
+ Enspricht:
+ environment( this_player() );
+
+WARNUNG:
+ Man sollte vorher nachschauen, ob nicht noch etwas auf dem Stack
+ liegt, denn wenn kein Lock da ist, werden zuaetzlich noch
+ ungewunschte Argumente mituebergeben.
+ Deshalb besser so: ,,me ``environment
diff --git a/obj/tools/teller/hilfe/callouts b/obj/tools/teller/hilfe/callouts
new file mode 100644
index 0000000..883042c
--- /dev/null
+++ b/obj/tools/teller/hilfe/callouts
@@ -0,0 +1,24 @@
+BEFEHL:
+ callouts
+ callouts!
+
+ARGUMENTE:
+ callouts: TOS String, nach dem gesucht wird.
+ callouts!: keine
+
+FUNKTION:
+ Gib eine Liste aller im Spiel laufenden call_outs aus. Ein call_out
+ wird in folgendem Format ausgegeben:
+ 1.) Zeit, bis zum Aufruf der Funktion.
+ 2.) Objekt, in dem die Funktion aufgerufen wird.
+ 3.) Name der Funktion.
+ 4.) Argument, das dem call_out uebergeben wird.
+
+ Wird der Befehl ohne Rufzeihen eingegeben, so werden nur die
+ Meldungen ausgegeben, die in den ersten drei (!) Argumenten
+ den angegebenen String enthalten.
+
+BEISPIEL:
+ ,"go" callouts
+ Gibt alle Monster aus, die mittels der Funktion "go" umherlaufen.
+ (Es gibt aber auch welche, die mittels "Walk" laufen. :-)
diff --git a/obj/tools/teller/hilfe/cleanof b/obj/tools/teller/hilfe/cleanof
new file mode 100644
index 0000000..6557cf1
--- /dev/null
+++ b/obj/tools/teller/hilfe/cleanof
@@ -0,0 +1,16 @@
+BEFEHL:
+ cleanof, clnof
+
+ARGUMENTE:
+ Die zwei obersten Stackelemente.
+
+FUNKTION:
+ Zerstoere alle Objekte in dem zweiten Objekt auf dem Stack,
+ die sich unter dem Namen, der in TOS steht, angesprochen fuehlen.
+ Die Objekte werden aber nur removed, das das der empfohlene Weg
+ ist, Objekte zu zerstoeren. Sollen die Objekte wirklich hart zerstoert
+ werden, so kann man ein Rufzeichen an den Befehl anhaengen.
+ (Also 'cleanof!'.)
+
+SIEHE AUCH:
+ "remove", "destruct"
diff --git a/obj/tools/teller/hilfe/clear b/obj/tools/teller/hilfe/clear
new file mode 100644
index 0000000..0acb5dc
--- /dev/null
+++ b/obj/tools/teller/hilfe/clear
@@ -0,0 +1,9 @@
+BEFEHL:
+ clear, clr
+
+ARGUMENTE:
+ STACK
+
+FUNKTION:
+ Loesche den ganzen Stack. Die Objekte auf dem Stack werden aber
+ nicht destructed.
diff --git a/obj/tools/teller/hilfe/clone b/obj/tools/teller/hilfe/clone
new file mode 100644
index 0000000..1c5620b
--- /dev/null
+++ b/obj/tools/teller/hilfe/clone
@@ -0,0 +1,7 @@
+BEFEHL:
+
+ARGUMENTE:
+
+FUNKTION:
+
+BEISPIELE:
diff --git a/obj/tools/teller/hilfe/destruct b/obj/tools/teller/hilfe/destruct
new file mode 100644
index 0000000..24ed234
--- /dev/null
+++ b/obj/tools/teller/hilfe/destruct
@@ -0,0 +1,14 @@
+BEFEHL:
+ destruct, dest, des
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Zerstoere das Objekt auf dem TOS. In wirklichkeit wird aber nur remove
+ aufgerufen, das das die empfohlene Art derZerstoerung von Objekten
+ ist. Will man jedoch ein Objekt wirklich hart destructen, so
+ haenge man ein Rufzeichen ('!') an das Kommando (also 'destruct!').
+
+SIEHE AUCH:
+ "remove"
diff --git a/obj/tools/teller/hilfe/dump b/obj/tools/teller/hilfe/dump
new file mode 100644
index 0000000..07be46b
--- /dev/null
+++ b/obj/tools/teller/hilfe/dump
@@ -0,0 +1,16 @@
+BEFEHL:
+ dump
+
+ARGUMENTE:
+ keins oder
+ TOS -- filename
+
+FUNKTION:
+ Speichere alle selbstdefinierten Funktionen in der angegebenen
+ Datei ab. Ist der TOS kein String, so wird in der Datei
+ ~/.memory.o gespeichert.
+
+ Es koennen nur Funktionen abgespeichert oder geladen werden!
+
+SIEHE AUCH:
+ "funktionen", "restore", "memory"
diff --git a/obj/tools/teller/hilfe/dup b/obj/tools/teller/hilfe/dup
new file mode 100644
index 0000000..3702b75
--- /dev/null
+++ b/obj/tools/teller/hilfe/dup
@@ -0,0 +1,9 @@
+BEFEHL:
+ dup
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Lege das Objekt, das oben auf dem Stack liegt, nocheinmal auf
+ den Stack, um es eventuell spaeter noch einmal wieder zu verwenden.
diff --git a/obj/tools/teller/hilfe/einleitung b/obj/tools/teller/hilfe/einleitung
new file mode 100644
index 0000000..0d19d03
--- /dev/null
+++ b/obj/tools/teller/hilfe/einleitung
@@ -0,0 +1,121 @@
+WICHTIG:
+ **********************
+ Das erste Zeichen muss ab jetzt ein Komma (,) sein. Bisher war
+ es ein Semikolon, aber das wechselwirkt ja mit dem emote.
+ **********************
+
+DER TELLERSTAPEL:
+
+ Der Tellerstapel ist ein stackorientiertes Magiertool.
+ Das heisst, man legt die Objekte, Strings oder was auch immer auf
+ den Stack und ruft als letztes die Funktion auf, die dann mit
+ dem Stackihnhalt irgendetwas macht. Das Ergebnis wird meistens
+ dann wieder auf dem Stack abgelegt.
+ Im grossen und ganzen dieses Tool von Macbeths Lupe inspiriert.
+
+ Im folgenden wird mit TOS (TopOfStack) das Ding bezeichnet, das
+ als letztes auf dem Stack abgelegt wurde.
+
+KOMMANDOS:
+
+ Jedes Kommando, das mit den Tellern ausgefuehrt werden soll,
+ wird mit ',' eingeleitet. Allerdings hat das Semikolon noch
+ eine weitere Funktion, aber dazu spaeter.
+
+DINGE AUF DEN STACK LEGEN:
+
+ Hinter dem Semikolon werden (beliebig viele) Stackoperationen
+ angegeben. Die meissten dieser Operationen legen irgendetwas auf
+ dem Stack ab. Will man Objekte auf dem Stack ablegen, so gibt
+ man einfach deren Filenamen an. Zahlen gibt man durch ein voran
+ gestelltes Doppelkreuz ('#') an. (Positive Zahlen gehen auch ohne.)
+ und Strings werden in Anfuehrungszeichen eingefasst, damit sie von
+ den Objekten unterschieden werden koennen. (Uebrigens ist das Zeichen
+ '\n' und das ESC-Zeichen ('\e') in Strings erlaubt.)
+
+STACKOPERATIONEN:
+
+ Stackoperationen, die den Stack nicht beeinflussen.
+
+ say - Meldungen an Mitspieler ein- und ausschalten.
+ Umstehende sehen normalerweise, wenn man mit den
+ Tellern arbeitet, eine Meldung der Art:
+ "Sowieso jongilert mit seinen Tellern." bzw
+ "Sowieso faellt beim Jonglieren ein Teller herunter."
+ names - Objekte mit oder ohne Namen bei Auflistungen
+ ausgeben.
+ stack - Gebe Stackinhalt aus (0 ist der TOS).
+ memory - Gebe Inhalt der Variablen aus.
+ top - Gebe den TOS aus.
+ inv - Gebe eine Liste der Objekte aus,
+ die sich im TOS-Objekt befinden.
+ scan - Gebe relevante Daten zu dem Spieler auf dem TOS aus.
+
+ Stackoperationen, die mit selbstdefinierten Funktionen zu tuen
+ haben:
+
+ ! - Definiere eine neue Funktion.
+ (Hilfe unter "funktionen".)
+ dump
+ restore - Speichern und Laden der benutzerdefinierten
+ Funktionen
+
+ Stackoperationen, die etwas auf dem Stack ablegen:
+
+ me - Lege dich selbst auf den Stack.
+ here - Lege den Raum, in dem Du bist, auf den Stack.
+
+ Stackoperationen zu dessen Verwaltung:
+
+ dup - Lege den TOS noch einmal auf den Stack.
+ pop - Loesche den TOS vom Stack.
+ swap - Verstauche den TOS mit dem Ding darunter.
+ clear - Loesche den ganzen Stack.
+
+ Die folgenden Funktionen poppen ihre Parameter vom Stack herunter.
+
+ Funktionen mit einem Parameter:
+
+ clone - Clone ein Objekt mit den angegebenen Filenamen.
+ Lege das geclonte Objekt auf den Stack.
+ update - Zerstoere die Blueprint des Objektes.
+ remove - Zerstoere das Objekt.
+
+ Funktionen mit mehreren Parametern:
+
+ move - Bewege das zweitoberste Element in das Oberste.
+ if - suche abhaengig vom obersten Element eines der
+ darunter liegenden aus.
+
+ Funktionen mit beliebig vielen Parametern:
+
+ Um zu wissen, wieviele der Stackelemente zu dem Funktions-
+ aufruf gehoeren, muss eine Information auf dem Stack
+ abgelegt werden. Dieses wird mit einem Lock (';') gemacht.
+ Unter dem Stichpunkt "lock" sind auch Beispiele.
+
+ array - Fuege alle Elemente zu einem Array zusammen.
+ split - Zerlege das Array auf dem Stack in Einzelteile.
+
+ -> - Rufe in dem untersten Objekt die hinter dem
+ Pfeil stehende Funktion auf. Uebergebe alle
+ dem Objekt folgenden Elemente als Parameter.
+ --> - Dito. Lege aber das Ergebnis wieder auf
+ auf dem Stack ab.
+ (Hilfe ist unter dem Begriff "call" zu finden.)
+
+ -* - Rufe die hinter dem -* stehende efun auf.
+ uebergib alle Stackelemente als Parameter.
+ --* - Dito mit Ergebnisrueckgabe.
+ (Hilfe unter dem Begriff "callefun".)
+
+ @ - Fuehre den LPC-Code hinter dem Klammeraffen aus.
+ @@ - Dito mit Returnwert.
+ (Hilfe unter "evaluate".)
+
+ Wie die Befehle im einzelnen funktionieren, kann man durch
+ ";hilfe <Befehl>" erfahren. Thema ist im Allgemeneinen der
+ Befehlsname. Bei Ausnahmen bitte oben nachlesen. ;-)
+
+ Viel Spass damit
+ Rumata, die Goettin der Morgenroete.
diff --git a/obj/tools/teller/hilfe/evaluate b/obj/tools/teller/hilfe/evaluate
new file mode 100644
index 0000000..91f6e0a
--- /dev/null
+++ b/obj/tools/teller/hilfe/evaluate
@@ -0,0 +1,22 @@
+BEFEHL:
+ evaluate, eval
+
+ARGUMENTE:
+ TOS - Name einer Funktion als String.
+
+FUNKTION:
+ Der Name wird von Stack genommen.
+ Der unter Namen gespeicherte Wert wird ausgewertet. Fuer normale
+ Werte bedeutet das, dass sie auf den Stack gelegt werden. Funktionen
+ werden ausgewertet.
+
+BEISPIEL:
+ ,!Q !1 pl !0 ->QueryProp
+ ,rumata title Q
+ liefert direkt den Titel.
+ ,rumata title "Q" eval
+ tut das selbe, nur das "Q" als String
+ zwischendurch auf dem Stack liegt.
+
+SIEHE AUCH:
+ "funktionen"
diff --git a/obj/tools/teller/hilfe/funktionen b/obj/tools/teller/hilfe/funktionen
new file mode 100644
index 0000000..dee7d75
--- /dev/null
+++ b/obj/tools/teller/hilfe/funktionen
@@ -0,0 +1,25 @@
+BEFEHL:
+ !funktionsname text
+
+ARGUMENTE:
+ text -- der *ganze* Rest der Zeile
+
+FUNKTION:
+ Erzeuge aus text eine neue Funktion mit dem angegebenen Namen. Dieser
+ Name ist als neuer Befehl innerhalb der Teller benutzbar wie die
+ eingebauten Befehle.
+ Wird ein Befehl ausgefuehrt, bekommt er auf einem neuen Stack seine
+ Parameter uebergeben. Was am Ende des Funktionsaufrufes auf dem
+ Stack legt, wird dann auf den urspruenglichen abgelegt.
+
+BEISPIEL:
+ ,!Query !1 pl !0 -->QueryProp
+ Definiere die Funktion "Query", sie hat zwei Parameter (!0 und !1),
+ wobei !0 der TOS ist.
+ ,rumata title Query
+ Liefert dann den Titel von Rumata auf dem Stack zurueck, da
+ am Ende der Auswertung dieser auf dem Stack liegen wuerde.
+ ,!Demo !1 stk
+ ,1 2 3 4 Demo
+ Zeigt einen Stack auf dem das zweitoberste Element von dem
+ ursprungsstack liegt; in diesem Fall also 3.
diff --git a/obj/tools/teller/hilfe/general b/obj/tools/teller/hilfe/general
new file mode 100644
index 0000000..826d743
--- /dev/null
+++ b/obj/tools/teller/hilfe/general
@@ -0,0 +1,17 @@
+Das sind die Befehle, die die magischen Teller zur Zeit beherrschen:
+(Letzte Aenderung am 20.01.1995 an den mit % markierten Funktionen,
+die mit * sind neu! AB JETZT GIBT ES AUCH FUNKTIONEN! )
+
+array destruct here memory% rekinv split
+call dump* if* message remove stack
+callefun dup inv move restore* swap
+callouts einleitung living names rupdate todo
+cleanof evaluate* lock object say top
+clear FUNKTIONEN* lpc player scan update
+clone general me pop snoop vars
+
+Mit ",hilfe <Befehl>" kannst Du Informationen zu den Befehlen abfragen.
+Wenn Du garnix verstehst, dann versuche mal ",hilfe einleitung". :-)
+
+WICHTIG: Das Semikolon wird nicht mehr unterstuetzt, stattdessen
+ kann nur noch das Komma benutzt werden.
diff --git a/obj/tools/teller/hilfe/here b/obj/tools/teller/hilfe/here
new file mode 100644
index 0000000..d0ebdf6
--- /dev/null
+++ b/obj/tools/teller/hilfe/here
@@ -0,0 +1,8 @@
+BEFEHL:
+ here
+
+ARGUMENTE:
+ Keins
+
+FUNKTION:
+ Lege den Raum, in man sich befindet oben auf den Stack.
diff --git a/obj/tools/teller/hilfe/if b/obj/tools/teller/hilfe/if
new file mode 100644
index 0000000..6994717
--- /dev/null
+++ b/obj/tools/teller/hilfe/if
@@ -0,0 +1,22 @@
+BEFEHL:
+ if
+
+ARGUMENTE:
+ wenn sonst bedingung(TOS)
+
+FUNKTION:
+ Wenn der TOS Null ist, liefere das drittoberste Element vom Stack,
+ sonst das zweitoberste. Dieser Befehl ist insbesondere im Zusammen-
+ hang mit "evaluate" interessant.
+
+BEISPIEL:
+ ,"bla" "blubb" 0 if
+ Liefert "blubb"
+ ,"bla" "bluibb" 1 if
+ Liefert "bla"
+ ,"Q" "R" test if evaluate
+ Werte Q aus, wenn der Wert "test" nicht null ist.
+ Anderenfalls werte R aus.
+
+SIEHE AUCH:
+ "evaluate", "funktionen"
diff --git a/obj/tools/teller/hilfe/inv b/obj/tools/teller/hilfe/inv
new file mode 100644
index 0000000..e943800
--- /dev/null
+++ b/obj/tools/teller/hilfe/inv
@@ -0,0 +1,17 @@
+BEFEHL:
+ inv
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Gebe alle Objekte an, die sich in dem Objekt TOS befinden.
+ Gib einen Fehler aus, wenn TOS kein Objekt ist.
+ TOS bleibt auf dem Stack, da dieser Befehl meistens dazu benutzt
+ wird, ein Objekt auf den Stack zu legen und dann bestimmte
+ Objekte in ihm zu suchen, und dann diese zu holen.
+
+BEISPIELE:
+ ,me inv
+ Dann sieht man .... ".2 /bla/bla/bla/objekt" und man kann dann
+ mittels ,.2 dieses Objekt holen.
diff --git a/obj/tools/teller/hilfe/living b/obj/tools/teller/hilfe/living
new file mode 100644
index 0000000..90606a7
--- /dev/null
+++ b/obj/tools/teller/hilfe/living
@@ -0,0 +1,17 @@
+BEFEHL:
+ living, lv
+
+ARGUMENTE:
+ TOS -- Name eines Monsters
+
+FUNKTION:
+ Hole einen Namen vom Stack und lege stattdessen das entsprechende
+ Monsterobjekt auf den Stack. Gebe eine Fehlermeldung aus, wenn kein
+ derartiges Monster vorhanden ist.
+
+BEISPIELE:
+ ,"ork" living
+ Sucht den erstbesten Ork.
+
+SIEHE AUCH:
+ "object", "player"
diff --git a/obj/tools/teller/hilfe/lock b/obj/tools/teller/hilfe/lock
new file mode 100644
index 0000000..f470db3
--- /dev/null
+++ b/obj/tools/teller/hilfe/lock
@@ -0,0 +1,26 @@
+BEFEHL:
+ ,
+
+ARGUMENTE:
+ Keine
+
+FUNKTION:
+ Lege einen 'Lock' auf dem Stack ab. Anhand eines Locks erkennen
+ Funktionen, die eine varibale Anzahl von Argumenten vom Stack
+ nehmen koennen, wieviele der Argumente fuer sie bestimmt sind.
+
+ Wichtig: Das Komma am Anfag jeder Eingabezeile ist KEIN Lock.
+
+BEISPIELE:
+ ,me, 1 2 3 array
+ Es werden nur die Zahlen 1 2 und 3 in das Array aufgenommen,
+ nicht der Spieler selbst. Auf dem Stack liegen nacher der
+ Spieler und das Array.
+ ,here, me "rumata" ->id
+ "id" wird im Spieler mit einem Argument ("rumata") aufgerufen.
+ ,here me "rumata" ->id
+ Hier wird die Funktion im Raum mit zwei Argumenten aufgerufen,
+ was hier natuerlich keinen Sinn macht.
+
+SIEHE AUCH:
+ "array", "split", "call", "callefun", "evaluate"
diff --git a/obj/tools/teller/hilfe/lpc b/obj/tools/teller/hilfe/lpc
new file mode 100644
index 0000000..bfa0e01
--- /dev/null
+++ b/obj/tools/teller/hilfe/lpc
@@ -0,0 +1,21 @@
+BEFEHL:
+ @ text
+ @@ text
+
+ARGUMENTE:
+ text -- der ganze(!) Rest der Eingabezeile.
+ Der Stack bis zum letzten Lock.
+
+FUNKTION:
+ Fuehre den LPC-Code <text> direkt aus. Dabei koennen die Argumente
+ vom Stack mit @<nummer>@ eingesetzt werden. Wichtig, wenn man ein
+ Ergebnis weiterberechnen will, muss man auch ein 'return' um
+ LPC-Code benutzt haben.
+
+ Bei der Ausfuehrung werden nicht alle Include-Dateien eingeladen.
+
+BEISPIEL:
+ ,me @ write( @0@->name(WER)+"\n" )
+ Gibt Deinen Namen aus.
+ ,me @@ return @0@->name(WER)
+ Gibt den Namen zurueck und legt ihn auf den Stack.
diff --git a/obj/tools/teller/hilfe/me b/obj/tools/teller/hilfe/me
new file mode 100644
index 0000000..8861f45
--- /dev/null
+++ b/obj/tools/teller/hilfe/me
@@ -0,0 +1,8 @@
+BEFEHL:
+ me
+
+ARGUMENTE:
+ Keine
+
+FUNKTION:
+ Lege den Eigentuemer (Dich!) oben auf den Stack.
diff --git a/obj/tools/teller/hilfe/memory b/obj/tools/teller/hilfe/memory
new file mode 100644
index 0000000..d012451
--- /dev/null
+++ b/obj/tools/teller/hilfe/memory
@@ -0,0 +1,15 @@
+BEFEHL:
+ memory, mem
+
+ARGUMENTE:
+ Keine
+
+FUNKTION:
+ Zeige den Inhalt aller Variablen an, die man angelegt hat.
+ Normalerweise wird der Inhalt in der Form Name = Inhalt angezeigt.
+ Ist unter dem Namen eine Funktion gespeichert, wird
+ Name > Inhalt
+ angezeigt, um Funktionen von Strings unterscheiden zu koennen.
+
+SIEHE AUCH:
+ "vars", "funktionen"
diff --git a/obj/tools/teller/hilfe/message b/obj/tools/teller/hilfe/message
new file mode 100644
index 0000000..656d94a
--- /dev/null
+++ b/obj/tools/teller/hilfe/message
@@ -0,0 +1,13 @@
+KOMMANDO:
+ message [to <spieler>]
+ msg [to <spieler>]
+
+FUNKTION:
+ Wenn man ganze Textbloecke sagen moechte, kann man das mit diesem
+ Befehl tun. Nach Eingabe von 'message' wird jede Eingabe direkt fuer
+ alle im Raum sichtbar oder fuer den angegebenen Spieler ausgegeben.
+ Mit '**' kann man wieder auf normale Eingabe zurueckschalten.
+
+ACHTUNG:
+ Dieser Befehl gehoert nicht zu denen, die mittels ',' eingeleitet
+ werden.
diff --git a/obj/tools/teller/hilfe/move b/obj/tools/teller/hilfe/move
new file mode 100644
index 0000000..b181c34
--- /dev/null
+++ b/obj/tools/teller/hilfe/move
@@ -0,0 +1,14 @@
+BEFEHL:
+ move, mv
+
+ARGUMENTE:
+ obj -- Objekt, das bewegt werden soll.
+ ziel(TOS) -- Raum, in den das Objekt soll
+
+FUNKTION:
+ Bewege das Objekt in den angegebenen Raum. Die meisten Sicherungen
+ werden bei diesem Verschiueben umgangen, also vorsicht!
+
+BEISPIELE:
+ ,me "~/workroom" ob mv
+ Man geht in den eigenen Workroom.
diff --git a/obj/tools/teller/hilfe/names b/obj/tools/teller/hilfe/names
new file mode 100644
index 0000000..4eebc3b
--- /dev/null
+++ b/obj/tools/teller/hilfe/names
@@ -0,0 +1,17 @@
+BEFEHL:
+ names, nam
+
+ARGUMENTE:
+ keine
+
+FUNKTION:
+ Normalerweise werden der Filename und der Name (QueryProp(P_NAME))
+ angezeigt, wenn man den Stack oder aehnliches betrachtet.
+ Mit diesem Befehl schaltet man den Namen aus oder an.
+
+ Durch Anschauen der Teller kann man feststellen, ob die Namen oder
+ nur die Filenamen angezeigt werden.
+
+SIEHE AUCH:
+ "inv", "stack", "move", "top", ...
+ Andere Schalter: "say", "inform"
diff --git a/obj/tools/teller/hilfe/object b/obj/tools/teller/hilfe/object
new file mode 100644
index 0000000..145b30a
--- /dev/null
+++ b/obj/tools/teller/hilfe/object
@@ -0,0 +1,22 @@
+BEFEHL:
+ object, ob
+
+ARGUMENTE:
+ TOS -- Name eines Objektes
+
+FUNKTION:
+ Hole einen Namen vom Stack und lege stattdessen das entsprechende
+ Objekt auf den Stack. Falls es kein geladenes Objekt dieses Namens,
+ wohl aber eine (nicht geladene) Blueprint, so wird diese geladen
+
+BEISPIELE:
+ ,"players/rumata/workroom" ob
+ Macht das selbe wie ',/players/rumata/workroom', da die Teller
+ Filenamen automatisch zu erkennen versuchen.
+ ,"~rumata/workroom" ob
+ geht auch.
+ ,"~/workroom" ob
+ liefert den eigenen Workroom.
+
+SIEHE AUCH:
+ "living", "player"
diff --git a/obj/tools/teller/hilfe/player b/obj/tools/teller/hilfe/player
new file mode 100644
index 0000000..e2caa16
--- /dev/null
+++ b/obj/tools/teller/hilfe/player
@@ -0,0 +1,21 @@
+BEFEHL:
+ player, pl
+
+ARGUMENTE:
+ TOS -- Name eines Spielers
+
+FUNKTION:
+ Hole einen Namen vom Stack und lege stattdessen das entsprechende
+ Spielerobjekt auf den Stack.
+
+ Am Ende des Spielernamens ist ein Stern ('*') als Wildcard erlaubt.
+ Die Namen nicht eingeloggter Spieler muessen in jedem Fall ausge-
+ schrieben werden.
+
+
+BEISPIELE:
+ ,"rumata" pl
+ Legt Rumata auf den Stack.
+
+SIEHE AUCH:
+ "living", "object"
diff --git a/obj/tools/teller/hilfe/pop b/obj/tools/teller/hilfe/pop
new file mode 100644
index 0000000..c30dc08
--- /dev/null
+++ b/obj/tools/teller/hilfe/pop
@@ -0,0 +1,8 @@
+BEFEHL:
+ pop
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Nimm das oberste Element vom Stack.
diff --git a/obj/tools/teller/hilfe/rekinv b/obj/tools/teller/hilfe/rekinv
new file mode 100644
index 0000000..cb51bd2
--- /dev/null
+++ b/obj/tools/teller/hilfe/rekinv
@@ -0,0 +1,12 @@
+BEFEHL:
+ rekinv
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Dieser Befehl mach das selbe wie "inv", zeigt aber rekursiv
+ auch den Inhalt der enthaltenen Objekte an.
+
+SIEHE AUCH:
+ "inv"
diff --git a/obj/tools/teller/hilfe/remove b/obj/tools/teller/hilfe/remove
new file mode 100644
index 0000000..dff2437
--- /dev/null
+++ b/obj/tools/teller/hilfe/remove
@@ -0,0 +1,16 @@
+BEFEHL:
+ remove, rem
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Zerstoere das Objekt auf dem TOS. Gib dem Objekt die Gelegenheit,
+ Aufraeumarbeiten durchzufuehren.
+
+BEISPIELE:
+ ,me remove
+ Man loggt sich selber aus.
+
+SIEHE AUCH:
+ "destruct"
diff --git a/obj/tools/teller/hilfe/restore b/obj/tools/teller/hilfe/restore
new file mode 100644
index 0000000..ad20a35
--- /dev/null
+++ b/obj/tools/teller/hilfe/restore
@@ -0,0 +1,15 @@
+BEFEHL:
+ restore
+
+ARGUMENTE:
+ keins oder
+ TOS -- filename
+
+FUNKTION:
+ Lade die in der Datei gespeicherten Funktionen. Wird kein Filename
+ angegeben, so wird die Datei ~/.memory.o ausgelesen.
+
+ Es koennen nur Funktionen abgespeichert oder geladen werden!
+
+SIEHE AUCH:
+ "funktionen", "dump", "memory"
diff --git a/obj/tools/teller/hilfe/rupdate b/obj/tools/teller/hilfe/rupdate
new file mode 100644
index 0000000..85f033e
--- /dev/null
+++ b/obj/tools/teller/hilfe/rupdate
@@ -0,0 +1,25 @@
+BEFEHL:
+ roomupdate, rupdate, rupd, rup
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Zerstoere den Raum und lade ihn neu, damit Aenderungen der Files
+ aktiv werden koennen. Sorge dafuer, dass die Objekte in dem alten Raum
+ in den neuen hinuebergerettet werden. (Diese Eigenschaft kann mittels
+ des Sternchens ('*') abgeschaltet werden.)
+
+ Gebe dem Raum jedoch Gelegenheit, Aufraeumarbeiten zu taetigen. Soll
+ der Raum wirklich hart zerstoert werden, so ist ein Rufzeichen an den
+ Befehl anzuhaengen. (also `rupdate!', ein Stern muss vor dem Rufzeichen
+ stehen, also `rupdate*!' und nicht `rupdate!*'.)
+ Wichtig: Raeume, die keine Blueprint sind, koennen nicht mit diesem
+ Befehl aktualisiert werden.
+
+BEISPIELE:
+ ,here rupdate
+ Aktualisiert den Raum, in dem der Magier sich befindet.
+
+SIEHE AUCH:
+ "update"
diff --git a/obj/tools/teller/hilfe/say b/obj/tools/teller/hilfe/say
new file mode 100644
index 0000000..cf23357
--- /dev/null
+++ b/obj/tools/teller/hilfe/say
@@ -0,0 +1,17 @@
+BEFEHL:
+ say
+
+ARGUMENTE:
+ keine
+
+FUNKTION:
+ Schalte die Meldung, die andere Spieler bekommen, wenn man
+ mit den Tellern arbeitet, aus oder an.
+
+ Ist man unsichtbar, gibt es in keinem Fall eine Meldung.
+
+ Durch Anschauen der Teller kann man feststellen, ob Mispieler
+ die Meldungen bekommen.
+
+SIEHE AUCH:
+ "names", "inform"
diff --git a/obj/tools/teller/hilfe/scan b/obj/tools/teller/hilfe/scan
new file mode 100644
index 0000000..7c251fd
--- /dev/null
+++ b/obj/tools/teller/hilfe/scan
@@ -0,0 +1,17 @@
+BEFEHL:
+ scan
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Wenn der TOS ein Spieler oder ein Monster ist, so gib die
+ spielrelevanten Informationen zu ihm aus. Wenn der TOS ein
+ String ist, so wird der Spieler mit diesem Namen gesucht.
+
+BEISPIELE:
+ ,me scan
+ ,"jof" pl scan (oder kuerzer: ;"jof" scan)
+
+SIEHE AUCH:
+ "player"
diff --git a/obj/tools/teller/hilfe/snoop b/obj/tools/teller/hilfe/snoop
new file mode 100644
index 0000000..1be1300
--- /dev/null
+++ b/obj/tools/teller/hilfe/snoop
@@ -0,0 +1,11 @@
+BEFEHLE:
+ snoop
+
+ARGUMENTE:
+ keine
+
+FUNKTION:
+ Zeige laufende Snoopvorgaenge an.
+
+ Wenn der Snooper einen hoeheren Magierlevel als man selbst hat,
+ wird der Snoop nicht angezeigt.
diff --git a/obj/tools/teller/hilfe/split b/obj/tools/teller/hilfe/split
new file mode 100644
index 0000000..319025a
--- /dev/null
+++ b/obj/tools/teller/hilfe/split
@@ -0,0 +1,14 @@
+BEFEHL:
+ split, spl
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Zerlege den Array, der auf dem Stack liegt und lege die
+ einzelnen Elemente (das Element mit Index 0 zuunterst)
+ auf dem Stack ab. Wenn der Stack vorher nicht leer war,
+ lege vorher ein Lock auf den Stack.
+
+SIEHE AUCH:
+ "array", "lock"
diff --git a/obj/tools/teller/hilfe/stack b/obj/tools/teller/hilfe/stack
new file mode 100644
index 0000000..c8f182e
--- /dev/null
+++ b/obj/tools/teller/hilfe/stack
@@ -0,0 +1,18 @@
+BEFEHL:
+ stack, stk
+
+ARGUMENTE:
+ STACK
+
+FUNKTION:
+ Zeige alle Dinge an, die auf dem Stack liegen.
+
+BEISPIEL:
+ ,me here; 1 2 array stk
+ Ergibt (zum Beispiel):
+ 0: ({
+ 1
+ 2
+ })
+ 1: /room/gilde (ein Raum)
+ 2: /std/shells/magier#7691 (Atamur)
diff --git a/obj/tools/teller/hilfe/swap b/obj/tools/teller/hilfe/swap
new file mode 100644
index 0000000..befafe3
--- /dev/null
+++ b/obj/tools/teller/hilfe/swap
@@ -0,0 +1,8 @@
+BEFEHL:
+ swap
+
+ARGUMENTE:
+ Die obersten 2 Stackelemente.
+
+FUNKTION:
+ Vertausche die beiden obersten Elemente vom Stack.
diff --git a/obj/tools/teller/hilfe/todo b/obj/tools/teller/hilfe/todo
new file mode 100644
index 0000000..662cefb
--- /dev/null
+++ b/obj/tools/teller/hilfe/todo
@@ -0,0 +1,14 @@
+Was noch kommen soll:
+
+ Doku verbessern, da eine Stackmachine nicht jedermanns Sache ist.
+ (schon ",hilfe einleitung" gemacht?)
+
+ Alles, was nicht player ist, aus dem Raum herausraeumen.
+ <cleanup> ?
+
+Was NICHT kommen soll:
+
+ Alarm, wenn man angeschaut wird. (Wozu auch? :-)
+
+Weitere Ideen werden von Rumata gerne entgegengenommen.
+Aber bitte nicht dauernd anlabern, sondern als mail :-)
diff --git a/obj/tools/teller/hilfe/top b/obj/tools/teller/hilfe/top
new file mode 100644
index 0000000..2b07fa9
--- /dev/null
+++ b/obj/tools/teller/hilfe/top
@@ -0,0 +1,23 @@
+BEFEHL:
+ top
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Zeigt das Objekt an, das auf dem Stack zuoberst liegt (=TOS).
+
+BEISPIELE:
+ ;me top
+ Zeige das Objekt, das man selbst ist, an.
+
+ ;here top
+ Zeige den Raum, in dem man sich befindet.
+
+ ;; 1 2 3 array top (Das zweite ';' ist wichtig)
+ Ergibt:
+ TOS= ({
+ 1
+ 2
+ 3
+ })
diff --git a/obj/tools/teller/hilfe/update b/obj/tools/teller/hilfe/update
new file mode 100644
index 0000000..bd35aad
--- /dev/null
+++ b/obj/tools/teller/hilfe/update
@@ -0,0 +1,22 @@
+BEFEHL:
+ update, upd
+
+ARGUMENTE:
+ TOS
+
+FUNKTION:
+ Zerstoere die Blueprint des Objektes, das auf dem Stack liegt, damit
+ Aenderungen der Files aktiv werden koennen. Gebe der Blueprint
+ jedoch Gelegenheit, Aufraeumarbeiten zu taetigen. Soll die Blueprint
+ wirklich hart zerstoert werden, so ist ein Rufzeichen an den Befehl
+ anzuhaengen. (also `update!')
+ Wichtig: Das geclonte Objekt, ueber das die Blueprint zerstoert wird,
+ bleibt erhalten, ebenso wie alle anderen geclonten Objekte.
+
+BEISPIELE:
+ ,me .teddy update
+ Zerstoert die Blueprint vom Teddy, den man hat. (Das ist natuerlich nur
+ fuer Magier sinnvoll, die das File editieren konnten.)
+
+SIEHE AUCH:
+ "roomupdate"
diff --git a/obj/tools/teller/hilfe/vars b/obj/tools/teller/hilfe/vars
new file mode 100644
index 0000000..1c6deab
--- /dev/null
+++ b/obj/tools/teller/hilfe/vars
@@ -0,0 +1,23 @@
+BEFEHLE:
+ <varname, >varname
+
+ARGUMENTE:
+ TOS
+ varname -- String
+
+FUNKTION:
+ >varname
+ Speichere das oberste Element des Stacks in der Variable
+ "varname" ab.
+ <varname
+ Kopiere den Inhalt der Variable "varname" auf den Stack.
+ Wenn der Inhalt der Variable eine Funktion ist, wo wird
+ diese in Stringform auf den Stack gelegt und nicht aus-
+ gewertet.
+
+ Es koennen ausser Objekten auch Arrays, Strings und Integers
+ in Variablen gespeichert werden. Wird eine 0 in einer Variable
+ gespeichert, so wird die Variable wieder geloescht.
+
+SIEHE AUCH:
+ "memory"
diff --git a/obj/tools/teller/t_base.c b/obj/tools/teller/t_base.c
new file mode 100644
index 0000000..8336d3b
--- /dev/null
+++ b/obj/tools/teller/t_base.c
@@ -0,0 +1,361 @@
+// ----------------------------------------------------------------------
+// Die Basis- und Hilfsfunktionen der Teller.
+// Stack und Memory
+// ----------------------------------------------------------------------
+#include "teller.h"
+
+#include <moving.h>
+#include <terminal.h>
+
+static mixed *stack;
+static mapping memory;
+static object *oldinv;
+static bool mit_namen;
+static bool fehler_passiert;
+static bool mit_say;
+static bool secureinv;
+static bool dologaccess;
+static bool pretty;
+static bool do_profile;
+
+static mixed top();
+static mixed pop();
+static void push( mixed ob );
+
+static void dump_obj( mixed ob, int indent );
+
+void create()
+{
+ stack = ({});
+ memory = ([]);
+ mit_namen = TRUE;
+ fehler_passiert = FALSE;
+ mit_say = TRUE;
+ secureinv = FALSE;
+ dologaccess = FALSE;
+ pretty = TRUE;
+}
+
+// ----------------------------------------------------------------------
+// Hilfsfunktionen
+// ----------------------------------------------------------------------
+
+static int error( string msg )
+{
+ write( "Fehler in "+msg+".\n" );
+ fehler_passiert = TRUE;
+ return FALSE;
+}
+
+static int memo( string msg )
+{
+ write( "MEMO: "+msg+".\n" );
+ return FALSE;
+}
+
+static int calcinv( string str )
+{
+ object* obs;
+ object ob;
+ int val;
+
+ if( sscanf( str, "%d", val ) == 1 )
+ {
+ obs = all_inventory(top());
+ if( val<0 || val>=sizeof(obs) )
+ return error( "'.': Kein Objekt mit dieser Nummer" );
+ pop();
+ push(obs[val]);
+ return TRUE;
+ }
+
+ if( !(ob=present(str,top())) )
+ return error( "'.': Kein Objekt namens \""+str+"\" gefunden" );
+ pop();
+ push(ob);
+ return TRUE;
+}
+
+static mixed push_str( string str )
+{
+ return
+ push( implode(old_explode( implode(old_explode( implode(old_explode(
+ " "+str+" ",
+ "\\n"),"\n"), "\\e"),ESC), "\\b"),"\b")
+ [1..<2] );
+}
+
+static void do_move( object ob, mixed dest )
+{
+ int weight;
+
+ weight = ob->QueryWeight();
+ if( environment(ob) )
+ environment(ob)->AddWeight(-weight);
+ ob->move(dest,M_NOCHECK);
+ dest->AddWeight(weight);
+}
+
+void heart_beat()
+{
+ object *newinv;
+ object owner;
+ int i,j;
+
+ if( owner=find_player(getuid()) )
+ {
+ newinv = sort_array( all_inventory(owner), lambda( ({'a,'b}),
+ ({ #'<,
+ ({ #'object_name, 'a }),
+ ({ #'object_name, 'b })
+ })
+ ) );
+ if( pointerp(oldinv) )
+ {
+ for( i=0,j=0; i<sizeof(newinv) && j<sizeof(oldinv) ; )
+ {
+ if( newinv[i] == oldinv[j] )
+ { i++; j++; }
+ else if( object_name(newinv[i]) > object_name(oldinv[j]) )
+ {
+ tell_object(owner,
+ "MEMO: \""+object_name(newinv[i])+"\" entered inventory.\n" );
+ i++;
+ }
+ else
+ j++;
+ }
+ for( ; i<sizeof(newinv) ; i++ )
+ tell_object( owner,
+ "MEMO: \""+object_name(newinv[i])+"\" entered inventory.\n" );
+ }
+ }
+ oldinv = newinv;
+}
+
+// ----------------------------------------------------------------------
+// Dumpfunktionen
+// ----------------------------------------------------------------------
+
+static void dump_array( mixed* ob, int indent )
+{
+ int i;
+ for( i=0; i<sizeof(ob); i++ )
+ {
+ printf( "%*s", indent, "" );
+ dump_obj( ob[i], indent );
+ }
+}
+
+static void dump_mapping( mapping ob, int indent )
+{
+ mixed *index;
+ mixed key;
+ int i,j,values;
+
+ index = m_indices( ob );
+ values = get_type_info(ob)[1];
+ for( i=0; i<sizeof(index); i++ )
+ {
+ key = index[i];
+ printf( "%*s", indent, "" );
+ dump_obj( key, indent );
+ for( j=0; j<values; j++ )
+ {
+ printf( "%*s: ", indent+1, "" );
+ dump_obj( ob[key,j], indent+3 );
+ }
+ }
+}
+
+static void dump_obj( mixed ob, int indent )
+{
+ if( !pretty )
+ {
+ printf( "%O\n", ob );
+ return;
+ }
+ if( intp(ob) )
+ write( ob + "\n" );
+ else if( floatp(ob) )
+ printf( "%1.5f\n", ob );
+ else if( stringp(ob) )
+ {
+ if ( ob==";" )
+ write( ";\n" );
+ else
+ {
+ write( "\"" + implode(old_explode( implode(old_explode( implode(old_explode(
+ " "+ob+" ",
+ "\n"),"\\n"), ESC), "\\e"), "\b"),"\\b")
+ [1..<2] + "\"\n"
+ );
+ }
+ }
+ else if( objectp(ob) )
+ {
+ if( mit_namen )
+ write( object_name(ob)+" ("+ob->name(WER,0)+")\n" );
+ else
+ write( object_name(ob)+"\n" );
+ }
+ else if( mappingp(ob) )
+ {
+ write( "([\n" );
+ dump_mapping( ob, indent + 2 );
+ printf( "%*s\n", indent + 2, "])" );
+ }
+ else if( pointerp(ob) )
+ {
+ write( "({\n" );
+ dump_array( ob, indent+2 );
+ printf( "%*s\n", indent+2 , "})" );
+ }
+ else
+ printf( "%O\n", ob );
+}
+
+// ----------------------------------------------------------------------
+// Speicherfunktionen
+// ----------------------------------------------------------------------
+
+static void do_recall( mixed arg )
+{
+ if( member(memory,arg) )
+ push( memory[arg,0] );
+}
+
+static void do_store( mixed arg )
+{
+ if ( sizeof(stack) )
+ {
+ if( !top() )
+ memory = m_delete(memory,arg);
+ else
+ memory += ([ arg: top(); 0 ]);
+ }
+ else
+ memo( "Es wurde kein Wert in \""+arg+"\" gespeichert" );
+}
+
+// ----------------------------------------------------------------------
+// Stack-Funktionen
+// ----------------------------------------------------------------------
+
+static void push( mixed ob )
+{
+ stack = ({ ob }) + stack;
+}
+
+static mixed pop()
+{
+ mixed answer;
+
+ if( !sizeof( stack ) )
+ return FALSE;
+ answer = stack[0];
+ stack = stack[1..];
+ return answer;
+}
+
+static mixed top()
+{
+ if( sizeof(stack) )
+ return stack[0];
+}
+
+static varargs int becomes_obj( mixed argv)
+{
+ object ob;
+
+ if( !pointerp(argv) ) // default ist der stack !
+ argv = stack;
+ if( !sizeof(argv) )
+ return FALSE;
+ if( stringp(argv[0]) && !catch(call_other(argv[0],"?")) )
+ {
+ argv[0] = find_object(argv[0]);
+ return TRUE;
+ }
+ else
+ return objectp(argv[0]);
+}
+
+static isSubStr( pl, str, len )
+{
+ return getuid(pl)[0..len] == str;
+}
+
+static becomes_pl(argv)
+{
+ object pl;
+ object* pllist;
+ string str;
+ int len;
+
+ if( !argv ) argv = stack;
+ if( !sizeof(argv) || ( becomes_obj() && !interactive(argv[0]) ) )
+ return FALSE;
+ if( stringp(argv[0]) )
+ {
+ str = lower_case( argv[0] );
+ pl = 0;
+ if( str[<1..<1] == "*" )
+ {
+ str = str[0..<2];
+ len = sizeof(str) - 1;
+ pllist = filter( users(), #'isSubStr, str, len );
+ if( sizeof(pllist) == 1 )
+ {
+ pl=pllist[0];
+ argv[0] = pl;
+ }
+ }
+ if( !pl && pl=find_player(argv[0]) )
+ argv[0] = pl;
+ return pl;
+ }
+ return argv[0];
+}
+
+static DumpObj( ob )
+{
+ string ans;
+ int i,j;
+
+ if( intp(ob) )
+ return ""+ob;
+ else if( stringp(ob) )
+ return "\""+implode(explode(ob,"\n"),"\\n")+"\"";
+ else if( objectp(ob) )
+ return "\""+object_name(ob)+"\"";
+ else if( mappingp(ob) )
+ {
+ ans="([";
+ for( i=0; i<sizeof(ob)-1; i++ )
+ ans += DumpMapp(ob,i)+",";
+ // rely on right value of i
+ return ans+DumpMapp(ob,i)+"])";
+ }
+ else
+ {
+ ans="({";
+ for( i=0; i<sizeof(ob)-1; i++ )
+ ans += DumpObj(ob[i])+",";
+ // rely on right value of i
+ return ans+DumpObj(ob[i])+"})";
+ }
+}
+
+static DumpMapp(ob,i)
+{
+ int j,vz;
+ string ans;
+
+ vz = get_type_info(ob)[1];
+ ans = DumpObj(m_indices(ob)[i])+":";
+ for( j=0; j<vz-1; j++ )
+ ans += DumpObj(ob[m_indices(ob)[i],j])+";";
+ // rely on value of j
+ return ans + DumpObj(ob[m_indices(ob)[i],j]);
+}
diff --git a/obj/tools/teller/t_cmds.c b/obj/tools/teller/t_cmds.c
new file mode 100644
index 0000000..68fa5d3
--- /dev/null
+++ b/obj/tools/teller/t_cmds.c
@@ -0,0 +1,1000 @@
+// ----------------------------------------------------------------------
+// Builtinkommandos der Teller.
+// ----------------------------------------------------------------------
+#include "teller.h"
+inherit T_BASE;
+
+#include <moving.h>
+#include <attributes.h>
+#include <terminal.h>
+#include <wizlevels.h>
+
+static void do_rinv( object env, int depth );
+static scan_obj( object player, object obj );
+static void mk_waitfor( mixed waitfor );
+static void mk_autoload( mixed autoload );
+static int do_roomupdate( int destflag, int noitems );
+static int do_cleanof( int strong );
+
+// from teller.c
+static int do_cmd( string str );
+
+static int cmd_clear()
+{
+ stack = ({});
+ return TRUE;
+}
+
+static int cmd_pop()
+{
+ if( !sizeof(stack) )
+ return error( "pop: Der Stack ist leer" );
+ pop();
+ return TRUE;
+}
+
+static int cmd_top()
+{
+ if( !sizeof(stack) )
+ return error( "top: Der Stack ist leer" );
+ write( "TOS= " );
+ dump_obj( top(), 5 );
+ return TRUE;
+}
+
+static int cmd_swap()
+{
+ mixed tmp;
+
+ if( sizeof(stack)<2 )
+ return error( "swap: Keine 2 Elemente auf dem Stack" );
+ tmp = stack[0];
+ stack[0] = stack[1];
+ stack[1] = tmp;
+ return TRUE;
+}
+
+static int cmd_dup()
+{
+ if( !sizeof(stack) )
+ return error( "dup: Der Stack ist leer" );
+ push(top());
+ return TRUE;
+}
+
+static int cmd_here()
+{
+ push(environment(PL));
+ return TRUE;
+}
+
+static int cmd_stack()
+{
+ int i;
+ if( !sizeof(stack) )
+ return memo( "Der Stack ist leer" );
+
+ for( i=0; i<sizeof(stack); i++ )
+ {
+ printf( "%2d: ", i );
+ dump_obj( stack[i], 4 );
+ }
+ return TRUE;
+}
+
+static int cmd_inv()
+{
+ int i;
+ object ob;
+
+ if( !becomes_obj() )
+ return error( "inv: TOS ist kein Objekt" );
+ write( "Inventar von " );
+ dump_obj( top(), 13 );
+ for( i=0, ob=first_inventory(top()); ob; ob=next_inventory(ob), i++ )
+ {
+ printf( "%2d. ", i );
+ dump_obj( ob, 4 );
+ }
+ return TRUE;
+}
+
+static int cmd_rekinv()
+{
+ if( !becomes_obj() )
+ return error( "rekinv: TOS ist kein Objekt" );
+ write( "Inventar von " );
+ dump_obj( top(), 13 );
+
+ do_rinv( top(), 2 );
+ return TRUE;
+}
+
+static void do_rinv( object env, int depth )
+{
+ int i;
+ object ob;
+
+ for( i=0, ob=first_inventory(env); ob; ob=next_inventory(ob), i++ )
+ {
+ printf( "%*d. ", depth, i );
+ dump_obj( ob, 2+depth );
+ do_rinv( ob, depth+2 );
+ }
+}
+
+static int cmd_me()
+{
+ push( PL );
+ return TRUE;
+}
+
+// Uebernommen aus dem Teddy (mit freundlicher Genehmigung von Sir).
+static int cmd_scan()
+{
+ object obj;
+
+ if( !becomes_pl() && ( !objectp(top()) || !living(top()) ) )
+ {
+ if( stringp(top()) && file_size( "/save/"+top()[0..0]+"/"+top()+".o") > 0 )
+ {
+ obj = clone_object( T_PLAYER );
+ obj->Load( top() );
+ obj->SetProp( P_NAME, capitalize( pop() ) );
+ scan_obj( TRUE, obj );
+ destruct( obj );
+ return TRUE;
+ }
+ return error( "scan: TOS ist kein Lebewesen" );
+ }
+
+ scan_obj( query_once_interactive( top() ), pop() );
+ return TRUE;
+}
+
+static int WizLevel( object obj )
+{
+ if( obj->Notlogged() )
+ return query_wiz_level( lower_case(obj->playername()) );
+ else
+ return query_wiz_level( obj );
+}
+
+static string IpName( object obj )
+{
+ string ip_name, ip_num, nm;
+
+ if( obj->Notlogged() )
+ {
+ // Aus Umstellungsgruenden werden CALLED_FROM_IP und IP_NAME
+ // abgefragt. IP_NAME ist neuer.
+
+ nm = lower_case(obj->playername());
+ ip_name = obj->QueryProp(P_CALLED_FROM_IP);
+ if( !ip_name ) ip_name = obj->Query(P_IP_NAME);
+ return ip_name + " ("
+ + dtime(get_dir("/save/"+nm[0..0]+"/"+nm+".o",4)[0]) +")";
+ }
+ else
+ {
+ nm = lower_case( obj->name(RAW) );
+ ip_name = query_ip_name( obj );
+ if( ip_name == "" || !ip_name )
+ {
+ ip_name = obj->QueryProp(P_CALLED_FROM_IP);
+ if( !ip_name ) ip_name = obj->Query(P_IP_NAME);
+ return ip_name + " ("
+ + dtime(get_dir("/save/"+nm[0..0]+"/"+nm+".o",4)[0]) +")";
+ }
+ return ip_name + " [" + query_ip_number(obj) + "]";
+ }
+}
+
+string IdleTime( object obj )
+{
+ if( obj->Notlogged() ) return "-nicht da-";
+ if( query_ip_number(obj) ) return ""+query_idle(obj);
+ return "-netztot-";
+}
+
+static scan_obj( object player, object obj )
+{
+ string title, level, gender, room, testpl,
+ weapon, armour, quest, stat_str, *arr;
+ int i,ac;
+ object weaponobj, *list, *gegner;
+ mixed *hands, *quests, *stats;
+
+ // 1.Zeile : Name Titel - Rasse - [ Wizlevel ]
+ title = obj->QueryProp(P_TITLE);
+
+ if( !player )
+ level = "Monster" ;
+ else if( WizLevel( obj ) < WIZARD_LVL )
+ {
+ if( testpl=obj->QueryProp( P_TESTPLAYER ) )
+ {
+ if( stringp(testpl) )
+ level = "("+testpl+")";
+ else
+ level = "Testspieler";
+ }
+ else if( WizLevel( obj ) >= SEER_LVL )
+ level = "Seher";
+ else
+ level = "Spieler" ;
+ }
+ else if( WizLevel( obj ) >= GOD_LVL )
+ level = "MudGott" ;
+ else if( WizLevel( obj ) >= ARCH_LVL )
+ level = "Erzmagier" ;
+ else if( WizLevel( obj ) >= LORD_LVL )
+ level = "Regionsmagier" ;
+ else
+ level = "Magier" ;
+
+ if( !obj->short() )
+ level += ", unsichtbar" ;
+ if( obj -> QueryProp( P_FROG ) )
+ level += ", Frosch" ;
+ if( obj->QueryProp( P_GHOST ) )
+ level += ", tot";
+ if( obj->Notlogged() )
+ level += ", ausgeloggt";
+ if(obj->QueryProp(P_SECOND) )
+ level +=", Zweitie";
+
+ if( environment(obj) )
+ room = object_name(environment( obj ));
+ else
+ room = "-nirgends-";
+
+ printf( "%s %s %s[ %s ].\nBefindet sich in %s.\n",
+ obj->name(RAW), title? title : "",
+ stringp(obj->QueryProp(P_RACE)) ? "- "+obj->QueryProp(P_RACE)+" - " : "",
+ level, room ) ;
+
+ // 1 abc Zeile : Host,Email,Snooper
+ if( player )
+ {
+ printf( "Host.......: %s\n", IpName(obj) );
+ printf( "E-Mail.....: %s.\n", obj->QueryProp(P_MAILADDR) );
+ if( !obj->Notlogged() && query_snoop(obj) )
+ printf( "Snooper....: %s.\n", capitalize(getuid(query_snoop(obj))) );
+
+ printf( "Vorsicht...: %11d Kurzmodus.: %11s Magierblick....: %11s.\n",
+ obj->QueryProp(P_WIMPY), obj->QueryProp(P_BRIEF) ? "-an-" : "-aus-",
+ obj->QueryProp(P_WANTS_TO_LEARN) ? "-an-" : "-aus-" );
+ printf( "Idlezeit...: %11s Alter.....: %11s Verheiratet mit: %-11s.\n",
+ IdleTime(obj), time2string("%5d:%02h:%02m",obj->QueryProp(P_AGE)*2),
+ (stringp(obj->QueryProp(P_MARRIED)) ? obj->QueryProp(P_MARRIED) : "-" )
+ );
+ }
+
+ // 2.Zeile : HP, SP und XP
+ printf( "Lebenspkt..: [%4d/%4d] Magiepkt..: [%4d/%4d].\n" +
+ "Questpunkte: [%4d/%4d] Erfahrung.: %11d.\n",
+ obj->QueryProp(P_HP), obj->QueryProp(P_MAX_HP),
+ obj->QueryProp(P_SP), obj->QueryProp(P_MAX_SP),
+ obj->QueryProp(P_QP), "/secure/questmaster"->QueryMaxQP(),
+ obj->QueryProp(P_XP) );
+
+ // 3.Zeile : FOOD, DRINK, ALCOHOL
+ printf( "Nahrung....: [%4d/%4d] Fluessigk.: [%4d/%4d] " +
+ "Alkohol........: [%4d/%4d].\n",
+ obj->QueryProp(P_FOOD), obj->QueryProp(P_MAX_FOOD),
+ obj->QueryProp(P_DRINK), obj->QueryProp(P_MAX_DRINK),
+ obj->QueryProp(P_ALCOHOL), obj->QueryProp(P_MAX_ALCOHOL) ) ;
+
+ // 4.Zeile : Geschlecht, Alignment, Level
+ switch( obj->QueryProp(P_GENDER) )
+ {
+ case FEMALE : gender = "weiblich " ; break ;
+ case MALE : gender = "maennlich " ; break ;
+ default : gender = "neutrum " ; break ;
+ }
+ printf(
+ "Geschlecht.: %s Charakter.: %11d (Magier)Stufe..: [%4s/%4d].\n",
+ gender, obj->QueryProp(P_ALIGN),
+ player ? WizLevel(obj)+"" : "-", obj->QueryProp(P_LEVEL) );
+
+ // 5.Zeile : Geld, Gewicht, Playerkills
+ printf( "Geld.......: %11d Traegt....: %11d Playerkills....: %11d.\n",
+ obj->QueryMoney(), obj->query_weight_contents(),
+ obj->QueryProp(P_KILLS) );
+
+ // 6.Zeile : stati
+ stats = obj->QueryProp(P_ATTRIBUTES) ;
+ arr = m_indices( stats );
+ stat_str = "" ;
+ for( i = 0; i < sizeof( arr ); i++ ) {
+ stat_str += capitalize(arr[ i ]) + "[" + stats[arr[ i ]];
+ if( ac = obj->QueryAttributeOffset(arr[i]) ) {
+ stat_str += "+" + ac;
+ }
+ stat_str += "], ";
+ }
+
+ if( stat_str == "" )
+ stat_str = "Keine" ;
+ else
+ stat_str = stat_str[0..sizeof( stat_str ) - 3] ;
+ printf( "Attribute..: %s.\n", stat_str ) ;
+
+ // 7.Zeile : Waffe( Dateiname )[ AC ]
+ // 8.Zeile : Ruestung(en)[ WC ]
+ weaponobj=obj->QueryProp(P_WEAPON);
+ if( weaponobj )
+ weapon = weaponobj->name(RAW) + " (" +
+ object_name( weaponobj ) + ") [" +
+ weaponobj->QueryProp(P_WC) + "]" ;
+ else
+ {
+ hands = obj->QueryProp(P_HANDS);
+ weapon = sprintf( "kaempft%s [%d]", hands[0], hands[1] );
+ }
+ ac = 0;
+ list = obj->QueryProp(P_ARMOURS);
+ armour = "";
+ for( i = 0; i < sizeof( list ); i++ )
+ {
+ armour += ( list[i]->name(RAW) + "[" +
+ list[i]->QueryProp(P_AC) + "]" + ", ") ;
+ ac += list[i]->QueryProp(P_AC);
+ }
+
+ if( armour == "" )
+ armour = "Keine " ;
+
+ arr = old_explode( break_string( armour[0..<3]+sprintf(" =>[%d]",
+ ac+obj->QueryProp(P_BODY) ), 65 ), "\n" ) ;
+ armour = arr[ 0 ] ;
+ for( i = 1; i < sizeof( arr ); i++ )
+ armour += "\n " + arr[ i ] ;
+ printf( "Waffe......: %s.\nRuestung...: %s.\n", weapon, armour ) ;
+
+ gegner = obj->QueryEnemies();
+ if( pointerp(gegner) )
+ {
+ gegner = gegner[0];
+ for( i=0; i<sizeof(gegner); i++ )
+ {
+ if( i==0 ) printf( "Gegner.....: "); else printf( " " );
+ if( !objectp(gegner[i]) )
+ printf( "<%O>\n", gegner[i] );
+ else
+ printf( "%s (%s)\n", gegner[i]->name(WER,0), object_name(gegner[i]) );
+ }
+ }
+
+ mk_waitfor( obj->QueryProp(P_WAITFOR) );
+
+ mk_autoload( obj->QueryProp(P_AUTOLOAD) );
+
+ return TRUE;
+}
+
+static void mk_waitfor( mixed waitfor )
+{
+ string str;
+ int i;
+
+ if( !pointerp(waitfor) || sizeof(waitfor)==0 )
+ return;
+ str = "Waiting for: ";
+ for( i=sizeof(waitfor)-1; i>0; i-- )
+ str += waitfor[i] + ", ";
+ str += waitfor[0];
+ write( str+"\n" );
+}
+
+static void mk_autoload( mixed autoload )
+{
+ string str, *objlist;
+ int i;
+
+ if( !mappingp(autoload) )
+ return;
+ str = "Autoload...: ";
+ objlist = m_indices(autoload);
+ for( i=sizeof(objlist)-1; i>=0; i-- )
+ {
+ str += "\"" + objlist[i] + "\"\n";
+ if( i>0 )
+ str += " ";
+ }
+ write( str );
+}
+
+static void print_memory_line( string key, object data, int flag )
+{
+ printf( " %-10s%s ", key, (flag ? ">" : "=") );
+ dump_obj( data, 13 );
+}
+
+static int cmd_memory()
+{
+ int i;
+ if( !sizeof(memory) )
+ return memo( "Keine Variablen definiert" );
+
+ walk_mapping( memory, #'print_memory_line );
+ return TRUE;
+}
+
+static int cmd_array()
+{
+ mixed *array;
+ mixed ob;
+
+ if( !sizeof(stack) )
+ return error( "array: Der Stack ist leer" );
+ array = ({});
+ while( sizeof(stack) && (ob=pop()) && ob!=";" )
+ array = ({ob}) + array;
+ push( array );
+ return TRUE;
+}
+
+static int cmd_split()
+{
+ mixed *array;
+ int i;
+
+ if( !pointerp(top()) )
+ return error( "split: TOS ist kein Array" );
+ array=pop();
+ if( sizeof(stack) )
+ push( ";" );
+ for( i=0; i<sizeof(array); i++ )
+ push(array[i]);
+ return TRUE;
+}
+
+static int cmd_player()
+{
+ object ob;
+ string str;
+
+ str = top();
+ if( !stringp(str) )
+ return error( "player: TOS ist kein String" );
+ ob = becomes_pl();
+ if( !ob )
+ return error( "player: Keinen Spieler namens \""+str+"\" gefunden" );
+ //pop();
+ //push(ob);
+ return TRUE;
+}
+
+static int cmd_object()
+{
+ object ob;
+ string err,fnam;
+
+ if( !stringp(top()) )
+ return error( "object: TOS ist kein String" );
+ ob = find_object(top());
+ if( !ob )
+ {
+ if( !(fnam=this_player()->find_file(top(),".c")) )
+ return error( "object: Kein Objekt namens \""+top()+"\" gefunden" );
+ if( err=(catch(call_other(fnam,"?"))) )
+ return error( "object: Fehler beim Laden: "+err[1..<3] );
+ ob = find_object(fnam);
+ }
+ pop();
+ push(ob);
+ return TRUE;
+}
+
+static int cmd_living()
+{
+ object ob;
+ if( !stringp(top()) )
+ return error( "object: TOS ist kein String" );
+ ob = find_living(top());
+ if( !ob )
+ return error( "object: Kein Objekt namens \""+top()+"\" gefunden" );
+ pop();
+ push(ob);
+ return TRUE;
+}
+
+static int cmd_say()
+{
+ mit_say = !mit_say;
+ if( mit_say )
+ memo( "Meldungen an Mitspieler an" );
+ else
+ memo( "Meldungen an Mitspieler aus" );
+ return TRUE;
+}
+
+static int cmd_names()
+{
+ mit_namen = !mit_namen;
+ if( mit_namen )
+ memo( "Namen werden angezeigt" );
+ else
+ memo( "Namen werden nicht angezeigt" );
+ return TRUE;
+}
+
+static int cmd_secureinv()
+{
+ secureinv = !secureinv;
+ if( secureinv )
+ memo( "Inventory wird ueberwacht" );
+ else
+ memo( "Inventory wird nicht ueberwacht" );
+ set_heart_beat(secureinv);
+ return TRUE;
+}
+
+static int cmd_logaccess()
+{
+ dologaccess = !dologaccess;
+ if( dologaccess )
+ memo( "Zugriffe werden gemeldet" );
+ else
+ memo( "Zugriffe werden nicht gemeldet" );
+ return TRUE;
+}
+
+static int cmd_destruct_bang()
+{
+ if( !becomes_obj() )
+ return error( "destruct: TOS ist kein Objekt" );
+ destruct(pop());
+ return TRUE;
+}
+
+static int cmd_destruct()
+{
+ if( !becomes_obj() )
+ return error( "remove: TOS ist kein Objekt" );
+ memo( "destruct: TOS wird 'removed'!" );
+ top()->remove();
+ if( top() )
+ memo( "destruct: TOS lebt noch." );
+ else
+ pop();
+ return TRUE;
+}
+
+static int cmd_remove()
+{
+ if( !becomes_obj() )
+ return error( "remove: TOS ist kein Objekt" );
+ top()->remove();
+ if( top() )
+ memo( "destruct: TOS lebt noch." );
+ else
+ pop();
+ return TRUE;
+}
+
+static int cmd_update()
+{
+ object blue;
+
+ if( !becomes_obj() )
+ return error( "update: TOS ist kein Objekt" );
+ blue = find_object(old_explode(object_name(top()),"#")[0]);
+ blue->remove();
+ if( blue )
+ memo( "update: TOS lebt noch" );
+ else
+ pop();
+ return TRUE;
+}
+
+static int cmd_update_bang()
+{
+ if( !becomes_obj() )
+ return error( "update: TOS ist kein Objekt" );
+ destruct(find_object(old_explode(object_name(pop()),"#")[0]));
+ return TRUE;
+}
+
+static int cmd_roomupdate()
+{
+ return do_roomupdate( FALSE, FALSE );
+}
+
+static int cmd_roomupdate_bang()
+{
+ return do_roomupdate( TRUE, FALSE );
+}
+
+static int cmd_extroomupdate()
+{
+ return do_roomupdate( FALSE, TRUE );
+}
+
+static int cmd_extroomupdate_bang()
+{
+ return do_roomupdate( TRUE, TRUE );
+}
+
+// Hilfsfunktionen zum Filtern von Items
+static object *collect_items;
+static void collect( object* data ) { collect_items += ({ data[0] }); }
+
+static int do_roomupdate( int destflag, int noitems )
+{
+ object tmproom,newroom;
+ object *inv;
+ string errmsg;
+ string *file;
+ object *items;
+ int i;
+
+ if( !becomes_obj() )
+ return error( "roomupdate: TOS ist kein Objekt" );
+ file = old_explode( object_name( top() ), "#" );
+ if( sizeof(file) > 1 )
+ return error( "roomupdate: TOS ist keine Blueprint" );
+ if( file[0] == "/room/void" )
+ return error( "roomupdate: Die `void' darf nicht geupdatet werden" );
+
+ // ----- Rettung
+ tell_room( top(),
+ "Der Raum verschwimmt vor Deinen Augen, um sich zu erneuern.\n"
+ );
+ tmproom = clone_object( "/room/void" );
+
+ if( noitems )
+ // Nur Spieler kommen raus.
+ inv = filter( all_inventory(top()), #'query_once_interactive );
+ else
+ { // Dinge, die P_ITEMS sind, bleiben da!
+ collect_items = ({});
+ map( top()->QueryProp(P_ITEMS), #'collect );
+ inv = all_inventory(top()) - collect_items;
+ }
+
+ for( i=sizeof(inv)-1; i>=0; i-- )
+ inv[i]->move( tmproom, M_NOCHECK | M_SILENT | M_NO_SHOW );
+
+ // ----- Vernichtung
+ if( destflag )
+ destruct( pop() );
+ else
+ {
+ top()->remove();
+ if( top() )
+ memo( "roomupdate : TOS ist nicht verschwunden." );
+ else
+ pop();
+ }
+
+ // ----- Neuerschaffung
+ errmsg = catch( call_other( file[0], "?" ) );
+ if( errmsg )
+ {
+ tell_room( tmproom, "Der Raum verbleicht in ein Nichts.\n" );
+ push( file[0] );
+ return error( "updateroom: " + errmsg[1..<2] );
+ }
+
+ // ----- Restaurierung
+ newroom = find_object( file[0] );
+ for( i=sizeof(inv)-1; i>=0; i-- )
+ if( objectp(inv[i]) ) // Objekte koennten sich beim ersten move zerstoeren.
+ inv[i]->move( newroom, M_NOCHECK | M_SILENT | M_NO_SHOW );
+ tell_room( newroom, "Die Konturen werden wieder scharf.\n" );
+ destruct( tmproom );
+ return TRUE;
+}
+
+static int cmd_clone()
+{
+ if( !stringp(top()) )
+ return error( "clone: TOS ist kein String" );
+ if( file_size(top()+".c")<=0 )
+ return error( "clone: Kein solches File" );
+ push(clone_object(pop()));
+ //do_move( top(), environment(PL) );
+ //top()->move(PL,M_GET|M_SILENT);
+ return TRUE;
+}
+
+static int cmd_move()
+{
+ object ob;
+
+ if( !becomes_obj() )
+ return error( "move: Ziel ist kein Objekt" );
+ ob = pop();
+ if( !becomes_obj() )
+ return error( "move: Kein solcher Gegenstand" );
+ do_move( pop(), ob );
+ return TRUE;
+}
+
+static int cmd_cleanof_bang()
+{
+ return do_cleanof( TRUE );
+}
+
+static int cmd_cleanof()
+{
+ return do_cleanof( FALSE );
+}
+
+static int do_cleanof( int strong )
+{
+ object *inv;
+ int i;
+ string clean_id;
+
+ if( !stringp(top()) )
+ return error( "cleanof: TOS ist kein String" );
+ clean_id = pop();
+ if( !becomes_obj() )
+ {
+ push( clean_id );
+ return error( "cleanof: Kein Objekt zum Leeren" );
+ }
+ for( i=0, inv=all_inventory(pop()); i<sizeof(inv); i++ )
+ if( inv[i]->id(clean_id) )
+ {
+ if( strong )
+ destruct( inv[i] );
+ else
+ inv[i]->remove();
+ }
+ return TRUE;
+}
+
+static int cmd_snoopers()
+{
+ object* u, snooper;
+ int i, flag;
+
+ flag = 0;
+ u = users();
+ for( i=0; i<sizeof(u); i++ )
+ {
+ if( snooper = query_snoop(u[i]) )
+ {
+ flag = 1;
+ printf( "%s wird gesnooped von: %s.\n",
+ capitalize(getuid(u[i])), capitalize(getuid(snooper)) );
+ }
+ }
+ if( !flag )
+ memo( "Momentan wird niemand gesnooped" );
+ return TRUE;
+}
+
+static int cmd_ping()
+{
+ object pl;
+
+ if( !becomes_pl() )
+ return error( "ping: TOS ist kein Spieler" );
+
+ pl=pop();
+ call_out( "ping", 0, ({ pl, 5 }) );
+ return TRUE;
+}
+
+static void ping( mixed* argv )
+{
+ if( !argv[0] || --argv[1] < 0 ) return;
+ tell_object( argv[0], BEEP+PL->name(WER)+" pingt Dich an.\n" );
+ call_out( "ping", 1, argv );
+}
+
+static void do_calloutinfo( mixed* call )
+{
+ int l,i;
+
+ if( pointerp(call) )
+ {
+ printf( "%5d:%O->%O(", call[2], call[0], call[1]);
+ if( (l=sizeof(call))>3 ) {
+ for( ; l>=3 && !call[--l]; ) ;
+ for( i=3; i<=l; i++ ) printf( "%O%s", call[i], (i==l)?"":"," );
+ }
+ write(")\n");
+ }
+}
+
+static int cmd_callouts_bang()
+{
+ mixed *calls;
+ object obj;
+ string name;
+ int i,j;
+
+ calls = call_out_info();
+ if( !pointerp(calls) || !sizeof(calls) )
+ {
+ memo( "Keine Callouts vorhanden" );
+ return TRUE;
+ }
+ map( calls, #'do_calloutinfo );
+ return TRUE;
+}
+
+static void do_calloutinfo2( mixed* call, string str )
+{
+ string s;
+ int i,l;
+
+ if( pointerp(call) )
+ {
+ s = sprintf( "%5d:%O->%O(", call[2], call[0], call[1]);
+ if( sizeof(explode(s,str)) > 1 )
+ {
+ write( s );
+ if( (l=sizeof(call))>3 ) {
+ for( ; l>=3 && !call[--l]; ) ;
+ for( i=3; i<=l; i++ ) printf( "%O%s", call[i], (i==l)?"":"," );
+ }
+ write(")\n");
+ }
+ }
+}
+
+static int cmd_callouts()
+{
+ mixed *calls;
+ object obj;
+ string str;
+ int i,j;
+
+ if( !stringp(top()) )
+ return error( "TOS ist kein String" );
+ str = pop();
+ calls = call_out_info();
+ if( !pointerp(calls) || !sizeof(calls) )
+ {
+ memo( "Keine Callouts vorhanden" );
+ return TRUE;
+ }
+ map( calls, #'do_calloutinfo2, str );
+ return TRUE;
+}
+
+static int cmd_heartbeats()
+{
+ mixed *beats;
+ int i;
+ object env;
+ string enam;
+
+ beats = heart_beat_info();
+ if( !pointerp(beats) || !sizeof(beats) )
+ {
+ memo( "Keine Heartbeats vorhanden" );
+ return TRUE;
+ }
+ for( i=0; i<sizeof(beats); i++ )
+ {
+ env = environment(beats[i]);
+ enam = env ? object_name(env) : "-- nirgends --";
+ printf( "%-35s %-35s\n", object_name(beats[i]), enam );
+ }
+ return TRUE;
+}
+
+static int cmd_wer()
+{
+ object* ppl;
+ string* pl;
+ int i;
+
+ ppl = sort_array( users(), lambda( ({ 'x, 'y }),
+ ({ #'<, ({ #'query_ip_number, 'x }), ({ #'query_ip_number, 'y }) })
+ ));
+ pl = ({});
+ for( i=0; i<sizeof(ppl); i++ )
+ {
+ pl += ({ sprintf( "%'.'-14s %-15s %3d %s \n",
+ capitalize(geteuid(ppl[i])),
+ query_ip_number(ppl[i]),
+ query_wiz_level(ppl[i])>0 ? query_wiz_level(ppl[i])
+ : ppl[i]->QueryProp(P_LEVEL),
+ query_wiz_level(ppl[i])>0 ? "W" : "P"
+ ) });
+ }
+ write( implode(pl,"") );
+ return TRUE;
+}
+
+static int cmd_debuginfo()
+{
+ if( !becomes_obj() )
+ return error( "dinfo: TOS ist kein Objekt" );
+ debug_info( 0, pop() );
+ return TRUE;
+}
+
+static int cmd_pretty()
+{
+ pretty = !pretty;
+ if( pretty )
+ memo( "Schoenmodus an" );
+ else
+ memo( "Schoenmodus aus" );
+ return TRUE;
+}
+
+static int cmd_doprofile()
+{
+ do_profile=!do_profile;
+ if( do_profile )
+ memo( "Profile wird geladen" );
+ else
+ memo( "Profile wird nicht geladen" );
+ return TRUE;
+}
+
+static int cmd_evaluate()
+{
+ string str;
+ if( !sizeof(stack) ) return error( "evaluate: Stack ist leer" );
+ if( !stringp(top()) ) return error( "evaluate: TOS ist kein String" );
+ str = pop();
+ return do_cmd( str );
+}
+
+static void write_memory( string nam, string str, int flag, string file )
+{
+ if( flag ) write_file( file, nam + " = " + str + "\n" );
+}
+
+static int cmd_dump()
+{
+ string file;
+
+ if( !sizeof(stack) || !stringp(top()) )
+ file = "/players/"+getuid(PL)+"/.memory.o";
+ else
+ file = pop();
+ rm( file );
+ write_file( file, "# Dump des Tellerstapels vom " + dtime(time()) + "\n" );
+ write_file( file, "# Owner = "+capitalize(getuid(PL))+"\n" );
+ walk_mapping( memory, #'write_memory, file );
+ return TRUE;
+}
+
+static int restore_line( string line )
+{
+ string nam,str;
+ if( sscanf( line, "%s = %s", nam, str ) != 2 )
+ return error( "restore: Fehler im file" );
+ memory += ([ nam: str; 1 ]);
+ return 1;
+}
+
+static int cmd_restore()
+{
+ string str, *lines;
+
+ if( !sizeof(stack) || !stringp(top()) )
+ str = "/players/"+getuid(PL)+"/.memory.o";
+ else
+ str = pop();
+
+ if(file_size(str)<=0)
+ return error( "restore: kann '"+str+"' nicht laden" );
+ lines = regexp( old_explode( read_file(str), "\n" ), "^[^#]" );
+ map( lines, #'restore_line );
+ return TRUE;
+}
+
+static int cmd_if()
+{
+ if( sizeof(stack) < 3 )
+ return error( "if: zuwenig Argumente" );
+ if( !pop() )
+ cmd_swap();
+ pop();
+ return TRUE;
+}
diff --git a/obj/tools/teller/t_efun.c b/obj/tools/teller/t_efun.c
new file mode 100644
index 0000000..c1a2ded
--- /dev/null
+++ b/obj/tools/teller/t_efun.c
@@ -0,0 +1,416 @@
+static efun_regexp( arg1, arg2 )
+{
+ return regexp( arg1, arg2 );
+}
+
+static efun_all_inventory( arg )
+{
+ return all_inventory( arg );
+}
+
+static efun_break_string( arg1, arg2, arg3 )
+{
+ return break_string( arg1, arg2, arg3 );
+}
+
+static efun_capitalize( arg )
+{
+ return capitalize( arg );
+}
+
+static efun_cat( arg1, arg2, arg3 )
+{
+ return cat( arg1, arg2, arg3 );
+}
+
+static efun_clear_bit( arg1, arg2 )
+{
+ return clear_bit( arg1, arg2 );
+}
+
+static efun_crypt( arg1, arg2 )
+{
+ return crypt( arg1, arg2 );
+}
+
+static efun_ctime( arg )
+{
+ return ctime( arg );
+}
+
+static efun_debug_info( arg1, arg2 )
+{
+ return debug_info( arg1, arg2 );
+}
+
+static efun_deep_inventory( arg )
+{
+ return deep_inventory( arg );
+}
+
+static efun_environment( arg )
+{
+ return environment( arg );
+}
+
+static efun_explode( arg1, arg2 )
+{
+ return old_explode( arg1, arg2 );
+}
+
+static efun_file_name( arg )
+{
+ return object_name( arg );
+}
+
+static efun_file_size( arg )
+{
+ return file_size( arg );
+}
+
+static efun_filter_array( arg1, arg2, arg3, arg4 )
+{
+ return filter( arg1, arg2, arg3, arg4 );
+}
+
+static efun_find_call_out( arg )
+{
+ return find_call_out( arg );
+}
+
+static efun_find_living( arg )
+{
+ return find_living( arg );
+}
+
+static efun_find_object( arg )
+{
+ return find_object( arg );
+}
+
+static efun_find_player( arg )
+{
+ return find_player( arg );
+}
+
+static efun_function_exists( arg1, arg2 )
+{
+ return function_exists( arg1, arg2 );
+}
+
+static efun_implode( arg1, arg2 )
+{
+ return implode( arg1, arg2 );
+}
+
+static efun_interactive( arg )
+{
+ return interactive( arg );
+}
+
+static efun_intp( arg )
+{
+ return intp( arg );
+}
+
+static efun_last_reboot_time()
+{
+ return last_reboot_time();
+}
+
+static efun_living( arg )
+{
+ return living( arg );
+}
+
+static efun_lower_case( arg )
+{
+ return lower_case( arg );
+}
+
+static efun_get_dir( arg1, arg2 )
+{
+ return get_dir( arg1, arg2 );
+}
+
+static efun_map_array( arg1, arg2, arg3, arg4 )
+{
+ return map( arg1, arg2, arg3, arg4 );
+}
+
+static efun_member( arg1, arg2 )
+{
+ return member( arg1, arg2 );
+}
+
+static efun_objectp( arg )
+{
+ return objectp( arg );
+}
+
+static efun_pointerp( arg )
+{
+ return pointerp( arg );
+}
+
+static efun_present( arg1, arg2 )
+{
+ return present( arg1, arg2 );
+}
+
+static efun_process_string( arg )
+{
+ return process_string( arg );
+}
+
+static efun_query_actions( arg1, arg2 )
+{
+ return query_actions( arg1, arg2 );
+}
+
+static efun_query_idle( arg )
+{
+ return query_idle( arg );
+}
+
+static efun_query_ip_name( arg )
+{
+ return query_ip_name( arg );
+}
+
+static efun_query_ip_number( arg )
+{
+ return query_ip_number( arg );
+}
+
+static efun_query_load_average()
+{
+ return query_load_average();
+}
+
+static efun_query_snoop( arg )
+{
+ return query_snoop( arg );
+}
+
+static efun_random( arg )
+{
+ return random( arg );
+}
+
+static efun_read_bytes( arg1, arg2, arg3 )
+{
+ return read_bytes( arg1, arg2, arg3 );
+}
+
+static efun_read_file( arg1, arg2, arg3 )
+{
+ return read_file( arg1, arg2, arg3 );
+}
+
+static efun_remove_call_out( arg )
+{
+ return remove_call_out( arg );
+}
+
+static efun_remove_interactive( arg )
+{
+ return remove_interactive( arg );
+}
+
+static efun_rusage()
+{
+ return rusage();
+}
+
+static efun_say( arg1, arg2 )
+{
+ if( !arg2 ) return say( arg1 );
+ return say( arg1, arg2 );
+}
+
+static efun_set_bit( arg1, arg2 )
+{
+ return set_bit( arg1, arg2 );
+}
+
+static efun_set_heart_beat( arg )
+{
+ return set_heart_beat( arg );
+}
+
+static efun_set_living_name( arg )
+{
+ return set_living_name( arg );
+}
+
+static efun_sizeof( arg )
+{
+ return sizeof( arg );
+}
+
+static efun_sort_array( arg1, arg2, arg3 )
+{
+ return sort_array( arg1, arg2, arg3 );
+}
+
+static efun_stringp( arg )
+{
+ return stringp( arg );
+}
+
+static efun_strlen( arg )
+{
+ return sizeof( arg );
+}
+
+static efun_tail( arg )
+{
+ return tail( arg );
+}
+
+static efun_shout( arg )
+{
+ return shout( arg );
+}
+
+static efun_tell_object( arg1, arg2 )
+{
+ return tell_object( arg1, arg2 );
+}
+
+static efun_tell_room( arg1, arg2, arg3 )
+{
+ return tell_room( arg1, arg2, arg3 );
+}
+
+static efun_test_bit( arg1, arg2 )
+{
+ return test_bit( arg1, arg2 );
+}
+
+static efun_time()
+{
+ return time();
+}
+
+static efun_unique_array( arg1, arg2, arg3 )
+{
+ return unique_array( arg1, arg2, arg3 );
+}
+
+static efun_users()
+{
+ return users();
+}
+
+static efun_version()
+{
+ return version();
+}
+
+static efun_write( arg )
+{
+ return write( arg );
+}
+
+static efun_write_bytes( arg1, arg2, arg3 )
+{
+ return write_bytes( arg1, arg2, arg3 );
+}
+
+static efun_write_file( arg1, arg2 )
+{
+ return write_file( arg1, arg2 );
+}
+
+static efun_geteuid( arg )
+{
+ return geteuid( arg );
+}
+
+static efun_getuid( arg )
+{
+ return getuid( arg );
+}
+
+static efun_first_inventory( arg )
+{
+ return first_inventory( arg );
+}
+
+static efun_next_inventory( arg )
+{
+ return next_inventory( arg );
+}
+
+static efun_inherit_list( arg )
+{
+ return inherit_list( arg );
+}
+
+static efun_strstr( arg1, arg2, arg3 )
+{
+ return strstr( arg1, arg2, arg3 );
+}
+
+static efun_program_time( arg )
+{
+ return program_time( arg );
+}
+
+static efun_get_error_file( arg1, arg2 )
+{
+ return get_error_file( arg1, arg2 );
+}
+
+static efun_set_prompt( arg1, arg2 )
+{
+ return set_prompt( arg1, arg2 );
+}
+
+static efun_filter_objects( arg1, arg2, arg3 )
+{
+ return filter_objects( arg1, arg2, arg3 );
+}
+
+static efun_map_objects( arg1, arg2, arg3 )
+{
+ return map_objects( arg1, arg2, arg3 );
+}
+
+static efun_transpose_array( arg )
+{
+ return transpose_array( arg );
+}
+
+static efun_query_once_interactive( arg )
+{
+ return query_once_interactive( arg );
+}
+
+static efun_wizlist( arg )
+{
+ wizlist( arg );
+ return 1;
+}
+
+static efun_mkdir( str )
+{
+ return mkdir( str );
+}
+
+static efun_rm( str )
+{
+ return rm( str );
+}
+
+static efun_country( str )
+{
+ return country( str );
+}
+
+static efun_dtime( val )
+{
+ return dtime( val );
+}
diff --git a/obj/tools/teller/t_player.c b/obj/tools/teller/t_player.c
new file mode 100644
index 0000000..f72b100
--- /dev/null
+++ b/obj/tools/teller/t_player.c
@@ -0,0 +1,60 @@
+// ----------------------------------------------------------------------
+// Zwischenobjekt zum Lesen der Spielerdaten auch von nichteingeloggten.
+// ----------------------------------------------------------------------
+#include "teller.h"
+
+inherit "std/player/base";
+
+create() {
+ used_attributes_offsets = ([]);
+}
+
+string name;
+string race;
+string hands;
+mapping autoload;
+
+_query_name() { return name; }
+playername() { return name; }
+_set_name( str ) { return name=str; }
+
+_query_race()
+{
+ if( race ) return race;
+
+ return "/secure/master"
+ ->query_player_object(lower_case(name))
+ ->QueryProp(P_RACE);
+}
+
+_query_hands()
+{
+ if( hands ) return hands;
+ return ({ " nicht", 0 });
+}
+
+_query_autoload()
+{
+ return autoload;
+}
+
+Load( str )
+{
+ restore_object( "/save/"+str[0..0]+"/"+str );
+}
+
+Notlogged() { return TRUE; }
+
+QueryMoney()
+{
+ if( !mappingp(autoload) )
+ return 0;
+ return autoload["/items/money"];
+}
+
+QueryEnemies()
+{
+ return ({({}),({})});
+}
+
+QueryAttributeOffset( arr ) { return "?"; }
diff --git a/obj/tools/teller/teller.c b/obj/tools/teller/teller.c
new file mode 100644
index 0000000..5f34f06
--- /dev/null
+++ b/obj/tools/teller/teller.c
@@ -0,0 +1,686 @@
+// ----------------------------------------------------------------------
+// Tellerstapel, ein Stackorientiertes magiertool.
+// Rumata 15.09.93
+// ----------------------------------------------------------------------
+#include "teller.h"
+inherit "std/secure_thing";
+inherit T_CMDS;
+inherit T_EFUN;
+inherit "std/more";
+
+#include "/secure/wizlevels.h"
+
+nosave mapping tcommands;
+nosave string owner_name;
+
+void logaccess( string s );
+static void do_msg( string s, object o );
+static string|int parseNext( string str, mixed auxstack, string funname );
+static mixed nextAlpha( string s );
+static varargs void restore_stack( string* argv, int args );
+static int do_call( string fun, int mit_return );
+static int do_call_efun( string fun, int mit_return );
+static int do_lpc( string str, int mit_return );
+static int do_cmd( string str );
+int error( string s );
+
+static void tAddCmd( mixed cmd )
+{
+ int i;
+
+ //if (find_player("rikus")) tell_object(find_player("rikus"),sprintf("%O\n",cmd));
+ if( !pointerp(cmd) )
+ m_add(tcommands, cmd, cmd);
+ else
+ for( i=0; i<sizeof(cmd); i++ )
+ m_add(tcommands, cmd[i], cmd[0]);
+}
+
+void create()
+{
+ if( IS_BLUE(ME) ) return;
+ if( !find_player(getuid()) ) return;
+ owner_name = find_player(getuid())->name(WESSEN,1);
+
+ secure_thing::create();
+ t_cmds::create();
+ SetProp( P_NAME, "Tellerstapel" );
+ SetProp( P_GENDER, MALE );
+ AddId( ({"teller","stapel","tellerstapel"}) );
+ SetProp( P_NODROP, "Wozu denn?\n" );
+ SetProp( P_NEVERDROP, 1 );
+ SetProp( P_READ_MSG, "Die Gravur besagt: 'Aus der Rumata-Manufaktur'\n" );
+ tcommands = ([]);
+
+ tAddCmd( "say" );
+ tAddCmd( ({"names","nam"}) );
+ tAddCmd( "secureinv" );
+ tAddCmd( "logaccess" );
+ tAddCmd( "pretty" );
+ tAddCmd( "doprofile" );
+ tAddCmd( ({"clear","clr"}));
+ tAddCmd( "pop" );
+ tAddCmd( "dup" );
+ tAddCmd( "swap" );
+ tAddCmd( ({"evaluate","eval"}) );
+
+ tAddCmd( "here" );
+ tAddCmd( "me" );
+
+ tAddCmd( ({"memory","mem"}) );
+ tAddCmd( "dump" );
+ tAddCmd( "restore" );
+ tAddCmd( "top" );
+ tAddCmd( "wer" );
+ tAddCmd( ({"stack","stk"}) );
+ tAddCmd( ({"snoopers","snoop"}) );
+ tAddCmd( "callouts" );
+ tAddCmd( ({"callouts_bang","callouts!"}) );
+ tAddCmd( ({"heartbeats","beats"}) );
+ tAddCmd( "inv" );
+ tAddCmd( ({"rekinv","rinv"}) );
+ tAddCmd( "scan" );
+ tAddCmd( "if" );
+
+ tAddCmd( ({"array","arr"}) );
+ tAddCmd( ({"split","spl"}) );
+ tAddCmd( ({"player","pl"}) );
+ tAddCmd( ({"living","lv"}) );
+ tAddCmd( ({"object","ob"}) );
+
+ tAddCmd( ({"debuginfo","dinfo"}) );
+ tAddCmd( ({"clone","cln"}) );
+ tAddCmd( ({"update","upd"}) );
+ tAddCmd( ({"update_bang","update!","upd!"}) );
+ tAddCmd( ({"move","mv"}) );
+ tAddCmd( ({"destruct","dest","des"}) );
+ tAddCmd( ({"remove","rem"}) );
+ tAddCmd( ({"destruct_bang","destruct!","dest!","des!","remove!","rem!"}) );
+ tAddCmd( ({"roomupdate","rupdate","rupd","rup"}) );
+ tAddCmd( ({"roomupdate_bang","roomupdate!","rupdate!","rupd!","rup!"}) );
+ tAddCmd( ({"extroomupdate","rupdate*","rupd*","rup*"}) );
+ tAddCmd( ({"extroomupdate_bang","roomupdate*!","rupdate*!","rupd*!","rup*!",
+ "rup!*" }) );
+ tAddCmd( ({"cleanof","clnof"}) );
+ tAddCmd( ({"cleanof_bang","cleanof!","clnof!"}) );
+
+ tAddCmd( "ping" );
+}
+
+void init()
+{
+ //logaccess( "init" );
+ ::init();
+ if ( !IS_WIZARD(PL) || environment()!=PL )
+ return;
+ add_action( "parse", ",", 1 );
+ add_action( "jonglier", "jonglier", 1 );
+ add_action( "message", "message" );
+ add_action( "message", "msg" );
+}
+
+short()
+{
+ logaccess( "short" );
+ return "Ein Stapel Teller.\n";
+}
+
+id( str )
+{
+ logaccess( "id" );
+ return ::id(str);
+}
+
+name( casus, dem, force )
+{
+ logaccess( "name" );
+ return ::name( casus, dem, force );
+}
+
+long()
+{
+ string answer;
+
+ answer =
+ "Du betrachtest "+owner_name+" magischen Tellerstapel. Die einzelnen Teller sind\n"
+ +"bis auf eine kleine Inschrift auf dem Boden weiss. Wenn Du hiermit\n"
+ +"jonglierst, kann ALLES passieren.\n";
+
+ if( getuid(PL) == getuid() )
+ {
+ answer +=
+ ( mit_say
+ ? "Die Teller sind beim Jonglieren sichtbar.\n"
+ : "Die Teller sind beim Jonglieren unsichtbar.\n"
+ ) + ( mit_namen
+ ? "Die Teller nennen die Dinge beim Namen.\n"
+ : "Die Teller nennen die Dinge beim Filenamen.\n"
+ ) + ( pretty
+ ? "Die Teller haben ein verschnoerkeltes Muster.\n"
+ : "Die Teller sind geradezu schmucklos.\n"
+ ) + ( dologaccess
+ ? "Die Teller spueren Zugriffe.\n"
+ : ""
+ ) + ( secureinv
+ ? "Die Teller bewachen Dein Inventar.\n"
+ : ""
+ ) + ( do_profile
+ ? "Die Teller werden beim Einloggen aktiv.\n"
+ : ""
+ );
+ }
+ return answer;
+}
+
+void _set_autoloadobj( mixed val )
+{
+ if( !pointerp(val) ) return;
+ val += ({ 0,0,0,0,0,0 });
+ mit_namen = val[0];
+ mit_say = val[1];
+ set_heart_beat( secureinv = val[2] );
+ dologaccess = val[3];
+ pretty = val[4];
+ do_profile = val[5];
+ if( do_profile ) call_out( "_load_profile", 0, this_player() );
+}
+
+mixed _query_autoloadobj()
+{
+ return ({ mit_namen, mit_say, secureinv, dologaccess, pretty,
+ do_profile });
+}
+
+void _load_profile( object pl )
+{
+ string pf,errmsg;
+
+ if( geteuid() && pl && geteuid(pl)==geteuid()
+ && file_size(pf="/players/"+geteuid()+"/.profile.c")>0
+ && (errmsg=catch(call_other(pf,"setup",pl)))
+ )
+ printf( "Error loading profile: %O\n", errmsg );
+}
+
+void logaccess( string str )
+{
+ if( RPL && dologaccess && getuid()!=getuid(RPL) && find_player(getuid())
+ && previous_object() && getuid(previous_object()) != ROOTID
+ && query_wiz_level(getuid())>=query_wiz_level(getuid(RPL))
+ )
+ tell_object( find_player(getuid()), "MEMO: " + str + "() von "
+ + RPL->name(WEM) + " via ["
+ + object_name(previous_object())+"].\n"
+ );
+ if( secureinv && find_player(getuid()) && !member(heart_beat_info(),ME) )
+ {
+ tell_object( find_player(getuid()), "MEMO: heart_beat restartet!.\n" );
+ set_heart_beat(TRUE);
+ }
+}
+
+// ----------------------------------------------------------------------
+// Hilfe-Funktionen
+// ----------------------------------------------------------------------
+static int secure()
+{
+ int i;
+ if( process_call() || secure_level()<query_wiz_level(RPL) ) return 0;
+ for( i=0; previous_object(i)==RPL; i++ )
+ ;
+ return (!previous_object(i) || previous_object()==ME)
+ && getuid()==getuid(RPL) && IS_WIZARD(RPL);
+}
+
+int jonglier( string str )
+{
+ string arg;
+
+ logaccess( "jongliere" );
+ if( !str || id(str) || sscanf( str, "mit %s", arg ) == 1 )
+ {
+ if( !secure() )
+ write(
+ "Dieser Tellerstapel ist nichts fuer Dich. Suche Dir einen eigenen.\n"
+ );
+ else
+ write(
+ "Der Jonglierbefehl lautet \";\" oder \",\".\n"
+ + "\";hilfe <befehl>\" gibt Dir Hilfestellung.\n"
+ );
+ return TRUE;
+ }
+ return 0;
+}
+
+static int zeige_hilfe( string str )
+{
+ if( !stringp(str) ) str = "general";
+ str = implode( old_explode( HELP(str), "/../" ), "/" );
+ if( file_size(str) > 0 )
+ {
+ More( str, 1 );
+ return TRUE;
+ }
+ write( "Zu diesem Thema gibt es keine Hilfe.\n" );
+ return TRUE;
+}
+
+int message( string str )
+{
+ string pl;
+ object dest;
+
+ if( !secure() ) return FALSE;
+
+ if( str )
+ {
+ if( sscanf( str, "to %s", pl ) == 1 )
+ str = pl;
+ if( !(dest = find_player(str) ) )
+ {
+ write( capitalize(str) + " ist nicht eingeloggt.\n" );
+ return TRUE;
+ }
+ }
+ else
+ dest = 0;
+
+ do_msg( "<Mitteilung von "+PL->name(WEM)+">", dest );
+ write( "Mitteilung"
+ + ( dest ? " an " + dest->name(WEN) : "" )
+ + " kann mit '**' beendet werden.\n" );
+
+ input_to( "more_message", 0, dest );
+ return TRUE;
+}
+
+static void do_msg( string str, object obj )
+{
+ if( obj )
+ tell_object( obj, str + "\n" );
+ else
+ say( str + "\n" );
+}
+
+static int more_message( string str, object obj )
+{
+ if( str != "**" )
+ {
+ do_msg( str, obj );
+ input_to( "more_message", 0, obj );
+ }
+ else
+ do_msg( "<Ende der Mitteilung>", obj );
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------
+// Parse-Funktionen
+// ----------------------------------------------------------------------
+int parse( string str )
+{
+ int i;
+ string arg, rest;
+
+ if( !secure() ) return FALSE;
+
+ // Die Hilfe faellt aus der allgemeinen Syntax heraus !
+ if( query_verb()[1..] == "hilfe" || query_verb()[1..] == "help" )
+ return zeige_hilfe( str );
+
+ if( str=this_player()->_unparsed_args() )
+ str = query_verb()[1..]+" "+str;
+ else
+ str = query_verb()[1..];
+
+ fehler_passiert = FALSE;
+ while( !fehler_passiert && str && str!="" )
+ str = parseNext( str, ({}), "-ROOT-" );
+
+ if( mit_say && !PL->QueryProp(P_INVIS) )
+ {
+ if( !fehler_passiert )
+ say( PL->name(WER)+" jongliert mit "
+ + PL->QPP(MALE,WEM,PLURAL)+" Tellern.\n" );
+ else
+ say( PL->name(WEM)+" faellt beim Jonglieren ein Teller herunter.\n" );
+ }
+ if( !fehler_passiert )
+ write( "OK.\n" );
+ return TRUE;
+}
+
+static string|int parseNext( string str, mixed auxstack, string funname )
+{
+ mixed *res;
+ string arg, rest;
+ bool mit_return;
+ int num;
+
+ while( str!="" && str[0]==' ' )
+ str = str[1..];
+ if( str=="" )
+ return FALSE;
+
+ switch( str[0] )
+ {
+ case ';': // ---------------------------------------- Kommandobeginn
+ case ',':
+ push( ";" );
+ return str[1..];
+ case '\"': // --------------------------------------- Stringkonstante
+ if( sscanf( str, "\"%s\"%s", arg, rest )==2 )
+ {
+ /* test auf numerisch fehlt hier noch */
+ push_str( arg );
+ return rest;
+ }
+ if( !sscanf( str, "\"%s\"", arg ) )
+ return error( "String ohne Ende" );
+ push_str( arg );
+ return FALSE;
+ case '#': // ---------------------------------------- Zahl
+ res = nextAlpha( str[1..] );
+ if( sscanf( res[0], "%d", num ) == 1 )
+ {
+ push( num );
+ return res[1];
+ }
+ return error( "'#': keine erlaubte Zahl" );
+ case '^': // ---------------------------------------- Hole env
+ if( !becomes_obj() )
+ return error( "'^': TOS ist kein Objekt" );
+ if( !environment(top()) )
+ return error( "'^': TOS hat kein Environment" );
+ push(environment(pop()));
+ return str[1..];
+ case '.': // ---------------------------------------- Hole aus inv
+ if( !becomes_obj() )
+ return error( "'.': TOS ist kein Objekt" );
+ res = nextAlpha( str[1..] );
+ calcinv( res[0] );
+ return res[1];
+ case '<': // ---------------------------------------- Recall
+ if( !sscanf( str, "<%s", arg ) || arg=="" )
+ return error( "'<': Variablenname fehlt" );
+ res = nextAlpha( str[1..] );
+ do_recall(res[0]);
+ return res[1];
+ case '>': // ---------------------------------------- Store
+ if( !sscanf( str, ">%s", arg ) || arg=="" )
+ return error( "'>': Variablenname fehlt" );
+ res = nextAlpha( str[1..] );
+ do_store(res[0]);
+ return res[1];
+ case '-': // ---------------------------------------- Call mit '-'
+ str = str[1..];
+ if( mit_return = (str[0] == '-') )
+ str = str[1..];
+ res = nextAlpha( str[1..] );
+ switch( str[0] )
+ {
+ case '>':
+ if( do_call( res[0], mit_return ) )
+ return res[1];
+ break;
+ case '*':
+ if( do_call_efun( res[0], mit_return ) )
+ return res[1];
+ break;
+ default:
+ return error( "'-': '>' oder '*' erwartet" );
+ }
+ return FALSE;
+ case '\'': // --------------------------------------- Call
+ str = str[1..];
+ if( mit_return = (str[0] == '\'') )
+ str = str[1..];
+ res = nextAlpha( str );
+ if( do_call( res[0], mit_return ) )
+ return res[1];
+ return FALSE;
+ case '`': // --------------------------------------- Call Efun
+ str = str[1..];
+ if( mit_return = (str[0] == '`') )
+ str = str[1..];
+ res = nextAlpha( str );
+ if( do_call_efun( res[0], mit_return ) )
+ return res[1];
+ return FALSE;
+ case '@': // --------------------------------------- Evaluate
+ str = str[1..];
+ if( mit_return = (str[0] == '@') )
+ str = str[1..];
+ if( do_lpc( str, mit_return ) )
+ return FALSE;
+ return FALSE;
+ case '!': // ------------------------------------------- META
+ if( sscanf(str,"!%d%s",num,arg)==2 )
+ {
+ if( num>=sizeof(auxstack) )
+ return error( "'"+funname+"': zu weing Argumente" );
+ push( auxstack[num] );
+ }
+ else
+ {
+ res = nextAlpha( str[1..] );
+ memory += ([ res[0]: res[1]; 1 ]);
+ return FALSE;
+ }
+ return arg;
+ default: // ----------------------------------------- default
+ res = nextAlpha( str );
+ do_cmd(res[0]);
+ return res[1];
+ }
+ return memo( "Etwas Seltsames ist passiert" );
+}
+
+static int do_cmd( string str )
+{
+ string fun, filename, *spl;
+ mixed* oldstack;
+ int i,max,num;
+
+ if( member(memory,str) )
+ {
+ fun = memory[str,0];
+ if( !memory[str,1] ) // normale Variablen
+ {
+ push( fun );
+ return TRUE;
+ }
+ oldstack = stack;
+ stack = ({});
+ spl = regexplode( fun, "![0-9][0-9]*" );
+ max = -1;
+ for( i=1; i<sizeof(spl); i+=2 )
+ if( sscanf(spl[i],"!%d",num) && max<num ) max = num;
+
+ while( !fehler_passiert && fun && fun!="" )
+ fun = parseNext( fun, oldstack, str );
+ if( fehler_passiert )
+ {
+ stack = oldstack;
+ return FALSE;
+ }
+ stack = stack + oldstack[(max+1)..];
+ return TRUE;
+ }
+ else if (fun=tcommands[str])
+ return call_other(ME,"cmd_"+fun);
+
+ if( sscanf( str, "%d", i ) )
+ push( i );
+ else
+ {
+ filename = MASTER->_get_path(str,getuid());
+ if( filename[<1] == '.' )
+ filename = filename[0..<2];
+ if( file_size( filename+".c" ) != -1 )
+ push( filename );
+ else
+ push( str );
+ }
+ return TRUE;
+}
+
+static mixed nextAlpha( string str )
+{
+ int pos;
+
+ for(
+ pos=0;
+ pos<sizeof(str) && member( " #\";,^.><", str[pos] ) == -1;
+ pos++
+ )
+ ;
+
+ if( pos==sizeof(str) )
+ return ({ str, 0 });
+ else
+ return ({ str[0..pos-1], str[pos..] });
+}
+
+static varargs void restore_stack( string* argv, int args )
+{
+ int i;
+ if( !args )
+ args = sizeof(argv);
+ if( sizeof(stack) ) push( ";" );
+ for( i=0; i<args; i++ )
+ push(argv[i]);
+}
+
+static int do_call( string fun, int mit_return )
+{
+ int args;
+ string err;
+ mixed result;
+ mixed arg, *argv;
+
+ argv = ({});
+ while( sizeof(stack) && (arg=pop())!=";" )
+ argv = ({arg}) + argv;
+ if( !becomes_obj(argv) )
+ {
+ restore_stack( argv );
+ return error( "call: Funktion nicht an Objekt gerichtet" );
+ }
+ if( !function_exists(fun,argv[0]) )
+ {
+ restore_stack(argv);
+ return error( "call: Funktion nicht gefunden" );
+ }
+
+ args = sizeof(argv);
+ argv += ({ 0,0,0,0,0 });
+ err=(catch(result=call_other(argv[0],fun,
+ argv[1],argv[2],argv[3],argv[4],argv[5])));
+ if( err )
+ {
+ restore_stack( argv, args );
+ return error( "call: "+err[1..<2] );
+ }
+ else
+ {
+ write( "=> " );
+ dump_obj( result, 3 );
+ if( mit_return )
+ push( result );
+ }
+ return TRUE;
+}
+
+static int do_call_efun( string fun, int mit_return )
+{
+ int args;
+ string err;
+ mixed result;
+ mixed arg, *argv;
+
+ argv = ({});
+ while( sizeof(stack) && (arg=pop())!=";" )
+ argv = ({arg}) + argv;
+
+ if( !function_exists( "efun_"+fun ) )
+ return error( "call efun: \""+fun+"\" nicht benutzbar" );
+ fun = "efun_"+fun;
+
+ args = sizeof(argv);
+ argv += ({ 0,0,0,0,0 });
+ err=(catch(result=call_other(ME,fun,
+ argv[0],argv[1],argv[2],argv[3],argv[4])));
+ if( err )
+ {
+ restore_stack( argv, args );
+ return error( "call efun: "+err[1..<2] );
+ }
+ else
+ {
+ write( "=> " );
+ dump_obj( result, 3 );
+ if( mit_return )
+ push( result );
+ }
+ return TRUE;
+}
+
+static int do_lpc( string str, int mit_return )
+{
+ int args, val;
+ string err;
+ string file, cmd, pre, post;
+ mixed result;
+ mixed arg, *argv;
+
+ argv = ({});
+ while( sizeof(stack) && (arg=pop())!=";" )
+ argv = argv + ({arg});
+
+ file = "/players/"+getuid()+"/.teller";
+ cmd = "#include <language.h>\n#include <properties.h>\n"
+ + "#include <moving.h>\n#include <defines.h>\n#include <terminal.h>\n"
+ + "#include <wizlevels.h>\n#include <ansi.h>\ncreate(){}doit(){";
+
+ while( str!="" && sscanf( str, "%s@%s", pre, post ) == 2 )
+ {
+ if( sscanf( str, "%s@%d@%s", pre, val, post ) == 3 )
+ {
+ if( sizeof(argv)<=val || val<0 )
+ {
+ restore_stack( argv, args );
+ return error( "lpc: Illegaler Index auf den Stack" );
+ }
+ cmd += pre + DumpObj(argv[val]);
+ str = post;
+ }
+ else
+ if( sscanf( str, "%s@%s", pre, post ) == 2 )
+ {
+ cmd += pre + "@";
+ str = post;
+ }
+ }
+ cmd += str;
+ rm( file+".c" );
+ write_file( file+".c" , cmd+";}\n" );
+ if( find_object(file) ) destruct( find_object(file) );
+ err=(catch(result=call_other(file,"doit")));
+ if( err )
+ {
+ //rm( file+".c" );
+ restore_stack( argv, args );
+ return error( "lpc: "+err[1..<2] );
+ }
+ else
+ {
+ //rm( file+".c" );
+ write( "=> " );
+ dump_obj( result, 3 );
+ if( mit_return )
+ push( result );
+ }
+ return TRUE;
+}
diff --git a/obj/tools/teller/teller.h b/obj/tools/teller/teller.h
new file mode 100644
index 0000000..841d796
--- /dev/null
+++ b/obj/tools/teller/teller.h
@@ -0,0 +1,22 @@
+#ifndef _TELLER_H_
+#define _TELLER_H_
+
+#include <properties.h>
+#include <language.h>
+#include <defines.h>
+
+#define TRUE 1
+#define FALSE 0
+#define bool int
+
+#define INFORMER "/secure/merlin"
+//#define MASTER "/secure/master"
+
+#define T_BASE "/obj/tools/teller/t_base"
+#define T_EFUN "/obj/tools/teller/t_efun"
+#define T_CMDS "/obj/tools/teller/t_cmds"
+#define T_PLAYER "/obj/tools/teller/t_player"
+
+#define HELP(x) ("/obj/tools/teller/hilfe/"+(x))
+
+#endif
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
diff --git a/obj/tools/xtool.c b/obj/tools/xtool.c
new file mode 100644
index 0000000..200c48a
--- /dev/null
+++ b/obj/tools/xtool.c
@@ -0,0 +1,7 @@
+void create()
+{
+ if(member(object_name(this_object()),'#')==-1)
+ return;
+ clone_object("/obj/tools/MGtool")->move(this_object());
+ call_out(lambda(({}),({#'destruct,({#'this_object})})),0);
+}
diff --git a/obj/tools/xxtool.c b/obj/tools/xxtool.c
new file mode 100644
index 0000000..fa3fb6c
--- /dev/null
+++ b/obj/tools/xxtool.c
@@ -0,0 +1,41 @@
+#include <properties.h>
+#include <language.h>
+
+inherit "obj/tools/MGtool";
+inherit "std/thing";
+
+void create()
+{
+ if(!clonep(this_object()))
+ return;
+ thing::create();
+ ::create();
+ SetProp(P_NAME,"Ankh");
+ SetProp(P_GENDER,NEUTER);
+ SetProp(P_IDS,({"ankh","xxtool"}));
+}
+
+string _query_short()
+{
+ ::_query_short();
+ return "Ein Ankh am Halsband.\n";
+}
+
+string _query_long()
+{
+ ::_query_long();
+ return
+ "Ein Halsband, an dem ein Ankh haengt.\n"
+ + "Ein Ankh sieht ungefaehr so aus wie ein Kreuz aber eben nicht ganz.\n";
+}
+
+string name( int d1, int d2 )
+{
+ return thing::name(d1,d2);
+}
+
+int id( string str )
+{
+ ::id(str);
+ return member( ({"ankh","xxtool"}),str ) != -1;
+}