blob: bcbb9f422b5586f2a58fef6f1d5266be284906b5 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// ----------------------------------------------------------------------
2// Tellerstapel, ein Stackorientiertes magiertool.
3// Rumata 15.09.93
4// ----------------------------------------------------------------------
Zesstraf4471b32018-11-08 23:54:53 +01005
MG Mud User88f12472016-06-24 23:31:02 +02006#include "teller.h"
Zesstraf4471b32018-11-08 23:54:53 +01007
8inherit "/std/secure_thing";
9protected functions virtual inherit "/std/util/path";
10
MG Mud User88f12472016-06-24 23:31:02 +020011inherit T_CMDS;
12inherit T_EFUN;
Zesstraf4471b32018-11-08 23:54:53 +010013inherit "/std/more";
MG Mud User88f12472016-06-24 23:31:02 +020014
15#include "/secure/wizlevels.h"
16
17nosave mapping tcommands;
18nosave string owner_name;
19
20void logaccess( string s );
21static void do_msg( string s, object o );
22static string|int parseNext( string str, mixed auxstack, string funname );
23static mixed nextAlpha( string s );
24static varargs void restore_stack( string* argv, int args );
25static int do_call( string fun, int mit_return );
26static int do_call_efun( string fun, int mit_return );
27static int do_lpc( string str, int mit_return );
28static int do_cmd( string str );
29int error( string s );
30
31static void tAddCmd( mixed cmd )
32{
33 int i;
34
35 //if (find_player("rikus")) tell_object(find_player("rikus"),sprintf("%O\n",cmd));
36 if( !pointerp(cmd) )
37 m_add(tcommands, cmd, cmd);
38 else
39 for( i=0; i<sizeof(cmd); i++ )
40 m_add(tcommands, cmd[i], cmd[0]);
41}
42
43void create()
44{
45 if( IS_BLUE(ME) ) return;
46 if( !find_player(getuid()) ) return;
47 owner_name = find_player(getuid())->name(WESSEN,1);
48
49 secure_thing::create();
50 t_cmds::create();
51 SetProp( P_NAME, "Tellerstapel" );
52 SetProp( P_GENDER, MALE );
53 AddId( ({"teller","stapel","tellerstapel"}) );
54 SetProp( P_NODROP, "Wozu denn?\n" );
55 SetProp( P_NEVERDROP, 1 );
56 SetProp( P_READ_MSG, "Die Gravur besagt: 'Aus der Rumata-Manufaktur'\n" );
57 tcommands = ([]);
58
59 tAddCmd( "say" );
60 tAddCmd( ({"names","nam"}) );
61 tAddCmd( "secureinv" );
62 tAddCmd( "logaccess" );
63 tAddCmd( "pretty" );
64 tAddCmd( "doprofile" );
65 tAddCmd( ({"clear","clr"}));
66 tAddCmd( "pop" );
67 tAddCmd( "dup" );
68 tAddCmd( "swap" );
69 tAddCmd( ({"evaluate","eval"}) );
70
71 tAddCmd( "here" );
72 tAddCmd( "me" );
73
74 tAddCmd( ({"memory","mem"}) );
75 tAddCmd( "dump" );
76 tAddCmd( "restore" );
77 tAddCmd( "top" );
78 tAddCmd( "wer" );
79 tAddCmd( ({"stack","stk"}) );
80 tAddCmd( ({"snoopers","snoop"}) );
81 tAddCmd( "callouts" );
82 tAddCmd( ({"callouts_bang","callouts!"}) );
83 tAddCmd( ({"heartbeats","beats"}) );
84 tAddCmd( "inv" );
85 tAddCmd( ({"rekinv","rinv"}) );
86 tAddCmd( "scan" );
87 tAddCmd( "if" );
88
89 tAddCmd( ({"array","arr"}) );
90 tAddCmd( ({"split","spl"}) );
91 tAddCmd( ({"player","pl"}) );
92 tAddCmd( ({"living","lv"}) );
93 tAddCmd( ({"object","ob"}) );
94
95 tAddCmd( ({"debuginfo","dinfo"}) );
96 tAddCmd( ({"clone","cln"}) );
97 tAddCmd( ({"update","upd"}) );
98 tAddCmd( ({"update_bang","update!","upd!"}) );
99 tAddCmd( ({"move","mv"}) );
100 tAddCmd( ({"destruct","dest","des"}) );
101 tAddCmd( ({"remove","rem"}) );
102 tAddCmd( ({"destruct_bang","destruct!","dest!","des!","remove!","rem!"}) );
103 tAddCmd( ({"roomupdate","rupdate","rupd","rup"}) );
104 tAddCmd( ({"roomupdate_bang","roomupdate!","rupdate!","rupd!","rup!"}) );
105 tAddCmd( ({"extroomupdate","rupdate*","rupd*","rup*"}) );
106 tAddCmd( ({"extroomupdate_bang","roomupdate*!","rupdate*!","rupd*!","rup*!",
107 "rup!*" }) );
108 tAddCmd( ({"cleanof","clnof"}) );
109 tAddCmd( ({"cleanof_bang","cleanof!","clnof!"}) );
110
111 tAddCmd( "ping" );
112}
113
Zesstraa9078422018-11-09 00:04:03 +0100114varargs void init( object orig )
MG Mud User88f12472016-06-24 23:31:02 +0200115{
116 //logaccess( "init" );
Zesstraa9078422018-11-09 00:04:03 +0100117 ::init( orig );
MG Mud User88f12472016-06-24 23:31:02 +0200118 if ( !IS_WIZARD(PL) || environment()!=PL )
119 return;
120 add_action( "parse", ",", 1 );
121 add_action( "jonglier", "jonglier", 1 );
122 add_action( "message", "message" );
123 add_action( "message", "msg" );
124}
125
126short()
127{
128 logaccess( "short" );
129 return "Ein Stapel Teller.\n";
130}
131
132id( str )
133{
134 logaccess( "id" );
135 return ::id(str);
136}
137
138name( casus, dem, force )
139{
140 logaccess( "name" );
141 return ::name( casus, dem, force );
142}
143
144long()
145{
146 string answer;
147
148 answer =
149 "Du betrachtest "+owner_name+" magischen Tellerstapel. Die einzelnen Teller sind\n"
150 +"bis auf eine kleine Inschrift auf dem Boden weiss. Wenn Du hiermit\n"
151 +"jonglierst, kann ALLES passieren.\n";
152
153 if( getuid(PL) == getuid() )
154 {
155 answer +=
156 ( mit_say
157 ? "Die Teller sind beim Jonglieren sichtbar.\n"
158 : "Die Teller sind beim Jonglieren unsichtbar.\n"
159 ) + ( mit_namen
160 ? "Die Teller nennen die Dinge beim Namen.\n"
161 : "Die Teller nennen die Dinge beim Filenamen.\n"
162 ) + ( pretty
163 ? "Die Teller haben ein verschnoerkeltes Muster.\n"
164 : "Die Teller sind geradezu schmucklos.\n"
165 ) + ( dologaccess
166 ? "Die Teller spueren Zugriffe.\n"
167 : ""
168 ) + ( secureinv
169 ? "Die Teller bewachen Dein Inventar.\n"
170 : ""
171 ) + ( do_profile
172 ? "Die Teller werden beim Einloggen aktiv.\n"
173 : ""
174 );
175 }
176 return answer;
177}
178
179void _set_autoloadobj( mixed val )
180{
181 if( !pointerp(val) ) return;
182 val += ({ 0,0,0,0,0,0 });
183 mit_namen = val[0];
184 mit_say = val[1];
185 set_heart_beat( secureinv = val[2] );
186 dologaccess = val[3];
187 pretty = val[4];
188 do_profile = val[5];
189 if( do_profile ) call_out( "_load_profile", 0, this_player() );
190}
191
192mixed _query_autoloadobj()
193{
194 return ({ mit_namen, mit_say, secureinv, dologaccess, pretty,
195 do_profile });
196}
197
198void _load_profile( object pl )
199{
200 string pf,errmsg;
201
202 if( geteuid() && pl && geteuid(pl)==geteuid()
203 && file_size(pf="/players/"+geteuid()+"/.profile.c")>0
204 && (errmsg=catch(call_other(pf,"setup",pl)))
205 )
206 printf( "Error loading profile: %O\n", errmsg );
207}
208
209void logaccess( string str )
210{
211 if( RPL && dologaccess && getuid()!=getuid(RPL) && find_player(getuid())
212 && previous_object() && getuid(previous_object()) != ROOTID
213 && query_wiz_level(getuid())>=query_wiz_level(getuid(RPL))
214 )
215 tell_object( find_player(getuid()), "MEMO: " + str + "() von "
216 + RPL->name(WEM) + " via ["
217 + object_name(previous_object())+"].\n"
218 );
219 if( secureinv && find_player(getuid()) && !member(heart_beat_info(),ME) )
220 {
221 tell_object( find_player(getuid()), "MEMO: heart_beat restartet!.\n" );
222 set_heart_beat(TRUE);
223 }
224}
225
226// ----------------------------------------------------------------------
227// Hilfe-Funktionen
228// ----------------------------------------------------------------------
229static int secure()
230{
231 int i;
232 if( process_call() || secure_level()<query_wiz_level(RPL) ) return 0;
233 for( i=0; previous_object(i)==RPL; i++ )
234 ;
235 return (!previous_object(i) || previous_object()==ME)
236 && getuid()==getuid(RPL) && IS_WIZARD(RPL);
237}
238
239int jonglier( string str )
240{
241 string arg;
242
243 logaccess( "jongliere" );
244 if( !str || id(str) || sscanf( str, "mit %s", arg ) == 1 )
245 {
246 if( !secure() )
247 write(
248 "Dieser Tellerstapel ist nichts fuer Dich. Suche Dir einen eigenen.\n"
249 );
250 else
251 write(
252 "Der Jonglierbefehl lautet \";\" oder \",\".\n"
253 + "\";hilfe <befehl>\" gibt Dir Hilfestellung.\n"
254 );
255 return TRUE;
256 }
257 return 0;
258}
259
260static int zeige_hilfe( string str )
261{
262 if( !stringp(str) ) str = "general";
263 str = implode( old_explode( HELP(str), "/../" ), "/" );
264 if( file_size(str) > 0 )
265 {
266 More( str, 1 );
267 return TRUE;
268 }
269 write( "Zu diesem Thema gibt es keine Hilfe.\n" );
270 return TRUE;
271}
272
273int message( string str )
274{
275 string pl;
276 object dest;
277
278 if( !secure() ) return FALSE;
279
280 if( str )
281 {
282 if( sscanf( str, "to %s", pl ) == 1 )
283 str = pl;
284 if( !(dest = find_player(str) ) )
285 {
286 write( capitalize(str) + " ist nicht eingeloggt.\n" );
287 return TRUE;
288 }
289 }
290 else
291 dest = 0;
292
293 do_msg( "<Mitteilung von "+PL->name(WEM)+">", dest );
294 write( "Mitteilung"
295 + ( dest ? " an " + dest->name(WEN) : "" )
296 + " kann mit '**' beendet werden.\n" );
297
298 input_to( "more_message", 0, dest );
299 return TRUE;
300}
301
302static void do_msg( string str, object obj )
303{
304 if( obj )
305 tell_object( obj, str + "\n" );
306 else
307 say( str + "\n" );
308}
309
310static int more_message( string str, object obj )
311{
312 if( str != "**" )
313 {
314 do_msg( str, obj );
315 input_to( "more_message", 0, obj );
316 }
317 else
318 do_msg( "<Ende der Mitteilung>", obj );
319 return TRUE;
320}
321
322// ----------------------------------------------------------------------
323// Parse-Funktionen
324// ----------------------------------------------------------------------
325int parse( string str )
326{
327 int i;
328 string arg, rest;
329
330 if( !secure() ) return FALSE;
331
332 // Die Hilfe faellt aus der allgemeinen Syntax heraus !
333 if( query_verb()[1..] == "hilfe" || query_verb()[1..] == "help" )
334 return zeige_hilfe( str );
335
336 if( str=this_player()->_unparsed_args() )
337 str = query_verb()[1..]+" "+str;
338 else
339 str = query_verb()[1..];
340
341 fehler_passiert = FALSE;
342 while( !fehler_passiert && str && str!="" )
343 str = parseNext( str, ({}), "-ROOT-" );
344
345 if( mit_say && !PL->QueryProp(P_INVIS) )
346 {
347 if( !fehler_passiert )
348 say( PL->name(WER)+" jongliert mit "
349 + PL->QPP(MALE,WEM,PLURAL)+" Tellern.\n" );
350 else
351 say( PL->name(WEM)+" faellt beim Jonglieren ein Teller herunter.\n" );
352 }
353 if( !fehler_passiert )
354 write( "OK.\n" );
355 return TRUE;
356}
357
358static string|int parseNext( string str, mixed auxstack, string funname )
359{
360 mixed *res;
361 string arg, rest;
362 bool mit_return;
363 int num;
364
365 while( str!="" && str[0]==' ' )
366 str = str[1..];
367 if( str=="" )
368 return FALSE;
369
370 switch( str[0] )
371 {
372 case ';': // ---------------------------------------- Kommandobeginn
373 case ',':
374 push( ";" );
375 return str[1..];
376 case '\"': // --------------------------------------- Stringkonstante
377 if( sscanf( str, "\"%s\"%s", arg, rest )==2 )
378 {
379 /* test auf numerisch fehlt hier noch */
380 push_str( arg );
381 return rest;
382 }
383 if( !sscanf( str, "\"%s\"", arg ) )
384 return error( "String ohne Ende" );
385 push_str( arg );
386 return FALSE;
387 case '#': // ---------------------------------------- Zahl
388 res = nextAlpha( str[1..] );
389 if( sscanf( res[0], "%d", num ) == 1 )
390 {
391 push( num );
392 return res[1];
393 }
394 return error( "'#': keine erlaubte Zahl" );
395 case '^': // ---------------------------------------- Hole env
396 if( !becomes_obj() )
397 return error( "'^': TOS ist kein Objekt" );
398 if( !environment(top()) )
399 return error( "'^': TOS hat kein Environment" );
400 push(environment(pop()));
401 return str[1..];
402 case '.': // ---------------------------------------- Hole aus inv
403 if( !becomes_obj() )
404 return error( "'.': TOS ist kein Objekt" );
405 res = nextAlpha( str[1..] );
406 calcinv( res[0] );
407 return res[1];
408 case '<': // ---------------------------------------- Recall
409 if( !sscanf( str, "<%s", arg ) || arg=="" )
410 return error( "'<': Variablenname fehlt" );
411 res = nextAlpha( str[1..] );
412 do_recall(res[0]);
413 return res[1];
414 case '>': // ---------------------------------------- Store
415 if( !sscanf( str, ">%s", arg ) || arg=="" )
416 return error( "'>': Variablenname fehlt" );
417 res = nextAlpha( str[1..] );
418 do_store(res[0]);
419 return res[1];
420 case '-': // ---------------------------------------- Call mit '-'
421 str = str[1..];
422 if( mit_return = (str[0] == '-') )
423 str = str[1..];
424 res = nextAlpha( str[1..] );
425 switch( str[0] )
426 {
427 case '>':
428 if( do_call( res[0], mit_return ) )
429 return res[1];
430 break;
431 case '*':
432 if( do_call_efun( res[0], mit_return ) )
433 return res[1];
434 break;
435 default:
436 return error( "'-': '>' oder '*' erwartet" );
437 }
438 return FALSE;
439 case '\'': // --------------------------------------- Call
440 str = str[1..];
441 if( mit_return = (str[0] == '\'') )
442 str = str[1..];
443 res = nextAlpha( str );
444 if( do_call( res[0], mit_return ) )
445 return res[1];
446 return FALSE;
447 case '`': // --------------------------------------- Call Efun
448 str = str[1..];
449 if( mit_return = (str[0] == '`') )
450 str = str[1..];
451 res = nextAlpha( str );
452 if( do_call_efun( res[0], mit_return ) )
453 return res[1];
454 return FALSE;
455 case '@': // --------------------------------------- Evaluate
456 str = str[1..];
457 if( mit_return = (str[0] == '@') )
458 str = str[1..];
459 if( do_lpc( str, mit_return ) )
460 return FALSE;
461 return FALSE;
462 case '!': // ------------------------------------------- META
463 if( sscanf(str,"!%d%s",num,arg)==2 )
464 {
465 if( num>=sizeof(auxstack) )
466 return error( "'"+funname+"': zu weing Argumente" );
467 push( auxstack[num] );
468 }
469 else
470 {
471 res = nextAlpha( str[1..] );
472 memory += ([ res[0]: res[1]; 1 ]);
473 return FALSE;
474 }
475 return arg;
476 default: // ----------------------------------------- default
477 res = nextAlpha( str );
478 do_cmd(res[0]);
479 return res[1];
480 }
481 return memo( "Etwas Seltsames ist passiert" );
482}
483
484static int do_cmd( string str )
485{
486 string fun, filename, *spl;
487 mixed* oldstack;
488 int i,max,num;
489
490 if( member(memory,str) )
491 {
492 fun = memory[str,0];
493 if( !memory[str,1] ) // normale Variablen
494 {
495 push( fun );
496 return TRUE;
497 }
498 oldstack = stack;
499 stack = ({});
500 spl = regexplode( fun, "![0-9][0-9]*" );
501 max = -1;
502 for( i=1; i<sizeof(spl); i+=2 )
503 if( sscanf(spl[i],"!%d",num) && max<num ) max = num;
504
505 while( !fehler_passiert && fun && fun!="" )
506 fun = parseNext( fun, oldstack, str );
507 if( fehler_passiert )
508 {
509 stack = oldstack;
510 return FALSE;
511 }
512 stack = stack + oldstack[(max+1)..];
513 return TRUE;
514 }
515 else if (fun=tcommands[str])
516 return call_other(ME,"cmd_"+fun);
517
518 if( sscanf( str, "%d", i ) )
519 push( i );
520 else
521 {
Zesstraf4471b32018-11-08 23:54:53 +0100522 filename = normalize_path(str, getuid(), 1);
MG Mud User88f12472016-06-24 23:31:02 +0200523 if( filename[<1] == '.' )
524 filename = filename[0..<2];
525 if( file_size( filename+".c" ) != -1 )
526 push( filename );
527 else
528 push( str );
529 }
530 return TRUE;
531}
532
533static mixed nextAlpha( string str )
534{
535 int pos;
536
537 for(
538 pos=0;
539 pos<sizeof(str) && member( " #\";,^.><", str[pos] ) == -1;
540 pos++
541 )
542 ;
543
544 if( pos==sizeof(str) )
545 return ({ str, 0 });
546 else
547 return ({ str[0..pos-1], str[pos..] });
548}
549
550static varargs void restore_stack( string* argv, int args )
551{
552 int i;
553 if( !args )
554 args = sizeof(argv);
555 if( sizeof(stack) ) push( ";" );
556 for( i=0; i<args; i++ )
557 push(argv[i]);
558}
559
560static int do_call( string fun, int mit_return )
561{
562 int args;
563 string err;
564 mixed result;
565 mixed arg, *argv;
566
567 argv = ({});
568 while( sizeof(stack) && (arg=pop())!=";" )
569 argv = ({arg}) + argv;
570 if( !becomes_obj(argv) )
571 {
572 restore_stack( argv );
573 return error( "call: Funktion nicht an Objekt gerichtet" );
574 }
575 if( !function_exists(fun,argv[0]) )
576 {
577 restore_stack(argv);
578 return error( "call: Funktion nicht gefunden" );
579 }
580
581 args = sizeof(argv);
582 argv += ({ 0,0,0,0,0 });
583 err=(catch(result=call_other(argv[0],fun,
584 argv[1],argv[2],argv[3],argv[4],argv[5])));
585 if( err )
586 {
587 restore_stack( argv, args );
588 return error( "call: "+err[1..<2] );
589 }
590 else
591 {
592 write( "=> " );
593 dump_obj( result, 3 );
594 if( mit_return )
595 push( result );
596 }
597 return TRUE;
598}
599
600static int do_call_efun( string fun, int mit_return )
601{
602 int args;
603 string err;
604 mixed result;
605 mixed arg, *argv;
606
607 argv = ({});
608 while( sizeof(stack) && (arg=pop())!=";" )
609 argv = ({arg}) + argv;
610
611 if( !function_exists( "efun_"+fun ) )
612 return error( "call efun: \""+fun+"\" nicht benutzbar" );
613 fun = "efun_"+fun;
614
615 args = sizeof(argv);
616 argv += ({ 0,0,0,0,0 });
617 err=(catch(result=call_other(ME,fun,
618 argv[0],argv[1],argv[2],argv[3],argv[4])));
619 if( err )
620 {
621 restore_stack( argv, args );
622 return error( "call efun: "+err[1..<2] );
623 }
624 else
625 {
626 write( "=> " );
627 dump_obj( result, 3 );
628 if( mit_return )
629 push( result );
630 }
631 return TRUE;
632}
633
634static int do_lpc( string str, int mit_return )
635{
636 int args, val;
637 string err;
638 string file, cmd, pre, post;
639 mixed result;
640 mixed arg, *argv;
641
642 argv = ({});
643 while( sizeof(stack) && (arg=pop())!=";" )
644 argv = argv + ({arg});
645
646 file = "/players/"+getuid()+"/.teller";
647 cmd = "#include <language.h>\n#include <properties.h>\n"
648 + "#include <moving.h>\n#include <defines.h>\n#include <terminal.h>\n"
649 + "#include <wizlevels.h>\n#include <ansi.h>\ncreate(){}doit(){";
650
651 while( str!="" && sscanf( str, "%s@%s", pre, post ) == 2 )
652 {
653 if( sscanf( str, "%s@%d@%s", pre, val, post ) == 3 )
654 {
655 if( sizeof(argv)<=val || val<0 )
656 {
657 restore_stack( argv, args );
658 return error( "lpc: Illegaler Index auf den Stack" );
659 }
660 cmd += pre + DumpObj(argv[val]);
661 str = post;
662 }
663 else
664 if( sscanf( str, "%s@%s", pre, post ) == 2 )
665 {
666 cmd += pre + "@";
667 str = post;
668 }
669 }
670 cmd += str;
671 rm( file+".c" );
672 write_file( file+".c" , cmd+";}\n" );
673 if( find_object(file) ) destruct( find_object(file) );
674 err=(catch(result=call_other(file,"doit")));
675 if( err )
676 {
677 //rm( file+".c" );
678 restore_stack( argv, args );
679 return error( "lpc: "+err[1..<2] );
680 }
681 else
682 {
683 //rm( file+".c" );
684 write( "=> " );
685 dump_obj( result, 3 );
686 if( mit_return )
687 push( result );
688 }
689 return TRUE;
690}