blob: 30d1bf0649d575ccabab5d8b79799edfcc790912 [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);
Arathornb3051452021-05-13 21:13:03 +0200211
212 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200213}
214
215static mixed _query_default_notify_fail()
216{
217 return default_notify_fail;
218}
219
220static int set_errormessage(string s)
221{
222 if (!(s=_unparsed_args()))
223 {
224 _set_default_notify_fail(0);
225 write("Standard-Fehlermeldung auf \"Wie bitte?\" gesetzt.\n");
226 } else
227 {
228 write(break_string(sprintf("Standard-Fehlermeldung auf %s gesetzt.\n",
229 s),78));
230 _set_default_notify_fail(s);
231 }
232 return 1;
233}
234
235void reconnect()
236{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200237 if (!mappingp(aliases))
238 aliases=([]);
239
Zesstra3fe70c62019-05-28 22:46:19 +0200240 merge_family_aliases(0,0);
MG Mud User88f12472016-06-24 23:31:02 +0200241
242 if ( !pointerp(commands) )
243 commands = ({});
244
245 max_commands = EPMASTER->QueryCommands();
246 cmd_types = EPMASTER->QueryCmdTypes() || ({});
247}
248
249static int show_hist()
250{
251 int i;
252 string comm;
253
254 tell_object( ME, "Die History-Liste enthaelt folgende Kommandos:\n" );
255
256 for( i = 0; i < hist_size; i++ )
257 if ((comm=history[(hist_now+i)% hist_size])!= "\n\n")
258 tell_object( ME, " &"+(hist_now+i-hist_size)+"/-"+ (hist_size-i-1)
259 +"\t= "+comm+"\n");
260 return 1;
261}
262
Zesstrafb4cc3d2019-05-06 21:16:30 +0200263static string present_alias(<string|int>* ali)
MG Mud User88f12472016-06-24 23:31:02 +0200264{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200265 int j;
266 <string|int> k;
MG Mud User88f12472016-06-24 23:31:02 +0200267 string s,s2;
268
269 for (s="",j=sizeof(ali)-1;j>=0;j--)
270 if (intp(ali[j]))
271 if ((k=ali[j])<0)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200272 s="$"+(k==-1?"":(string)-k)+"*"+s;
MG Mud User88f12472016-06-24 23:31:02 +0200273 else
Zesstrafb4cc3d2019-05-06 21:16:30 +0200274 s="$"+(string)k+s;
MG Mud User88f12472016-06-24 23:31:02 +0200275 else
276 {
277 s2=implode(explode(ali[j],"\\"),"\\\\");
278 s=implode(explode(s2,"$"),"\\$")+s;
279 }
280 return s;
281}
282
283#define ALIFORMAT ({" %s\t= %s", "alias %s %s"})[display_as_aliascommand]
Zesstrafb4cc3d2019-05-06 21:16:30 +0200284#define FALIFORMAT ({" %s\t= %s", "alias -f %s %s"})[display_as_aliascommand]
MG Mud User88f12472016-06-24 23:31:02 +0200285// Ich weiss, den Variablennamen im define zu haben ist unfein, aber das
286// macht es im Code dann angenehm uebersichtlich. -HrT
287
Zesstrafb4cc3d2019-05-06 21:16:30 +0200288static int query_aliases(int display_as_aliascommand, int familymode)
MG Mud User88f12472016-06-24 23:31:02 +0200289{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200290 mapping selected_aliases;
MG Mud User88f12472016-06-24 23:31:02 +0200291
Zesstrafb4cc3d2019-05-06 21:16:30 +0200292 if (familymode)
293 selected_aliases=FALIASDB->QueryFamilyAlias();
294 else
295 selected_aliases = aliases;
296
Bugfix0c5133d2019-05-28 10:38:44 +0200297 string *alis = sort_array(m_indices(selected_aliases),#'>);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200298
299 if(sizeof(alis))
MG Mud User88f12472016-06-24 23:31:02 +0200300 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200301 foreach(string a : &alis)
302 a = sprintf( (familymode ? FALIFORMAT : ALIFORMAT),
303 a, present_alias(selected_aliases[a]) );
304 More("Du hast folgende "
305 + (familymode ? "Familien-" : "")
Bugfix080e3ff2019-05-28 10:06:47 +0200306 + "Aliase definiert:\n" + CountUp(alis, "\n", "\n"));
MG Mud User88f12472016-06-24 23:31:02 +0200307 }
308 else
Zesstrafb4cc3d2019-05-06 21:16:30 +0200309 write("Du hast keine "
310 +(familymode ? "Familien-" : "") + "Aliase definiert.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200311 return 1;
312}
313
MG Mud User88f12472016-06-24 23:31:02 +0200314static int alias(string str)
315{
Zesstraf86ed742019-04-25 18:37:27 +0200316 // unbearbeitetes Kommando ohne Verb ermitteln (auch ohne Trim an Anfang und
317 // Ende)
Zesstrafb4cc3d2019-05-06 21:16:30 +0200318 string um;
Zesstraf86ed742019-04-25 18:37:27 +0200319 if (unmodified && unmodified!="")
MG Mud User88f12472016-06-24 23:31:02 +0200320 um=implode(old_explode(unmodified," ")[1..]," ");
Zesstraf86ed742019-04-25 18:37:27 +0200321
MG Mud User88f12472016-06-24 23:31:02 +0200322 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200323 if( !(str = um||_unparsed_args()) || str=="*")
Zesstrafb4cc3d2019-05-06 21:16:30 +0200324 return query_aliases(0, 0);
MG Mud User88f12472016-06-24 23:31:02 +0200325
Zesstrafb4cc3d2019-05-06 21:16:30 +0200326 // optionen auswerten bis keine mehr kommen, dabei vorne den String
327 // verkuerzen
328 int display_as_aliascommand, familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200329 while(sizeof(str) >= 2 && str[0] == '-')
330 {
331 if (str[1] == 'a')
332 display_as_aliascommand = 1;
333 else if (str[1] == 'f')
334 familymode = 1;
335 else
336 break;
337 // "-? " abschneiden
338 str = trim(str[2..], TRIM_LEFT);
MG Mud User88f12472016-06-24 23:31:02 +0200339 }
Zesstraf332ded2019-04-25 18:40:02 +0200340 if (!sizeof(str) || str=="*")
Zesstrafb4cc3d2019-05-06 21:16:30 +0200341 return query_aliases(display_as_aliascommand, familymode);
MG Mud User88f12472016-06-24 23:31:02 +0200342
Zesstrafb4cc3d2019-05-06 21:16:30 +0200343 int pos=member(str,' ');
Zesstraf86ed742019-04-25 18:37:27 +0200344 if (pos < 0) // Nur 1 Arg, Alias abfragen
MG Mud User88f12472016-06-24 23:31:02 +0200345 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200346 <string|int>* tmp;
347 if (familymode)
Bugfixc487d4c2019-05-28 11:04:29 +0200348 tmp=FALIASDB->QueryFamilyAlias(str)[str];
Zesstrafb4cc3d2019-05-06 21:16:30 +0200349 else
350 tmp=aliases[str];
351
352 if (tmp) // genau eins angegebenen
353 printf((familymode ? FALIFORMAT : ALIFORMAT)
354 +"\n",str,present_alias(tmp));
Zesstraf86ed742019-04-25 18:37:27 +0200355 else if (str[<1]=='*') // * am Ende, alle ausgeben, die passend anfangen
356 {
357 str=str[0..<2];
Zesstrafb4cc3d2019-05-06 21:16:30 +0200358 mapping selected_aliases;
359 if (familymode)
360 selected_aliases=FALIASDB->QueryFamilyAlias();
361 else
362 selected_aliases = aliases;
363 string *hits=filter(m_indices(selected_aliases),
364 function int (string alname, string start)
365 { return strstr(alname, start) == 0; },
366 str);
Zesstraf86ed742019-04-25 18:37:27 +0200367 if (!sizeof(hits))
MG Mud User88f12472016-06-24 23:31:02 +0200368 {
Zesstraf86ed742019-04-25 18:37:27 +0200369 printf("Du hast kein Alias, das mit \"%s\" anfaengt.\n", str);
370 return 1;
MG Mud User88f12472016-06-24 23:31:02 +0200371 }
Zesstraf86ed742019-04-25 18:37:27 +0200372 hits=sort_array(hits, #'>);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200373 foreach(string hit: &hits)
374 hit = sprintf((familymode ? FALIFORMAT : ALIFORMAT),
375 hit, present_alias(selected_aliases[hit]));
Zesstraf86ed742019-04-25 18:37:27 +0200376 More("Folgende Aliase beginnen mit \""+str+"\":\n"+implode(hits,"\n"));
377 }
378 else // Nix gefunden
MG Mud User88f12472016-06-24 23:31:02 +0200379 printf("Du hast kein Alias \"%s\" definiert.\n",str);
380 return 1;
381 }
Zesstraf86ed742019-04-25 18:37:27 +0200382
MG Mud User88f12472016-06-24 23:31:02 +0200383 if (!pos)
384 {
Zesstraf86ed742019-04-25 18:37:27 +0200385 write("Fehler: Leerzeichen am Alias-Anfang\n");
MG Mud User88f12472016-06-24 23:31:02 +0200386 return 1;
387 }
Zesstraf86ed742019-04-25 18:37:27 +0200388 // Kommandoverb alles bis zum ersten " ".
Zesstrafb4cc3d2019-05-06 21:16:30 +0200389 string commandverb=str[0..pos-1];
Zesstraf86ed742019-04-25 18:37:27 +0200390 if (commandverb=="unalias")
MG Mud User88f12472016-06-24 23:31:02 +0200391 {
392 write
393 ("Es nicht moeglich, den Befehl unalias zu ueberladen (waer dumm :))\n");
394 return 1;
395 }
Zesstraf86ed742019-04-25 18:37:27 +0200396 if (commandverb=="*")
MG Mud User88f12472016-06-24 23:31:02 +0200397 {
398 write
399 ("Es nicht moeglich, den Befehl \"*\" zu ueberladen.\n");
400 return 1;
401 }
402
Zesstrafb4cc3d2019-05-06 21:16:30 +0200403 // ab hier wird der Expansionstext in ein Array von Strings geparst. Alle
404 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
405 // laufender Index im Array. Negative Zahlen stehen fuer $n*, d.h. alle
406 // Argument nach dem genannten.
407 // Bsp: ({"stecke ", 1, " in ", -2 })
408 //TODO: regexplode("teile $1 mit $2* Ich bin jetzt weg, \$ verdienen!","[$][0-9][*]{0,1}",RE_PCRE)
409 str=str[pos+1..];
410 <string|int>* tmp=({}); // Alias-Array
411 int l, num;
MG Mud User88f12472016-06-24 23:31:02 +0200412 while (l=sizeof(str)) {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200413 pos=0; // Positionszaehler in str
414 int cont=1; // Statusflag fuer inneres while
415 while (cont)
416 {
417 // innere Schleife: scannt ein Argument und haengt es als Element in
418 // tmp an. Laeuft ueber den String bis Stringende oder & oder $
419 // erreicht wird, dann ist ein Argument vollstaendig und das naechste
420 // faengt an.
421 if (pos<l)
422 {
423 if(str[pos]=='\\') // escapte '\' werden zu einzelnen '\'.
424 {
MG Mud User88f12472016-06-24 23:31:02 +0200425 str=str[0..pos-1]+str[pos+1..];
426 l--;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200427 }
428 else
429 {
430 if (str[pos]=='$' || str[pos]=='&') // & ist historisch...
431 { // Argument-Platzhalter gefunden
MG Mud User88f12472016-06-24 23:31:02 +0200432 cont=0;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200433 if (pos>0) { // vorhergehender Textblock vollstaendig, anhaengen
MG Mud User88f12472016-06-24 23:31:02 +0200434 tmp+=({str[0..pos-1]});
435 }
436 if (pos==l-1) {
437 printf("Fehler: %c am Zeilenende\n",str[pos]);
438 return 1;
439 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200440 // $* oder $n ? Im Falle von $n landet in num der ASCII-Wert des
441 // Zeichens, von welchem der Wert von '0' abgezogen wird -> num
442 // enthaelt danach 0..9, wenn eine Ziffer angegeben wurde.
443 num=str[++pos]; // naechstes Zeichen holen
444 if (num=='*') {
445 // Argument 1 und pos muss wieder eins zurueck.
MG Mud User88f12472016-06-24 23:31:02 +0200446 num=1;
447 pos--;
448 } else {
449 num-='0';
450 }
451 if (num<0 || num>9) {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200452 printf("Fehler: Nach %c muss eine Ziffer oder * folgen\n",
MG Mud User88f12472016-06-24 23:31:02 +0200453 str[pos-1]);
454 return 1;
455 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200456 // str nach Argumentkennung weiter verarbeiten.
457 str=str[pos+1..];
458 // Aber fuer den Fall $n* das naechste Zeichen auch untersuchen
459 if (sizeof(str) && str[0]=='*') {
460 str=str[1..]; // auch ueberspringen
461 num = negate(num); // Im Array negiert kodieren
MG Mud User88f12472016-06-24 23:31:02 +0200462 }
463 tmp+=({num});
464 }
465 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200466 ++pos; // naechstes Zeichen im naechste inner while angucken
MG Mud User88f12472016-06-24 23:31:02 +0200467 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200468 // Ende des gesamten Strings erreicht.
469 else
470 {
471 cont=0; // ende inner while
472 // letzten Argumentblock anhaengen
473 if (str!="") tmp+=({str});
474 str=""; // beendet outer while
475 }
476 } // inner while
477 } // outer while
478
479 if (familymode)
480 {
481 int err=FALIASDB->AddOrReplaceFamilyAlias(commandverb, tmp);
482 if (err < 1)
483 {
484 printf("Neues Familienalias konnte nicht definiert werden.\n");
485 if (err==-2)
486 printf("Du hast schon genuegend Aliase definiert!\n");
487 }
488 else
489 {
490 printf("Neues Familienalias: %s\t= %s\n",
491 commandverb, present_alias(tmp));
492 // Alias direkt aktivieren, aber nur falls es keins in diesem Char gibt
493 // (was dann eh schon aktiv ist).
494 if (!member(aliases, commandverb))
495 active_aliases[commandverb] = tmp;
MG Mud User88f12472016-06-24 23:31:02 +0200496 }
497 }
MG Mud User88f12472016-06-24 23:31:02 +0200498 else
499 {
Zesstra1b98da72020-10-19 21:50:22 +0200500 if ((!aliases[commandverb]) && (sizeof(aliases)>1500))
Zesstrafb4cc3d2019-05-06 21:16:30 +0200501 printf("Du hast schon genuegend Aliase definiert!\n");
502 else
503 {
Zesstrac687e292019-05-28 22:43:11 +0200504 if (member(active_aliases, commandverb)
505 && !member(aliases, commandverb))
506 printf("Hinweis: das neue Alias ueberschattet ein Familienalias.\n");
507 aliases[commandverb] = tmp;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200508 active_aliases[commandverb] = tmp;
509 printf("Neues Alias: %s\t= %s\n",commandverb, present_alias(tmp));
Zesstra1b98da72020-10-19 21:50:22 +0200510 if (sizeof(aliases)>1000)
511 {
Arathorn6efbd2f2021-04-02 15:07:51 +0200512 printf("Du hast bereits %d Aliase definiert. Bitte raeume auf!\n",
513 sizeof(aliases));
Zesstra1b98da72020-10-19 21:50:22 +0200514 }
515 }
MG Mud User88f12472016-06-24 23:31:02 +0200516 }
517 return 1;
518}
519
520static int unalias(string str) {
MG Mud User88f12472016-06-24 23:31:02 +0200521
Zesstrafb4cc3d2019-05-06 21:16:30 +0200522 string um;
MG Mud User88f12472016-06-24 23:31:02 +0200523 if (unmodified&&unmodified!="")
524 um=implode(old_explode(unmodified," ")[1..]," ");
525 if (um=="") um=0;
Zesstraf86ed742019-04-25 18:37:27 +0200526 if ( !(str=um || _unparsed_args()))
527 return 0;
528
Zesstrafb4cc3d2019-05-06 21:16:30 +0200529 int familymode;
Zesstraf332ded2019-04-25 18:40:02 +0200530 while(sizeof(str) >= 2 && str[0] == '-')
531 {
532 if (str[1] == 'f')
533 familymode = 1;
534 else
535 break;
536 // "-f " abschneiden
537 str = trim(str[2..], TRIM_LEFT);
538 }
539
MG Mud User88f12472016-06-24 23:31:02 +0200540 if (str == "*.*" || str == "*") {
541 write(break_string(
542 "Versuchs mal mit 'unalias .*', wenn Du wirklich alle Alias entfernen "
543 "willst.",78));
544 return 1;
545 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200546
547 mapping selected_aliases;
548 if (familymode)
549 selected_aliases=FALIASDB->QueryFamilyAlias();
550 else
551 selected_aliases = aliases;
552
553 string *to_delete;
554 // Genau ein Alias gegeben?
555 if (member(selected_aliases,str))
556 to_delete = ({str});
557 else // sonst als RegExp interpretieren
558 to_delete=regexp(m_indices(selected_aliases),("^"+str+"$"));
559
560 if (sizeof(to_delete))
Zesstraf86ed742019-04-25 18:37:27 +0200561 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200562 foreach(string key : to_delete)
Zesstraf86ed742019-04-25 18:37:27 +0200563 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200564 if (familymode)
565 FALIASDB->DeleteFamilyAlias(key);
566 else
567 m_delete(aliases, key);
Arathorn0875e102021-01-20 00:33:17 +0100568
569 if (!familymode || !member(aliases,key))
Zesstrafb4cc3d2019-05-06 21:16:30 +0200570 // auf jeden Fall noch deaktivieren
Arathorn0875e102021-01-20 00:33:17 +0100571 m_delete(active_aliases, key);
MG Mud User88f12472016-06-24 23:31:02 +0200572 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200573 if (sizeof(to_delete) == 1)
574 write("Du entfernst das Alias \""+ to_delete[0] +"\".\n");
575 else
576 write(break_string(("Du entfernst folgende Aliase: "
577 +CountUp(to_delete) + ".\n"),75));
Zesstra3fe70c62019-05-28 22:46:19 +0200578 // Wenn nicht im Familienmodus (d.h. Char-Aliase wurden geloescht), wird
579 // versucht, gleichnamige Familienaliase (sofern vorhanden) zu
580 // aktivieren.
581 if (!familymode)
582 {
583 merge_family_aliases(to_delete, 1);
584 }
MG Mud User88f12472016-06-24 23:31:02 +0200585 }
Zesstrafb4cc3d2019-05-06 21:16:30 +0200586 else
587 write("So ein Alias hast Du nicht definiert.\n");
588
MG Mud User88f12472016-06-24 23:31:02 +0200589 return 1;
590}
591
592varargs string _unparsed_args(int level)
593{
594 return unparsed_args[level];
595}
596
597#define ARTIKEL ({"das","der","die","des","dem","den","ein","eine","einer",\
598 "eines"})
599
600#define TRENNER ({"in","aus","ueber","auf","unter","mit","durch","fuer",\
601 "von","vom","im","aufs","ein","weg","zurueck"})
602
603static string _single_spaces(string str)
604{
605 return regreplace(str, " *", " ", 1);
606}
607
608static mixed _return_args(string str)
609{
Arathorn794677b2021-04-03 13:06:52 +0200610 string *t,*t2,verb;
MG Mud User88f12472016-06-24 23:31:02 +0200611 int i,l,j,l2;
612
613 t=explode(trim(str,TRIM_BOTH)," ");
614 verb=t[0];
615 t = t[1..];
616 if (!sizeof(t))
617 {
618 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=0;
619 return str=verb;
620 }
621 else
622 str = unparsed_args[0] = implode(t, " ");
623
624 str=unparsed_args[1]=lower_case(_single_spaces(str));
625 t=regexplode(str,"\\<im\\>|\\<ins\\>");
626 for (i=1;i<sizeof(t);i+=2) t[i]="in";
627 t=regexplode(implode(t,""),"[\\,\\!\\:][\\,\\!\\:]*");
628 l=sizeof(t);
629 for(i=1;i<l;i+=2) t[i]="";
630 t=old_explode(implode(t,"")," ")-({""});
631 for (i=sizeof(t)-2;i>=0;i--)
632 {
633 if (member(ARTIKEL,t[i])>=0)
634 t=t[0..i-1]+t[i+1..];
635 }
636 unparsed_args[2]=implode(t," ");
637 t=regexplode((str=implode(t," ")),"[0-9][0-9]*\\.");
638 if ((l=sizeof(t))>2)
639 {
640 i=1;
641 while (i<l-1)
642 {
643 t[i]=" "+t[i][0..<2]+" ";
644 if ((l2=sizeof(t2=old_explode(t[i+1]," ")))<2)
645 t[i+1]+=t[i];
646 else
647 {
648 for (j=1;j<l2;j++)
649 {
650 if (member(TRENNER,t2[j])>=0)
651 {
652 t2[j-1]+=t[i];
653 l2=0;
654 }
655 }
656 if (!l2)
657 t[i+1]=implode(t2," ");
658 else
659 t[i+1]+=t[i];
660 }
661 t[i]="";
662 i+=2;
663 }
664 str=_single_spaces(verb+" "+implode(t," "));
665 if (str[<1]==' ') str=str[0..<2];
666 } else str=verb+(str==""?"":" "+str);
667 if (show_processing>2)
668 printf("-> {%s}\n",str);
669 return str;
670}
671
672static void decay_average()
673{
674 if (absolute_hb_count()-last_chg>14)
675 {
676 last_chg=absolute_hb_count()-last_chg;
677 if (last_chg>3000)
678 last_chg=absolute_hb_count(),cmds_per_time=0;
679 else
680 {
681 while (last_chg>14)
682 cmds_per_time=cmds_per_time*9/10, last_chg-=15;
683 last_chg=absolute_hb_count()-last_chg;
684 }
685 }
686}
687
688private void DelayPreparedSpells() {
689 mixed ps;
690
691 if (pointerp(ps=QueryProp(P_PREPARED_SPELL))
692 && sizeof(ps)>=1 && intp(ps[0])) {
693 ps[0]++;
694 SetProp(P_PREPARED_SPELL,ps);
695 write("Die Ausfuehrung Deines vorbereiteten Spruches wird verzoegert.\n");
696 } else if (ps) {
697 SetProp(P_PREPARED_SPELL,0);
698 }
699}
700
701static mixed bb;
702#ifndef BBMASTER
703#define BBMASTER "/secure/bbmaster"
704#endif
705
706/** Interpretiert Aliase und History-Kommandos
MG Mud User88f12472016-06-24 23:31:02 +0200707 \param[in] str string - Kommando des Spielers
708 \return interpretiertes Alias bzw. korrektes Kommando aus der History
709*/
710private string parsecommand(string str)
711{
712 if (str[0]=='\\')
713 {
714 // Kommando soll nicht interpretiert werden
715 return str[1..];
716 }
717 else if (str[0]=='&')
718 {
719 // Kommando aus der History
720 string cmd = str[1..];
721 int cmd_size = sizeof(cmd);
722 int cmd_found = 0;
723 if (cmd_size)
724 {
725 // Test ob &<text> etwas findet
726 for (int i=0;i<hist_size-1 && !cmd_found;i++)
727 {
728 int idx = (hist_size-i+hist_now-1)%hist_size;
729 if (history[idx][0..cmd_size-1]==cmd)
730 {
731 str = history[idx];
732 cmd_found = 1;
733 }
734 if (cmd_found)
735 {
736 if (show_processing)
737 printf("[%s]\n",str);
738 }
739 }
740 }
741 if (!cmd_found)
742 {
743 // Test, ob &<nr> klappt
744 int nummer;
745 if (str=="&&")
746 str = "&-0";
747 if (sscanf(str,"&%d",nummer))
748 {
749 if (nummer<0 || (!nummer && str[1]=='-'))
750 {
751 if (nummer<-(hist_size-1))
752 nummer=-1;
753 else
754 nummer=(hist_now+nummer-1+hist_size)%hist_size;
755 }
756 else
757 {
758 if (nummer>hist_now || hist_now-nummer>hist_size)
759 nummer=-1;
760 else
761 nummer=nummer%hist_size;
762 }
763 if (nummer<0
764 || ( (cmd=history[nummer]) =="\n\n") )
765 notify_fail("Der Befehl ist nicht in der History!\n");
766 else
767 {
768 str = cmd;
769 if (show_processing)
770 printf("[%s]\n",str);
771 }
772 }
773 }
774 }
775 switch (str)
776 {
777 case "n": return "norden";
778 case "s": return "sueden";
779 case "w": return "westen";
780 case "o": return "osten";
781 case "nw": return "nordwesten";
782 case "sw": return "suedwesten";
783 case "so": return "suedosten";
784 case "no": return "nordosten";
785 case "ob": return "oben";
786 case "u": return "unten";
787 }
788 // Test auf Alias
789 string output = "";
790 string* input = explode(str," ");
791 int input_size = sizeof(input);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200792 mixed alias = active_aliases[input[0]];
MG Mud User88f12472016-06-24 23:31:02 +0200793 if (!alias)
794 return str;
Zesstrafb4cc3d2019-05-06 21:16:30 +0200795 // Das Alias ist in ein Array von Strings gespeichert. Alle
796 // Alias-Argument ($n, $* oder $n*) stehen an der jeweiligen Stelle als
797 // laufender Index im Array. An der Stelle werden die Argumente vom Alias
798 // eingefuegt, alle anderen Elemente werden in den output kopiert. Negative
799 // Zahlen stehen fuer $n*, d.h. alle Argument nach dem genannten.
800 // Bsp: ({"stecke ", 1, " in ", -2 })
MG Mud User88f12472016-06-24 23:31:02 +0200801 foreach (mixed a:alias)
802 {
803 if (!intp(a))
804 output += a;
805 else
806 {
807 if (a >= 0)
808 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200809 // Einzelnes Argument ($n). Argument anstelle von a einfuegen, falls
810 // genug angegeben wurden
MG Mud User88f12472016-06-24 23:31:02 +0200811 if (input_size > a)
812 output += input[a];
813 }
814 else
815 {
Zesstrafb4cc3d2019-05-06 21:16:30 +0200816 // Argumente ab n ($n*). Alle von a bis Ende einfuegen.
MG Mud User88f12472016-06-24 23:31:02 +0200817 a = -a;
818 if (input_size > a)
819 output += implode(input[a..]," ");
820 }
821 }
822 }
823 output = _single_spaces(output);
824 str = trim(output,TRIM_RIGHT);
825 if (show_processing>1)
826 printf("[%s]\n",str);
827 return str;
828}
829
830/** Behandelt alle Sonderfaelle der Eingabe des Spielers
831 Alle Befehle des Spielers, die nicht durch Objekte behandelt
832 werden sollen, werden hier erkannt und ausgefuehrt.
833 Dazu gehoert auch die Interpretation von Aliases und History-
834 befehlen.
835 \param[in] str string: Kommando des Spielers
836 \return auszufuehrendes Kommando
837 oder 0 fuer ein nicht interpretierbares Kommando
838 oder 1 fuer ein bereits durchgefuehrtes Kommando
839*/
840mixed modify_command(string str)
841{
842
843 if (extern_call() && previous_object() &&
844 (previous_object()!=this_object() || process_call()) )
845 {
846 return 0;
847 }
848
849 // Leerzeichen an den Enden abschneiden.
850 str = trim(str, TRIM_BOTH);
851
852 if (bb)
853 BBMASTER->BBWrite(trim(str,TRIM_RIGHT,"\n"), 0);
854
855 decay_average();
856 cmds_per_time+=10000;
857
858 unparsed_args[0]=unparsed_args[1]=unparsed_args[2]=unmodified="";
859
860 if (!sizeof(str)) return "";
861
862 // Kommando wird geparst
863 unmodified=parsecommand(str);
864
865 // Environment schonmal merken.
866 last_command_env=environment();
867
868 if (unmodified == "")
869 return "";
870 // Kommando in History merken, auch wenn es im Kommandoblock abgebrochen
871 // wird.
872 AddHistory(unmodified);
873
874 // pruefen, ob Kommandoblock gesetzt ist.
875 // (Fuer Magier mit mschau ein wird das ignoriert.)
876 // BTW: Es wird absichtlich nicht das Ergebnis der Closure zurueckgegeben,
877 // sonst wuerde man beliebigen Objekten nicht nur das Abbrechen, sondern
878 // auch das Aendern von Kommandos ermoeglichen.
879 if (disablecommands && !IS_LEARNING(ME) )
880 {
881 if (disablecommands[B_TIME] >= time()
882 && objectp(disablecommands[B_OBJECT]))
883 {
884 // disablecommands valid
885 // hart-kodierte Ausnameliste pruefen
886 if ( member(({"mrufe","mschau","bug","idee","typo","detail"}),
887 explode(str," ")[0]) == -1)
888 {
889 if (closurep(disablecommands[B_VALUE]))
890 {
891 if (funcall(disablecommands[B_VALUE],_return_args(unmodified)))
892 {
893 // Non-zero Closure-Ergebnis, Abbruch. Die gerufene Funktion ist
894 // fuer eine geeignete Meldung an den Spieler verantwortlich.
895 return 1;
896 }
897 }
898 // wenn Text, dann auch pruefen, ob das Kommandoverb in den Ausnahmen
899 // steht. (query_verb() geht leider hier noch nicht.)
900 else if (stringp(disablecommands[B_VALUE])
901 && member(disablecommands[B_EXCEPTIONS],
902 explode(str," ")[0]) == -1)
903 {
904 // meldung ausgeben...
905 tell_object(PL, disablecommands[B_VALUE]);
906 // und Ende...
907 return 1;
908 }
909 }
910 }
911 else disablecommands=0;
912 }
913
914 // Verfolger direkt ins Env reinholen.
915 if (remove_call_out("TakeFollowers")>=0)
916 catch(TakeFollowers();publish);
917
918 DelayPreparedSpells();
919
920 // Historyeintrag korrigieren
921 if (unmodified[0]=='^')
922 {
923 string *oldnew,pre,post;
924 if (sizeof(oldnew=explode(unmodified,"^"))>2)
925 {
926 int hist_idx = (hist_now-1)%hist_size;
927 sscanf(history[hist_idx],"%s"+oldnew[1]+"%s", pre, post);
928 unmodified = pre+oldnew[2]+post;
929 if (show_processing)
930 write("["+unmodified+"]\n");
931 // korrigiertes Kommando natuerlich auch in die History.
932 AddHistory(unmodified);
933 }
934 }
935
936 if( bb )
937 BBMASTER->BBWrite(" -> " + unmodified, 1);
938
939 if (show_processing>1)
940 printf("[%s]\n",unmodified);
941
942 mixed ret = _return_args(unmodified);
943
944 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
945 // dorthin melden.
946 if (syntaxdb)
947 {
948 if (!objectp(syntaxdb[0]))
949 syntaxdb[0] = find_object("/secure/syntaxdb");
950 if (syntaxdb[0])
951 catch(syntaxdb[0]->start_cmd(unmodified);nolog);
952 }
953 return ret;
954}
955
956static int do_list(string str)
957{
958 string *cmdlist;
959 int i;
960
961 if (!QueryProp(P_WANTS_TO_LEARN))
962 return 0;
963 cmdlist=old_explode(_unparsed_args()||"",";")-({ "" });
964 for (i=0;i<sizeof(cmdlist);i++)
965 {
966 cmdlist[i]=implode(old_explode(cmdlist[i]," ")-({}), " ");
967 if (show_processing)
968 write("["+cmdlist[i]+"]\n");
969 command(cmdlist[i]);
970 }
971 return 1;
972}
973
974//falls die aliasliste kaputt ist ...
975
976int unalias_all()
977{
Zesstrafb4cc3d2019-05-06 21:16:30 +0200978 if (IS_ELDER(this_interactive()))
979 {
980 aliases=([]);
Zesstra3fe70c62019-05-28 22:46:19 +0200981 merge_family_aliases(0,0);
Zesstrafb4cc3d2019-05-06 21:16:30 +0200982 }
MG Mud User88f12472016-06-24 23:31:02 +0200983 return 1;
984}
985
986object _query_last_command_env()
987{
988 return last_command_env;
989}
990
991int _query_show_alias_processing()
992{
993 return show_processing;
994}
995
996int _query_histmin()
997{
998 return histmin;
999}
1000
1001varargs void AddAction(mixed fun, mixed cmd, int flag, int lvl)
1002{
1003 int i;
1004 mixed *cmds;
1005
1006 log_file( "ARCH/ADD_ACTION", sprintf(
1007 "%s:\n TO: %O TP: %O PO: %O\n fun: %O cmd: %O flag: %O lvl: %O",
1008 dtime(time()), this_object(), this_player(), previous_object(),
1009 fun, cmd, flag, lvl));
1010
1011 if (!(cmds=Query(P_LOCALCMDS))) cmds=({});
1012
1013 if (!pointerp(cmd)) cmd=({cmd});
1014
1015 for (i = sizeof(cmd)-1; i>=0; i--)
1016 cmds += ({({ cmd[i] , fun, flag, lvl})});
1017
1018 Set(P_LOCALCMDS, cmds);
1019}
1020
1021static int auswerten(mixed cmd, string str)
1022{
1023 if (closurep(cmd))
1024 return funcall(cmd,str);
1025 if (stringp(cmd))
1026 return call_other(this_object(),cmd,str);
1027 return 0;
1028}
1029
1030static varargs int __auswerten(string str, string intern)
1031{
1032 string verb;
1033 mixed *cmd, cmds;
1034 int i,ret,lvl,l,vl;
1035
1036 if (!intern)
1037 verb=query_verb();
1038 else
1039 verb=intern;
1040 lvl=query_wiz_level(ME);
1041 vl=sizeof(verb);
1042 cmds=QueryProp(P_LOCALCMDS);
1043
1044 for(i=sizeof(cmds)-1;i>=0;i--)
1045 {
1046 cmd=cmds[i],l=sizeof(cmd[0]);
1047 if (cmd[0]==verb[0..l-1] && cmd[3]<=lvl && (cmd[2]||vl==l) &&
1048 (ret=auswerten(cmd[1],str)))
1049 return ret;
1050 }
1051 // An dieser Stelle gibt es hier und vermutlich nirgendwo anders etwas, was
1052 // dieses Kommando als gueltig betrachtet. Wir informieren ggf. die
1053 // Syntax-DB. (Achtung: wenn jemand ne add_action() im Spielerobjekt
1054 // einbaut, die vor dieser eingetragen wird, ist die Annahme ggf. falsch.)
1055 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1056 // dorthin melden.
1057 if (syntaxdb)
1058 {
1059 if (!objectp(syntaxdb[0]))
1060 syntaxdb[0] = find_object("/secure/syntaxdb");
1061 if (syntaxdb[0])
1062 catch(syntaxdb[0]->cmd_unsuccessful();nolog);
1063 }
1064
1065 return 0;
1066}
1067
1068public void syntax_log_ep(int type)
1069{
1070 // wenn Spieler eingewilligt hat und die SyntaxDB geladen ist, Befehl
1071 // dorthin melden.
1072 if (syntaxdb && syntaxdb[0])
1073 {
1074 catch(syntaxdb[0]->LogEP(type);nolog);
1075 }
1076}
1077
1078static mixed _query_localcmds()
1079{
1080 mixed *l;
1081
1082 l=Query(P_LOCALCMDS);
1083 if (!pointerp(l))
1084 l=({});
1085 return ({
1086 ({"ali","alias",0,0}),
1087 ({"alias","alias",0,0}),
1088 ({"unali","unalias",1,0}),
1089 ({"histmin","histmin",0,0}),
1090 ({"histlen","histlen",0,0}),
1091 ({"hist","show_hist",0,0}),
1092 ({"history","show_hist",0,0}),
1093 ({"do","do_list",0,LEARNER_LVL}),
1094 ({"ersetzungsanzeige","replacedisplay",0,0}),
1095 ({"syntaxsammlung","collect_cmds",0,0}),
1096 ({"fehlermeldung","set_errormessage",0,SEER_LVL}),
1097 })+l;
1098}
1099
1100static int collect_cmds(string cmd)
1101{
1102 if (!stringp(cmd))
1103 {
Bugfixb1d9b4d2021-09-14 20:07:04 +02001104 ReceiveNotify("Mit diesem Befehl kannst Du mithelfen, Syntaxen im MG zu "
MG Mud User88f12472016-06-24 23:31:02 +02001105 "verbessern. Wenn Du einverstanden bist, speichern wir "
1106 "anonym (d.h. ohne Deinen Charnamen), welche Deiner Befehle "
1107 "erfolgreich und nicht erfolgreich waren. Uebliche "
1108 "Kommunikationsbefehle werden dabei nicht gespeichert.",
1109 0);
Bugfixb1d9b4d2021-09-14 20:07:04 +02001110 ReceiveNotify("Mit 'syntaxsammlung ja' kannst Du die Speicherung einschalten, "
MG Mud User88f12472016-06-24 23:31:02 +02001111 "mit 'syntaxsammlung nein' kannst Du sie ausschalten.",0);
Bugfixb1d9b4d2021-09-14 20:07:04 +02001112 ReceiveNotify("Deine Befehle werden zur Zeit"
MG Mud User88f12472016-06-24 23:31:02 +02001113 + (QueryProp("_syntaxdb") ? " " : " NICHT ")
1114 + "gespeichert.", 0);
1115 }
1116 else if (cmd == "ja")
1117 {
1118 SetProp("_syntaxdb", 1);
Bugfixb1d9b4d2021-09-14 20:07:04 +02001119 ReceiveNotify("Ab jetzt werden Deine Befehle gespeichert. Vielen Dank!", 0);
MG Mud User88f12472016-06-24 23:31:02 +02001120 }
1121 else
1122 {
1123 SetProp("_syntaxdb", 0);
Bugfixb1d9b4d2021-09-14 20:07:04 +02001124 ReceiveNotify("Ab jetzt werden Deine Befehle NICHT gespeichert.", 0);
MG Mud User88f12472016-06-24 23:31:02 +02001125 }
1126 return 1;
1127}
1128
1129int _query_command_average()
1130{
1131 decay_average();
1132 return cmds_per_time;
1133}
1134
1135nomask void __set_bb(int flag) {
1136 if( previous_object()!=find_object(BBMASTER) || process_call() )
1137 return;
1138 bb=flag;
1139}
1140
1141
1142nomask public void countCmds( int type, string key )
1143{
1144 string tmp;
1145
1146 if ( this_player() != this_interactive()
1147 || this_interactive() != this_object()
1148 || member( cmd_types, type ) < 0 )
1149 return;
1150
1151 tmp = sprintf( "%d\n%s", type, key );
1152
1153 commands -= ({ tmp });
1154 commands += ({ tmp });
1155 commands = commands[0..max_commands-1];
1156}
1157
1158
1159nomask public string *getCmds()
1160{
1161 string *tmp;
1162
1163 if ( previous_object() != find_object(BBMASTER) )
1164 return ({});
1165
1166 tmp = commands;
1167 commands = ({});
1168
1169 return tmp;
1170}
1171
1172/*
1173 * Force the monster to do a command. The force_us() function isn't
1174 * always good, because it checks the level of the caller, and this function
1175 * can be called by a room.
1176 */
1177int command_me(string cmd)
1178{
1179 if (IS_LEARNER(ME))
1180 {
1181 if (!this_interactive() || !previous_object())
1182 return 0;
1183 if( geteuid(ME)!=geteuid(this_interactive())
1184 || geteuid(ME)!=geteuid(previous_object()) )
1185 {
1186 if( query_wiz_level(ME)<query_wiz_level(previous_object()))
1187 tell_object(ME,previous_object()->name()+" zwingt Dich zu: "
1188 + cmd + ".\n");
1189 else
1190 {
1191 tell_object(ME,previous_object()->name()
1192 + " versucht, Dich zu " + cmd + " zu zwingen.\n" );
1193 return 0;
1194 }
1195 }
1196 }
1197 return command(cmd);
1198}
1199
1200
1201static mixed _query_p_lib_disablecommands() {
1202 // abgelaufen oder Objekt zerstoert? Weg damit.
1203 if (pointerp(disablecommands)
1204 && (disablecommands[B_TIME] < time()
1205 || !objectp(disablecommands[B_OBJECT])) )
1206 return(disablecommands = 0);
1207
1208 // sonst Kopie zurueck (copy(0) geht)
1209 return(copy(disablecommands));
1210}
1211
1212static mixed _set_p_lib_disablecommands(mixed data) {
1213
1214 // setzendes Objekt ermitteln, da diese Funktion nur per SetProp() gerufen
1215 // werden sollte (!), ist das PO(1);
1216 object origin = previous_object(1);
1217 // wenn nicht existent, direkt abbruch
1218 if (!objectp(origin))
1219 return _query_p_lib_disablecommands();
1220
1221 // Prop loeschen? Explizit loeschen darf jeder, allerdings nicht direkt
1222 // ungeprueft ueberschreiben.
1223 if (!data) {
1224 return (disablecommands = 0 );
1225 }
1226 // mal direkt buggen bei falschen Datentyp, damits auffaellt.
1227 if (!pointerp(data) || sizeof(data) < 2 || !intp(data[0])
1228 || (!stringp(data[1]) && !closurep(data[1]))
1229 || (sizeof(data) >= 3 && !pointerp(data[2])) )
1230 raise_error(sprintf(
1231 "Wrong data type for P_DISABLE_COMMANDS. Expected Array with "
1232 "2 or 3 elements (int, string|closure, [string*]), got %.25O\n",
1233 data));
1234
1235 // Wenn abgelaufen oder gleiches Objekt wie letztes Mal: eintragen.
1236 if (!disablecommands || (disablecommands[B_TIME] < time()
1237 || !objectp(disablecommands[B_OBJECT])
1238 || disablecommands[B_OBJECT] == origin) ) {
1239 // Loggen nur, wenn eine Closure eingetragen wird. Reduziert den
1240 // Logscroll und Strings haben deutlich weniger Missbrauchspotential.
1241 if (closurep(data[1])) {
1242 CBLOG(sprintf("[%s] CB gesetzt von %O, gueltig bis %s, Daten: %O\n",
1243 strftime("%Y%m%d-%H:%M:%S"),origin,
1244 strftime("%Y%m%d-%H:%M:%S",data[0]),
1245 (stringp(data[1]) ? regreplace(data[1],"\n","\\n",0)
1246 : data[1])));
1247 }
1248 if (sizeof(data)+1 <= B_EXCEPTIONS)
1249 disablecommands = ({ origin, data[0], data[1], ({}) });
1250 else
1251 disablecommands = ({ origin, data[0], data[1], data[2] });
1252 return(copy(disablecommands));
1253 }
1254
1255 return(_query_p_lib_disablecommands());
1256}
1257
1258static mixed _set__syntaxdb(mixed v)
1259{
1260 Set("_syntaxdb", v, F_VALUE);
1261 if (v)
1262 syntaxdb = ({find_object("/secure/syntaxdb")});
1263 else
1264 syntaxdb = 0;
1265 return QueryProp("_syntaxdb");
1266}
1267