Dialog - eine Programmiersprache für Dialoge

ArticleCategory

Software Development

AuthorImage

Philipp Gühring

AuthorName

Philipp Gühring

AboutTheAuthor

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.

Abstract

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.

ArticleIllustration

Josi, einer der Kunden

ArticleBody:

Einleitung

Würstelstand ist eine österreichische Handelssimulation, bei der der Kundenkontakt schon fast zu einem Adventure wurde. Und eben für diesen Kundenkontakt entwickelte ich eine Dialogsprache, die folgende Anforderungen erfüllen soll: Als wir dann noch Telefongespräche realisierten, griff ich wieder auf die Dialogsprache zurück und erweiterte sie. Der Spieler steuert den Hauptcharakter Leni, dem der Würstelstand gehört, mittels Multiple-Choice, die Kunden werden vom Computer simuliert. Das Ziel des Spielers soll es sein, die Kunden zu beraten, ihnen etwas zu verkaufen, und mit ihnen zu plaudern. Die Kunden kommen automatisch, wenn sie Zeit und Hunger haben. Dann gibt es noch die Möglichkeit für den Spieler, selbst aktiv zu werden, und bei verschiedenen Telefonnummern anzurufen.

Dialogsprache

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!
Leni redet
Kundin redet 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

Ende
auf.

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

Beispiel
...
Leni: 1
//Zuerst wird dies hier get
SPRUNG MENÜ_0
//Jetzt wurde gesprungen
...
//Diese Befehle werden übersprungen
Leni: 2
:MENÜ_0
//Und hier gehts wieder weiter
Leni: 3
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:

Kommentare beginnen mit ;(Strichpunkt),//(Zwei Schrägstriche), (Leerzeichen),*(Stern). Sie dienen zur Hilfe und Dokumentation, und werden vom Interpreter ignoriert. z.b:
// 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

Das Multiple Choice System

Multiple-Choice Auswahl Die Dialogsprache geht vom folgenden System aus: Das System stellt eine Liste zur Verfügung, in die im Laufe der Zeit die Einträge eingetragen werden, die der Benutzer als Antwortmöglichkeiten haben soll. Wenn die Zeit gekommen ist, wird das Menü auf den Bildschirm gebracht, der Benutzer kann auswählen, und dann wird zu einem Programmteil gesprungen, der die Auswahl weiterbehandelt. Zuerst werden also immer mit dem Befehl NEU oder ALT Auswahlmöglichkeiten in eine Liste hinzugefügt. Beiden Befehlen muß angegeben werden, zu welchem Sprungziel gesprungen werden soll, wenn der Eintrag ausgewählt werden sollte, und dann natürlich der ganze Auswahltext. Dieser kann ruhig länger sein, er wird vom System automatisch in mehrere Zeilen umgebrochen. Dann wird mit dem Befehl MENÜ die Liste angezeigt, und der Spieler kann sich einen Eintrag aus der Liste aussuchen.

Nun gibt es drei Arten von Abfragen.

Themen

Die erste Art ist zum Beispiel für Gesprächsthemen geeignet:
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: Nun, es gibt auch eine andere Art von Abfragen:

Auswahl

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:

Kontext/Themenwechsel

Eine weitere Nuance der menschlichen Dialoge haben wir auch noch erkannt und umgesetzt: Wenn man mit dem Gesprächspartner über ein Thema diskutiert hat, und noch eine Anmerkung übrig hat, kann man entweder diese Anmerkung ausspielen, oder das Thema wechseln. Wenn das Thema gewechselt wird, dann verfällt der Kontext der Anmerkung, und sie wird sinnlos. Man hat also die Möglichkeit, das Thema beizubehalten, oder zu einem anderen Thema zu springen. Diese Möglichkeit wurde so umgesetzt, daß man die Anmerkung wie ein normales Thema in die Themenliste einfügt, und angibt, daß die Anmerkung kontextbezogen ist, und daher auch gelöscht wird, wenn sie nicht ausgewählt wird.
Kunde: Jaja, das waren Zeiten.
Alt Erinnerung,Da fällt mir ein, du ...
MENÜ

Umsetzung

Jetzt kommt sicher die Frage auf, wie man die doch verschiedenen Konzepte realisieren kann. Wie Sie vielleicht schon bemerkt haben, liegt der Unterschied in der Verwendung von NEU oder ALT. Wenn man einen Eintrag mit NEU einfügt, dann bleibt er in der Liste erhalten, nur wenn er nicht ausgewählt wird. Wenn ein Eintrag mit ALT eingefügt wird, dann wird er nach dem Menü automatisch gelöscht, unabhängig davon, ob er ausgewählt wurde oder nicht. (Er ist dann verALTert).

