par Philipp Gühring L´auteur: Philipp vient juste de passer son bac scientifique à HTL Wiener Neustadt, une école technique supérieure en informatique. Il a maintenant du temps à consacrer à son équipe de développement appelée Futureware 2001. Il est également fan de Linux et membre actif du Linux User Group Austria Sommaire:
|
Résumé:
Dialog est un langage de programmation spécialisé dans les dialogues avec l'utilisateur. Il a été utilisé dans le logiciel de simulation commerciale Würstelstand. Cet article décrit le développement de Dialog et ses applications.
Les dialogues sont
stockés dans des fichiers ASCII, et sont
interprétés ligne par ligne. Il est également
possible d'avancer à une ligne déterminée
à tout moment. Ces fichiers sont simplement créés
avec un éditeur de texte. Le nom de fichier est
Name.BAT (i.e. : HALR.BAT). Quand le joueur (Leni) parle, cela
donne quelque chose comme :
Leni: Text Leni: Bonjour, monsieur ! Que souhaitez vous aujourd'hui ? Leni: Regardez-moi ces jeunes ! Incroyable ! |
Regardez-moi ces jeunes ! Incroyable ! Etes-vous tombé du lit ? |
Deux Francfort avec du pain et deux Colas. Allons, laisses tomber, vieil homme ! |
Quand l'interlocuteur dit quelque chose: (Kunde signifie client en Allemand, et Telefon signifie téléphone.) Kunde: Text Kunde: Deux Francfort avec du pain et deux Cola. Allons, laisses tomber, vieil homme ! Telefon: Futureware 2001, Philipp Gühring. Que puis-je pour vous ? |
Tous les dialogues habituels se terminent par
Ende(Ende signifie fin en Allemand)
Un exemple simple : |
Leni: Bonjour! Que souhaitez-vous ce matin ? Kunde: Salut ! Un Käsekrainer s'il-vous-plaît ! Leni: Un instant. Leni: Et voilà. Kunde: Merci beaucoup. Au revoir. Leni: Au revoir ! Ende |
Les étiquettes de saut sont définies par un caractère "deux points" au début d'une ligne, qui est suivi immédiatement par le nom de l'étiquette. On peut atteindre une étiquette avec la commande Sprung (Sprung signifie saut en Allemand) :
:Target //Suit un exemple de saut : Sprung Target
| Que fait l'interpréteur dans cet exemple ? Tout d'abord, il trouve la commande Leni: et affiche le texte 1. Ensuite il y a un commentaire sur la ligne suivante (Commençons par ceci) qui sera ignoré. Après celà, il trouve la commande Sprung. L'interpréteur recherche alors l'étiquette MENU_0 dans tout le dialogue, la trouve quelques lignes plus loin, et effectue un saut à cette position. De nouveau, on trouve un commentaire (Je suis de retour !). Enfin, la dernière commande est Leni:, qui affiche 3 à l'écran. En fin de compte, la commande Leni: 2 a été laissée de coté dans l'exemple et Leni ne dit pas 2. |
Comme nous l'avons vu, une ligne peut :
// Ceci est un commentaire ************************************************** *On peut faire aussi des commentaires comme celà.* **************************************************Les commentaires ne peuvent pas être sur la même ligne qu'une commande :
Leni: Je ne comprends plus rien. // SANS COMMENTAIREL'interpreteur va reconnaître Je ne comprends plus rien. // SANS COMMENTAIRE comme le texte à afficher !
| Dialog propose
le mécanisme suivant : Le système gère une liste, dans laquelle sont
insérées les entrées correspondantes aux possibilités offertes à
l'utilisateur. En temps utile, le menu est affiché à l'écran et
l'utilisateur fait son choix. L'interpréteur poursuit l'exécution par
la partie du programme qui gère l'entrée choisie.
Tout d'abord, les entrées sont insérées dans la liste par les commandes NEU et ALT. Ces deux commandes sont suivies de l'étiquette cible pour le saut et du texte de l'entrée. Le texte peut être très long, dans ce cas, le système insère automatiquement des sauts de lignes. Avec la commande MENÜ, toute la liste est affichée et le joueur peut alors choisir une des propositions. |
Neu acheter, un bien chaud, comme d'hab, ou pas ? Neu travail, Comment ca va au travail ? Neu langue, Suivez vous toujours le cours de langues à WIFI ? Neu family, Comment va la famille ? Neu weather, Vous profitez du beau temps ? MenüDe cette façon, le joueur a la possibilité de choisir chacune des entrées dans un ordre quelconque. Les choix peuvent être répétés. Les entrées qui ne sont pas choisies restent dans la liste et pourront être sélectionnées plus tard. Ainsi, si nous choisissons travail dans l'exemple précédent :
:travail Leni: Comment ca va le travail ? Client: Trop de choses à faire, comme toujours. MenüComme prévu, seule la ligne choisie disparait. Dans le menu suivant, restent les sujets :
Client: Combien vous en voulez ? Alt un lot, 10 Pièces Alt deux lots, 20 Pièces Alt dix lots, 100 Pièces Menü :un lot //Nous continuons ici, quand l'utilisateur choisit 10 pièces. :deux lots ... :dix lots ...Comme cela n'a pas de sens de conserver les entrées choisies dans la liste, toutes les entrées seront automatiquement effacées après le choix de l'utilisateur. Si par exemple celui-ci choisit deux lots, l'interpréteur saute à l'étiquette deux lots:
:deux lots Client: Etes-vous sûr ? Leni: Oui, je veux 20 pièces. Client: Pour quand les voulez-vous ? Alt 1, Demain Alt 2, Après demain Alt 3, Plus tard MenüFinalement, nous allons associer ces deux types :
Kunde: Rappelles-toi le bon vieux temps. Alt Memoire, Ah oui, je viens juste de me souvenir, que ... MENÜ
La liste 0 est recommandée pour les options. La liste 1 est destinée aux sujets généraux, par exemple famille, travail, loisirs, cuisine... Si l'on veut parler travail, et qu'il y a d'autres sujets à l'intérieur du sujet travail, on choisira la liste 2. Nous avons vu un exemple avec le dialogue avec Hale. Dans le cas ou un plus grand nombre de listes seraient nécéssaires, il faudra changer la constante dans le source de l'interpréteur.
LISTE 0 LISTE 1 LISTE 2Evidemment, les entrées de chaque liste ne sont pas modifiées par cette action. Les commandes NEU, ALT, MENÜ et LÖSCHEN s'appliquent toujours à la liste courante.
Neu Memoire, Ah oui, je viens juste de me souvenir, que ...La liste 0 était automatiquement effacée après le menu. Elle n'était donc utile que pour des options, et non pour les thèmes.
Je vous recommande maintenant de consulter les exemples HALE.BAT et PETER.BAT, dans lesquels les listes sont très largement utilisées.
LÖSCHEN étiquetteefface toutes les entrées de la liste courante pointant vers étiquette. Par exemple:
LÖSCHEN famillePour effacer toutes les entrées de la liste courante, on ajoute un astérisque :
LÖSCHEN *(Si désiré, le support des expressions régulières peut être ajouté ;-)
Menü affiche toutes les entrées de la liste courante, et permet à l'utilisateur de faire son choix parmi celles-ci. Après celà, l'entrée choisie et toutes les options ( ajoutées avec ALT) seront supprimées. Enfin l'interpréteur effectue un saut vers l'étiquette correspondante. Dans le cas où il ne reste plus qu'une seule entrée dans la liste, cette entrée est supposée être choisie et donc aucun choix n'est proposé. Si la liste est vide, ou si la cible est introuvable, l'interpréteur continuera à la ligne suivant MENÜ.
1 | Event; | //Numéro d'évênement (voir texte.h) | |
2 | geliefert; | //S | //0-10 nombre de dixièmes fournis |
3 | wtag; | //jour de la semaine | |
4 | tag; | //jour du mois | |
5 | monat; | //mois | |
6 | jahr; | //année | |
7 | Datum; | //code du jour (1.1.1997 = 0) | |
8 | wetter; | //la météo du jour | |
9 | konto; | //S | //compte bancaire |
10 | kapital; | //S | //cash |
11 | ausgaben; | //S | //dépenses du jour |
12 | einnahmen; | //S | //revenus du jour |
13 | sterne; | //S | // évaluation de la qualité du stand (0-5 étoiles) |
14 | wverkauf; | //Nombre de produit vendus cette semaine | |
15 | weinnahmen; | //revenu de la semaine | |
16 | wausgaben; | //dépense de la semaine | |
17 | 0; | //S | //nouveau revenu/dépense (conséquence du dialogue) |
18 | Nachrichtenserie; | //quelle série d'infos(0=Elch,1=...) | |
19 | Nachricht; | //quelle info dans la série courante (0=1.Tag,1=2...) | |
20 | LottoNr[0]; | //combien de numeros cochés dans la grille(0-6) | |
21 | LottoErgebnis[0]; | //combien de numéros corrects | |
22 | LottoGewinn[LottoErgebnis[0]]; | //gains de Leni | |
23 | S.Image; | //S | //Image de Leni |
24 | S.Override; | //S | //Evênement masque |
25 | S.wverkauf[1]; | //produits vendus la semaine dernière | |
26 | S.weinnahmen[1]; | //revenus de la semaine dernière | |
27 | S.wausgaben[1]; | //dépenses de la semaine dernière | |
28 | S.wverkauf[2]; | //produits vendus il y a deux semaine | |
29 | S.weinnahmen[2]; | //revenus d'il y a deux semaine | |
30 | S.wausgaben[2]; | //dépenses d'il y a deux semaines | |
31 | S.NOverride; | //S | //evênement masque de demain |
32 | S.wetter_bericht; | // prévision météo | |
33 | Gesamtwert(); | //Valeur totale dy stand | |
34 | Wetterbericht[S.wetter_bericht].Ereignis; | //Evênement météo | |
35 | Tageszeit; | //Heure du jour en minutes | |
70..79 | Lagermenge | //stocks | |
80..89 | Verkaufspreis | //S | //prix de vente |
90..99 | Kaufmenge | //S | //quantité commandée |
batch.cpp |
// Client: Peter Hinzing // // Registres utilisés //[100] Combien de fois il est venu //[101] Argent de poche //[102] Différents évênements //[103] Nombre aléatoire: commande //[104] Nombre aléatore: réponse à la commande //[105] dialogues différents : thème travail à partir du 5ème jour //[106] Vente //[107] Le jeu commence. Jeu après choix. //[108] Jeu.mise.type //[109] Jeu.mise.quantite //[110] Jeu.choix.Peter //[111] Jeu.choix.Leni //[112] Activation Hobby //[113] Activation Maison //[114] Dialogue à propos de Würstelstand //[115] stock total coke //[116] trop cher ?************************* //* à implanter |
Tous les dialogues voient les mêmes valeurs et tous peuvent y écrire. Il devrait y avoir un système pour réguler l'usage de ces registres. Les trois registres suivants sont utilisés par des dialogues de Würstelstand (documentés dans daten.h) :
[200]: Leni peut aller au bureau de l'immigration avec Hale. [201]: Leni lit la circulaire sur les chiens recherchés [202]: Leni a joué à papier caillou ciseau avec Peter. (terrible !)
Comment déclencher des évênements ?
Aktion expression // activation des Cheats: Aktion 3 // activating de l'évênement, qui a été calculé dans le registre 100 : Aktion [100]Que faire de ces évênements ? Voici un extrait de la liste d'évênements de Würstelstand :
0 | Erreur/Jamais | L'Evênement 0 a été reçu sans pouvoir être géré. |
1 | Initialisation | est déclenché au démarrage et active de nombreux produits clients, ... |
2 | Fin | devrait être déclenché à la fin du jeu. |
3 | activation FW-Cheat | Qui a codé ça ?!? |
4 | désactivation FW-Cheat | Gardez le secret ! |
5 | Leni.competition.journal | L'image de Leni est suffisament bonne -> activation de l''article de journal sur la prochaine compétition |
6 | Leni.competition.journal->No Téléphone | L'article du journal active le numéro de téléphone pour s'inscrire à la compétition. |
7 | Leni.competition.deactivation No Téléphone | Après l'appel téléphonque et tout étant réglé, le numéro est désactivé. |
8 | désactivation de Hale | Hale se désactive, car Leni l'a offensé. |
9 | Hale recommande Josi | Hale active Josi dès qu'il en a parlé. (Smalltalk est important!) |
10 | deactivation Josi | Josi se désactive |
11 | deactivation Peter | Peter se désactive |
12 | Info de Sepp, sans accord de Leni | Sepp offre une production illégale, Leni refuse, toute l'histoire devient publique. |
13 | Info de Sepp, avec accord de Leni | Leni accepte la production illégale et les problèmes suivent |
14 | jeu perdu | Le postier Gottfried annonce la fin du jeu |
15 | jeu gagné | Gottfried réalise la valeur du stand de hot-dog et Leni gagne |
16 | Hale.info article droit d'asile activation | Leni parle à Hale de sa famille, ce qui suscite un article de journal sur le droit d'asile. |
17 | Hale.info article->No téléphone activation | Le journal publie le numéro qui peut maintenant être utilisé. |
18 | Hale-> article->No téléphone desactivation | La conversation désactivates le numéro de téléphone |
19 | Hale->Famille activation | La famille de Hale reçoit le droit d'asile. |
20 | activation de l'espion | Leni devrait se voir recommandé un détective, mais cela n'a jamais été mis en pratique.. |
33 | Nouveau produit 1 (Nouveau fournisseur) | Cet évênement étend la gamme produit. |
100 | competition gagnée | Leni remporte le concours, les clients vont maintenant en parler, ... |
101 | compétion perdue | |
102 | Prix de Loterie | Leni a gagné à la loterie |
Rechne [100]: 20 + [30] * 10Le contenu du registre 30, multiplié par 10, ajouté à 20 est placé dans le registre 100.
Les opérations suivantes sont disponibles :
Opération | Notation | Example | Solution |
Parenthèse | (a) | (10+20)*30 | 900 |
Registre | [a] | [20] | Le contenu du registre 20 |
Multiplication | a*b | 3*4 | 12 |
Division | a/b | 10/5 | 2 |
Modulo | a%b | 10%3 | 1 |
Addition | a+b | 1+1 | 2 |
Soustraction | a-b | 1-1 | 0 |
Accès mémoire | [a]:b | [10]:20 | Place la valeur 20 à l'emplacement 10. |
Test booléen | a?b | Oui(1) ou Non(0) | |
Test égalite | a=b | 10=20 | Non(0) |
Test inférieur | a<b | 10<20 | Oui(1) |
Test supérieur | a>b | [10]>[20] | |
ET | a&b | 1=1 & 2=2 | Si 1 égale 1 ET 2 égale 2 |
OU | a|b | 1=1 | 2=2 | Si 1 égale 1 OU 2 égale 2 ist |
Nombre aléatoire | a Z b | 1 Z 6 | retourne un nombre aléatoire entre 1 et 6 |
Résultat des comparaisons en nombre : 1 pour VRAI et 0 pour FAUX. Ils peuvent être également placés dans les registres. Les espaces ont autorisés dans les expressions ( 10 + 20 ), mais pas obligatoires (10+10).
Le plus grand challenge a été le développement de l'évaluateur mathématique, qui est maintenant capable de gérer des expressions de la forme :
Hypothèse : [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 ]:7Solution: [6]:7 LA valeur 7 est sauvée dans le registre 6.
Wenn condition thenon peut faire des comparaisons, par exemple :
Wenn [100+1]>10 Client: Le nombre dans le registre 101 est supérieur à 10 ! Wenn 1>1 Client: ERREUR !Si la condition est vraie, l'interpréteur passe à la ligne suivante, sinon il passe une ligne. Cette instruction peut être utilisée en association avec des sauts:
Wenn [102]<10 Sprung PLUSPETIT Wenn [102]=10 Sprung EGAL Wenn [102]>10 Sprung PLUSGRAND ... :PLUSPETIT ... :EGAL ... :PLUSGRAND
BILD expression(Bild signifie image en allemand) Si par example
Bild 5est contenu dans HALE.BAT, alors HALE5.DAT (un format d'image spécial) est affiché. Un click souris est attendu puis le dialogue se poursuit.
// commentaire | COMMAND REFERENCE |
Client: text | Le client dit quelquechose |
Tel: text | L'interlocuteur dit quelquechose. |
Leni: text | Leni dit quelquechose |
:target | Etiquette à laquelle l'interpréteur peut sauter |
Liste number | Faire d'une liste la liste courante. |
Löschen * | Effacer toutes les entrées de la liste courante. |
Löschen target | Effacer toutes les entrées de la liste courante qui pointent vers target. |
Aktion number | Déclenche un évênement |
Ende | Fin du dialogue |
Bild number | Affiche l'image dans le fichier NameNumber.dat |
Sprung target | Effectue un saut vers target |
Neu target,Text | Insère un nouveau sujet dans la liste courante |
Alt target,Text | Insère un nouveau choix dans la liste courante |
Menü | Affiche le menu, fait choisir le joueur, ... |
Wenn condition | Comparaison (voir plus loin) |
//then | Si vraie, l'interpréteur exécute la ligne suivante. |
//else | Si fausse, l'interpréteur passe la ligne suivante. |
Rechne expression | Evalue l'expressions dans un registre |
Bild expression | Affiche une image, attends un click souris |
batch.cpp |
#ifndef _DIALOG_H #define _DIALOG_H #ifndef MAIN_MODULE #define DIALOG_TEXT #define DEBUG //Ici sont les fichiers include nécessaires #include <stdio.h> //... #endif //Ici sont les routines du dialogue //.. S2 Dialog(char *Filename, TYP Array[]) { //... } #ifndef MAIN_MODULE //Ici tout dont a besoin le programme de test TYP Feld[256]; int main(short argc,char *argv[]) { // Programme de test 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]); } |
Site Web maintenu par l´équipe d´édition LinuxFocus
© Philipp Gühring LinuxFocus 1999 |
Translation information:
|
1999-11-22, generated by lfparser version 0.7