|
|
Dieses Dokument ist verfübar auf: English ChineseGB Deutsch Francais Nederlands Turkce |
von Philipp Gühring Über den Autor: Philipp hat gerade die Matura der HTL Wiener Neustadt bestanden, einer höheren technischen Schule für Informationssysteme. Dadurch hat er jetzt wieder Zeit, sich um seine Softwareentwicklungsgruppe Futureware 2001 zu kümmern. Er ist Linux Fan und aktives Mitglied der Linux User Group Austria. Inhalt:
|
Zusammenfassung:
Dialog ist eine Programmiersprache, in der man Dialoge mit dem Benutzer entwickeln kann. Sie kam in der Handelssimulation Würstelstand zum Einsatz. Dieser Artikel beschreibt ihre Entwicklung.
Die Dialoge werden in Ascii Textdateien abgelegt, und dann zeilenweise interpretiert.
Damals wurden sie mit einem einfachen Editor erstellt.
Der Dateiname ist Name.BAT (z.B.: HALE.BAT)
Diese Datei wird zeilenweise interpretiert, wobei Sprünge möglich sind.
Wenn der Spieler/Leni etwas sagen soll, dann geht das so:
Leni: Text Leni: Guten Tag, der Herr! Was darfs denn sein? Leni: Da schau sich einer mal die heutige Jugend an! | |
Wenn der Kunde/Geprächspartner etwas sagen soll:
Kunde: Text Kunde: Zwei mal Frankfurter mit Semmel und zwei Cola, aber dalli. Telefon: Futureware 2001, Philipp Gühring. Was kann ich für sie tun? |
Jeder ordentliche Dialog hört mit
Endeauf.
Ein einfaches Beispiel: |
Leni: Guten Tag, der Herr! Was darfs denn sein? Kunde: Guten Tag! Einen Käsekrainer bitte! Leni: Kommt gleich. Leni: Hier, bitte sehr. Kunde: Danke sehr. Auf wiedersehen! Leni: Auf bald! Ende |
Sprungziele werden definiert, in dem eine Zeile mit einem Doppelpunkt anfängt, und dann der Name des Sprungziels folgt. Angesprungen werden die Sprungziele mit dem Befehl Sprung:
:Sprungmarke //Und so springen wir dorthin: Sprung Sprungmarke
| Was macht der Interpreter bei diesem Beispiel? Zuerst findet er den Befehl Leni: und gibt den Text 1 aus. Dann ist in der nächsten Zeile ein Kommentar, der natürlich ignoriert wird. In der nächsten Zeile ist der Befehl Sprung. Der Interpreter sucht den ganzen Dialog nach dem Sprungziel MENÜ_0 ab, und findet es ein paar Zeilen darunter, und springt dort hin. Dann geht es gleich wieder bei einem Kommentar weiter (Und hier gehts wieder weiter). Und schlußendlich kommt noch der Befehl Leni:, worauf 3 ausgegeben wird. Der Befehl Leni: 2 wird in diesem Beispiel einfach übersprungen, und daher wird 2 nicht ausgegeben. |
Wie wir nun gesehen haben, kann eine Zeile:
// Dies ist ein Kommentar ************************************** * Auch so kann man Kommentare machen * **************************************Kommentare dürfen nicht in der selben Zeile wie ein Befehl stehen:
Leni: Ich kenn mich nicht mehr aus. // Kein Kommentar
Nun gibt es drei Arten von Abfragen.
Neu kaufen,A Schoaffe, wie imma, oder net ? Neu arbeit,Was macht die Arbeit ? Neu sprachkurs,Mochst nu oiwei den Sprachkurs beim WIFI? Neu familie,Wie gehts deina Familie ? Neu wetter,Wie taugt da eigentli des Wetta ? MenüBei dieser Art hat der Spieler die Möglichkeit, der Reihe nach alle Möglichkeiten durchzuspielen. Die Einträge, die nicht ausgewählt wurden, verbleiben also in der Liste, und können beim nächsten MENÜ auch wieder ausgewählt werden. Wählen wir zum Beispiel Arbeit aus:
:arbeit Leni: Was macht die Arbeit? Kunde: Wie immer viel zu tun. MenüWie gesagt, wird hier nur die ausgewählte Zeile gelöscht und bearbeitet. Bei der nächsten Auswahl bleiben folgende Möglichkeiten:
Kunde: Wieviel Stück brauchst du? Alt einige, 10 Stück Alt mehrere, 20 Stück Alt viele, 100 Stück Menü :einige //Hier gehts weiter, wenn 10 Stück ausgewählt wurden :mehrere ... :viele ...Da es keinen Sinn macht, die nicht ausgewählten Einträge noch länger in der Liste zu lassen, sollten alle Listeneinträge nach der Auswahl des Benutzers automatisch gelöscht werden. Nehmen wir an, der Benutzer hat 20 Stück ausgewählt, dann springen wir zum Sprungziel mehrere:
:mehrere Kunde: Bist du sicher? Leni: Ja, ich nehme 20 Stück. Kunde: Bis wann brauchst du sie? Alt 1, Morgen Alt 2, Übermorgen Alt 3, Irgendwann MenüUnd schlußendlich kann man die beiden Arten noch vermischen:
Kunde: Jaja, das waren Zeiten. Alt Erinnerung,Da fällt mir ein, du ... MENÜ
Liste 0 wird für das erste Abfragekonzept empfohlen. Liste 1 habe ich für die allgemeinen Gesprächsthemen vorgeschlagen. Also Familie, Beruf, Freizeit, was man Essen will, ... Wenn man nun zum Beispiel über den Beruf redet, und dort wieder verschiedene Themen auftauchen, die man behandeln könnte, dann nimmt man die Liste 2. Ein Beispiel findet sich im Dialog von Hale. Sollte jemand noch weitere Listen brauchen, muß nur eine Konstante im Quellcode des Interpreters geändert werden.
LISTE 0wechselt man in die Liste 0. Mit dem Befehl
LISTE 1kommt man dann wieder zurück in die Themen-Liste. Die Einträge der Listen bleiben natürlich erhalten. Die Befehle wie NEU, ALT, MENÜ, LÖSCHEN beziehen sich immer auf die gerade aktuelle Liste.
Neu Erinnerung,§Da fällt mir ein, du ...Und die Liste 0 wurde automatisch nach dem Menü gelöscht, war also nur für direkte Abfragen geeignet, nicht für Gesprächsthemen.
Ich empfehle nun, die HALE.BAT und die PETER.BAT als Beispiel anzusehen, dort werden die Listen ausgiebig verwendet.
Mit
LÖSCHEN Sprungzielwird jeder Eintrag aus der aktuellen Liste gelöscht, der auf Sprungziel zeigt. z.B.:
LÖSCHEN familieUm alle Einträge der aktuellen Liste zu löschen, gibt man den Stern an:
LÖSCHEN *(Wer will, kann ja Regular-Expression Support einführen ;-)
Mit Menü werden alle Menüeinträge der aktuellen Menüliste angezeigt und der Benutzer kann aus diesen auswählen. Dann wird der ausgewählte Eintrag und alle mit ALT eingefügten Einträge gelöscht. Schließlich wird noch zum bei NEU angegebenen Sprungziel gesprungen. Sollte nur eine Auswahlmöglichkeit in der Liste sein, dann wird die Auswahl natürlich nicht angeboten, sondern direkt nur ausgegeben. Sollte die Liste leer sein, oder das Sprungziel nicht gefunden werden, dann wird in der nächsten Zeile nach MENÜ weitergemacht.
1 | Event; | //Ereignis Nummer (siehe texte.h) | |
2 | geliefert; | //S | //0-10 wieviel zehntel geliefert werden) |
3 | wtag; | //Wochentag | |
4 | tag; | //Monatstag | |
5 | monat; | //Monat | |
6 | jahr; | //Jahr | |
7 | Datum; | //fortlaufender Tag (1.1.1997 = 0) | |
8 | wetter; | //Das Tageswetter | |
9 | konto; | //S | //Wieviel Geld am Konto ist |
10 | kapital; | //S | //Kapital |
11 | ausgaben; | //S | //Wieviel Ausgaben heute gemacht wurden |
12 | einnahmen; | //S | //Wieviel Einnahmen heute gemacht wurden |
13 | sterne; | //S | //Wieviel Sterne der Würstelstand hat(0-5) |
14 | wverkauf; | //Wieviel diese Woche verkauft wurde | |
15 | weinnahmen; | //Wieviel diese Woche eingenommen wurde | |
16 | wausgaben; | //Wieviel diese Woche ausgegeben wurde | |
17 | 0; | //S | //Neue Ein/Ausgaben (durch Dialog ausgelöst) |
18 | Nachrichtenserie; | //Welche Nachrichtenserie (0=Elch,1=...) | |
19 | Nachricht; | //Welche Nachricht in der Serie (0=1.Tag,1=2. | |
20 | LottoNr[0]; | //Wieviele LottoNr angekreuzt sind(0-6) | |
21 | LottoErgebnis[0]; | //Wieviele LottoNr richtig waren | |
22 | LottoGewinn[LottoErgebnis[0]]; | //Wieviel gewonnen wurde | |
23 | S.Image; | //S | //Lenis Image |
24 | S.Override; | //S | //Override-Ereignis |
25 | S.wverkauf[1]; | //Wieviel letzte Woche verkauft wurde | |
26 | S.weinnahmen[1]; | //Wieviel letzte Woche eingenommen wurde | |
27 | S.wausgaben[1]; | //Wieviel letzte Woche ausgegeben wurde | |
28 | S.wverkauf[2]; | //Wieviel vorletzte Woche verkauft wurde | |
29 | S.weinnahmen[2]; | //Wieviel vorletzte Woche eingenommen wurde | |
30 | S.wausgaben[2]; | //Wieviel vorletzte Woche ausgegeben wurde | |
31 | S.NOverride; | //S | //Override für morgen |
32 | S.wetter_bericht; | //Welcher Wetterbericht verwendet wurde | |
33 | Gesamtwert(); | //Gesamtwert des Würstelstandes | |
34 | Wetterbericht[S.wetter_bericht].Ereignis; | //Welches Wetterereignis | |
35 | Tageszeit; | //Tageszeit in Minuten | |
70..79 | Lagermenge | //Lagermenge der bestellten Produkte | |
80..89 | Verkaufspreis | //Verkaufspreis der bestellten Produkte | |
90..99 | Kaufmenge | //S | //Menge die gekauft wird |
batch.cpp |
// Kunde:Peter Hinzing // // Verwendung der Register: //[100] Wie oft er da war //[101] Taschengeld //[102] Verschiedene Ereignisse //[103] Zufallszahl Bestellung //[104] Zufallszahl Antwort auf Bestellung //[105] Unterschiedliche Dialoge Arbeit rede erst am 5. Tag //[106] Geschäft //[107] Das Spiel beginnt.Nach Auswahl Spiele //[108] Glückspiel.Einsatz.Art //[109] Glückspiel.Einsatz //[110] Glückspiel.Auswahl.Kunde //[111] Glückspiel.Auswahl.Leni //[112] Aktivierung Hobby //[113] Aktivierung Wohnen //[114] Dialoge über Würstelstand //[115] Gesamtbestand Cola //[116] zu Teuer?************************* //* noch nicht erledigt |
[200]: Leni soll mit Hale zum Asylantragsbüro gehen [201]: Leni hat den Hunde-Steckbrief gelesen [202]: Leni hat mit Peter Stein-Schere-Papier gespielt! (Böse)
Wie können Events ausgelöst werden?
Aktion Ausdruck // Aktivieren des Cheats: Aktion 3 // Aktivieren des Ereignisses, das im Register 100 berechnet wurde: Aktion [100]Was kann man nun mit diesen Events so alles machen? Hier ist ein Teil der Events vom Würstelstand:
0 | Fehler/Nie | Event 0 wird abgefangen und nicht behandelt |
1 | Initialisierung | Wird am Anfang aufgerufen und aktiviert viele Produkte, Kunden, ... |
2 | Ende | Sollte am Ende aufgerufen werden |
3 | FW-Cheat aktivieren | Wer hat das denn programmiert? |
4 | FW-Cheat deaktivieren | |
5 | Leni.Wettbewerb.Zeitung aktivieren | Sobald Lenis Image gut genug ist, wird hiermit die Zeitungsmeldung des bevorstehenden Wettbewerbs aktiviert |
6 | Leni.Wettbewerb.Zeitung->TelefonNr | Der Zeitungsartikel aktiviert die Telefonnummer, bei der man dann anrufen kann |
7 | Leni.Wettbewerb.TelNr deaktivieren | Nachdem angerufen wurde und alles geklärt ist, wird die Telefonnummer wieder deaktiviert |
8 | Hale deaktivieren | Hale deaktiviert sich selbst, weil er beleidigt wurde |
9 | Hale empfiehlt Josi | Hale aktiviert Josi sobald darüber geredet wurde (Smalltalk ist wichtig!) |
10 | Josi deaktivieren | Josi deaktiviert sich selbst |
11 | Peter deaktivieren | Peter deaktiviert sich selbst |
12 | Sepp Nachricht ohne Leni aktivieren | Sepp hat Leni Schwarzbrennen angeboten, Leni hat abgelehnt, die ganze Sache ist aufgeflogen und veröffentlicht worden |
13 | Sepp Nachricht mit Leni aktivieren | Leni hat beim Schwarzbrennen zugestimmt, und kriegt Probleme |
14 | Spiel verloren | Der Brieftäger löst das Ende des Spiels aus |
15 | Spiel gewonnen | Gottfried sieht das Kapital von Leni, und Leni gewinnt |
16 | Hale->Zeitungsbericht Asyl aktivieren | Leni hat mit Hale über seine Familie gesprochen, und dadurch die Zeitungsmeldung über das neue Asylrecht ausgelöst. |
17 | Hale->Zeitungsbericht->Telefonnr aktivieren | In der Zeitung steht die Telefonnummer, bei der jetzt angerufen werden kann. |
18 | Hale->Zeitungsbericht->Telefonnr deaktivieren | Das Gespräch deaktiviert die Telefonnummer wieder. |
19 | Hale->Familie aktivieren | Hales Familie bekommt Asyl |
20 | Spion aktivieren | Leni sollte einen Detektiv empfohlen bekommen, aber dieser wurde nie realisiert. |
33 | Neues Sortiment 1 (Neuer Lieferant) | Dieses Ereignis erweitert die Produktpalette |
100 | Wettbewerb gewonnen | Leni hat den Wettbewerb gewonnen, die Kunden reden darüber, ... |
101 | Wettbewerb verloren | |
102 | Lottogewinn | Leni hat im Lotto gewonnen |
Rechne [100]:= 20 + [30] * 10Der Inhalt des Registers 30 wird mit 10 multipiliziert, zu 20 addiert und das Ergebnis in das Register 100 geschrieben.
Es sind folgende Rechenoperationen möglich:
Operation | Notation | Beispiel | Ergebnis |
Klammern | (a) | (10+20)*30 | 900 |
Register | [a] | [20] | Der Inhalt des Registers 20 |
Multiplizieren | a*b | 3*4 | 12 |
Dividieren | a/b | 10/5 | 2 |
Rest | a%b | 10%3 | 1 |
Addieren | a+b | 1+1 | 2 |
Subtrahieren | a-b | 1-1 | 0 |
Zuweisung | [a]:b | [10]:20 | Schreibt in Stelle 10 den Wert 20 |
Vergleiche: | a?b | Ja(1) oder Nein(0) | |
Ist gleich | a=b | 10=20 | Nein(0) |
Kleiner | a<b | 10<20 | Ja(1) |
Größer | a>b | [10]>[20] | ob der Inhalt des Registers 10 größer als der Inhalt des Registers 20 ist |
AND | a&b | 1=1 & 2=2 | Wenn 1 gleich 1 ist UND 2 gleich 2 ist |
OR | a|b | 1=1 | 2=2 | Wenn 1 gleich 1 ist ODER 2 gleich 2 ist |
Zufallszahl | a Z b | 1 Z 6 | Liefert eine Zufallszahl im Bereich von 1 bis 6 |
Vergleiche liefern Zahlenwerte: 1 für Richtig/Wahr und 0 für Falsch Diese können auch in die Register geschrieben werden. Leerzeichen ( 10 + 20 ) sind erlaubt, aber nicht nötig (10+10).
Die größte Herausforderung war das Entwickeln des mathematischen Evaluierers, der jetzt fähig ist, Ausdrücke wie den folgenden richtig zu verarbeiten:
Annahmen: [100]=5, [24]=14, 1Z6=2 [[100]+1]:((1Z6)*([24]>3)+10/2-10%5) [5 +1]:((2 )*(14 >3)+10/2-10%5) [6 ]:(2 *(1 )+5 -0 ) [6 ]:(2 *1 +5 ) [6 ]:(7 ) [6 ]:7Ergebnis: [6]:7 Also in das Register 6 wird der Wert 7 geschrieben.
Wenn Bedingung Dannkönnen Abfragen gemacht werden. z.B.:
Wenn [100+1]>10 Kunde: Die Zahl im Register 101 ist größer als 10 ! Wenn 1>1 Kunde: FEHLER!Wenn die Bedingung erfüllt ist, dann geht es in der nächsten Zeile weiter, sonst in der übernächsten. Implementiert wurde es dadurch, daß die nächste Zeile übersprungen wird, wenn die Bedingung nicht erfüllt ist. Dies kann für Sprungbefehle genutzt werden:
Wenn [102]<10 Sprung KLEINER Wenn [102]=10 Sprung GLEICH Wenn [102]>10 Sprung GRÖSSER ... :KLEINER ... :GLEICH ... :GRÖSSER
BILD AusdruckWenn zum Beispiel in der HALE.BAT
Bild 5steht, dann wird HALE5.DAT (ein spezielles Bildformat) angezeigt, auf einen Mausklick gewartet, und dann geht der Dialog weiter.
// Kommentar: | BEFEHLSÜBERSICHT |
Kunde: Text | Der Kunde sagt etwas |
Tel: Text | Gesprächspartner sagt etwas |
Leni: Text | Leni sagt etwas |
:Sprungmarke | Sprungmarke wird angesprungen |
Liste Nummer | Wählt aktuelle Liste |
Löschen * | löscht alle Einträge der aktuellen Liste |
Löschen Sprungmarke | löscht Eintrag, der auf Sprungmarke zeigt, aus Liste |
Aktion Nummer | Führt besondere Aktionen aus |
Ende | Beendet den Dialog |
Bild Nummer | Zeigt das Bild mit dem Dateinamen NameNummer.dat |
Sprung Sprungmarke | Springt zur Sprungmarke |
Neu Sprungmarke,Text | Neues Thema in die aktuelle Liste einfügen |
Alt Sprungmarke,Text | Neue Option in die aktuelle Liste einfügen |
Menü | Menü anzeigen, auswählen lassen,... |
Wenn Bedingung | Abfrage (siehe nächste Zeilen) |
//Dann | Wenn ja, dann geht es in der nächsten Zeile weiter |
//Sonst | Wenn nein, dann wird die nächste Zeile übersprungen |
Rechne Ausdruck | Rechnet in die Register |
Bild Ausdruck | Zeigt Bilder an, und wartet auf Mausklick/Taste |
batch.cpp |
#ifndef _DIALOG_H #define _DIALOG_H #ifndef MAIN_MODULE #define DIALOG_TEXT #define DEBUG //Hier werden die benötigten Header Files inkludiert #include <stdio.h> //... #endif //Hier sind die ganzen Dialogroutinen //.. S2 Dialog(char *Filename, TYP Array[]) { //... } #ifndef MAIN_MODULE //Hier nun die nötigen Sachen für das Testprogramm TYP Feld[256]; int main(short argc,char *argv[]) { //Testprogramm Dialog(Filename,Feld); } #endif |
wurst.cpp |
#define MAIN_MODULE #include "batch.cpp" TYP Felder[10][256]; int main(short argc,char *argv[]) { Dialog(Filename,Felder[i]); } |
|
Der LinuxFocus Redaktion schreiben
© Philipp Gühring, FDL LinuxFocus.org Einen Fehler melden oder einen Kommentar an LinuxFocus schicken |
2002-02-24, generated by lfparser version 2.26