Un petit article aujourd’hui sur une technique générale pour gérer la progression du joueur dans un jeu linéaire. C’est une technique que j’ai vue la première fois dans le code source de Filaments, de FibreTigre, et je l’ai utilisée dans quasiment tous mes jeux ; mais j’imagine que la technique est classique et a été mise en œuvre dans de nombreux jeux, notamment anglophones.

Pour gérer la progression du joueur, il y a plusieurs approches, et la meilleure dépendra de la structure de votre jeu. Est-ce que votre jeu se passe toujours dans le même environnement ? Est-ce que toutes les salles sont accessibles au début du jeu, façon open world à la Morrowind, ou est-ce que le joueur avance petit à petit et découvre des salles nouvelles, jusqu’à arriver à la dernière, façon Aventure ? Est-ce que votre jeu a une progression plutôt linéaire, une énigme ou une étape après l’autre, ou est-ce que le joueur peut travailler sur plusieurs énigmes en même temps, de façon à ne jamais être bloqué ?

Je vais partir du principe que vous voulez, pour débuter, faire un jeu simple, linéaire : une histoire qui se lit du début à la fin, qui ne change pas beaucoup d’une session à l’autre (un peu comme un jeu d’aventure point-and-click classique), où il faut résoudre une énigme pour avancer, puis on en trouve une autre, etc. Dans ce cas, le plus simple pour gérer la progression est d’utiliser une variable pour l’avancement du joueur. Cette variable, vous pouvez l’appeler avancement, progression, plot (mot anglais pour l’histoire dans une œuvre) ou comme vous voulez ; l’idée est qu’elle démarre à 0 et que, quand il se passe quelque chose dans l’histoire qui change la situation, débloque des choses, ou autre — dès que l’histoire avance, donc — vous augmentez cette variable.

Concrètement, je vous recommande de mettre la signification des différentes valeurs en commentaire – c’est-à-dire sur une ligne qui démarre par un « ! », qui ne sera pas lue par le compilateur (et qui ne compte donc pas comme du vrai code). Ça vous évitera de vous gratter la tête après une pause de quinze jours dans votre travail : « alors, euh, ça veut dire quoi déjà quand l’avancement est à 7 ? je sais plus… »

Ça donnera quelque chose comme ceci, à mettre assez tôt dans votre code :

 ! Variable d’avancement
 Global avancement = 0
 ! 0 = début du jeu, le joueur n’a pas encore touché l’idole maléfique
 ! 1 = l’idole s’est réveillée, le joueur doit parler au chef du village
 ! 2 = le chef est au courant, tout le monde cherche l’entrée de la caverne
 ! 3 = l’entrée est trouvée, tout le monde essaie d’ouvrir la porte de la caverne
 ! 4 = tout le monde est dans la caverne, le jeu est fini si le joueur creuse au bon endroit

Pour augmenter la variable « avancement », il faut se placer aux bons endroits du code et augmenter la variable à ce moment-là. Par exemple, vous pouvez faire comme ceci :

Object idole "idole maléfique" jungle
 with description "Une idole aux grands yeux vous regarde fixement.",
 name 'idole' 'maléfique' 'yeux',
 before [; Touch: avancement = 1; print "Vous touchez l’idole, et elle se réveille ! Une voix caverneuse se fait entendre et vous voilà maudit !" ; return true; ],
 has scenery concealed;

Vous pouvez même faire un peu plus subtil : avoir un message qui s’affiche la première fois que le joueur touche l’idole (et vous mettez la variable avancement à 1 à ce moment-là), et un autre message les autres fois. Ça pourrait donner :

before [; Touch: if (avancement == 0) {
                  avancement = 1; print "Vous touchez l’idole, et elle se réveille ! Une voix caverneuse se fait entendre et vous voilà maudit !" ; return true;
               } else {
                  print "Vous retouchez l’idole, en espérant que cela enlève le maléfice, mais rien ne se passe."; return true;
               } ],

Ce genre de mécanismes, où l’on donne une réponse la première fois, et une autre les fois suivantes, est crucial et énormément utilisé dans les fictions interactives. Ceci permet de faire varier les textes et d’avoir un monde plus réactif, mais aussi (voire surtout) de rappeler au joueur qu’il a déjà fait l’action ; par exemple, « Vous lui avez déjà demandé, et la réponse est non. Il va falloir trouver un autre moyen », ou « Vous avez déjà perdu deux heures à compter les feuilles, et vous en aviez trouvé 69 105 », ou encore « Le souvenir de cette texture gluante sur le bout de vos doigts vous fait encore frémir ».
À chaque fois, la structure est la même : si une variable a une certaine valeur de base, on affiche la première réponse et on change la variable ; les autres fois, la variable n’aura plus la valeur de base et on pourra afficher quelque chose d’autre. Vous pouvez même faire plusieurs réponses à la suite, comme faire en sorte que le garde craque et donne le mot de passe la septième fois que vous lui demandez, ou juste des réponses de plus en plus loufoques à une action !

Enfin, l’utilisation d’une variable d’avancement vous permet d’implanter une fonctionnalité très appréciée : des indices contextuels, c’est-à-dire adaptés à la situation. Par exemples, vous pouvez programmer le verbe « indice » pour qu’il donne un indice dépendant de la variable « avancement ». Ça donnerait :

[ IndiceSub ;
 if (avancement == 0) { return "Promenez-vous et soyez aventureux !"; }
 if (avancement == 1) { return "Oh oh... On dirait que toucher cette idole n’était pas la meilleure idée qu’il soit. Peut-être pourrez vous demander de l’aide au village voisin..."; }
 if (avanc…

Bon, en fait il y a plus rapide que d’écrire if (avancement == ... 5 fois, c’est d’utiliser switch, qui sert pour distinguer différents cas selon les valeurs que peut prendre une variable. Ça donne :

[ IndiceSub ;
 switch(avancement){
 0: return "Promenez-vous et soyez aventureux !";
 1: return "Oh oh... On dirait que toucher cette idole n’était pas la meilleure idée qu’il soit. Peut-être pourrez vous demander de l’aide au village voisin...";
 2: return "Le chef a dit de trouver l’entrée de la caverne, qui doit être cachée quelque part dans la jungle...";
 3: return "Cette porte doit bien s’ouvrir, peut-être avec un mécanisme caché...";
 4: return "Où cacheriez-vous un trésor pour qu’il soit à l’abri des regards ?";
 }
];

Verb 'indice'
 * ->Indice;

Et voilà, vous avez une histoire linéaire avec des indices pour faire avancer le joueur !

Si vous voulez plus d’exemples, mes jeux Gossip (qui avait une variable plot et un verbe spécifique pour donner des indices) et Life On Mars? utilisent quelque chose comme ça, et je vous encourage à aller consulter leur code source (à part que pour Gossip, je ne sais plus à quoi correspond chaque valeur, donc je suis bien embêté !) ; et comme je le disais en introduction, il y a aussi Filaments (variable plot_depth), dont le code source est disponible librement. Cette technique, bien que basique, vous permet déjà de construire un jeu linéaire suivant une trame narrative définie, qui progresse à mesure que le joueur résout les énigmes !