| |
| AddCmd_bsp() |
| ************ |
| |
| |
| 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 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 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 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 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 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 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 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|hin |
| auf|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 --- |
| |
| Letzte Aenderung: 22.12.2016, Bugfix |