| ADDCMD() - BEISPIELE |
| FUNKTION |
| varargs void AddCmd(mixed cmd, mixed func, mixed flag); |
| |
| BEMERKUNGEN |
| Die hier aufgefuehrten Komplexbeispiele sind zum Verstaendnis gedacht, |
| daher fuehren sie oft Alternativen auf. Die letzte Variante ist dann |
| jeweils diejenige, welche am leichtesten das Problem loesen koennte. |
| Falls die einem zu komplex ist, hilft vielleicht die vorletzte. |
| |
| BEISPIELE |
| // SIMPEL: ganz simpel, beinahe wie add_action |
| AddCmd("befiehl","action_befehlen"); |
| ... |
| int action_befehlen(string str) { |
| if(!str || !strlen(str)) |
| // Fehlermeldung, falls gar keine Funktion 1 dafuer zurueckgibt |
| notify_fail("Was willst du befehlen?!\n"); |
| else { |
| write("Du befiehlst \""+str+"\", und alle folgen!\n"); |
| say(TP->Name(WER)+" befiehlt \""+str+"\", und du folgst!\n"); |
| return 1; // ERFOLG - Abbruch der Kommandoauswertung |
| } |
| return 0; // MISSERFOLG - Fehlermeldung oben gesetzt |
| } |
| |
| // SIMPEL .. weitere Beispiele |
| AddCmd(({"kletter","klettere"}),"action_klettern" ); |
| AddCmd(({"renn","renne"}),#'action_rennen); |
| |
| // REGELN: eine komplexere Regel |
| AddCmd("loesch|loesche|ersticke&feuer|brand|flammen&decke|wolldecke", |
| "action_loeschen", |
| "Was willst du loeschen?|Womit willst du loeschen?"); |
| |
| // REGELN: mit Platzhaltern im Fehlerstring |
| AddCmd("spring|springe|huepf|huepfe&von|vom&baum|ast|eiche", |
| #'action_huepfe, |
| "Willst du von etwas @verben?|Von wo willst du @verben?"); |
| |
| // SCHLECHT: eine unscharfe Regel - sie sollten eine Ausnahme sein (!) |
| AddCmd("kletter","fun_klettern",1); |
| |
| // FALSCH: sehr schlecht, kein Imperativ verwendet |
| // ausserdem sollte man fuer solche Syntaxen AddReadDetail benutzen |
| AddCmd("lese","eval_lesen"); |
| |
| // SIMPLE REGEL |
| static int action_jump(string str); // Prototype (wegen closure) |
| ... |
| AddCmd("spring|springe|huepf|huepfe&von&baum|ast",#'action_jump, |
| "Willst Du von etwas @verben?|Wovon willst Du @verben?"); |
| ... |
| static int action_jump(string str) { |
| write(break_string("Du springst vom Baum und kommst hart auf!",78)); |
| this_player()->move((XXXROOM+"boden"), M_GO, 0, |
| "springt unelegant vom Baum","faellt vom Baum"); |
| this_player()->Defend(random(100),({DT_BLUDGEON}),([SP_RECURSIVE:1]), |
| this_object()); |
| return 1; |
| } |
| |
| // SIMPLE REGEL OHNE METHODE |
| // mit Regeln kann man auch Aktivitaeten im Raum erlauben, ohne eine |
| // Funktion aufrufen zu muessen: die letzte Regel ist fuer Spieler |
| // unmoeglich zu erfuellen, die dazugehoerige Fehlermeldung wird mit |
| // dem ^ (write-Flag) versehen und entsprechend an den Spieler |
| // (und den Raum (hinter dem ^)) ausgegeben |
| AddCmd("spring|springe&herunter|runter&\n\bimpossible",0, |
| "Wohin oder wovon willst Du springen?|" |
| "Du springst vom Baum und kommst hart auf.^" |
| "@WER1 springt vom Baum und kommt hart auf."); |
| |
| ## Komplexbeispiel: Regeln mit Fehlermeldungen ## |
| ## Variante 1, OHNE REGELN ## |
| // bei Nichtverwendung von Regeln muss man Parameter selbst auswerten |
| AddCmd(({"bohr","bohre"}),#'action_bohren); |
| ... |
| private static int action_bohren(string str) { |
| string *tmp; |
| notify_fail("Wo willst (etwas) Du bohren?\n"); |
| if(!str) return 0; // Tja, keine Argumente ... |
| tmp=explode(str," "); // nach " " in Argument-Array aufspalten |
| if((i=member(tmp,"loch"))>=0) { // aha, ab jetzt uebernehmen wir :) |
| if((j=member(tmp[(i+1)..],"in"))<0 && |
| (j=member(tmp[(i+1)..],"durch"))<0) |
| write("Willst Du das Loch in etwas bohren?\n"); |
| else if((i=member(tmp[(j+1)..],"boden"))<0 && |
| (i=member(tmp[(j+1)..],"erde"))<0) |
| write("In/Durch was willst du das Loch bohren?\n"); |
| else { |
| write("Du bohrst ein Loch in den Boden.\n"); |
| say(this_player()->Name(WER)+" bohrt ein Loch in den Boden.\n"); |
| } |
| return 1; // "bohre loch" war so eindeutig, dass nur diese |
| // Methode gemeint sein konnte, also brechen wir die |
| // weitere Auswertung auf jeden Fall ab (und geben |
| // eine write-Fehlermeldung) |
| } // end if(..."loch") |
| return 0; // "bohre" allein muss nicht diese Methode meinen, |
| // also nur obige notify_fail()-Meldung, falls |
| // sich nach dieser Methode gar keine sonst |
| // angesprochen fuehlt |
| } // end fun |
| |
| ## Variante 1a, OHNE REGELN ## |
| // prinzipiell koennte die Methode action_bohren auch so |
| // aussehen, ist aber nicht ganz so flexibel: |
| private static int action_bohren(string str) { |
| string tmp; |
| if(!str || (sprintf(str,"loch in erde%s",tmp)!=1 && |
| sprintf(str,"loch durch erde%s",tmp)!=1 && |
| sprintf(str,"loch in boden%s",tmp)!=1 && |
| sprintf(str,"loch durch boden%s",tmp)!=1)) |
| notify_fail("Willst Du in irgendwas ein Loch bohren?\n"); |
| else { |
| ... |
| return 1; |
| } |
| return 0; |
| } |
| |
| ## Variante 2, MIT REGEL ## |
| // das gleiche in etwa mal als einfache Regel |
| AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren, |
| "Was willst du (wohin) bohren?|" |
| "Willst du das Loch in etwas bohren?|" |
| "Wohin willst du das Loch bohren?"); |
| ... |
| private static int action_bohren(string str, mixed *param) { |
| write("Du bohrst ein Loch in den Boden.\n"); |
| say(this_player()->Name(WER)+" bohrt ein Loch in den Boden.\n"); |
| ... |
| return 1; |
| } |
| |
| ## Variante 3, MIT REGEL UND FEHLERMELDUNG ## |
| // und nun mit Fehlermeldungen mit Ersetzungen, so dass wir mehr |
| // auf die Eingaben des Spielers eingehen |
| AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren, |
| "Was willst du (wohin) @verben?|" |
| "Willst du das Loch in etwas @verben?|" |
| "@WER3 was willst du das Loch @verben?"); |
| ... |
| private static int action_bohren(string str, mixed *param) ... |
| |
| ## Variante 4, MIT REGEL, FEHLERMELDUNG UND RETURN 1 ## |
| // in Variante 1 kam sinnvollerweise sehr frueh der Abbruch mit |
| // "return 1;" und die Ausgabe von write-Fehlermeldungen, |
| // das koennen wir auch |
| AddCmd("bohr|bohre&loch&in|durch&erde|boden",#'action_bohren, |
| "Was willst du (wohin) @verben?|" |
| "Willst du das Loch in etwas @verben?^|" |
| "@WER3 was willst du das Loch @verben?^"); |
| ... |
| private static int action_bohren(string str, mixed *param) ... |
| |
| ## Variante 5, MIT REGEL, FEHLERMELDUNG, RETURN 1, OHNE FUN ## |
| // und falls in action_bohren() nichts ausser Ausgaben passiert, koennen |
| // wir uns die auch ganz sparen indem wir eine nichterfuellbare Regel |
| // samt Fehlermeldung bauen |
| AddCmd("bohr|bohre&loch&in|durch&erde|boden&\nimpossible",0, |
| "Was willst du (wohin) @verben?|" |
| "Willst du das Loch in etwas @verben?^|" |
| "@WER3 was willst du das Loch @verben?^|" |
| "Du @verbst ein Loch @WER3 den Boden.^@WER1 @verbt " |
| "ein Loch @WER3 den Boden."); |
| |
| --- Ende Komplexbeispiel Regeln mit Fehlermeldungen --- |
| |
| ## Komplexbeispiel: Spezialregeln @PRESENT und @ID ## |
| ## Variante 1, OHNE REGELN ## |
| // oft agieren Kommandos auf Objekten im Raum, diese muessen dabei per |
| // present() identifiziert werden: |
| // Beispiel ist ein Geldautomat (den man besser mit einem Container |
| // mit PreventInsert() basteln sollte) |
| AddCmd(({"stopf","stopfe"}),#'action_stopf); |
| ... |
| private static int action_stopf(string str) { |
| string tmp,tmp2; |
| object o; |
| |
| if(str && (sprintf("%s in automat%s",tmp,tmp2)==2 || |
| sprintf("%s in geldautomat%s",tmp,tmp2)==2 || |
| sprintf("%s in bankomat%s",tmp,tmp2)==2) { |
| o=present(tmp,this_player()); |
| if(o) { |
| if(o->QueryProp(...)) { |
| write(break_string( |
| "Du stopfst "+o->name(WEN,1)+" in den Automaten.",78)); |
| say(...); |
| } else { |
| write(break_string( |
| "Du versuchst "+o->name(WEN,1)+" in den Automaten zu stopfen, " |
| "aber "+o->QueryPronoun(WER)+" passt nicht hinein.",78)); |
| say(...); |
| } |
| } else { |
| write("Was willst du in den Automaten stopfen?\n"); |
| say(....); |
| } |
| return 1; |
| } |
| notify_fail("Was willst du wohin stecken?\n"); |
| return 0; |
| } |
| |
| ## Variante 2, MIT REGEL ## |
| // einerseits koennen wir das Finden von Objekten in Inv und Env |
| // integrieren und uns andererseits das Aufzaehlen aller IDs des |
| // Automaten ersparen |
| AddCmd("steck|stecke&@PRESENT&in&@ID",#'action_stopf, |
| "Was willst du wohin stopfen?|" |
| "Willst du @WEN2 in etwas stopfen?|" |
| "Wohinein willst du @WEN2 stopfen?"); |
| ... |
| // dabei werden wie immer die gefunden Matches als Parameterarray |
| // uebergeben ... und die @PRESENT und @ID als Objekte! |
| private static int action_stopf(string str, mixed *param) { |
| if(param[0]->QueryProp(...)) { |
| write(break_string( |
| "Du stopfst "+param[0]->name(WEN,1)+" in den Automaten.",78)); |
| say(...); |
| } else { |
| write(break_string( |
| "Du versuchst "+param[0]->name(WEN,1)+" in den Automaten zu " |
| "stopfen, aber "+param[0]->QueryPronoun(WER)+" passt nicht " |
| "hinein.",78)); |
| say(...); |
| } |
| return 1; |
| } |
| |
| --- Ende Komplexbeispiel Spezialregeln @PRESENT und @ID --- |
| |
| ## Komplexbeispiel: gleiches Verb, mehrere Regeln ## |
| // Das Problem mehrerer Regeln fuer ein Kommandoverb besteht darin, dass |
| // letztlich nur eine der Fehlermeldungen zum Tragen kommt - welche |
| // genau ist etwas vage. |
| // Dabei kann man sich auf eines verlassen: juengere AddCmd werden |
| // zuerst ausgewertet. Wenn sich das aendert, tretet euren EM. |
| |
| ## Problem 1: Mehrere Regeln weil mehrere Zwecke ## |
| ## Variante 1 - GLEICHLAUTENDE FEHLERMELDUNG |
| // fuer alles wird eine identische Fehlermeldung gesetzt, das ist |
| // natuerlich nicht sehr flexibel oder schoen |
| AddCmd("kriech|krieche&hoch|hinauf|hinaus|heraus|raus",#'result_kriech, |
| "Wohin willst Du kriechen?"); |
| AddCmd("kriech|krieche&nach&oben",#'result_kriech, |
| "Wohin willst Du kriechen??|Wohin willst Du kriechen?"); |
| AddCmd("kriech|krieche&aus&loch|grube|falle",#'result_kriech); |
| "Wohin willst Du kriechen?|Wohin willst Du kriechen?"); |
| |
| // oder man versucht eine bessere Regel zu schaffen, was hier durch |
| // die Moeglichkeit von zwei oder drei Parameter unmoeglich ist |
| |
| ## Variante 2 - EIGENE AUSWERTUNG |
| // es bietet sich also eigene Weiterauswertung an, was durch die |
| // Uebergabe der getriggerten Verben erleichtert wird: |
| AddCmd("kriech|krieche&hoch|hinauf|hinaus|heraus|raus|aus|nach", |
| #'result_kriech, |
| "Wohin willst Du kriechen?"); |
| ... |
| static int result_kriech(string str, mixed *extra) { |
| if(member(extra,"aus")>=0 && |
| !sizeof(({str}),"*.\\<(hoehle|grube|falle)\\>.*")) |
| notify_fail("Woraus willst Du kriechen?\n"); |
| else if(member(extra,"nach")>=0 && strstr(str,"oben")<0) |
| notify_fail("In welche Richtung willst Du kriechen?\n"); |
| else if(this_player()->QueryAttribute(A_DEX)>10 || |
| member(holding_root,this_player())) { |
| write("Du kriechst mit Muehe heraus.\n"); |
| this_player()->move((XXXROOM+"draussen"), M_GO, 0, |
| "kriecht mit Muehe aus der Grube", |
| "kriecht aus einer Grube"); |
| return 1; |
| } else |
| write("Du bist zu ungeschickt, halt Dich irgendwo fest.\n"); |
| return 1; |
| } |
| return 0; |
| } |
| // (ob sich der Aufwand fuer diese Beispielsyntax lohnt ist fraglich) |
| |
| ## Problem 2: mehrere Regeln, weil optionale Parameter ## |
| // Manchmal will man optionale Parameter erlauben, die aber eine |
| // Wirkung zeigen sollen: |
| AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart, |
| "Was oder wen willst du @verben?|" |
| "Wie willst du @WEN2 schlagen?"); |
| AddCmd("schlag|schlage&@ID",#'action_schlag, |
| "Was oder wen willst du @verben?"); |
| |
| // Da juengere AddCmd aelteren vorgehen, wird die komplexere Regel samt |
| // ihrer Fehlermeldung nie ausgewertet, da ein "schlag ball hart" auch |
| // die zweite Regel triggert. |
| |
| // anders herum: |
| AddCmd("schlag|schlage&@ID",#'action_schlag, |
| "Was oder wen willst du @verben?"); |
| AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart, |
| "Was oder wen willst du @verben?|" |
| "Wie willst du @WEN2 schlagen?"); |
| |
| // Jetzt wird die komplexere Regel zuerst ueberprueft und triggert |
| // auch die richtige Funktion. |
| // Leider kommt die Fehlermeldung nie zum Tragen, denn was durch Regel 2 |
| // durchfaellt, triggert entweder Regel 1 oder faellt auch durch Regel 1 |
| // durch und ueberschreibt dabei die Meldung. |
| |
| AddCmd("schlag|schlage&@ID",#'action_schlag, |
| "Was oder wen willst du wie @verben?"); |
| AddCmd("schlag|schlage&@ID&hart",#'action_schlag_hart); |
| |
| // Fast perfekt. Besser wird es nicht. |
| |
| |
| --- Ende Komplexbeispiel mehrere Regeln --- |
| |
| 10 Juni 2004 Gloinson |