blob: 3dc879d5a42d7efc5a4db257a4933b46d456304b [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// thing/commands.c -- thing description
4//
5// $Id: commands.c 9514 2016-02-23 20:33:09Z Gloinson $
6//
7// Aus Regenbogen MUDLib
8// aus Gueldenland/Wunderland MUDlib (Morgengrauen MUDlib)
9//
10// P_COMMANDS data-structure:
11//
12// AddCmd(verb,fun1,1);
13// AddCmd(verb+syn1a|syn1b&syn2a|syn2b|syn2c,fun2,
Zesstra16698ff2016-12-13 22:19:16 +010014// error1_notify|error2_notify^error2_write);
MG Mud User88f12472016-06-24 23:31:02 +020015// -->
Zesstra16698ff2016-12-13 22:19:16 +010016// ([verb:
17// ({fun1,fun2}); // funs
18// ({1,({error1_notify, error2_write^error2_say, 1})}); // flags
19// ({0,({({syn1a,syn1b}),({syn2a,syn2b,syn2c})})}); // rules
20// 0; // IDs
21// ({closure auf fun1, closure auf fun2}) ]) // Cache
MG Mud User88f12472016-06-24 23:31:02 +020022//
Zesstra16698ff2016-12-13 22:19:16 +010023// Funs: ({<fun1> ,...
24// 'fun' kann sein: Closure
25// String: Methodenname - wird etwas geprueft
26// Objekt: wenn keine Methode, this_object() fuer
27// intern, previous_object() fuer extern
28// 0 (erloschenes externes Objekt)
MG Mud User88f12472016-06-24 23:31:02 +020029// Rules: ({<Regelsatz fuer fun1>, ({<1. Synonymgruppe>,
Zesstra16698ff2016-12-13 22:19:16 +010030// <2. Synonymgruppe, ...}), ...})
MG Mud User88f12472016-06-24 23:31:02 +020031// Flags: ({<Flag fuer fun1>, ({<Fehlermeldung 1. Synonymgruppe>, ... ,
Zesstra16698ff2016-12-13 22:19:16 +010032// [, Index fuer write anstatt notify_fail]}),
33// ... })
MG Mud User88f12472016-06-24 23:31:02 +020034// IDs: 0 oder ({<ID fuer fun1>}) oder ({0, <ID fuer fun2>}) ...
Zesstra16698ff2016-12-13 22:19:16 +010035// Cache: ({<closure fuer fun1>, ...
36// Cache-Closures sind bei Export (QueryProp) immer genullt
MG Mud User88f12472016-06-24 23:31:02 +020037#pragma strict_types
38#pragma save_types
39#pragma range_check
40#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020041
42#include <moving.h>
43#include <thing/language.h>
44#include <exploration.h>
Zesstrabab5a9d2016-07-30 12:53:35 +020045#include <defines.h>
46#include <living/comm.h>
Zesstra16698ff2016-12-13 22:19:16 +010047#include <functionlist.h>
MG Mud User88f12472016-06-24 23:31:02 +020048
49#define NEED_PROTOTYPES
Zesstrabab5a9d2016-07-30 12:53:35 +020050#include <thing/properties.h>
MG Mud User88f12472016-06-24 23:31:02 +020051#include <thing/description.h>
52#include <thing/commands.h>
53#undef NEED_PROTOTYPES
54
Zesstra16698ff2016-12-13 22:19:16 +010055#define CMDS_WIDTH 5
56// Mapping-Indizes
57#define CMDIDX_FUN 0
58#define CMDIDX_FLAG 1
59#define CMDIDX_RULE 2
60#define CMDIDX_ID 3
61#define CMDIDX_CACHE 4
62
MG Mud User88f12472016-06-24 23:31:02 +020063#ifdef DBG
64#undef DBG
65#endif
66#define DBG(x) printf("Object %O tmpstr=%s\n", explode(object_name(this_object()),"#")[1], x);
67
68private nosave mapping added_cmds;
69
Zesstra2a4b5702016-08-16 19:08:47 +020070protected int _cmd_syntaxhelp(string str, mixed *args)
Zesstrabab5a9d2016-07-30 12:53:35 +020071{
72 mapping|closure restr;
73 mixed help = QueryProp(P_SYNTAX_HELP);
74 if (pointerp(help))
75 {
76 restr = help[1];
77 help = help[0];
78 }
79 // Restriktionen vor dem Anzeigen pruefen.
80 if (mappingp(restr))
81 {
bugfixd94d0932020-04-08 11:27:13 +020082 string res = ({string})"/std/restriction_checker"->check_restrictions(PL,restr);
Zesstrabab5a9d2016-07-30 12:53:35 +020083 if (res)
84 {
bugfixd94d0932020-04-08 11:27:13 +020085 ({int})PL->ReceiveMsg("Fuer " + name(WEN,1) + " darfst Du "
Zesstrabab5a9d2016-07-30 12:53:35 +020086 "die Syntaxhilfe (noch) nicht lesen:\n"
87 + res,
88 MT_NOTIFICATION|MSG_BS_LEAVE_LFS,
89 "syntaxhilfe",0,this_object());
90 return 1;
91 }
92 }
93 else if (closurep(restr))
94 {
95 string res = funcall(restr, ME);
96 if (res)
97 {
98 if (intp(res))
bugfixd94d0932020-04-08 11:27:13 +020099 ({int})PL->ReceiveMsg("Fuer " + name(WEN,1) + " darfst Du "
Zesstrabab5a9d2016-07-30 12:53:35 +0200100 "die Syntaxhilfe (noch) nicht lesen.",
101 MT_NOTIFICATION|MSG_BS_LEAVE_LFS,
102 "syntaxhilfe",0,this_object());
103 else if (stringp(res))
bugfixd94d0932020-04-08 11:27:13 +0200104 ({int})PL->ReceiveMsg(res,
Zesstrabab5a9d2016-07-30 12:53:35 +0200105 MT_NOTIFICATION|MSG_BS_LEAVE_LFS,
106 "syntaxhilfe",0,this_object());
107 return 1;
108 }
109 }
110
111 if (stringp(help))
112 {
113 help = "Fuer " + name(WEN,1) + " gibt es folgende Syntaxhilfe:\n"
114 + help;
115 }
116 else if (closurep(help))
117 {
118 help = funcall(help, this_object());
119 }
120 else
121 {
122 // wenn das Objekt keine Syntaxhilfe hat, braucht es das Kommando auch
123 // nicht.
124 notify_fail("Fuer " + name(WEN,1)
125 + " gibt es keine Syntaxhilfe.\n");
126 RemoveCmd(0,0, "_cmd_syntaxhelp");
127 return 0;
128 }
129 if (stringp(help) && sizeof(help))
bugfixd94d0932020-04-08 11:27:13 +0200130 ({int})PL->ReceiveMsg(help, MT_NOTIFICATION|MSG_BS_LEAVE_LFS,
Zesstrabab5a9d2016-07-30 12:53:35 +0200131 "syntaxhilfe",0,this_object());
132
133 return 1;
134}
135
MG Mud User88f12472016-06-24 23:31:02 +0200136protected void create()
137{
Zesstrabab5a9d2016-07-30 12:53:35 +0200138 AddCmd("syntaxhilfe&@ID", #'_cmd_syntaxhelp,
139 "Fuer WAS moechtest Du eine Syntaxhilfe?\n",
140 "_cmd_syntaxhelp");
MG Mud User88f12472016-06-24 23:31:02 +0200141}
142
143protected void create_super() {
144 set_next_reset(-1);
Zesstrabab5a9d2016-07-30 12:53:35 +0200145}
MG Mud User88f12472016-06-24 23:31:02 +0200146
Zesstra16698ff2016-12-13 22:19:16 +0100147private closure _check_stringmethod(mixed func, int ex, string resp) {
Christian Georg Becker903cc992017-06-24 15:54:36 +0200148 closure cl = symbol_function(func, this_object());
149 if(!cl)
150 {
Christian Georg Becker9ddeb092017-06-24 00:39:44 +0200151 catch(raise_error(sprintf(
Zesstra16698ff2016-12-13 22:19:16 +0100152 resp+"string-Methode '%s' fehlt oder ist private.\n", func));
Christian Georg Becker9ddeb092017-06-24 00:39:44 +0200153 publish);
Christian Georg Becker903cc992017-06-24 15:54:36 +0200154 return 0;
155 }
Zesstra16698ff2016-12-13 22:19:16 +0100156
157 // extern erstellte auf Sichtbarkeit pruefen und abbrechen/davor warnen
158 if(ex) {
159 mixed *fl = functionlist(this_object(), RETURN_FUNCTION_NAME|
160 RETURN_FUNCTION_FLAGS);
161 int index = member(fl, func)+1;
Christian Georg Becker903cc992017-06-24 15:54:36 +0200162 if(index<=0 || sizeof(fl)<=index) // sollte nicht passieren, s.o.
163 raise_error(sprintf(
164 resp+"string-Methode '%s' trotz function_exists() nicht in "
165 "functionlist. WTF?\n", func));
166 else if(fl[index]&TYPE_MOD_PROTECTED || fl[index]&TYPE_MOD_STATIC) {
Christian Georg Becker9ddeb092017-06-24 00:39:44 +0200167 catch(raise_error(sprintf(
Zesstra16698ff2016-12-13 22:19:16 +0100168 resp+"string-Methode '%s' ist protected/static. Extern "
169 "definiertes Kommando darf so eine Methode nicht aufrufen!\n",
170 func));
Christian Georg Becker9ddeb092017-06-24 00:39:44 +0200171 publish);
Christian Georg Becker903cc992017-06-24 15:54:36 +0200172 return 0;
173 }
Zesstra16698ff2016-12-13 22:19:16 +0100174 }
175
176 // ansonsten Methode erstmal cachen
Zesstra16698ff2016-12-13 22:19:16 +0100177 return cl;
178}
179
MG Mud User88f12472016-06-24 23:31:02 +0200180varargs void AddCmd(mixed cmd, mixed func, mixed flag, mixed cmdid) {
181 int i,j;
Zesstra16698ff2016-12-13 22:19:16 +0100182 closure cachedcl;
MG Mud User88f12472016-06-24 23:31:02 +0200183 mixed *rule;
184
185 // potentielle AddCmd mit Regel?
186 if(stringp(cmd)) {
187 // eine Regel? - aufsplitten
188 if((i=member(cmd,'&'))>0) {
189 // ... in Array mit Verknuepfungselementen
190 rule=explode(cmd[(i+1)..],"&");
191 j=sizeof(rule);
192 // ... in Array mit Arrays mit Alternativelementen:
193 // "p|q&r|s" -> ({ ({"p","q"}), ({"r","s"}} })
194 while(j--)
195 rule[j]=explode(rule[j],"|");
196
197 // Regeln von Kommandoverben abschneiden
198 cmd=cmd[0..(i-1)];
199 }
200 // Kommandoverben extrahieren
201 cmd=explode(cmd,"|");
202
203 // Satz von Regeln existiert: Aufsplitten von Fehlermeldungen
204 if(rule)
205 if(stringp(flag)) {
206 mixed *fail;
207 // in einfaches Array mit jeweiligen Fehlermeldungen
208 fail=explode(flag,"|");
209 j=0;
210 i=sizeof(fail);
211 while(j<i) {
212 // write - Fehlermeldung entdeckt - Position ggf. eintragen
213 if(member(fail[j],'^')>=0 && !intp(fail[<1]))
214 fail+=({j});
215 if(member(fail[j],'@')>=0) {
216 int s;
217 flag=regexplode(fail[j], "@WE[A-SU]*[0-9]");
218 s=sizeof(flag);
219 while((s-=2)>0) {
220 int tmpint;
221 tmpint=flag[s][<1]-'1';
222 if(tmpint<0 || tmpint>j)
223 raise_error(sprintf(
224 "AddCmd: error-message %d contains out-of-bounds @WExx-rule.\n",j+1));
225 }
226 }
227 j++;
228 }
229 // "Was?|Wie das?" -> ({"Was?","Wie das?"})
230 // "Was?|Wie das?^|Womit das?|Worauf das?^@WER1 macht was." ->
231 // ({"Was?",
232 // "Wie das?^Womit das?",
233 // "Worauf das?^@WER1 macht was.",1})
234 flag=sizeof(fail);
235 if(flag && flag<sizeof(rule))
236 raise_error(
237 "AddCmd: number of error-messages does not match number of rules.\n");
238 flag=fail; // ueberschreiben mit den parsefreundlichen Format
239 } else if(flag)
240 raise_error("AddCmd: rules exist but flags are not an error-string.\n");
241 } // end if(stringp(cmd)) ... kein Regelstring vorhanden
242
243 // kein Kommandoarray gewesen noch erzeugt?
244 if(!pointerp(cmd))
245 raise_error("AddCmd: missing string/pointer-parameter for command.\n");
246
Zesstra16698ff2016-12-13 22:19:16 +0100247 // String-Methode auf Sichtbarkeit pruefen, Cache gleich anpassen
248 switch(typeof(func)) {
249 case T_STRING:
250 cachedcl=_check_stringmethod(func, extern_call(), "AddCmd: ");
251 break;
252 case T_CLOSURE:
253 cachedcl=func;
Christian Georg Beckerc5e23212017-06-24 15:00:56 +0200254 // an und fuer sich koennte man LFun-Stringnamen hier extrahieren,
255 // um Serialisierung via P_COMMANDS zu ermoeglichen. Momentan: nein.
256 func=0;
Zesstra16698ff2016-12-13 22:19:16 +0100257 break;
258 default:
259 if(extern_call()) func=previous_object();
260 else func=this_object();
261 break;
262 }
MG Mud User88f12472016-06-24 23:31:02 +0200263
Zesstra16698ff2016-12-13 22:19:16 +0100264 // jedes einzelne Verb mit seinen Regeln und Funktionen eintragen
MG Mud User88f12472016-06-24 23:31:02 +0200265 i=sizeof(cmd);
Zesstra16698ff2016-12-13 22:19:16 +0100266 if(!added_cmds) added_cmds=m_allocate(i, CMDS_WIDTH);
MG Mud User88f12472016-06-24 23:31:02 +0200267 while(i--) {
268 string str;
269 str=cmd[i];
MG Mud User88f12472016-06-24 23:31:02 +0200270 if(!member(added_cmds,str))
Zesstra16698ff2016-12-13 22:19:16 +0100271 added_cmds+=([str:allocate(0);allocate(0);allocate(0);0;allocate(0)]);
MG Mud User88f12472016-06-24 23:31:02 +0200272 // existierendes Verb ergaenzen
Zesstra16698ff2016-12-13 22:19:16 +0100273 added_cmds[str, CMDIDX_FUN]+=({func});
274 added_cmds[str, CMDIDX_FLAG]+=({flag});
275 added_cmds[str, CMDIDX_RULE]+=({rule});
276 added_cmds[str, CMDIDX_CACHE]+=({cachedcl});
MG Mud User88f12472016-06-24 23:31:02 +0200277 // ggf. id in das ID-Mapping eintragen
278 if(cmdid) {
279 mixed *tmp;
Vanion50652322020-03-10 21:13:25 +0100280 j=sizeof(added_cmds[str, CMDIDX_FUN]);
Zesstra16698ff2016-12-13 22:19:16 +0100281 tmp=added_cmds[str, CMDIDX_ID]||allocate(j);
MG Mud User88f12472016-06-24 23:31:02 +0200282 if(sizeof(tmp)<j) tmp+=allocate(j-sizeof(tmp));
283 tmp[<1]=cmdid;
Zesstra16698ff2016-12-13 22:19:16 +0100284 added_cmds[str, CMDIDX_ID]=tmp;
MG Mud User88f12472016-06-24 23:31:02 +0200285 }
286 }
287}
288
289// Auswertung fuer ein Verb loeschen
290varargs int RemoveCmd(mixed cmd, int del_norule, mixed onlyid) {
291 int ret;
292
293 // Falls Magier das RemoveCmd falsch nutzen (z.B. analog zu AddCmd)
294 // wird das Regelsystem verwirrt. Da das del_norule nur int sein darf,
295 // gibt es hier eine gute Chance den Fehler abwaertskompatibel zu ent-
296 // decken. Damit Spieler den Fehler nicht mitbekommen, wird hier auf
297 // ein raise_error verzichtet, und statt dessen in ein Logfile ge-
298 // schrieben.
299 if (!intp(del_norule))
300 {
301 log_file("REMOVE_CMD",
302 sprintf("\n-- %s --\nIllegal RemoveCommand() in Object [%O]:\n %O\n",
303 dtime(time()), this_object(), cmd));
304 del_norule=0;
305 onlyid=0;
306 }
307
308 if(!added_cmds || (!cmd && !del_norule && !onlyid))
Christian Georg Becker20a3db62018-01-09 23:08:09 +0100309 added_cmds=m_allocate(0, CMDS_WIDTH);
MG Mud User88f12472016-06-24 23:31:02 +0200310 else {
311 int i, j;
Zesstra16698ff2016-12-13 22:19:16 +0100312 mixed *rule, *flag, *fun, *delrule, *ids, *cachecl;
MG Mud User88f12472016-06-24 23:31:02 +0200313
314 if(stringp(cmd)) {
315 // Regeln entdeckt - Zerlegen (wie AddCmd)
316 if((i=member(cmd,'&'))>0) {
317 delrule=explode(cmd[(i+1)..],"&");
318 j=sizeof(delrule);
319 while(j--)
320 delrule[j]=explode(delrule[j],"|");
321 cmd=cmd[0..(i-1)];
322 }
323 cmd=explode(cmd,"|");
324 } else if(del_norule || onlyid) cmd=m_indices(added_cmds);
325
326 if(!pointerp(cmd))
327 raise_error("RemoveCmd: missing string/pointer-parameter.\n");
328 i=sizeof(cmd);
329
330 while(i--) {
331 // keine Regeln da und Regeln loeschen erlaubt: alles loeschen
332 if(!delrule && !del_norule && !onlyid) m_delete(added_cmds,cmd[i]);
Zesstra16698ff2016-12-13 22:19:16 +0100333 else if(m_contains(&fun, &flag, &rule, &ids, &cachecl, added_cmds, cmd[i])) {
MG Mud User88f12472016-06-24 23:31:02 +0200334 j=sizeof(fun);
335 while(j--) {
336 int k;
337 // DBG(rule[j]);
Zesstra9ad254c2019-09-27 00:30:41 +0200338 // Regeln nicht loeschen und Regel?
MG Mud User88f12472016-06-24 23:31:02 +0200339 if(!(del_norule && pointerp(rule[j])) &&
Zesstra9ad254c2019-09-27 00:30:41 +0200340 // nur bestimmte ID loeschen und ID passt nicht?
MG Mud User88f12472016-06-24 23:31:02 +0200341 !(onlyid && (!pointerp(ids) || sizeof(ids)<=j || ids[j]!=onlyid)) &&
Zesstra9ad254c2019-09-27 00:30:41 +0200342 // Loeschregel existiert und passt nicht auf Regel?
MG Mud User88f12472016-06-24 23:31:02 +0200343 !(delrule && (k=sizeof(rule[j]))!=sizeof(delrule))) {
Zesstra9ad254c2019-09-27 00:30:41 +0200344 // partielles Testen einer Loeschregel ...
MG Mud User88f12472016-06-24 23:31:02 +0200345 if(delrule) {
346 while(k--)
347 if(!sizeof(rule[j][k]&delrule[k])) break;
348 if(k>=0) continue;
349 }
Zesstra9ad254c2019-09-27 00:30:41 +0200350 // alles korrekt: Loeschen!
MG Mud User88f12472016-06-24 23:31:02 +0200351 // (Arraybereich durch leeres Array loeschen)
Zesstra16698ff2016-12-13 22:19:16 +0100352 flag[j..j] = allocate(0);
353 fun[j..j] = allocate(0);
354 rule[j..j] = allocate(0);
355 cachecl[j..j] = allocate(0);
MG Mud User88f12472016-06-24 23:31:02 +0200356 if(ids) {
357 ids[j..j] = allocate(0);
Vanion50652322020-03-10 21:13:25 +0100358 if(!sizeof(ids-allocate(1)))
359 ids=0;
MG Mud User88f12472016-06-24 23:31:02 +0200360 }
361 ret++;
362 }
363 } // end while(j--) {
364 }
365 // Funktions/Regelliste update oder ggf. Kommando voellig loeschen
366 if(sizeof(rule)) {
Zesstra16698ff2016-12-13 22:19:16 +0100367 added_cmds[cmd[i], CMDIDX_FUN]=fun;
368 added_cmds[cmd[i], CMDIDX_FLAG]=flag;
369 added_cmds[cmd[i], CMDIDX_RULE]=rule;
370 added_cmds[cmd[i], CMDIDX_ID]=ids;
371 added_cmds[cmd[i], CMDIDX_CACHE]=cachecl;
MG Mud User88f12472016-06-24 23:31:02 +0200372 } else m_delete(added_cmds,cmd[i]);
373 }
MG Mud User88f12472016-06-24 23:31:02 +0200374 }
375 return ret;
376}
377
378// Ausfuehren samt geparstem Inputstring und getriggerten Parserergebnissen
379static int _execute(mixed fun, string str, mixed *parsed) {
Zesstra16698ff2016-12-13 22:19:16 +0100380 switch(typeof(fun)) {
381 case T_CLOSURE:
Vanion50652322020-03-10 21:13:25 +0100382 return (({int})funcall(fun,str,&parsed));
Zesstra16698ff2016-12-13 22:19:16 +0100383 case T_STRING:
384 int ret;
385 if(!call_resolved(&ret, this_object(), fun, str, &parsed))
386 raise_error(sprintf(
387 "AddCmd: String-Methode '%s' in Kommando %#O scheint zu fehlen "
388 "oder nicht zugreifbar zu sein.\n", fun, parsed));
389 return ret;
390 default:
391 break;
392 }
393 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200394}
395
Bugfixea2dc8d2021-12-15 14:19:56 +0100396// Objekt fuer @PRESENT suchen. Es sollen keine Objekte mit P_INVIS
397// auftauchen.
398private object _GetPresentObject(string str)
399{
400 // erst Inventory des PL, spaeter Environment des PL durchsuchen. 2 foreach,
401 // um zu vermeiden, die zwei Arrays (unnoetig) zu erzeugen und zu addieren.
402 foreach(object ob : all_inventory(PL))
403 {
404 // Kein call_strict(), falls Objekte ohne die Funktionen rumliegen.
405 if(({int})ob->id(str) && !({int})ob->QueryProp(P_INVIS))
406 return ob;
407 }
408 foreach(object ob : all_inventory(environment(PL)))
409 {
410 if(({int})ob->id(str) && !({int})ob->QueryProp(P_INVIS))
411 return ob;
412 }
413 return 0;
414}
415
416
MG Mud User88f12472016-06-24 23:31:02 +0200417#define CHECK_PRESENT 1
418#define CHECK_ID 2
419#define CHECK_PUTGETNONE 4
420#define CHECK_PUTGETDROP 8
421#define CHECK_PUTGETTAKE 16
422#define CHECK_PUTGET (CHECK_PUTGETNONE|CHECK_PUTGETDROP|CHECK_PUTGETTAKE)
423
424// Wert fuer Fehlschlag, Fallback-Wert der benutzten while-- - Schleifen
425#define NOMATCHFOUND -1
426
427// Regeln fuer ein (nun unwichtiges) Verb triggern
428static int _process_command(string str, string *noparsestr,
Zesstra16698ff2016-12-13 22:19:16 +0100429 mixed fun, mixed flag, mixed rule,
430 mixed id, mixed cachedcl) {
MG Mud User88f12472016-06-24 23:31:02 +0200431 mixed *parsed, *objmatches;
432
433 // eine Regel ... auswerten ...
434 if(pointerp(rule)) {
435 int nrul;
436 parsed=objmatches=allocate(0);
437 int lastmatchpos=NOMATCHFOUND;
438
439 // Abgleichen der gesplitteten Eingabe mit Regeln:
440 // vorwaerts durch die Synonymgruppen
441 int rs=sizeof(rule);
442 while(nrul<rs) {
443 int matchpos;
444 string *synonym;
445 mixed matchstr;
446
447 matchpos=NOMATCHFOUND;
448 matchstr=0;
449
450 // Synonyme extrahieren
451 int nrsynonyms=sizeof(synonym=rule[nrul]);
452
453 // egal wie durch Synonyme bis Match - Abgleich mit Eingabe
454 while(nrsynonyms--) {
455 int tmppos = member(noparsestr,synonym[nrsynonyms]);
456 // ist Synonym im Eingabestring und kommt spaeter als vorheriges Synonym?
457 if(tmppos>=0 && tmppos>lastmatchpos) {
458 // Erfolg: merken der Position im Eingabestring und den matchenden String
459 matchpos=tmppos;
460 matchstr=noparsestr[tmppos];
461 break;
462 }
463 }
464
465 // kein Match durch Synonyme? Pruefe die @-Spezialvariablen.
466 if(matchpos == NOMATCHFOUND) {
467 int check_present;
468 // ist Abpruefen von ID/PRESENT in der Synonymgruppe verlangt
469 // bei present()/find_obs gleich Voraussetzung gueltiger TP mitprufen
470 if(member(synonym,"@ID")>=0) check_present=CHECK_ID;
471 if(this_player()) {
472 if(member(synonym,"@PRESENT")>=0) check_present|=CHECK_PRESENT;
473 else if(member(synonym,"@PUT_GET_NONE")>=0)
474 check_present|=CHECK_PUTGETNONE;
475 else if(member(synonym,"@PUT_GET_TAKE")>=0)
476 check_present|=CHECK_PUTGETDROP;
477 else if(member(synonym,"@PUT_GET_DROP")>=0)
478 check_present|=CHECK_PUTGETTAKE;
479 }
480
481 if(check_present) {
482 // wir fangen hinter dem letzten Match an
483 int q_start=lastmatchpos+1;
484 int r_end=sizeof(noparsestr)-1;
485
486 int range;
487 while((range=r_end-q_start)>=0) {
488 mixed tmpobj;
489
Christian Georg Becker903cc992017-06-24 15:54:36 +0200490 // wie weit wollen wir zurückgehen?
MG Mud User88f12472016-06-24 23:31:02 +0200491 if(range)
492 if(!(check_present&CHECK_PUTGET))
493 range=range>2?2:range; // 3 Fragmente fuer @ID/@PRESENT (Adverb/Nr)
494 else if(range>4)
495 range=4; // 5 Fragmente fuer @PUT_XXX
496
497 // und jetzt die Substrings pruefen
498 while(range>=0 && !matchstr) {
499 string tmpstr;
500
501 // zu pruefenden String aus den Teilen zusammensetzen
502 if(range) tmpstr=implode(noparsestr[q_start..(q_start+range)]," ");
503 else tmpstr=noparsestr[q_start];
504
505 //DBG(tmpstr);
Bugfixea2dc8d2021-12-15 14:19:56 +0100506 if(check_present&CHECK_PRESENT && // PRESENT ?
507 matchstr = _GetPresentObject(tmpstr));
MG Mud User88f12472016-06-24 23:31:02 +0200508 else if(check_present&CHECK_ID && id(tmpstr)) // ID ?
509 matchstr=this_object();
510 else if((check_present&CHECK_PUTGET) && // PUT_GET_??? ?
Vanion50652322020-03-10 21:13:25 +0100511 (tmpobj=({object*})
MG Mud User88f12472016-06-24 23:31:02 +0200512 this_player()->find_obs(tmpstr,
513 ([CHECK_PUTGETNONE:PUT_GET_NONE,
514 CHECK_PUTGETDROP:PUT_GET_TAKE,
515 CHECK_PUTGETTAKE:PUT_GET_DROP])
516 [CHECK_PUTGET&check_present])) &&
517 sizeof(tmpobj)) {
518 if(sizeof(tmpobj)==1) matchstr=tmpobj[0];
519 else { // Arrays werden zwischengespeichert ...
520 objmatches+=({sizeof(parsed),tmpobj});
521 matchstr=tmpstr;
522 }
523 } else { // dieser Substring hat nicht gematcht
524 // ab weniger als 3 Teilen ist das Nichtmatching eines Substrings mit
525 // beendendem Numeral Kriterium fuer Abbruch ("objekt 2" soll matchen)
526 string numeralcheck;
527 if(range && range<=2 &&
528 sizeof(numeralcheck=noparsestr[q_start+range]) &&
529 to_string(to_int(numeralcheck))==numeralcheck)
530 break;
531
532 // Substringlaenge verkuerzen und weiter
533 range--;
534 }
535 }
536
537 // Match gefunden!
538 if(matchstr) {
539 matchpos=range+q_start;
540 // DBG(matchpos);
541 break;
542 }
543 q_start++;
544 } // end while
545 }
546 }
547
548 // Fehlermeldung fuer diese fehlgeschlagene Synonymgruppe setzen
549 if(matchpos == NOMATCHFOUND) {
550 // Fehlermeldungen und ein Eintrag an der Fehlerstelle?
551 if(pointerp(flag) && sizeof(flag)>nrul) {
552
553 matchstr=flag[nrul];
554
555 if(stringp(matchstr) && sizeof(matchstr)) {
556 if(member(matchstr,'@')>=0) {
557 matchstr=replace_personal(&matchstr,({this_player()})+parsed,1);
558 string stamm=((query_verb()[<1]^'e')?query_verb():query_verb()[0..<2]);
559 matchstr=regreplace(matchstr,"@VERB",capitalize(stamm),1);
560 matchstr=regreplace(matchstr,"@verb",stamm,1);
561 }
562
563 // ist Fehlermeldung ein WRITE?
564 // dann return 1 !
565 if(intp(flag[<1]) && flag[<1]<=nrul) {
566 if(member(matchstr,'^')>=0) {
567 matchstr=explode(matchstr,"^");
568 write(capitalize(break_string(matchstr[0],78,0,1)));
569 if(sizeof(matchstr[1]))
570 say(capitalize(break_string(matchstr[1],78,0,1)),({this_player()}) );
571 } else write(capitalize(break_string(matchstr,78,0,1)));
572 return 1;
573 } else notify_fail(capitalize(break_string(matchstr,78,0,1)));
574 }
575 }
576 return 0;
577 }
578
579 // Updaten der Hilfsvariablen
580 parsed+=({matchstr});
581 lastmatchpos=matchpos;
582 nrul++;
583 } // end while(nrul<rs) ... Erfolg ... ab zum naechsten Regelteil
584 }
585
586 // Arrays der @-Objectmatches in Parameter fuer Methode resubstituieren
587 int objsize;
588 if((objsize=sizeof(objmatches)))
589 while((objsize-=2)>=0)
590 parsed[objmatches[objsize]]=objmatches[objsize+1];
591
592 // erfolgreich Methode gefunden/eine Regel bis zum Ende durchgeparst:
Zesstra16698ff2016-12-13 22:19:16 +0100593 return(_execute(cachedcl||fun, str, &parsed));
MG Mud User88f12472016-06-24 23:31:02 +0200594}
595
596// Auswertung - add_action-Fun
597public int _cl(string str) {
598 int nindex;
599 string *keys;
600 mixed *flag;
601 // Verb existiert, Kommandos auch, Eintrag fuer Verb gefunden
602 if(mappingp(added_cmds) && query_verb()) {
Zesstra16698ff2016-12-13 22:19:16 +0100603 mixed *fun, *rule, *ids, *cachecl;
MG Mud User88f12472016-06-24 23:31:02 +0200604
605 // ist das Verb ein Key im Kommandomapping?
Zesstra16698ff2016-12-13 22:19:16 +0100606 if(m_contains(&fun, &flag, &rule, &ids, &cachecl, added_cmds, query_verb())) {
MG Mud User88f12472016-06-24 23:31:02 +0200607 string *noparsestr;
608 nindex=sizeof(fun);
609 noparsestr=explode((str||"")," ")-({""});
610 // dann matche ungeparsten Input gegen etwaige Regeln
611 // -- nicht aendern: neue Kommandos sollen alte "ueberschreiben" koennen
612 while(nindex--)
Zesstra@Morgengrauen4ba72dc2016-09-08 23:13:26 +0200613 {
614 mixed cmd_id = (pointerp(ids) && sizeof(ids)>nindex) ? ids[nindex] : 0;
615 if(_process_command(&str, noparsestr, fun[nindex], flag[nindex],
Zesstra16698ff2016-12-13 22:19:16 +0100616 rule[nindex], cmd_id, cachecl[nindex])) {
MG Mud User88f12472016-06-24 23:31:02 +0200617 GiveEP(EP_CMD, query_verb());
618 return 1;
619 }
Zesstra@Morgengrauen4ba72dc2016-09-08 23:13:26 +0200620 }
MG Mud User88f12472016-06-24 23:31:02 +0200621 }
622
623 // keine Regel passte, unscharfe Auswertung auf alle
624 // AddCmdverben ausdehnen
625 keys=m_indices(added_cmds);
626 nindex=sizeof(keys);
627 while(nindex--)
628 if(!strstr(query_verb(),keys[nindex]) &&
Zesstra16698ff2016-12-13 22:19:16 +0100629 member((flag=added_cmds[keys[nindex], CMDIDX_FLAG]),1)>=0) {
Arathornb3051452021-05-13 21:13:03 +0200630 int i = sizeof(flag);
MG Mud User88f12472016-06-24 23:31:02 +0200631 // Reihenfolge nicht aendern !
632 while(i--)
633 if(flag[i]==1) {
Zesstra16698ff2016-12-13 22:19:16 +0100634 mixed *fuzzyfuns = added_cmds[keys[nindex], CMDIDX_FUN];
635 mixed *fuzzycache = added_cmds[keys[nindex], CMDIDX_CACHE];
636 if(!pointerp(fuzzyfuns) || sizeof(fuzzyfuns)<=i)
MG Mud User88f12472016-06-24 23:31:02 +0200637 catch(raise_error(
638 "AddCmd-Auswertung: CatchAll-Kommando \""+keys[nindex]+"\""
639 " wurde waehrend der Ausfuehrung veraendert oder geloescht. "
640 "Klartext: Das ist schlecht. Sucht ein RemoveCmd? ");
641 publish);
Zesstra16698ff2016-12-13 22:19:16 +0100642 else if(_execute(fuzzycache[i]||fuzzyfuns[i], str, 0)) {
MG Mud User88f12472016-06-24 23:31:02 +0200643 GiveEP(EP_CMD, query_verb());
644 return 1;
645 }
646 }
647 }
648 }
649 return 0;
650}
651
Zesstra5b71ebb2018-03-07 20:50:35 +0100652public varargs void init(object origin) {
MG Mud User88f12472016-06-24 23:31:02 +0200653 add_action("_cl","",1);
654}
655
656
Zesstra16698ff2016-12-13 22:19:16 +0100657private void _check_importentry(string ind, mixed *fun, mixed *flag,
658 mixed *rule, int|mixed id, mixed *cachedcl) {
Christian Georg Beckerb128c652017-01-08 18:03:08 +0200659 // Check der Stringmethoden: Fehler werden abgefangen, um generelles
660 // Kopieren zu ermoeglichen. Es koennen aber Kommandomethoden verloren gehen.
Zesstra16698ff2016-12-13 22:19:16 +0100661 cachedcl = map(fun, function int|closure(string clfun) {
662 closure ret;
663 catch(ret=_check_stringmethod(
664 clfun, 1,
665 "Warnung SetProp(P_COMMANDS): ");
666 publish);
667 return ret;
668 });
669 if(sizeof(fun)!=sizeof(flag) || sizeof(fun)!=sizeof(rule))
670 raise_error("SetProp(P_COMMANDS): corrupt commands-mapping.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200671}
672
Zesstra16698ff2016-12-13 22:19:16 +0100673private void _cleanup_exportcl(string ind, mixed *fun, mixed *flag,
674 mixed *rule, int|mixed id,
Christian Georg Beckerb128c652017-01-08 18:03:08 +0200675 mixed *cachedcl) {
Zesstra16698ff2016-12-13 22:19:16 +0100676 cachedcl = allocate(sizeof(fun));
MG Mud User88f12472016-06-24 23:31:02 +0200677}
678
679static mapping _query_commands() {
Zesstra16698ff2016-12-13 22:19:16 +0100680 mapping ret;
681 if(mappingp(added_cmds)) {
682 ret = deep_copy(added_cmds);
Christian Georg Beckerb128c652017-01-08 18:03:08 +0200683 // Closures im Cache werden immer geloescht, da sonst versehentlich
684 // doch exportiert werden koennte
685 walk_mapping(ret, #'_cleanup_exportcl);
Zesstra16698ff2016-12-13 22:19:16 +0100686 }
687 return ret;
MG Mud User88f12472016-06-24 23:31:02 +0200688}
689
Zesstra16698ff2016-12-13 22:19:16 +0100690static mapping _set_commands(mapping commands) {
Vanion50652322020-03-10 21:13:25 +0100691 if(!commands) added_cmds=0;
Zesstra16698ff2016-12-13 22:19:16 +0100692 else if(mappingp(commands)) {
693 if(widthof(commands) != CMDS_WIDTH)
694 raise_error("SetProp(P_COMMANDS): corrupt commands-mapping.\n");
695 mapping tmp = deep_copy(commands);
696 walk_mapping(tmp, #'_check_importentry);
Zesstradd69a342017-01-08 19:46:37 +0100697 added_cmds = tmp;
Zesstra16698ff2016-12-13 22:19:16 +0100698 }
699 return _query_commands();
700}