Mehrere Listen

Was macht man nun, wenn man in der Liste die Gesprächsthemen verwaltet, und in einem Thema eine Auswahl braucht, aber die Gesprächsthemen nicht mit anzeigen will? Zu diesem Zweck habe ich nicht nur eine Liste, sondern gleich 3 Listen angelegt:

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.

Wie verwendet man nun die verschiedenen Listen?

Am Anfang ist die Liste 1 die aktuelle Liste. Mit dem Befehl
LISTE 0
wechselt man in die Liste 0. Mit dem Befehl
LISTE 1
kommt 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.

Alte Version von Dialog

In der früheren Version von Dialog, die beim Würstelstand verwendet wurde, ging das ganze noch etwas anders: Statt dem Befehl ALT wurde dem Befehl NEU nach dem Beistrich ein Paragraphenzeichen angegeben:
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 Sprungziel
wird jeder Eintrag aus der aktuellen Liste gelöscht, der auf Sprungziel zeigt. z.B.:
LÖSCHEN familie
Um 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.

Schnittstellen

Wie kann der Dialog nun auf die Umgebung reagieren, die Umgebung beeinflussen, und mit anderen Dialogen Daten austauschen?

Register

Beim Würstelstand hat jeder Dialog auf 256 Register Zugriff. Jedes dieser Register fasst Zahlen im Bereich von -2Mrd. bis +2Mrd. Diese sind in 3 Bereiche unterteilt:

Systemregister

Die ersten 100 Register(von 0 bis 99) sind vom System reserviert: Sie werden vom System vor dem Start des Dialogs mit den Werten gefüllt. Alle mit //S markierten Register werden nach dem Ende des Dialogs vom System ausgewertet und verarbeitet. Hier nun die Liste der zur Zeit vom Würstelstand verwendeten Systemregister:
1Event; //Ereignis Nummer (siehe texte.h)
2geliefert;//S//0-10 wieviel zehntel geliefert werden)
3wtag; //Wochentag
4tag; //Monatstag
5monat; //Monat
6jahr; //Jahr
7Datum; //fortlaufender Tag (1.1.1997 = 0)
8wetter; //Das Tageswetter
9konto;//S//Wieviel Geld am Konto ist
10kapital;//S//Kapital
11ausgaben;//S//Wieviel Ausgaben heute gemacht wurden
12einnahmen;//S//Wieviel Einnahmen heute gemacht wurden
13sterne;//S//Wieviel Sterne der Würstelstand hat(0-5)
14wverkauf; //Wieviel diese Woche verkauft wurde
15weinnahmen; //Wieviel diese Woche eingenommen wurde
16wausgaben; //Wieviel diese Woche ausgegeben wurde
170;//S//Neue Ein/Ausgaben (durch Dialog ausgelöst)
18Nachrichtenserie; //Welche Nachrichtenserie (0=Elch,1=...)
19Nachricht; //Welche Nachricht in der Serie (0=1.Tag,1=2.
20LottoNr[0]; //Wieviele LottoNr angekreuzt sind(0-6)
21LottoErgebnis[0]; //Wieviele LottoNr richtig waren
22LottoGewinn[LottoErgebnis[0]]; //Wieviel gewonnen wurde
23S.Image;//S//Lenis Image
24S.Override;//S//Override-Ereignis
25S.wverkauf[1]; //Wieviel letzte Woche verkauft wurde
26S.weinnahmen[1]; //Wieviel letzte Woche eingenommen wurde
27S.wausgaben[1]; //Wieviel letzte Woche ausgegeben wurde
28S.wverkauf[2]; //Wieviel vorletzte Woche verkauft wurde
29S.weinnahmen[2]; //Wieviel vorletzte Woche eingenommen wurde
30S.wausgaben[2]; //Wieviel vorletzte Woche ausgegeben wurde
31S.NOverride;//S//Override für morgen
32S.wetter_bericht; //Welcher Wetterbericht verwendet wurde
33Gesamtwert(); //Gesamtwert des Würstelstandes
34Wetterbericht[S.wetter_bericht].Ereignis; //Welches Wetterereignis
35Tageszeit; //Tageszeit in Minuten
70..79Lagermenge //Lagermenge der bestellten Produkte
80..89Verkaufspreis //Verkaufspreis der bestellten Produkte
90..99Kaufmenge//S//Menge die gekauft wird

