blob: ec8ff17acfff23705e75e56e452fe01e3de9b72d [file] [log] [blame]
Zesstra953f9972017-02-18 15:37:36 +01001
2AddCmd_bsp()
3************
4
5
6ADDCMD() - BEISPIELE
7====================
8
9
10FUNKTION
11========
12
13 varargs void AddCmd(mixed cmd, mixed func, mixed flag);
14
15
16BEMERKUNGEN
17===========
18
19 Die hier aufgefuehrten Komplexbeispiele sind zum Verstaendnis gedacht,
20 daher fuehren sie oft Alternativen auf. Die letzte Variante ist dann
21 jeweils diejenige, welche am leichtesten das Problem loesen koennte.
22 Falls die einem zu komplex ist, hilft vielleicht die vorletzte.
23
24
25BEISPIELE
26=========
27
28 // SIMPEL: ganz simpel, beinahe wie add_action
29 AddCmd("befiehl","action_befehlen");
30 ...
31 int action_befehlen(string str) {
32 if(!str || !strlen(str))
33 // Fehlermeldung, falls gar keine Funktion 1 dafuer zurueckgibt
34 notify_fail("Was willst du befehlen?!\n");
35 else {
36 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
39 }
40 return 0; // MISSERFOLG - Fehlermeldung oben gesetzt
41 }
42
43 // SIMPEL .. weitere Beispiele
44 AddCmd(({"kletter","klettere"}),"action_klettern" );
45 AddCmd(({"renn","renne"}),#'action_rennen);
46
47 // REGELN: eine komplexere Regel
48 AddCmd("loesch|loesche|ersticke&feuer|brand|flammen&decke|wolldecke",
49 "action_loeschen",
50 "Was willst du loeschen?|Womit willst du loeschen?");
51
52 // REGELN: mit Platzhaltern im Fehlerstring
53 AddCmd("spring|springe|huepf|huepfe&von|vom&baum|ast|eiche",
54 #'action_huepfe,
55 "Willst du von etwas @verben?|Von wo willst du @verben?");
56
57 // SCHLECHT: eine unscharfe Regel - sie sollten eine Ausnahme sein (!)
58 AddCmd("kletter","fun_klettern",1);
59
60 // FALSCH: sehr schlecht, kein Imperativ verwendet
61 // ausserdem sollte man fuer solche Syntaxen AddReadDetail benutzen
62 AddCmd("lese","eval_lesen");
63
64 // SIMPLE REGEL
65 static int action_jump(string str); // Prototype (wegen closure)
66 ...
67 AddCmd("spring|springe|huepf|huepfe&von&baum|ast",#'action_jump,
68 "Willst Du von etwas @verben?|Wovon willst Du @verben?");
69 ...
70 static int action_jump(string str) {
71 write(break_string("Du springst vom Baum und kommst hart auf!",78));
72 this_player()->move((XXXROOM+"boden"), M_GO, 0,
73 "springt unelegant vom Baum","faellt vom Baum");
74 this_player()->Defend(random(100),({DT_BLUDGEON}),([SP_RECURSIVE:1]),
75 this_object());
76 return 1;
77 }
78
79 // SIMPLE REGEL OHNE METHODE
80 // mit Regeln kann man auch Aktivitaeten im Raum erlauben, ohne eine
81 // Funktion aufrufen zu muessen: die letzte Regel ist fuer Spieler
82 // unmoeglich zu erfuellen, die dazugehoerige Fehlermeldung wird mit
83 // dem ^ (write-Flag) versehen und entsprechend an den Spieler
84 // (und den Raum (hinter dem ^)) ausgegeben
85 AddCmd("spring|springe&herunter|runter&\n\bimpossible",0,
86 "Wohin oder wovon willst Du springen?|"
87 "Du springst vom Baum und kommst hart auf.^"
88 "@WER1 springt vom Baum und kommt hart auf.");
89
90## Komplexbeispiel: Regeln mit Fehlermeldungen ##
91 ## Variante 1, OHNE REGELN ##
92 // bei Nichtverwendung von Regeln muss man Parameter selbst
93 auswerten AddCmd(({"bohr","bohre"}),#'action_bohren); ...
94 private int action_bohren(string str) {
95
96 string >>*<<tmp; notify_fail("Wo willst (etwas) Du
97 bohren?n"); if(!str) return 0; // Tja, keine Argumente
98 ... tmp=explode(str," "); // nach " " in Argument-Array
99 aufspalten if((i=member(tmp,"loch"))>=0) { // aha, ab jetzt
100 uebernehmen wir :)
101
102 if((j=member(tmp[(i+1)..],"in"))<0 &&
103 (j=member(tmp[(i+1)..],"durch"))<0)
104
105 write("Willst Du das Loch in etwas bohren?n");
106
107 else if((i=member(tmp[(j+1)..],"boden"))<0 &&
108 (i=member(tmp[(j+1)..],"erde"))<0)
109
110 write("In/Durch was willst du das Loch bohren?n");
111
112 else {
113 write("Du bohrst ein Loch in den Boden.n");
114 say(this_player()->Name(WER)+" bohrt ein Loch in den
115 Boden.n");
116
117 } return 1; // "bohre loch" war so eindeutig, dass
118 nur diese
119
120 // Methode gemeint sein konnte, also brechen wir die
121 // weitere Auswertung auf jeden Fall ab (und geben
122 // eine write-Fehlermeldung)
123
124 } // end if(..."loch") return 0; // "bohre" allein
125 muss nicht diese Methode meinen,
126
127 // also nur obige notify_fail()-Meldung, falls // sich
128 nach dieser Methode gar keine sonst // angesprochen fuehlt
129
130 } // end fun
131
132 ## Variante 1a, OHNE REGELN ##
133 // prinzipiell koennte die Methode action_bohren auch so //
134 aussehen, ist aber nicht ganz so flexibel: private int
135 action_bohren(string str) {
136
137 string tmp; if(!str || (sprintf(str,"loch in erde%s",tmp)!=1
138 &&
139
140 sprintf(str,"loch durch erde%s",tmp)!=1 &&
141 sprintf(str,"loch in boden%s",tmp)!=1 &&
142 sprintf(str,"loch durch boden%s",tmp)!=1))
143
144 notify_fail("Willst Du in irgendwas ein Loch bohren?n");
145
146 else {
147 ... return 1;
148
149 } return 0;
150
151 }
152
153 ## Variante 2, MIT REGEL ##
154 // das gleiche in etwa mal als einfache Regel
155 AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren,
156
157 "Was willst du (wohin) bohren?|" "Willst du das Loch in etwas
158 bohren?|" "Wohin willst du das Loch bohren?");
159
160 ... private int action_bohren(string str, mixed >>*<<param) {
161
162 write("Du bohrst ein Loch in den Boden.n");
163 say(this_player()->Name(WER)+" bohrt ein Loch in den
164 Boden.n"); ... return 1;
165
166 }
167
168 ## Variante 3, MIT REGEL UND FEHLERMELDUNG ##
169 // und nun mit Fehlermeldungen mit Ersetzungen, so dass wir mehr
170 // auf die Eingaben des Spielers eingehen
171 AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren,
172
173 "Was willst du (wohin) @verben?|" "Willst du das Loch in
174 etwas @verben?|" "@WER3 was willst du das Loch @verben?");
175
176 ... private int action_bohren(string str, mixed >>*<<param) ...
177
178 ## Variante 4, MIT REGEL, FEHLERMELDUNG UND RETURN 1 ##
179 // in Variante 1 kam sinnvollerweise sehr frueh der Abbruch mit
180 // "return 1;" und die Ausgabe von write-Fehlermeldungen, // das
181 koennen wir auch
182 AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren,
183
184 "Was willst du (wohin) @verben?|" "Willst du das Loch in
185 etwas @verben?^|" "@WER3 was willst du das Loch @verben?^");
186
187 ... private int action_bohren(string str, mixed >>*<<param) ...
188
189 ## Variante 5, MIT REGEL, FEHLERMELDUNG, RETURN 1, OHNE FUN ##
190 // und falls in action_bohren() nichts ausser Ausgaben
191 passiert, koennen // wir uns die auch ganz sparen indem wir
192 eine nichterfuellbare Regel // samt Fehlermeldung bauen
193 AddCmd("bohr|bohre&loch&in|durch&erde|boden&nimpossible",0,
194
195 "Was willst du (wohin) @verben?|" "Willst du das Loch in
196 etwas @verben?^|" "@WER3 was willst du das Loch
197 @verben?^|" "Du @verbst ein Loch @WER3 den Boden.^@WER1
198 @verbt " "ein Loch @WER3 den Boden.");
199
200 --- Ende Komplexbeispiel Regeln mit Fehlermeldungen ---
201
202## Komplexbeispiel: Spezialregeln @PRESENT und @ID ##
203 ## Variante 1, OHNE REGELN ##
204 // oft agieren Kommandos auf Objekten im Raum, diese muessen
205 dabei per // present() identifiziert werden: // Beispiel ist ein
206 Geldautomat (den man besser mit einem Container // mit
207 PreventInsert() basteln sollte)
208 AddCmd(({"stopf","stopfe"}),#'action_stopf); ... private int
209 action_stopf(string str) {
210
211 string tmp,tmp2; object o;
212
213 if(str && (sprintf("%s in automat%s",tmp,tmp2)==2 ||
214 sprintf("%s in geldautomat%s",tmp,tmp2)==2 ||
215 sprintf("%s in bankomat%s",tmp,tmp2)==2) {
216
217 o=present(tmp,this_player()); if(o) {
218
219 if(o->QueryProp(...)) {
220 write(break_string(
221 "Du stopfst "+o->name(WEN,1)+" in den
222 Automaten.",78));
223
224 say(...);
225
226 } else {
227 write(break_string(
228 "Du versuchst "+o->name(WEN,1)+" in den Automaten
229 zu stopfen, " "aber "+o->QueryPronoun(WER)+"
230 passt nicht hinein.",78));
231
232 say(...);
233
234 }
235
236 } else {
237 write("Was willst du in den Automaten stopfen?n");
238 say(....);
239
240 } return 1;
241
242 } notify_fail("Was willst du wohin stecken?n"); return 0;
243
244 }
245
246 ## Variante 2, MIT REGEL ##
247 // einerseits koennen wir das Finden von Objekten in Inv und
248 Env // integrieren und uns andererseits das Aufzaehlen aller
249 IDs des // Automaten ersparen
250 AddCmd("steck|stecke&@PRESENT&in&@ID",#'action_stopf,
251
252 "Was willst du wohin stopfen?|" "Willst du @WEN2 in etwas
253 stopfen?|" "Wohinein willst du @WEN2 stopfen?");
254
255 ... // dabei werden wie immer die gefunden Matches als
256 Parameterarray // uebergeben ... und die @PRESENT und @ID als
257 Objekte! private int action_stopf(string str, mixed
258 >>*<<param) {
259
260 if(param[0]->QueryProp(...)) {
261 write(break_string(
262 "Du stopfst "+param[0]->name(WEN,1)+" in den
263 Automaten.",78));
264
265 say(...);
266
267 } else {
268 write(break_string(
269 "Du versuchst "+param[0]->name(WEN,1)+" in den
270 Automaten zu " "stopfen, aber
271 "+param[0]->QueryPronoun(WER)+" passt nicht "
272 "hinein.",78));
273
274 say(...);
275
276 } return 1;
277
278 }
279
280 --- Ende Komplexbeispiel Spezialregeln @PRESENT und @ID ---
281
282## Komplexbeispiel: gleiches Verb, mehrere Regeln ##
283 // Das Problem mehrerer Regeln fuer ein Kommandoverb besteht darin,
284 dass // letztlich nur eine der Fehlermeldungen zum Tragen kommt -
285 welche // genau ist etwas vage. // Dabei kann man sich auf eines
286 verlassen: juengere AddCmd werden // zuerst ausgewertet. Wenn sich
287 das aendert, tretet euren EM.
288
289 ## Problem 1: Mehrere Regeln weil mehrere Zwecke ##
290 ## Variante 1 - GLEICHLAUTENDE FEHLERMELDUNG // fuer alles wird
291 eine identische Fehlermeldung gesetzt, das ist // natuerlich
292 nicht sehr flexibel oder schoen AddCmd("kriech|krieche&hoch|hin
293 auf|hinaus|heraus|raus",#'result_kriech,
294
295 "Wohin willst Du kriechen?");
296
297 AddCmd("kriech|krieche&nach&oben",#'result_kriech,
298 "Wohin willst Du kriechen??|Wohin willst Du kriechen?");
299
300 AddCmd("kriech|krieche&aus&loch|grube|falle",#'result_kriech);
301 "Wohin willst Du kriechen?|Wohin willst Du kriechen?");
302
303 // oder man versucht eine bessere Regel zu schaffen, was hier
304 durch // die Moeglichkeit von zwei oder drei Parameter
305 unmoeglich ist
306
307 ## Variante 2 - EIGENE AUSWERTUNG // es bietet sich also eigene
308 Weiterauswertung an, was durch die // Uebergabe der getriggerten
309 Verben erleichtert wird:
310 AddCmd("kriech|krieche&hoch|hinauf|hinaus|heraus|raus|aus|nach",
311
312 #'result_kriech, "Wohin willst Du kriechen?");
313
314 ... static int result_kriech(string str, mixed >>*<<extra) {
315
316 if(member(extra,"aus")>=0 &&
317 !sizeof(({str}),"*.\<(hoehle|grube|falle)\>.*"))
318
319 notify_fail("Woraus willst Du kriechen?n");
320
321 else if(member(extra,"nach")>=0 && strstr(str,"oben")<0)
322 notify_fail("In welche Richtung willst Du kriechen?n");
323
324 else if(this_player()->QueryAttribute(A_DEX)>10 ||
325 member(holding_root,this_player())) {
326
327 write("Du kriechst mit Muehe heraus.n");
328 this_player()->move((XXXROOM+"draussen"), M_GO, 0,
329
330 "kriecht mit Muehe aus der Grube", "kriecht aus einer
331 Grube");
332
333 return 1;
334
335 } else
336 write("Du bist zu ungeschickt, halt Dich irgendwo
337 fest.n"); return 1;
338
339 } return 0;
340
341 } // (ob sich der Aufwand fuer diese Beispielsyntax lohnt ist
342 fraglich)
343
344 ## Problem 2: mehrere Regeln, weil optionale Parameter ##
345 // Manchmal will man optionale Parameter erlauben, die aber eine
346 // Wirkung zeigen sollen:
347 AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart,
348
349 "Was oder wen willst du @verben?|" "Wie willst du @WEN2
350 schlagen?");
351
352 AddCmd("schlag|schlage&@ID",#'action_schlag,
353 "Was oder wen willst du @verben?");
354
355 // Da juengere AddCmd aelteren vorgehen, wird die komplexere
356 Regel samt // ihrer Fehlermeldung nie ausgewertet, da ein
357 "schlag ball hart" auch // die zweite Regel triggert.
358
359 // anders herum: AddCmd("schlag|schlage&@ID",#'action_schlag,
360
361 "Was oder wen willst du @verben?");
362
363 AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart,
364 "Was oder wen willst du @verben?|" "Wie willst du @WEN2
365 schlagen?");
366
367 // Jetzt wird die komplexere Regel zuerst ueberprueft und
368 triggert // auch die richtige Funktion. // Leider kommt die
369 Fehlermeldung nie zum Tragen, denn was durch Regel 2 //
370 durchfaellt, triggert entweder Regel 1 oder faellt auch durch
371 Regel 1 // durch und ueberschreibt dabei die Meldung.
372
373 AddCmd("schlag|schlage&@ID",#'action_schlag,
374 "Was oder wen willst du wie @verben?");
375
376 AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart);
377
378 // Fast perfekt. Besser wird es nicht.
379
380 --- Ende Komplexbeispiel mehrere Regeln ---
381
382Letzte Aenderung: 22.12.2016, Bugfix