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