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