Dialogregister

Die nächsten 100 Register (von 100 bis 199) sind für jeden Dialog. Sie werden am Anfang des Spieles auf 0 gesetzt, bleiben dem Dialog über das ganze Spiel erhalten (werden also auch in den Spielständen gespeichert, ...), und können nur vom dazugehörigen Dialog gelesen und geschrieben werden. Am Anfang des Dialoges sollte in Kommentaren dokumentiert werden, welche Register wofür verwendet werden.
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 
Im Register [100] merkt sich Peter, wie oft er schon da war. Beim ersten Mal stellt er sich dann vor, beim 10. Mal bietet er das "du" an. In [101] verwaltet er sein tägliches Taschengeld, ...

Shared Memory

Die letzten 56 Register (könnten auch mehr sein, die genaue Zahl ist ja nicht so wichtig) sind Shared Memory zwischen den Dialogen. Das heißt, daß alle Dialoge auf diese Register zugreifen können, und alle Dialoge hier dieselben Register sehen. Es muß also eine zentrale Stelle geben, bei der festgelegt wird, welches Register mit welchen Daten belegt wird. Folgende 3 Register wurden beim Würstelstand verwendet:
[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) 

Events

Für den Würstelstand haben wir ein Event-System entwickelt, das dem Slot System von KDE ähnlich sein dürfte. (Ich kenne letzteres zuwenig) Jeder Event hat eine eindeutige Nummer, die in einer zentralen Datei festgelegt wird. Events können folgende Dinge auslösen: Wie wird das gemacht? In den jeweiligen Datendateien (Produkte, Kunden, Telefonnummern, Nachrichtenserien) als Start/End Wert die Eventnummer eintragen.

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:
0Fehler/NieEvent 0 wird abgefangen und nicht behandelt
1InitialisierungWird am Anfang aufgerufen und aktiviert viele Produkte, Kunden, ...
2EndeSollte am Ende aufgerufen werden
3FW-Cheat aktivierenWer hat das denn programmiert?
4FW-Cheat deaktivieren
5Leni.Wettbewerb.Zeitung aktivierenSobald Lenis Image gut genug ist, wird hiermit die Zeitungsmeldung des bevorstehenden Wettbewerbs aktiviert
6Leni.Wettbewerb.Zeitung->TelefonNrDer Zeitungsartikel aktiviert die Telefonnummer, bei der man dann anrufen kann
7Leni.Wettbewerb.TelNr deaktivierenNachdem angerufen wurde und alles geklärt ist, wird die Telefonnummer wieder deaktiviert
8Hale deaktivierenHale deaktiviert sich selbst, weil er beleidigt wurde
9Hale empfiehlt JosiHale aktiviert Josi sobald darüber geredet wurde (Smalltalk ist wichtig!)
10Josi deaktivierenJosi deaktiviert sich selbst
11Peter deaktivierenPeter deaktiviert sich selbst
12Sepp Nachricht ohne Leni aktivierenSepp hat Leni Schwarzbrennen angeboten, Leni hat abgelehnt, die ganze Sache ist aufgeflogen und veröffentlicht worden
13Sepp Nachricht mit Leni aktivierenLeni hat beim Schwarzbrennen zugestimmt, und kriegt Probleme
14Spiel verlorenDer Brieftäger löst das Ende des Spiels aus
15Spiel gewonnenGottfried sieht das Kapital von Leni, und Leni gewinnt
16Hale->Zeitungsbericht Asyl aktivierenLeni hat mit Hale über seine Familie gesprochen, und dadurch die Zeitungsmeldung über das neue Asylrecht ausgelöst.
17Hale->Zeitungsbericht->Telefonnr aktivierenIn der Zeitung steht die Telefonnummer, bei der jetzt angerufen werden kann.
18Hale->Zeitungsbericht->Telefonnr deaktivierenDas Gespräch deaktiviert die Telefonnummer wieder.
19Hale->Familie aktivierenHales Familie bekommt Asyl
20Spion aktivierenLeni sollte einen Detektiv empfohlen bekommen, aber dieser wurde nie realisiert.
33Neues Sortiment 1 (Neuer Lieferant)Dieses Ereignis erweitert die Produktpalette
100Wettbewerb gewonnenLeni hat den Wettbewerb gewonnen, die Kunden reden darüber, ...
101Wettbewerb verloren
102LottogewinnLeni hat im Lotto gewonnen
Wie man sieht, sind die Events ein sehr leistungsfähiges Mittel, die Logik des Spiels umzusetzen.

Berechnungen

