blob: f3b848e1122fb2b3ec500585a6d3c8d004b66784 [file] [log] [blame]
Zesstra18626972017-01-31 10:38:27 +01001ADDCMD() - BEISPIELE
Arathorn655333e2019-11-26 19:20:27 +01002********************
Zesstra18626972017-01-31 10:38:27 +01003
4FUNKTION
Arathorn655333e2019-11-26 19:20:27 +01005========
Zesstra18626972017-01-31 10:38:27 +01006::
7
8 varargs void AddCmd(mixed cmd, mixed func, mixed flag);
9
10BEMERKUNGEN
Arathorn655333e2019-11-26 19:20:27 +010011===========
Zesstra18626972017-01-31 10:38:27 +010012::
13
14 Die hier aufgefuehrten Komplexbeispiele sind zum Verstaendnis gedacht,
15 daher fuehren sie oft Alternativen auf. Die letzte Variante ist dann
16 jeweils diejenige, welche am leichtesten das Problem loesen koennte.
17 Falls die einem zu komplex ist, hilft vielleicht die vorletzte.
18
19BEISPIELE
Arathorn655333e2019-11-26 19:20:27 +010020=========
Zesstra18626972017-01-31 10:38:27 +010021
Arathorn655333e2019-11-26 19:20:27 +010022Einfache Beispiele
23------------------
24
251. SIMPEL: ganz simpel, beinahe wie add_action()
26
27.. code-block:: pike
28
29 AddCmd("befiehl","action_befehlen");
30 // ...
31 int action_befehlen(string str) {
Zesstra18626972017-01-31 10:38:27 +010032 if(!str || !strlen(str))
Arathorn655333e2019-11-26 19:20:27 +010033 // Fehlermeldung, falls gar keine Funktion 1 dafuer zurueckgibt
34 notify_fail("Was willst du befehlen?!\n");
Zesstra18626972017-01-31 10:38:27 +010035 else {
Arathorn655333e2019-11-26 19:20:27 +010036 write("Du befiehlst \""+str+"\", und alle folgen!\n");
37 say(TP->Name(WER)+" befiehlt \""+str+"\", und du folgst!\n");
38 return 1; // ERFOLG - Abbruch der Kommandoauswertung
Zesstra18626972017-01-31 10:38:27 +010039 }
Arathorn655333e2019-11-26 19:20:27 +010040 return 0; // MISSERFOLG - Fehlermeldung oben gesetzt
41 }
Zesstra18626972017-01-31 10:38:27 +010042
Arathorn655333e2019-11-26 19:20:27 +0100432. SIMPEL .. weitere Beispiele
Zesstra18626972017-01-31 10:38:27 +010044
Arathorn655333e2019-11-26 19:20:27 +010045.. code-block:: pike
Zesstra18626972017-01-31 10:38:27 +010046
Arathorn655333e2019-11-26 19:20:27 +010047 AddCmd(({"kletter","klettere"}),"action_klettern" );
48 AddCmd(({"renn","renne"}),#'action_rennen);
Zesstra18626972017-01-31 10:38:27 +010049
Arathorn655333e2019-11-26 19:20:27 +0100503. REGELN: eine komplexere Regel
Zesstra18626972017-01-31 10:38:27 +010051
Arathorn655333e2019-11-26 19:20:27 +010052.. code-block:: pike
Zesstra18626972017-01-31 10:38:27 +010053
Arathorn655333e2019-11-26 19:20:27 +010054 AddCmd("loesch|loesche|ersticke&feuer|brand|flammen&decke|wolldecke",
55 "action_loeschen",
56 "Was willst du loeschen?|Womit willst du loeschen?");
Zesstra18626972017-01-31 10:38:27 +010057
Arathorn655333e2019-11-26 19:20:27 +0100584. REGELN: mit Platzhaltern im Fehlerstring
Zesstra18626972017-01-31 10:38:27 +010059
Arathorn655333e2019-11-26 19:20:27 +010060.. code-block:: pike
61
62 AddCmd("spring|springe|huepf|huepfe&von|vom&baum|ast|eiche",
63 #'action_huepfe,
64 "Willst du von etwas @verben?|Von wo willst du @verben?");
65
665. SCHLECHT: eine unscharfe Regel - sie sollten eine Ausnahme sein (!)
67
68.. code-block:: pike
69
70 AddCmd("kletter","fun_klettern",1);
71
726. FALSCH: sehr schlecht, kein Imperativ verwendet
73
74.. code-block:: pike
75
76 AddCmd("lese","eval_lesen");
77
78 ausserdem sollte man fuer Lese-Syntaxen AddReadDetail benutzen
79
807. SIMPLE REGEL
81
82.. code-block:: pike
83
84 static int action_jump(string str); // Prototype (wegen closure)
85 // ...
86 AddCmd("spring|springe|huepf|huepfe&von&baum|ast",#'action_jump,
87 "Willst Du von etwas @verben?|Wovon willst Du @verben?");
88 // ...
89 static int action_jump(string str) {
90 write(break_string("Du springst vom Baum und kommst hart auf!",78));
91 this_player()->move((XXXROOM+"boden"), M_GO, 0,
92 "springt unelegant vom Baum","faellt vom Baum");
93 this_player()->Defend(random(100),({DT_BLUDGEON}),([SP_RECURSIVE:1]),
94 this_object());
95 return 1;
96 }
97
988. SIMPLE REGEL OHNE METHODE
99
100 mit Regeln kann man auch Aktivitaeten im Raum erlauben, ohne eine
101 Funktion aufrufen zu muessen: die letzte Regel ist fuer Spieler
102 unmoeglich zu erfuellen, die dazugehoerige Fehlermeldung wird mit
103 dem ^ (write-Flag) versehen und entsprechend an den Spieler
104 (und den Raum (hinter dem ^)) ausgegeben
105
106.. code-block:: pike
107
108 AddCmd("spring|springe&herunter|runter&\n\bimpossible",0,
109 "Wohin oder wovon willst Du springen?|"
110 "Du springst vom Baum und kommst hart auf.^"
111 "@WER1 springt vom Baum und kommt hart auf.");
112
113
114Komplexbeispiel: Regeln mit Fehlermeldungen
115-------------------------------------------
116
117Variante 1a, OHNE REGELN
118^^^^^^^^^^^^^^^^^^^^^^^^
119
120 Wenn man keine Regeln verwendet, muss man die Eingabe selbst auswerten.
121
122.. code-block:: pike
123
124 AddCmd(({"bohr","bohre"}),#'action_bohren);
125 // ...
126 private int action_bohren(string str) {
127 string *tmp;
128 notify_fail("Wo willst (etwas) Du bohren?\n");
129 if(!str) return 0; // Tja, keine Argumente ...
130 tmp=explode(str," "); // nach " " in Argument-Array aufspalten
131 if((i=member(tmp,"loch"))>=0) { // aha, ab jetzt uebernehmen wir :)
Zesstra18626972017-01-31 10:38:27 +0100132 if((j=member(tmp[(i+1)..],"in"))<0 &&
133 (j=member(tmp[(i+1)..],"durch"))<0)
134 write("Willst Du das Loch in etwas bohren?\n");
Arathorn655333e2019-11-26 19:20:27 +0100135 else if((i=member(tmp[(j+1)..],"boden"))<0 &&
136 (i=member(tmp[(j+1)..],"erde"))<0)
Zesstra18626972017-01-31 10:38:27 +0100137 write("In/Durch was willst du das Loch bohren?\n");
Arathorn655333e2019-11-26 19:20:27 +0100138 else {
Zesstra18626972017-01-31 10:38:27 +0100139 write("Du bohrst ein Loch in den Boden.\n");
140 say(this_player()->Name(WER)+" bohrt ein Loch in den Boden.\n");
Zesstra18626972017-01-31 10:38:27 +0100141 }
Arathorn655333e2019-11-26 19:20:27 +0100142 return 1; // "bohre loch" war so eindeutig, dass nur diese
143 // Methode gemeint sein konnte, also brechen wir die
144 // weitere Auswertung auf jeden Fall ab (und geben
145 // eine write-Fehlermeldung)
146 } // end if(..."loch")
147 return 0; // "bohre" allein muss nicht diese Methode meinen,
148 // also nur obige notify_fail()-Meldung, falls
149 // sich nach dieser Methode gar keine sonst
150 // angesprochen fuehlt
151 } // end fun
152
153Variante 1b, OHNE REGELN, Alternative
154^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
155
156 prinzipiell koennte die Methode action_bohren() auch so
157 aussehen, ist aber nicht ganz so flexibel:
158
159.. code-block:: pike
160
161 private int action_bohren(string str) {
162 string unused;
163 if(!str || (sprintf(str,"loch in erde%s", unused)!=1 &&
164 sprintf(str,"loch durch erde%s", unused)!=1 &&
165 sprintf(str,"loch in boden%s", unused)!=1 &&
166 sprintf(str,"loch durch boden%s", unused)!=1))
167 notify_fail("Willst Du in irgendwas ein Loch bohren?\n");
168 else {
169 // ...
Zesstra18626972017-01-31 10:38:27 +0100170 return 1;
Arathorn655333e2019-11-26 19:20:27 +0100171 }
172 return 0;
173 }
174
175Variante 2, MIT REGEL
176^^^^^^^^^^^^^^^^^^^^^
177
178 das gleiche in etwa mal als einfache Regel
179
180.. code-block:: pike
181
182 AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren,
183 "Was willst du (wohin) bohren?|"
184 "Willst du das Loch in etwas bohren?|"
185 "Wohin willst du das Loch bohren?");
186 // ...
187 private int action_bohren(string str, mixed *param) {
188 write("Du bohrst ein Loch in den Boden.\n");
189 say(this_player()->Name(WER)+" bohrt ein Loch in den Boden.\n");
190 // ...
191 return 1;
192 }
193
194Variante 3, MIT REGEL UND FEHLERMELDUNG
195^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
196
197 und nun mit Fehlermeldungen mit Ersetzungen, so dass wir mehr
198 auf die Eingaben des Spielers eingehen
199
200.. code-block:: pike
201
202 AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren,
203 "Was willst du (wohin) @verben?|"
204 "Willst du das Loch in etwas @verben?|"
205 "@WER3 was willst du das Loch @verben?");
206 // ...
207 private int action_bohren(string str, mixed *param) // ...
208
209Variante 4, MIT REGEL, FEHLERMELDUNG UND RETURN 1
210^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
211
212 In Variante 1 kam sinnvollerweise sehr frueh der Abbruch mit
213 "return 1;" und mit Ausgabe von write-Fehlermeldungen, das koennen
214 wir auch direkt und ohne eigene Methode.
215
216.. code-block:: pike
217
218 AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren,
219 "Was willst du (wohin) @verben?|"
220 "Willst du das Loch in etwas @verben?^|"
221 "@WER3 was willst du das Loch @verben?^");
222 // ...
223 private int action_bohren(string str, mixed *param) // ...
224
225Variante 5, MIT REGEL, FEHLERMELDUNG, RETURN 1, OHNE FUN
226^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
227
228.. code-block:: pike
229
230 // und falls in action_bohren() nichts ausser Ausgaben passiert, koennen
231 // wir uns die auch ganz sparen indem wir eine nichterfuellbare Regel
232 // samt Fehlermeldung bauen
233 AddCmd("bohr|bohre&loch&in|durch&erde|boden&\nimpossible",0,
234 "Was willst du (wohin) @verben?|"
235 "Willst du das Loch in etwas @verben?^|"
236 "@WER3 was willst du das Loch @verben?^|"
237 "Du @verbst ein Loch @WER3 den Boden.^@WER1 @verbt "
238 "ein Loch @WER3 den Boden.");
239
240Komplexbeispiel: Spezialregeln @PRESENT und @ID
241-----------------------------------------------
242
243Variante 1, OHNE REGELN
244^^^^^^^^^^^^^^^^^^^^^^^
245
246 Oft agieren Kommandos auf Objekten im Raum, diese muessen dabei per
247 present() identifiziert werden:
248 Beispiel ist ein Geldautomat
249 (Hinweis: dieses Beispiel dient der Illustration, die Funktionalitaet an
250 sich sollte man besser mit einem Container mit PreventInsert() erzeugen.)
251
252.. code-block:: pike
253
254 AddCmd(({"stopf","stopfe"}),#'action_stopf);
255 // ...
256 private int action_stopf(string str) {
257 string was, unused;
258 if(str && (sprintf("%s in automat%s", was, unused)==2 ||
259 sprintf("%s in geldautomat%s", was, unused)==2 ||
260 sprintf("%s in bankomat%s", was, unused)==2) {
261 object o = present(was, this_player());
262 if(o) {
263 if(o->QueryProp(...)) {
264 write(break_string(
265 "Du stopfst "+o->name(WEN,1)+" in den Automaten.",78));
266 say(...);
267 } else {
268 write(break_string(
269 "Du versuchst "+o->name(WEN,1)+" in den Automaten zu stopfen, "
270 "aber "+o->QueryPronoun(WER)+" passt nicht hinein.",78));
271 say(...);
272 }
273 } else {
274 write("Was willst du in den Automaten stopfen?\n");
275 say(....);
276 }
277 return 1;
Zesstra18626972017-01-31 10:38:27 +0100278 }
279 notify_fail("Was willst du wohin stecken?\n");
280 return 0;
Arathorn655333e2019-11-26 19:20:27 +0100281 }
Zesstra18626972017-01-31 10:38:27 +0100282
Arathorn655333e2019-11-26 19:20:27 +0100283Variante 2, MIT REGEL
284^^^^^^^^^^^^^^^^^^^^^
285
286 einerseits koennen wir auf diese Weise das Finden von Objekten in Inv
287 und Env in die AddCmd()-Regel integrieren und uns andererseits das
288 Aufzaehlen aller IDs des Automaten ersparen.
289
290 Wie immer werden die gefundenen Matches als Parameterarray an die
291 angegebene Methode uebergeben. Das Array enthaelt die mit @PRESENT und
292 @ID gefundenen Treffer praktischerweise als Objekte.
293
294.. code-block:: pike
295
296 AddCmd("steck|stecke&@PRESENT&in&@ID",#'action_stopf,
297 "Was willst du wohin stopfen?|"
298 "Willst du @WEN2 in etwas stopfen?|"
299 "Wohinein willst du @WEN2 stopfen?");
300 // ...
301 private int action_stopf(string str, mixed *param) {
302 if(param[0]->QueryProp(...)) {
Zesstra18626972017-01-31 10:38:27 +0100303 write(break_string(
Arathorn655333e2019-11-26 19:20:27 +0100304 "Du stopfst "+param[0]->name(WEN,1)+" in den Automaten.",78));
Zesstra18626972017-01-31 10:38:27 +0100305 say(...);
Arathorn655333e2019-11-26 19:20:27 +0100306 } else {
Zesstra18626972017-01-31 10:38:27 +0100307 write(break_string(
Arathorn655333e2019-11-26 19:20:27 +0100308 "Du versuchst "+param[0]->name(WEN,1)+" in den Automaten zu "
309 "stopfen, aber "+param[0]->QueryPronoun(WER)+" passt nicht "
310 "hinein.",78));
Zesstra18626972017-01-31 10:38:27 +0100311 say(...);
Zesstra18626972017-01-31 10:38:27 +0100312 }
Arathorn655333e2019-11-26 19:20:27 +0100313 return 1;
314 }
Zesstra18626972017-01-31 10:38:27 +0100315
Arathorn655333e2019-11-26 19:20:27 +0100316Komplexbeispiel: gleiches Verb, mehrere Regeln
317----------------------------------------------
Zesstra18626972017-01-31 10:38:27 +0100318
Arathorn655333e2019-11-26 19:20:27 +0100319 Das Problem mehrerer Regeln fuer ein Kommandoverb besteht darin, dass
320 letztlich nur eine der Fehlermeldungen zum Tragen kommt - welche
321 genau, ist etwas vage.
322 Dabei kann man sich auf eines verlassen: juengere AddCmd werden
323 zuerst ausgewertet. Wenn sich das aendert, tretet euren EM.
Zesstra18626972017-01-31 10:38:27 +0100324
Arathorn655333e2019-11-26 19:20:27 +0100325Problem 1: Mehrere Regeln weil mehrere Zwecke
326---------------------------------------------
Zesstra18626972017-01-31 10:38:27 +0100327
Arathorn655333e2019-11-26 19:20:27 +0100328Variante 1 - GLEICHLAUTENDE FEHLERMELDUNG
329^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
330
331 Fuer alles wird eine identische Fehlermeldung gesetzt, das ist
332 natuerlich nicht sehr flexibel oder schoen
333 oder man versucht eine bessere Regel zu schaffen, was hier durch
334 die Moeglichkeit von zwei oder drei Parameter unmoeglich ist
Zesstra18626972017-01-31 10:38:27 +0100335
Arathorn655333e2019-11-26 19:20:27 +0100336.. code-block:: pike
337
338 AddCmd("kriech|krieche&hoch|hinauf|hinaus|heraus|raus",#'result_kriech,
339 "Wohin willst Du kriechen?");
340 AddCmd("kriech|krieche&nach&oben",#'result_kriech,
341 "Wohin willst Du kriechen??|Wohin willst Du kriechen?");
342 AddCmd("kriech|krieche&aus&loch|grube|falle",#'result_kriech);
343 "Wohin willst Du kriechen?|Wohin willst Du kriechen?");
344
345
346Variante 2 - EIGENE AUSWERTUNG
347^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
348
349 Statt der Verwendung mehrerer aehnlicher AddCmd() bietet sich die eigene
350 Weiterauswertung an, was durch die Uebergabe der getriggerten Argumente
351 erleichtert wird.
352
353.. code-block:: pike
354
Zesstra18626972017-01-31 10:38:27 +0100355 AddCmd("kriech|krieche&hoch|hinauf|hinaus|heraus|raus|aus|nach",
356 #'result_kriech,
357 "Wohin willst Du kriechen?");
Arathorn655333e2019-11-26 19:20:27 +0100358 // ...
359 private int result_kriech(string str, mixed *extra) {
Zesstra18626972017-01-31 10:38:27 +0100360 if(member(extra,"aus")>=0 &&
361 !sizeof(({str}),"*.\\<(hoehle|grube|falle)\\>.*"))
Arathorn655333e2019-11-26 19:20:27 +0100362 notify_fail("Woraus willst Du kriechen?\n");
Zesstra18626972017-01-31 10:38:27 +0100363 else if(member(extra,"nach")>=0 && strstr(str,"oben")<0)
Arathorn655333e2019-11-26 19:20:27 +0100364 notify_fail("In welche Richtung willst Du kriechen?\n");
Zesstra18626972017-01-31 10:38:27 +0100365 else if(this_player()->QueryAttribute(A_DEX)>10 ||
366 member(holding_root,this_player())) {
367 write("Du kriechst mit Muehe heraus.\n");
368 this_player()->move((XXXROOM+"draussen"), M_GO, 0,
369 "kriecht mit Muehe aus der Grube",
370 "kriecht aus einer Grube");
371 return 1;
372 } else
373 write("Du bist zu ungeschickt, halt Dich irgendwo fest.\n");
374 return 1;
375 }
376 return 0;
377 }
Zesstra18626972017-01-31 10:38:27 +0100378
Arathorn655333e2019-11-26 19:20:27 +0100379Problem 2: mehrere Regeln aufgrund von optionalen Parametern
380------------------------------------------------------------
Zesstra18626972017-01-31 10:38:27 +0100381
Arathorn655333e2019-11-26 19:20:27 +0100382 Manchmal will man optionale Parameter erlauben, die aber eine
383 Wirkung zeigen sollen. Hierbei ist die Reihenfolge der AddCmd()-
384 Anweisungen und ggf. deren Aufbau entscheidend.
Zesstra18626972017-01-31 10:38:27 +0100385
Arathorn655333e2019-11-26 19:20:27 +0100386.. code-block:: pike
Zesstra18626972017-01-31 10:38:27 +0100387
Arathorn655333e2019-11-26 19:20:27 +0100388 AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart,
389 "Was oder wen willst du @verben?|"
390 "Wie willst du @WEN2 schlagen?");
391 AddCmd("schlag|schlage&@ID",#'action_schlag,
392 "Was oder wen willst du @verben?");
Zesstra18626972017-01-31 10:38:27 +0100393
Arathorn655333e2019-11-26 19:20:27 +0100394 Da juengere AddCmd aelteren vorgehen, wird die komplexere Regel samt
395 ihrer Fehlermeldung nie ausgewertet, da ein "schlag ball hart" auch
396 die zweite Regel triggert.
Zesstra18626972017-01-31 10:38:27 +0100397
Arathorn655333e2019-11-26 19:20:27 +0100398 Anders herum:
Zesstra18626972017-01-31 10:38:27 +0100399
Arathorn655333e2019-11-26 19:20:27 +0100400.. code-block:: pike
Zesstra18626972017-01-31 10:38:27 +0100401
Arathorn655333e2019-11-26 19:20:27 +0100402 AddCmd("schlag|schlage&@ID",#'action_schlag,
403 "Was oder wen willst du @verben?");
404 AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart,
405 "Was oder wen willst du @verben?|"
406 "Wie willst du @WEN2 schlagen?");
Zesstra18626972017-01-31 10:38:27 +0100407
Arathorn655333e2019-11-26 19:20:27 +0100408 Jetzt wird die komplexere Regel zuerst ueberprueft und triggert
409 auch die richtige Funktion.
410 Leider kommt die Fehlermeldung nie zum Tragen, denn was durch Regel 2
411 durchfaellt, triggert entweder Regel 1 oder faellt auch durch Regel 1
412 durch und ueberschreibt dabei die Meldung.
413
414.. code-block:: pike
415
416 AddCmd("schlag|schlage&@ID",#'action_schlag,
417 "Was oder wen willst du wie @verben?");
418 AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart);
419
420 Das ist zwar auch nur fast perfekt, besser wird es aber nicht.
421
422Letzte Aenderung: 20.11.2019, Arathorn
Zesstra18626972017-01-31 10:38:27 +0100423