blob: beea800ee20667004972ef08d8f6c7a99875332a [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// player/commands.c -- alias, history and player command handling
4//
5// $Id: command.c 9576 2016-06-18 15:00:01Z Zesstra $
6#pragma strong_types
7#pragma save_types
8//#pragma range_check
9#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020010
11#define NEED_PROTOTYPES
12#include <player/command.h>
13#include <player/comm.h>
14#include <thing/properties.h>
15#include <living/moving.h>
16#include <player.h>
17#undef NEED_PROTOTYPES
18
19#include <properties.h>
20#include <language.h>
21#include <new_skills.h>
22#include <config.h>
23#include <defines.h>
24#include <wizlevels.h>
25#include <logging.h>
26#include <strings.h>
27
28#define CBLOG(x) log_file(SHELLLOG("DISABLECOMMANDS"),x,200000)
Zesstrafb4cc3d2019-05-06 21:16:30 +020029#define FALIASDB "/secure/zweities"
MG Mud User88f12472016-06-24 23:31:02 +020030
31#define HIST_SIZE 40
32#define EPMASTER "/secure/explorationmaster"
33
Zesstrafb4cc3d2019-05-06 21:16:30 +020034// Im Char gespeicherte Aliase
MG Mud User88f12472016-06-24 23:31:02 +020035private mapping aliases;
Zesstrafb4cc3d2019-05-06 21:16:30 +020036// Vereinigte Liste aktiver Aliase aus im Char gespeicherten und
37// Familienaliases. Wird nicht gespeichert, sondern bei Login erzeugt!
38private nosave mapping active_aliases = ([]);
39
MG Mud User88f12472016-06-24 23:31:02 +020040private string *commands;
41private int hist_size, show_processing, histmin;
42private string default_notify_fail;
43private nosave string *history, *unparsed_args, unmodified;
44private nosave int hist_now;
45private nosave object last_command_env;
46private nosave int cmds_per_time, last_chg, max_commands, *cmd_types;
47// Datenstruktur: ({Setzer, Ablaufzeit, String/Closure})
48private nosave mixed disablecommands;
49private nosave object* syntaxdb;
50
51nomask void __set_bb(int flag);
52
53static varargs int __auswerten(string str, string intern);
54varargs int SoulComm(string str, string _verb);
55varargs mixed More(string str, int fflag, string returnto);
MG Mud User88f12472016-06-24 23:31:02 +020056static void reallocate_histbuf();
57
58private void AddHistory(string str)
59{
60 if (!stringp(str) || str=="" || str[0]=='&' || str[0]=='^' ||
61 str=="hist")
62 return;
63 if (!hist_size) return;
64 if (!pointerp(history) || sizeof(history)!=hist_size)
65 reallocate_histbuf();
66 if (sizeof(str)>=histmin && history[(hist_size+hist_now-1)%hist_size]!=str)
67 history[(hist_now++)%hist_size]=str;
68}
69
70static void create()
71{
72 last_chg=0;
73 histmin=hist_now=0;
74 Set(P_LOCALCMDS,({}));
75 Set(P_LOCALCMDS,PROTECTED,F_MODE_AS);
76 Set("_syntaxdb", SECURED|SAVE, F_MODE_AS);
77
78 show_processing=1;
79 unparsed_args=({0,0,0});
80 hist_size=HIST_SIZE;
81}
82
83static int replacedisplay(string str)
84{
85 if (!str || str=="" || !sscanf(str,"%d",show_processing))
86 printf("Unzulaessige Eingabe!\n%s 0|1|2\n",query_verb());
87 printf("Ersetzungsanzeige auf Level %d.\nLevel 0: Nichts anzeigen\n"+
88 "Level 1: Nur History-Ersetzungen anzeigen\n"+
89 "Level 2: History- und Alias-Ersetzungen anzeigen\n",show_processing);
90 if (show_processing>2&&!IS_WIZARD(ME)) show_processing=2;
91 return 1;
92}
93
94static int histmin(string str)
95{
96 int len;
97
98 if (!str||!sscanf(str,"%d",len)||len<0)
99 {
100 write("Benutzung: histmin ZAHL\nLegt die Mindestlaenge fest, die eine \
101Befehlszeile haben muss, um in den\nHistory-Puffer zu gelangen. Derzeit \
102eingestellt auf "+(string)histmin+" Zeichen.\n");
103 return 1;
104 }
105 histmin=len;
106 write("Mindestlaenge auf "+(string)len+" eingestellt.\n");
107 return 1;
108}
109
110static void reallocate_histbuf()
111{
112 int i;
113
114 history=allocate(hist_size);
115 hist_now=0;
116 for (i=0;i<hist_size;i++)
117 if (!stringp(history[i]))
118 history[i]="\n\n";
119}
120
121static int histlen(string str)
122{
123 int d;
124 if (!str||!sscanf(str,"%d",d)||d<0||d>40)
125 {
126 write("Benutzung: histlen ZAHL\nZAHL muss zwischen 0 und 40 liegen.\n");
127 printf("Deine History-Buffer-Laenge liegt bei %d Befehlen.\n",hist_size);
128 return 1;
129 }
130 hist_size=d;
131 printf("Deine History-Buffer-Laenge liegt jetzt bei %d Befehlen.\n",
132 hist_size);
133 reallocate_histbuf();
134 return 1;
135}
136
Zesstra3fe70c62019-05-28 22:46:19 +0200137// Wenn keine bestimmten Aliasnamen angegeben sind, werden alle
138// Familienaliase geholt und mit den Charaliasen vereinigt.
139// Sonst werden nur bestimmte ermittelt und der Liste der aktiven
140// Aliase ersetzt/ergaenzt.
141// Wenn <verbose>, dann wird eine Meldung ausgegeben.
142private void merge_family_aliases(string *to_update, int verbose)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200143{
Zesstra3fe70c62019-05-28 22:46:19 +0200144 mapping family;
145 if (!to_update)
146 {
147 // Char- und Familienaliase addieren und als neues aktives Set
148 // speichern.
149 // Die Aliase des Char haben Prioritaet und ueberdecken die der Familie.
150 family = FALIASDB->QueryFamilyAlias();
151 active_aliases = family + aliases;
152 }
153 else
154 {
155 // Die uebergebene Liste neuholen (alle davon vorhandenen) und
156 // im aktiven Set aktualisieren/eintragen.
157 family = m_allocate(sizeof(to_update));
158 foreach(string key: &to_update)
159 {
160 family += FALIASDB->QueryFamilyAlias(key);
161 }
162 active_aliases = active_aliases + family;
163 }
164 if (verbose && sizeof(family))
165 {
166 write(break_string((
167 "Es wurden folgende Familienaliase aktiviert: "
168 +CountUp(m_indices(family)) + ".\n"),75));
169 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200170}
171
MG Mud User88f12472016-06-24 23:31:02 +0200172static void initialize()
173{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200174 if (!pointerp(history)||sizeof(history)!=hist_size)
175 reallocate_histbuf();
176 add_action("__auswerten","",1);
MG Mud User88f12472016-06-24 23:31:02 +0200177 max_commands = EPMASTER->QueryCommands();
178 cmd_types = EPMASTER->QueryCmdTypes() || ({});
179
180 if ( !mappingp(aliases) )
181 aliases = ([]);
182
Zesstra3fe70c62019-05-28 22:46:19 +0200183 merge_family_aliases(0,0);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200184
MG Mud User88f12472016-06-24 23:31:02 +0200185 if ( !pointerp(commands) )
186 commands = ({});
187
188 if (QueryProp("_syntaxdb"))
189 syntaxdb = ({find_object("/secure/syntaxdb")});
190/* else if (QueryProp(P_TESTPLAYER))
191 {
192 SetProp("_syntaxdb", 1);
193 call_out(#'_notify, 2,
194 "\nDa Du als Testspieler markiert bist, wurde bei Dir "
195 "die Syntaxsammlung eingeschaltet. Du kannst dies "
196 "wieder ausschalten. (hilfe syntaxsammlung) "
197 "Es waere schoen, wenn Du es beim Testen von "
198 "Gebieten einschaltest.", 0);
199 }*/
200}
201
202static mixed _set_default_notify_fail(string s)
203{
204 if (stringp(s)&&s!="")
205 {
206 if (s[<1]!='\n') s+="\n";
207 return default_notify_fail=s;
208 }
209 else if (!s||s=="")
210 return (default_notify_fail=0);
211}
212
213static mixed _query_default_notify_fail()
214{
215 return default_notify_fail;
216}
217
218static int set_errormessage(string s)
219{
220 if (!(s=_unparsed_args()))
221 {
222 _set_default_notify_fail(0);
223 write("Standard-Fehlermeldung auf \"Wie bitte?\" gesetzt.\n");
224 } else
225 {
226 write(break_string(sprintf("Standard-Fehlermeldung auf %s gesetzt.\n",
227 s),78));
228 _set_default_notify_fail(s);
229 }
230 return 1;
231}
232
233void reconnect()
234{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200235 if (!mappingp(aliases))
236 aliases=([]);
237
Zesstra3fe70c62019-05-28 22:46:19 +0200238 merge_family_aliases(0,0);
MG Mud User88f12472016-06-24 23:31:02 +0200239
240 if ( !pointerp(commands) )
241 commands = ({});
242
243 max_commands = EPMASTER->QueryCommands();
244 cmd_types = EPMASTER->QueryCmdTypes() || ({});
245}
246
247static int show_hist()
248{
249 int i;
250 string comm;
251
252 tell_object( ME, "Die History-Liste enthaelt folgende Kommandos:\n" );
253
254 for( i = 0; i < hist_size; i++ )
255 if ((comm=history[(hist_now+i)% hist_size])!= "\n\n")
256 tell_object( ME, " &"+(hist_now+i-hist_size)+"/-"+ (hist_size-i-1)
257 +"\t= "+comm+"\n");
258 return 1;
259}
260
Zesstrafb4cc3d2019-05-06 21:16:30 +0200261static string present_alias(<string|int>* ali)
MG Mud User88f12472016-06-24 23:31:02 +0200262{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200263 int j;
264 <string|int> k;
MG Mud User88f12472016-06-24 23:31:02 +0200265 string s,s2;
266
267 for (s="",j=sizeof(ali)-1;j>=0;j--)
268 if (intp(ali[j]))
269 if ((k=ali[j])<0)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200270 s="$"+(k==-1?"":(string)-k)+"*"+s;
MG Mud User88f12472016-06-24 23:31:02 +0200271 else
Zesstrafb4cc3d2019-05-06 21:16:30 +0200272 s="$"+(string)k+s;
MG Mud User88f12472016-06-24 23:31:02 +0200273 else
274 {
275 s2=implode(explode(ali[j],"\\"),"\\\\");
276 s=implode(explode(s2,"$"),"\\$")+s;
277 }
278 return s;
279}
280
281#define ALIFORMAT ({" %s\t= %s", "alias %s %s"})[display_as_aliascommand]
Zesstrafb4cc3d2019-05-06 21:16:30 +0200282#define FALIFORMAT ({" %s\t= %s", "alias -f %s %s"})[display_as_aliascommand]
MG Mud User88f12472016-06-24 23:31:02 +0200283// Ich weiss, den Variablennamen im define zu haben ist unfein, aber das
284// macht es im Code dann angenehm uebersichtlich. -HrT
285
Zesstrafb4cc3d2019-05-06 21:16:30 +0200286static int query_aliases(int display_as_aliascommand, int familymode)
MG Mud User88f12472016-06-24 23:31:02 +0200287{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200288 mapping selected_aliases;
MG Mud User88f12472016-06-24 23:31:02 +0200289
Zesstrafb4cc3d2019-05-06 21:16:30 +0200290 if (familymode)
291 selected_aliases=FALIASDB->QueryFamilyAlias();
292 else
293 selected_aliases = aliases;
294
Bugfix0c5133d2019-05-28 10:38:44 +0200295 string *alis = sort_array(m_indices(selected_aliases),#'>);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200296
297 if(sizeof(alis))
MG Mud User88f12472016-06-24 23:31:02 +0200298 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200299 foreach(string a : &alis)
300 a = sprintf( (familymode ? FALIFORMAT : ALIFORMAT),
301 a, present_alias(selected_aliases[a]) );
302 More("Du hast folgende "
303 + (familymode ? "Familien-" : "")
Bugfix080e3ff2019-05-28 10:06:47 +0200304 + "Aliase definiert:\n" + CountUp(alis, "\n", "\n"));
MG Mud User88f12472016-06-24 23:31:02 +0200305 }
306 else
Zesstrafb4cc3d2019-05-06 21:16:30 +0200307 write("Du hast keine "
308 +(familymode ? "Familien-" : "") + "Aliase definiert.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200309 return 1;
310}
311
MG Mud User88f12472016-06-24 23:31:02 +0200312static int alias(string str)
313{
Zesstraf86ed742019-04-25 18:37:27 +0200314 // unbearbeitetes Kommando ohne Verb ermitteln (auch ohne Trim an Anfang und
315 // Ende)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200316 string um;
Zesstraf86ed742019-04-25 18:37:27 +0200317 if (unmodified && unmodified!="")
MG Mud User88f12472016-06-24 23:31:02 +0200318 um=implode(old_explode(unmodified," ")[1..]," ");
Zesstraf86ed742019-04-25 18:37:27 +0200319
MG Mud User88f12472016-06-24 23:31:02 +0200320 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200321 if( !(str = um||_unparsed_args()) || str=="*")
Zesstrafb4cc3d2019-05-06 21:16:30 +0200322 return query_aliases(0, 0);
MG Mud User88f12472016-06-24 23:31:02 +0200323
Zesstrafb4cc3d2019-05-06 21:16:30 +0200324 // optionen auswerten bis keine mehr kommen, dabei vorne den String
325 // verkuerzen
326 int display_as_aliascommand, familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200327 while(sizeof(str) >= 2 && str[0] == '-')
328 {
329 if (str[1] == 'a')
330 display_as_aliascommand = 1;
331 else if (str[1] == 'f')
332 familymode = 1;
333 else
334 break;
335 // "-? " abschneiden
336 str = trim(str[2..], TRIM_LEFT);
MG Mud User88f12472016-06-24 23:31:02 +0200337 }
Zesstraf332ded2019-04-25 18:40:02 +0200338 if (!sizeof(str) || str=="*")
Zesstrafb4cc3d2019-05-06 21:16:30 +0200339 return query_aliases(display_as_aliascommand, familymode);
MG Mud User88f12472016-06-24 23:31:02 +0200340
Zesstrafb4cc3d2019-05-06 21:16:30 +0200341 int pos=member(str,' ');
Zesstraf86ed742019-04-25 18:37:27 +0200342 if (pos < 0) // Nur 1 Arg, Alias abfragen
MG Mud User88f12472016-06-24 23:31:02 +0200343 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200344 <string|int>* tmp;
345 if (familymode)
Bugfixc487d4c2019-05-28 11:04:29 +0200346 tmp=FALIASDB->QueryFamilyAlias(str)[str];
Zesstrafb4cc3d2019-05-06 21:16:30 +0200347 else
348 tmp=aliases[str];
349
350 if (tmp) // genau eins angegebenen
351 printf((familymode ? FALIFORMAT : ALIFORMAT)
352 +"\n",str,present_alias(tmp));
Zesstraf86ed742019-04-25 18:37:27 +0200353 else if (str[<1]=='*') // * am Ende, alle ausgeben, die passend anfangen
354 {
355 str=str[0..<2];
Zesstrafb4cc3d2019-05-06 21:16:30 +0200356 mapping selected_aliases;
357 if (familymode)
358 selected_aliases=FALIASDB->QueryFamilyAlias();
359 else
360 selected_aliases = aliases;
361 string *hits=filter(m_indices(selected_aliases),
362 function int (string alname, string start)
363 { return strstr(alname, start) == 0; },
364 str);
Zesstraf86ed742019-04-25 18:37:27 +0200365 if (!sizeof(hits))
MG Mud User88f12472016-06-24 23:31:02 +0200366 {
Zesstraf86ed742019-04-25 18:37:27 +0200367 printf("Du hast kein Alias, das mit \"%s\" anfaengt.\n", str);
368 return 1;
MG Mud User88f12472016-06-24 23:31:02 +0200369 }
Zesstraf86ed742019-04-25 18:37:27 +0200370 hits=sort_array(hits, #'>);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200371 foreach(string hit: &hits)
372 hit = sprintf((familymode ? FALIFORMAT : ALIFORMAT),
373 hit, present_alias(selected_aliases[hit]));
Zesstraf86ed742019-04-25 18:37:27 +0200374 More("Folgende Aliase beginnen mit \""+str+"\":\n"+implode(hits,"\n"));
375 }
376 else // Nix gefunden
MG Mud User88f12472016-06-24 23:31:02 +0200377 printf("Du hast kein Alias \"%s\" definiert.\n",str);
378 return 1;
379 }
Zesstraf86ed742019-04-25 18:37:27 +0200380
MG Mud User88f12472016-06-24 23:31:02 +0200381 if (!pos)
382 {
Zesstraf86ed742019-04-25 18:37:27 +0200383 write("Fehler: Leerzeichen am Alias-Anfang\n");
MG Mud User88f12472016-06-24 23:31:02 +0200384 return 1;
385 }
Zesstraf86ed742019-04-25 18:37:27 +0200386 // Kommandoverb alles bis zum ersten " ".
Zesstrafb4cc3d2019-05-06 21:16:30 +0200387 string commandverb=str[0..pos-1];
Zesstraf86ed742019-04-25 18:37:27 +0200388 if (commandverb=="unalias")
MG Mud User88f12472016-06-24 23:31:02 +0200389 {
390 write
391 ("Es nicht moeglich, den Befehl unalias zu ueberladen (waer dumm :))\n");
392 return 1;
393 }
Zesstraf86ed742019-04-25 18:37:27 +0200394 if (commandverb=="*")
MG Mud User88f12472016-06-24 23:31:02 +0200395 {
396 write
397 ("Es nicht moeglich, den Befehl \"*\" zu ueberladen.\n");
398 return 1;
399 }
400
Zesstrafb4cc3d2019-05-06 21:16:30 +0200401 // ab hier wird der Expansionstext in ein Array von Strings geparst. Alle
402 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
403 // laufender Index im Array. Negative Zahlen stehen fuer $n*, d.h. alle
404 // Argument nach dem genannten.
405 // Bsp: ({"stecke ", 1, " in ", -2 })
406 //TODO: regexplode("teile $1 mit $2* Ich bin jetzt weg, \$ verdienen!","[$][0-9][*]{0,1}",RE_PCRE)
407 str=str[pos+1..];
408 <string|int>* tmp=({}); // Alias-Array
409 int l, num;
MG Mud User88f12472016-06-24 23:31:02 +0200410 while (l=sizeof(str)) {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200411 pos=0; // Positionszaehler in str
412 int cont=1; // Statusflag fuer inneres while
413 while (cont)
414 {
415 // innere Schleife: scannt ein Argument und haengt es als Element in
416 // tmp an. Laeuft ueber den String bis Stringende oder & oder $
417 // erreicht wird, dann ist ein Argument vollstaendig und das naechste
418 // faengt an.
419 if (pos<l)
420 {
421 if(str[pos]=='\\') // escapte '\' werden zu einzelnen '\'.
422 {
MG Mud User88f12472016-06-24 23:31:02 +0200423 str=str[0..pos-1]+str[pos+1..];
424 l--;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200425 }
426 else
427 {
428 if (str[pos]=='$' || str[pos]=='&') // & ist historisch...
429 { // Argument-Platzhalter gefunden
MG Mud User88f12472016-06-24 23:31:02 +0200430 cont=0;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200431 if (pos>0) { // vorhergehender Textblock vollstaendig, anhaengen
MG Mud User88f12472016-06-24 23:31:02 +0200432 tmp+=({str[0..pos-1]});
433 }
434 if (pos==l-1) {
435 printf("Fehler: %c am Zeilenende\n",str[pos]);
436 return 1;
437 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200438 // $* oder $n ? Im Falle von $n landet in num der ASCII-Wert des
439 // Zeichens, von welchem der Wert von '0' abgezogen wird -> num
440 // enthaelt danach 0..9, wenn eine Ziffer angegeben wurde.
441 num=str[++pos]; // naechstes Zeichen holen
442 if (num=='*') {
443 // Argument 1 und pos muss wieder eins zurueck.
MG Mud User88f12472016-06-24 23:31:02 +0200444 num=1;
445 pos--;
446 } else {
447 num-='0';
448 }
449 if (num<0 || num>9) {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200450 printf("Fehler: Nach %c muss eine Ziffer oder * folgen\n",
MG Mud User88f12472016-06-24 23:31:02 +0200451 str[pos-1]);
452 return 1;
453 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200454 // str nach Argumentkennung weiter verarbeiten.
455 str=str[pos+1..];
456 // Aber fuer den Fall $n* das naechste Zeichen auch untersuchen
457 if (sizeof(str) && str[0]=='*') {
458 str=str[1..]; // auch ueberspringen
459 num = negate(num); // Im Array negiert kodieren
MG Mud User88f12472016-06-24 23:31:02 +0200460 }
461 tmp+=({num});
462 }
463 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200464 ++pos; // naechstes Zeichen im naechste inner while angucken
MG Mud User88f12472016-06-24 23:31:02 +0200465 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200466 // Ende des gesamten Strings erreicht.
467 else
468 {
469 cont=0; // ende inner while
470 // letzten Argumentblock anhaengen
471 if (str!="") tmp+=({str});
472 str=""; // beendet outer while
473 }
474 } // inner while
475 } // outer while
476
477 if (familymode)
478 {
479 int err=FALIASDB->AddOrReplaceFamilyAlias(commandverb, tmp);
480 if (err < 1)
481 {
482 printf("Neues Familienalias konnte nicht definiert werden.\n");
483 if (err==-2)
484 printf("Du hast schon genuegend Aliase definiert!\n");
485 }
486 else
487 {
488 printf("Neues Familienalias: %s\t= %s\n",
489 commandverb, present_alias(tmp));
490 // Alias direkt aktivieren, aber nur falls es keins in diesem Char gibt
491 // (was dann eh schon aktiv ist).
492 if (!member(aliases, commandverb))
493 active_aliases[commandverb] = tmp;
MG Mud User88f12472016-06-24 23:31:02 +0200494 }
495 }
MG Mud User88f12472016-06-24 23:31:02 +0200496 else
497 {
Zesstra1b98da72020-10-19 21:50:22 +0200498 if ((!aliases[commandverb]) && (sizeof(aliases)>1500))
Zesstrafb4cc3d2019-05-06 21:16:30 +0200499 printf("Du hast schon genuegend Aliase definiert!\n");
500 else
501 {
Zesstrac687e292019-05-28 22:43:11 +0200502 if (member(active_aliases, commandverb)
503 && !member(aliases, commandverb))
504 printf("Hinweis: das neue Alias ueberschattet ein Familienalias.\n");
505 aliases[commandverb] = tmp;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200506 active_aliases[commandverb] = tmp;
507 printf("Neues Alias: %s\t= %s\n",commandverb, present_alias(tmp));
Zesstra1b98da72020-10-19 21:50:22 +0200508 if (sizeof(aliases)>1000)
509 {
Arathorn6efbd2f2021-04-02 15:07:51 +0200510 printf("Du hast bereits %d Aliase definiert. Bitte raeume auf!\n",
511 sizeof(aliases));
Zesstra1b98da72020-10-19 21:50:22 +0200512 }
513 }
MG Mud User88f12472016-06-24 23:31:02 +0200514 }
515 return 1;
516}
517
518static int unalias(string str) {
MG Mud User88f12472016-06-24 23:31:02 +0200519
Zesstrafb4cc3d2019-05-06 21:16:30 +0200520 string um;
MG Mud User88f12472016-06-24 23:31:02 +0200521 if (unmodified&&unmodified!="")
522 um=implode(old_explode(unmodified," ")[1..]," ");
523 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200524 if ( !(str=um || _unparsed_args()))
525 return 0;
526
Zesstrafb4cc3d2019-05-06 21:16:30 +0200527 int familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200528 while(sizeof(str) >= 2 && str[0] == '-')
529 {
530 if (str[1] == 'f')
531 familymode = 1;
532 else
533 break;
534 // "-f " abschneiden
535 str = trim(str[2..], TRIM_LEFT);
536 }
537
MG Mud User88f12472016-06-24 23:31:02 +0200538 if (str == "*.*" || str == "*") {
539 write(break_string(
540 "Versuchs mal mit 'unalias .*', wenn Du wirklich alle Alias entfernen "
541 "willst.",78));
542 return 1;
543 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200544
545 mapping selected_aliases;
546 if (familymode)
547 selected_aliases=FALIASDB->QueryFamilyAlias();
548 else
549 selected_aliases = aliases;
550
551 string *to_delete;
552 // Genau ein Alias gegeben?
553 if (member(selected_aliases,str))
554 to_delete = ({str});
555 else // sonst als RegExp interpretieren
556 to_delete=regexp(m_indices(selected_aliases),("^"+str+"$"));
557
558 if (sizeof(to_delete))
Zesstraf86ed742019-04-25 18:37:27 +0200559 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200560 foreach(string key : to_delete)
Zesstraf86ed742019-04-25 18:37:27 +0200561 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200562 if (familymode)
563 FALIASDB->DeleteFamilyAlias(key);
564 else
565 m_delete(aliases, key);
Arathorn0875e102021-01-20 00:33:17 +0100566
567 if (!familymode || !member(aliases,key))
Zesstrafb4cc3d2019-05-06 21:16:30 +0200568 // auf jeden Fall noch deaktivieren
Arathorn0875e102021-01-20 00:33:17 +0100569 m_delete(active_aliases, key);
MG Mud User88f12472016-06-24 23:31:02 +0200570 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200571 if (sizeof(to_delete) == 1)
572 write("Du entfernst das Alias \""+ to_delete[0] +"\".\n");
573 else
574 write(break_string(("Du entfernst folgende Aliase: "
575 +CountUp(to_delete) + ".\n"),75));
Zesstra3fe70c62019-05-28 22:46:19 +0200576 // Wenn nicht im Familienmodus (d.h. Char-Aliase wurden geloescht), wird
577 // versucht, gleichnamige Familienaliase (sofern vorhanden) zu
578 // aktivieren.
579 if (!familymode)
580 {
581 merge_family_aliases(to_delete, 1);
582 }
MG Mud User88f12472016-06-24 23:31:02 +0200583 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200584 else
585 write("So ein Alias hast Du nicht definiert.\n");
586
MG Mud User88f12472016-06-24 23:31:02 +0200587 return 1;
588}
589
590varargs string _unparsed_args(int level)
591{
592 return unparsed_args[level];
593}
594
595#define ARTIKEL ({"das","der","die","des","dem","den","ein","eine","einer",\
596 "eines"})
597
598#define TRENNER ({"in","aus","ueber","auf","unter","mit","durch","fuer",\
599 "von","vom","im","aufs","ein","weg","zurueck"})
600
601static string _single_spaces(string str)
602{
603 return regreplace(str, " *", " ", 1);
604}
605
606static mixed _return_args(string str)
607{
Arathorn794677b2021-04-03 13:06:52 +0200608 string *t,*t2,verb;
MG Mud User88f12472016-06-24 23:31:02 +0200609 int i,l,j,l2;
610
611 t=explode(trim(str,TRIM_BOTH)," ");
612 verb=t[0];
613 t = t[1..];
614 if (!sizeof(t))
615 {
616 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=0;
617 return str=verb;
618 }
619 else
620 str = unparsed_args[0] = implode(t, " ");
621
622 str=unparsed_args[1]=lower_case(_single_spaces(str));
623 t=regexplode(str,"\\<im\\>|\\<ins\\>");
624 for (i=1;i<sizeof(t);i+=2) t[i]="in";
625 t=regexplode(implode(t,""),"[\\,\\!\\:][\\,\\!\\:]*");
626 l=sizeof(t);
627 for(i=1;i<l;i+=2) t[i]="";
628 t=old_explode(implode(t,"")," ")-({""});
629 for (i=sizeof(t)-2;i>=0;i--)
630 {
631 if (member(ARTIKEL,t[i])>=0)
632 t=t[0..i-1]+t[i+1..];
633 }
634 unparsed_args[2]=implode(t," ");
635 t=regexplode((str=implode(t," ")),"[0-9][0-9]*\\.");
636 if ((l=sizeof(t))>2)
637 {
638 i=1;
639 while (i<l-1)
640 {
641 t[i]=" "+t[i][0..<2]+" ";
642 if ((l2=sizeof(t2=old_explode(t[i+1]," ")))<2)
643 t[i+1]+=t[i];
644 else
645 {
646 for (j=1;j<l2;j++)
647 {
648 if (member(TRENNER,t2[j])>=0)
649 {
650 t2[j-1]+=t[i];
651 l2=0;
652 }
653 }
654 if (!l2)
655 t[i+1]=implode(t2," ");
656 else
657 t[i+1]+=t[i];
658 }
659 t[i]="";
660 i+=2;
661 }
662 str=_single_spaces(verb+" "+implode(t," "));
663 if (str[<1]==' ') str=str[0..<2];
664 } else str=verb+(str==""?"":" "+str);
665 if (show_processing>2)
666 printf("-> {%s}\n",str);
667 return str;
668}
669
670static void decay_average()
671{
672 if (absolute_hb_count()-last_chg>14)
673 {
674 last_chg=absolute_hb_count()-last_chg;
675 if (last_chg>3000)
676 last_chg=absolute_hb_count(),cmds_per_time=0;
677 else
678 {
679 while (last_chg>14)
680 cmds_per_time=cmds_per_time*9/10, last_chg-=15;
681 last_chg=absolute_hb_count()-last_chg;
682 }
683 }
684}
685
686private void DelayPreparedSpells() {
687 mixed ps;
688
689 if (pointerp(ps=QueryProp(P_PREPARED_SPELL))
690 && sizeof(ps)>=1 && intp(ps[0])) {
691 ps[0]++;
692 SetProp(P_PREPARED_SPELL,ps);
693 write("Die Ausfuehrung Deines vorbereiteten Spruches wird verzoegert.\n");
694 } else if (ps) {
695 SetProp(P_PREPARED_SPELL,0);
696 }
697}
698
699static mixed bb;
700#ifndef BBMASTER
701#define BBMASTER "/secure/bbmaster"
702#endif
703
704/** Interpretiert Aliase und History-Kommandos
MG Mud User88f12472016-06-24 23:31:02 +0200705 \param[in] str string - Kommando des Spielers
706 \return interpretiertes Alias bzw. korrektes Kommando aus der History
707*/
708private string parsecommand(string str)
709{
710 if (str[0]=='\\')
711 {
712 // Kommando soll nicht interpretiert werden
713 return str[1..];
714 }
715 else if (str[0]=='&')
716 {
717 // Kommando aus der History
718 string cmd = str[1..];
719 int cmd_size = sizeof(cmd);
720 int cmd_found = 0;
721 if (cmd_size)
722 {
723 // Test ob &<text> etwas findet
724 for (int i=0;i<hist_size-1 && !cmd_found;i++)
725 {
726 int idx = (hist_size-i+hist_now-1)%hist_size;
727 if (history[idx][0..cmd_size-1]==cmd)
728 {
729 str = history[idx];
730 cmd_found = 1;
731 }
732 if (cmd_found)
733 {
734 if (show_processing)
735 printf("[%s]\n",str);
736 }
737 }
738 }
739 if (!cmd_found)
740 {
741 // Test, ob &<nr> klappt
742 int nummer;
743 if (str=="&&")
744 str = "&-0";
745 if (sscanf(str,"&%d",nummer))
746 {
747 if (nummer<0 || (!nummer && str[1]=='-'))
748 {
749 if (nummer<-(hist_size-1))
750 nummer=-1;
751 else
752 nummer=(hist_now+nummer-1+hist_size)%hist_size;
753 }
754 else
755 {
756 if (nummer>hist_now || hist_now-nummer>hist_size)
757 nummer=-1;
758 else
759 nummer=nummer%hist_size;
760 }
761 if (nummer<0
762 || ( (cmd=history[nummer]) =="\n\n") )
763 notify_fail("Der Befehl ist nicht in der History!\n");
764 else
765 {
766 str = cmd;
767 if (show_processing)
768 printf("[%s]\n",str);
769 }
770 }
771 }
772 }
773 switch (str)
774 {
775 case "n": return "norden";
776 case "s": return "sueden";
777 case "w": return "westen";
778 case "o": return "osten";
779 case "nw": return "nordwesten";
780 case "sw": return "suedwesten";
781 case "so": return "suedosten";
782 case "no": return "nordosten";
783 case "ob": return "oben";
784 case "u": return "unten";
785 }
786 // Test auf Alias
787 string output = "";
788 string* input = explode(str," ");
789 int input_size = sizeof(input);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200790 mixed alias = active_aliases[input[0]];
MG Mud User88f12472016-06-24 23:31:02 +0200791 if (!alias)
792 return str;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200793 // Das Alias ist in ein Array von Strings gespeichert. Alle
794 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
795 // laufender Index im Array. An der Stelle werden die Argumente vom Alias
796 // eingefuegt, alle anderen Elemente werden in den output kopiert. Negative
797 // Zahlen stehen fuer $n*, d.h. alle Argument nach dem genannten.
798 // Bsp: ({"stecke ", 1, " in ", -2 })
MG Mud User88f12472016-06-24 23:31:02 +0200799 foreach (mixed a:alias)
800 {
801 if (!intp(a))
802 output += a;
803 else
804 {
805 if (a >= 0)
806 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200807 // Einzelnes Argument ($n). Argument anstelle von a einfuegen, falls
808 // genug angegeben wurden
MG Mud User88f12472016-06-24 23:31:02 +0200809 if (input_size > a)
810 output += input[a];
811 }
812 else
813 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200814 // Argumente ab n ($n*). Alle von a bis Ende einfuegen.
MG Mud User88f12472016-06-24 23:31:02 +0200815 a = -a;
816 if (input_size > a)
817 output += implode(input[a..]," ");
818 }
819 }
820 }
821 output = _single_spaces(output);
822 str = trim(output,TRIM_RIGHT);
823 if (show_processing>1)
824 printf("[%s]\n",str);
825 return str;
826}
827
828/** Behandelt alle Sonderfaelle der Eingabe des Spielers
829 Alle Befehle des Spielers, die nicht durch Objekte behandelt
830 werden sollen, werden hier erkannt und ausgefuehrt.
831 Dazu gehoert auch die Interpretation von Aliases und History-
832 befehlen.
833 \param[in] str string: Kommando des Spielers
834 \return auszufuehrendes Kommando
835 oder 0 fuer ein nicht interpretierbares Kommando
836 oder 1 fuer ein bereits durchgefuehrtes Kommando
837*/
838mixed modify_command(string str)
839{
840
841 if (extern_call() && previous_object() &&
842 (previous_object()!=this_object() || process_call()) )
843 {
844 return 0;
845 }
846
847 // Leerzeichen an den Enden abschneiden.
848 str = trim(str, TRIM_BOTH);
849
850 if (bb)
851 BBMASTER->BBWrite(trim(str,TRIM_RIGHT,"\n"), 0);
852
853 decay_average();
854 cmds_per_time+=10000;
855
856 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=unmodified="";
857
858 if (!sizeof(str)) return "";
859
860 // Kommando wird geparst
861 unmodified=parsecommand(str);
862
863 // Environment schonmal merken.
864 last_command_env=environment();
865
866 if (unmodified == "")
867 return "";
868 // Kommando in History merken, auch wenn es im Kommandoblock abgebrochen
869 // wird.
870 AddHistory(unmodified);
871
872 // pruefen, ob Kommandoblock gesetzt ist.
873 // (Fuer Magier mit mschau ein wird das ignoriert.)
874 // BTW: Es wird absichtlich nicht das Ergebnis der Closure zurueckgegeben,
875 // sonst wuerde man beliebigen Objekten nicht nur das Abbrechen, sondern
876 // auch das Aendern von Kommandos ermoeglichen.
877 if (disablecommands && !IS_LEARNING(ME) )
878 {
879 if (disablecommands[B_TIME] >= time()
880 && objectp(disablecommands[B_OBJECT]))
881 {
882 // disablecommands valid
883 // hart-kodierte Ausnameliste pruefen
884 if ( member(({"mrufe","mschau","bug","idee","typo","detail"}),
885 explode(str," ")[0]) == -1)
886 {
887 if (closurep(disablecommands[B_VALUE]))
888 {
889 if (funcall(disablecommands[B_VALUE],_return_args(unmodified)))
890 {
891 // Non-zero Closure-Ergebnis, Abbruch. Die gerufene Funktion ist
892 // fuer eine geeignete Meldung an den Spieler verantwortlich.
893 return 1;
894 }
895 }
896 // wenn Text, dann auch pruefen, ob das Kommandoverb in den Ausnahmen
897 // steht. (query_verb() geht leider hier noch nicht.)
898 else if (stringp(disablecommands[B_VALUE])
899 && member(disablecommands[B_EXCEPTIONS],
900 explode(str," ")[0]) == -1)
901 {
902 // meldung ausgeben...
903 tell_object(PL, disablecommands[B_VALUE]);
904 // und Ende...
905 return 1;
906 }
907 }
908 }
909 else disablecommands=0;
910 }
911
912 // Verfolger direkt ins Env reinholen.
913 if (remove_call_out("TakeFollowers")>=0)
914 catch(TakeFollowers();publish);
915
916 DelayPreparedSpells();
917
918 // Historyeintrag korrigieren
919 if (unmodified[0]=='^')
920 {
921 string *oldnew,pre,post;
922 if (sizeof(oldnew=explode(unmodified,"^"))>2)
923 {
924 int hist_idx = (hist_now-1)%hist_size;
925 sscanf(history[hist_idx],"%s"+oldnew[1]+"%s", pre, post);
926 unmodified = pre+oldnew[2]+post;
927 if (show_processing)
928 write("["+unmodified+"]\n");
929 // korrigiertes Kommando natuerlich auch in die History.
930 AddHistory(unmodified);
931 }
932 }
933
934 if( bb )
935 BBMASTER->BBWrite(" -> " + unmodified, 1);
936
937 if (show_processing>1)
938 printf("[%s]\n",unmodified);
939
940 mixed ret = _return_args(unmodified);
941
942 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
943 // dorthin melden.
944 if (syntaxdb)
945 {
946 if (!objectp(syntaxdb[0]))
947 syntaxdb[0] = find_object("/secure/syntaxdb");
948 if (syntaxdb[0])
949 catch(syntaxdb[0]->start_cmd(unmodified);nolog);
950 }
951 return ret;
952}
953
954static int do_list(string str)
955{
956 string *cmdlist;
957 int i;
958
959 if (!QueryProp(P_WANTS_TO_LEARN))
960 return 0;
961 cmdlist=old_explode(_unparsed_args()||"",";")-({ "" });
962 for (i=0;i<sizeof(cmdlist);i++)
963 {
964 cmdlist[i]=implode(old_explode(cmdlist[i]," ")-({}), " ");
965 if (show_processing)
966 write("["+cmdlist[i]+"]\n");
967 command(cmdlist[i]);
968 }
969 return 1;
970}
971
972//falls die aliasliste kaputt ist ...
973
974int unalias_all()
975{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200976 if (IS_ELDER(this_interactive()))
977 {
978 aliases=([]);
Zesstra3fe70c62019-05-28 22:46:19 +0200979 merge_family_aliases(0,0);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200980 }
MG Mud User88f12472016-06-24 23:31:02 +0200981 return 1;
982}
983
984object _query_last_command_env()
985{
986 return last_command_env;
987}
988
989int _query_show_alias_processing()
990{
991 return show_processing;
992}
993
994int _query_histmin()
995{
996 return histmin;
997}
998
999varargs void AddAction(mixed fun, mixed cmd, int flag, int lvl)
1000{
1001 int i;
1002 mixed *cmds;
1003
1004 log_file( "ARCH/ADD_ACTION", sprintf(
1005 "%s:\n TO: %O TP: %O PO: %O\n fun: %O cmd: %O flag: %O lvl: %O",
1006 dtime(time()), this_object(), this_player(), previous_object(),
1007 fun, cmd, flag, lvl));
1008
1009 if (!(cmds=Query(P_LOCALCMDS))) cmds=({});
1010
1011 if (!pointerp(cmd)) cmd=({cmd});
1012
1013 for (i = sizeof(cmd)-1; i>=0; i--)
1014 cmds += ({({ cmd[i] , fun, flag, lvl})});
1015
1016 Set(P_LOCALCMDS, cmds);
1017}
1018
1019static int auswerten(mixed cmd, string str)
1020{
1021 if (closurep(cmd))
1022 return funcall(cmd,str);
1023 if (stringp(cmd))
1024 return call_other(this_object(),cmd,str);
1025 return 0;
1026}
1027
1028static varargs int __auswerten(string str, string intern)
1029{
1030 string verb;
1031 mixed *cmd, cmds;
1032 int i,ret,lvl,l,vl;
1033
1034 if (!intern)
1035 verb=query_verb();
1036 else
1037 verb=intern;
1038 lvl=query_wiz_level(ME);
1039 vl=sizeof(verb);
1040 cmds=QueryProp(P_LOCALCMDS);
1041
1042 for(i=sizeof(cmds)-1;i>=0;i--)
1043 {
1044 cmd=cmds[i],l=sizeof(cmd[0]);
1045 if (cmd[0]==verb[0..l-1] && cmd[3]<=lvl && (cmd[2]||vl==l) &&
1046 (ret=auswerten(cmd[1],str)))
1047 return ret;
1048 }
1049 // An dieser Stelle gibt es hier und vermutlich nirgendwo anders etwas, was
1050 // dieses Kommando als gueltig betrachtet. Wir informieren ggf. die
1051 // Syntax-DB. (Achtung: wenn jemand ne add_action() im Spielerobjekt
1052 // einbaut, die vor dieser eingetragen wird, ist die Annahme ggf. falsch.)
1053 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1054 // dorthin melden.
1055 if (syntaxdb)
1056 {
1057 if (!objectp(syntaxdb[0]))
1058 syntaxdb[0] = find_object("/secure/syntaxdb");
1059 if (syntaxdb[0])
1060 catch(syntaxdb[0]->cmd_unsuccessful();nolog);
1061 }
1062
1063 return 0;
1064}
1065
1066public void syntax_log_ep(int type)
1067{
1068 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1069 // dorthin melden.
1070 if (syntaxdb && syntaxdb[0])
1071 {
1072 catch(syntaxdb[0]->LogEP(type);nolog);
1073 }
1074}
1075
1076static mixed _query_localcmds()
1077{
1078 mixed *l;
1079
1080 l=Query(P_LOCALCMDS);
1081 if (!pointerp(l))
1082 l=({});
1083 return ({
1084 ({"ali","alias",0,0}),
1085 ({"alias","alias",0,0}),
1086 ({"unali","unalias",1,0}),
1087 ({"histmin","histmin",0,0}),
1088 ({"histlen","histlen",0,0}),
1089 ({"hist","show_hist",0,0}),
1090 ({"history","show_hist",0,0}),
1091 ({"do","do_list",0,LEARNER_LVL}),
1092 ({"ersetzungsanzeige","replacedisplay",0,0}),
1093 ({"syntaxsammlung","collect_cmds",0,0}),
1094 ({"fehlermeldung","set_errormessage",0,SEER_LVL}),
1095 })+l;
1096}
1097
1098static int collect_cmds(string cmd)
1099{
1100 if (!stringp(cmd))
1101 {
1102 _notify("Mit diesem Befehl kannst Du mithelfen, Syntaxen im MG zu "
1103 "verbessern. Wenn Du einverstanden bist, speichern wir "
1104 "anonym (d.h. ohne Deinen Charnamen), welche Deiner Befehle "
1105 "erfolgreich und nicht erfolgreich waren. Uebliche "
1106 "Kommunikationsbefehle werden dabei nicht gespeichert.",
1107 0);
1108 _notify("Mit 'syntaxsammlung ja' kannst Du die Speicherung einschalten, "
1109 "mit 'syntaxsammlung nein' kannst Du sie ausschalten.",0);
1110 _notify("Deine Befehle werden zur Zeit"
1111 + (QueryProp("_syntaxdb") ? " " : " NICHT ")
1112 + "gespeichert.", 0);
1113 }
1114 else if (cmd == "ja")
1115 {
1116 SetProp("_syntaxdb", 1);
1117 _notify("Ab jetzt werden Deine Befehle gespeichert. Vielen Dank!", 0);
1118 }
1119 else
1120 {
1121 SetProp("_syntaxdb", 0);
1122 _notify("Ab jetzt werden Deine Befehle NICHT gespeichert.", 0);
1123 }
1124 return 1;
1125}
1126
1127int _query_command_average()
1128{
1129 decay_average();
1130 return cmds_per_time;
1131}
1132
1133nomask void __set_bb(int flag) {
1134 if( previous_object()!=find_object(BBMASTER) || process_call() )
1135 return;
1136 bb=flag;
1137}
1138
1139
1140nomask public void countCmds( int type, string key )
1141{
1142 string tmp;
1143
1144 if ( this_player() != this_interactive()
1145 || this_interactive() != this_object()
1146 || member( cmd_types, type ) < 0 )
1147 return;
1148
1149 tmp = sprintf( "%d\n%s", type, key );
1150
1151 commands -= ({ tmp });
1152 commands += ({ tmp });
1153 commands = commands[0..max_commands-1];
1154}
1155
1156
1157nomask public string *getCmds()
1158{
1159 string *tmp;
1160
1161 if ( previous_object() != find_object(BBMASTER) )
1162 return ({});
1163
1164 tmp = commands;
1165 commands = ({});
1166
1167 return tmp;
1168}
1169
1170/*
1171 * Force the monster to do a command. The force_us() function isn't
1172 * always good, because it checks the level of the caller, and this function
1173 * can be called by a room.
1174 */
1175int command_me(string cmd)
1176{
1177 if (IS_LEARNER(ME))
1178 {
1179 if (!this_interactive() || !previous_object())
1180 return 0;
1181 if( geteuid(ME)!=geteuid(this_interactive())
1182 || geteuid(ME)!=geteuid(previous_object()) )
1183 {
1184 if( query_wiz_level(ME)<query_wiz_level(previous_object()))
1185 tell_object(ME,previous_object()->name()+" zwingt Dich zu: "
1186 + cmd + ".\n");
1187 else
1188 {
1189 tell_object(ME,previous_object()->name()
1190 + " versucht, Dich zu " + cmd + " zu zwingen.\n" );
1191 return 0;
1192 }
1193 }
1194 }
1195 return command(cmd);
1196}
1197
1198
1199static mixed _query_p_lib_disablecommands() {
1200 // abgelaufen oder Objekt zerstoert? Weg damit.
1201 if (pointerp(disablecommands)
1202 && (disablecommands[B_TIME] < time()
1203 || !objectp(disablecommands[B_OBJECT])) )
1204 return(disablecommands = 0);
1205
1206 // sonst Kopie zurueck (copy(0) geht)
1207 return(copy(disablecommands));
1208}
1209
1210static mixed _set_p_lib_disablecommands(mixed data) {
1211
1212 // setzendes Objekt ermitteln, da diese Funktion nur per SetProp() gerufen
1213 // werden sollte (!), ist das PO(1);
1214 object origin = previous_object(1);
1215 // wenn nicht existent, direkt abbruch
1216 if (!objectp(origin))
1217 return _query_p_lib_disablecommands();
1218
1219 // Prop loeschen? Explizit loeschen darf jeder, allerdings nicht direkt
1220 // ungeprueft ueberschreiben.
1221 if (!data) {
1222 return (disablecommands = 0 );
1223 }
1224 // mal direkt buggen bei falschen Datentyp, damits auffaellt.
1225 if (!pointerp(data) || sizeof(data) < 2 || !intp(data[0])
1226 || (!stringp(data[1]) && !closurep(data[1]))
1227 || (sizeof(data) >= 3 && !pointerp(data[2])) )
1228 raise_error(sprintf(
1229 "Wrong data type for P_DISABLE_COMMANDS. Expected Array with "
1230 "2 or 3 elements (int, string|closure, [string*]), got %.25O\n",
1231 data));
1232
1233 // Wenn abgelaufen oder gleiches Objekt wie letztes Mal: eintragen.
1234 if (!disablecommands || (disablecommands[B_TIME] < time()
1235 || !objectp(disablecommands[B_OBJECT])
1236 || disablecommands[B_OBJECT] == origin) ) {
1237 // Loggen nur, wenn eine Closure eingetragen wird. Reduziert den
1238 // Logscroll und Strings haben deutlich weniger Missbrauchspotential.
1239 if (closurep(data[1])) {
1240 CBLOG(sprintf("[%s] CB gesetzt von %O, gueltig bis %s, Daten: %O\n",
1241 strftime("%Y%m%d-%H:%M:%S"),origin,
1242 strftime("%Y%m%d-%H:%M:%S",data[0]),
1243 (stringp(data[1]) ? regreplace(data[1],"\n","\\n",0)
1244 : data[1])));
1245 }
1246 if (sizeof(data)+1 <= B_EXCEPTIONS)
1247 disablecommands = ({ origin, data[0], data[1], ({}) });
1248 else
1249 disablecommands = ({ origin, data[0], data[1], data[2] });
1250 return(copy(disablecommands));
1251 }
1252
1253 return(_query_p_lib_disablecommands());
1254}
1255
1256static mixed _set__syntaxdb(mixed v)
1257{
1258 Set("_syntaxdb", v, F_VALUE);
1259 if (v)
1260 syntaxdb = ({find_object("/secure/syntaxdb")});
1261 else
1262 syntaxdb = 0;
1263 return QueryProp("_syntaxdb");
1264}
1265