Der Dialog lebt nicht vom Text allein, auch Zahlen müssen rein. Mit Rechne kann man Werte berechnen und zur späteren Verwendung in den Registern ablegen. z.B.:
Rechne [100]:= 20 + [30] * 10
Der 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:
OperationNotationBeispielErgebnis
Klammern(a)(10+20)*30900
Register[a][20]Der Inhalt des Registers 20
Multiplizierena*b3*412
Dividierena/b10/52
Resta%b10%31
Addierena+b1+12
Subtrahierena-b1-10
Zuweisung[a]:b[10]:20Schreibt in Stelle 10 den Wert 20
Vergleiche:a?bJa(1) oder Nein(0)
Ist gleicha=b10=20Nein(0)
Kleinera<b10<20Ja(1)
Größera>b[10]>[20]ob der Inhalt des Registers 10 größer als der Inhalt des Registers 20 ist
ANDa&b1=1 & 2=2Wenn 1 gleich 1 ist UND 2 gleich 2 ist
ORa|b1=1 | 2=2Wenn 1 gleich 1 ist ODER 2 gleich 2 ist
Zufallszahla Z b1 Z 6Liefert 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      ]:7
Ergebnis: [6]:7 Also in das Register 6 wird der Wert 7 geschrieben.

Auf Register reagieren

Mit
Wenn Bedingung
Dann
kö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

Bilder anzeigen

Und hier noch etwas ganz Aktuelles aus der Dialogschmiede:
BILD Ausdruck
Wenn zum Beispiel in der HALE.BAT
Bild 5
steht, dann wird HALE5.DAT (ein spezielles Bildformat) angezeigt, auf einen Mausklick gewartet, und dann geht der Dialog weiter.

Befehlsübersicht

Um einen besseren Überblick zu erhalten, habe ich hier noch eine Befehlsübersicht erstellt:
// Kommentar:BEFEHLSÜBERSICHT

Kunde: TextDer Kunde sagt etwas
Tel: TextGesprächspartner sagt etwas
Leni: TextLeni sagt etwas
:SprungmarkeSprungmarke wird angesprungen
Liste NummerWählt aktuelle Liste
Löschen *löscht alle Einträge der aktuellen Liste
Löschen Sprungmarkelöscht Eintrag, der auf Sprungmarke zeigt, aus Liste
Aktion NummerFührt besondere Aktionen aus
EndeBeendet den Dialog
Bild NummerZeigt das Bild mit dem Dateinamen NameNummer.dat
Sprung SprungmarkeSpringt zur Sprungmarke
Neu Sprungmarke,TextNeues Thema in die aktuelle Liste einfügen
Alt Sprungmarke,TextNeue Option in die aktuelle Liste einfügen
MenüMenü anzeigen, auswählen lassen,...
Wenn BedingungAbfrage (siehe nächste Zeilen)
//DannWenn ja, dann geht es in der nächsten Zeile weiter
//SonstWenn nein, dann wird die nächste Zeile übersprungen
Rechne AusdruckRechnet in die Register
Bild AusdruckZeigt Bilder an, und wartet auf Mausklick/Taste

Nachteile des Multiple-Choice Systems

Dialog Maker

Markus Muntaneau hat ein Delphi Programm namens Dialog-Maker entwickelt, mit dem die Dialoge leichter zu entwickeln sein sollten. Leider wurde Dialog-Maker nicht fertiggestellt (hat noch einige Bugs), und ist daher nur eingeschränkt verwendbar. Aber ein Blick darauf wird sich für Entwickler sicherlich auszahlen.

Programmier Tricks

Da das ganze Würstelstand-Projekt nur ca. 10.000 Zeilen C(++)-Code umfaßt hat, und die Kompilierzeiten noch erträglich waren, verzichtete ich auf eine saubere Modularisierung (ok, Faulheit war auch dabei). Stattdessen habe ich das Test-Include System entwickelt: Der Modulcode kommt in eine .c Datei, die für sich lauffähig ist, und zu den Modulroutinen gleich ein Testprogramm mitliefert, das per #ifdef deaktiviert wird, wenn es vom Hauptmodul inkludiert wird. So spart man Header Files. ;-)

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]);
}

Abschließende Bemerkungen

Übrigens, die Linux Version vom Würstelstand sollte ab September 1999 bei Futureware (http://poboxes.com/futureware) erhältlich sein. Wenn genügend Nachfrage besteht (E-Mails an den Autor), dann werden weitere Artikel über praktische Anwendungsbeispiele von Dialog folgen.