Aujourd’hui, l’article a été écrit par Corax, un membre récent de la communauté. Il explique comment il a codé ses FI (telle que sa participation au concours), qui ont été très bien accueillies. Le niveau requis est assez élevé, mais il n’y a pas besoin de comprendre en détail ce qui est présenté pour pouvoir l’utiliser.

Sur ce, laissons la place à Corax !

Nathanaël


Inform 7 propose de créer des jeux selon un certain modèle. Peut-être ce modèle ne vous convient-il pas tout à fait, voire pas du tout, et vous aimeriez donc pouvoir vous en éloigner. Or, bien souvent, il est plus facile de créer que de modifier.

Bien sûr, il faut s’assurer que ça correspond à vos besoins. Pas besoin de modifier le comportement d’Inform s’il correspond bien à votre projet !

Cet article va vous donner des astuces qui vous aideront à intercepter toutes les commandes du joueur afin, dans un premier temps, de les bloquer, puis, dans un second temps, de les filtrer et de les personnaliser.

Les deux règles capitales

Créons un nouveau projet, et mettons-y un endroit. L’environnement de test est prêt.

"Le Labo de Test" by Corax (in French)

Le Labo est un endroit.

Fondamentalement, le joueur ne peut faire que deux choses : soit il tape du texte, soit il ne tape rien. S’il tape une commande, celle-ci passe par la règle suivante avant d’être analysée :

After reading a command:

La commande elle-même sera contenue dans la variable player's command, qui ne peut normalement être utilisée ailleurs que dans cette règle. Nous allons faire en sorte que le jeu se contente désormais d’indiquer ce que le joueur a tapé.

After reading a command:
	dire "Le joueur a tapé[_]: «[_][player's command][_]».";
	rejeter la commande du joueur.

Vous pouvez tester. Tapez ce que vous voulez, les messages par défaut d’Inform ne s’afficheront plus. En trois lignes de code, La quasi-totalité des commandes ont été bloquées, mais pour autant, vous restez capable de savoir ce que le joueur tape. S’il ne tape rien, c’est cette règle qui agit :

For printing a parser error when the latest parser error is the I beg your pardon error:

Avec ce code, nous bloquons le fait de ne rien taper :

For printing a parser error when the latest parser error is the I beg your pardon error:
	dire "Le joueur n'a rien tapé.".

Cette règle se déclenche quand l’analyseur de commande n’a pas compris quelque chose ; on spécifie ici que l’on souhaite intercepter uniquement la commande vide.

Attention, il faut éviter de faire autre chose que d’afficher du texte ou d’effacer l’écran. Changer l’état du monde du jeu lors d’une erreur de l’analyseur peut créer des bugs !

Bloquer les exceptions

Certaines commandes particulières échappent aux deux règles que nous venons de voir. Si vous êtes comme moi, ça va vous chiffonner car vous désirez que tout soit sous votre contrôle. Pour remédier au problème, il faut agir directement sur les réponses par défaut d’Inform qui correspondent à ces exceptions. Le code suivant place dans ces messages la procédure de blocage.

Use UNDO prevention.

To dire annuleexception:
	dire "Une exception a été bloquée.[sans passage à la ligne]".
The immediately undo rule response (A) is "[annuleexception]".
The parser command internal rule response (A) is "[annuleexception]".
The parser command internal rule response (B) is "[annuleexception]".
The parser command internal rule response (C) is "[annuleexception]".
The parser command internal rule response (D) is "[annuleexception]".

Vous pouvez tester, par exemple avec la commande « annuler ». Désormais, tout, absolument tout ce que peut taper le joueur est bloqué. Et les seuls textes qui s’affichent sont ceux que vous avez écrits.

Ce n’est en fait pas tout à fait vrai que tout a été bloqué, mais ce qui ne l’a pas été n’est en pratique jamais tapé par le joueur. Il existe d’autres manières de bloquer les commandes spéciales comme « annuler », mais il faut plonger dans Inform 6, qui est le code sous-jacent à Inform 7. Ce serait sûrement trop compliqué pour rien.

Filtrer les commandes

Imaginons maintenant que vous désiriez que certaines commandes s’exécutent normalement en laissant toutes les autres bloquées. Vous pouvez procéder ainsi :

After reading a command:
	si la player's command matches the text "aller", ne pas prendre de décision;
	dire "Le joueur a tapé[_]: «[_][player's command][_]».";
	rejeter la commande du joueur.

Dans cet exemple, dès que la commande du joueur comporte le texte « aller », elle est traitée normalement. Notez en revanche que les commandes « Aller nord » (avec une majuscule) ou « allér nord » seront bloquées car la casse et les accents ne sont pas gérés par le code ci-dessus. Notez aussi que la commande « youpiallerlulu » franchira le filtrage puisqu’elle comporte bien le texte « aller ».

After reading a command:
	let TxtChoix be la player's command en minuscules;
	si TxtChoix correspond au texte "aller", ne pas prendre de décision;
	dire "Le joueur a tapé[_]: «[_][player's command][_]».";
	rejeter la commande du joueur.

Ce code s’affranchit déjà de la casse du texte. Le principe est là, à vous de vous l’approprier en manipulant les chaînes de caractères à votre guise et en introduisant autant d’exceptions au blocage que nécessaire.

Ici, il faut spécifier toutes les variantes possibles pour une action (par exemple si le joueur tape seulement « n » pour aller au nord). Il est possible d’utiliser des expressions régulières (section 20.6 de la documentation) ou des jetons de grammaire (section 17.13) pour faciliter l’écriture de ces conditions, même si ce serait peut-être en faire trop selon le cas. Mais comme mes jeux utilisent des liens plutôt que des commandes, je n’ai pas à anticiper toutes les commandes possibles que le joueur pourraient taper.

Personnaliser des commandes

Imaginons maintenant que vous désiriez inventer une commande inédite, la commande “plouf”. Elle aurait comme effet extraordinaire de renvoyer un texte rigolo.

After reading a command:
	let TxtChoix be la player's command en minuscules;
	si TxtChoix est "plouf":
		suivre l' ActionPlouf rule;
		rejeter la commande du joueur;
	si TxtChoix correspond au texte "aller", ne pas prendre de décision;
	dire "Le joueur a tapé[_]: «[_][player's command][_]».";
	rejeter la commande du joueur.

This is the ActionPlouf rule:
	dire "Vous sautez dans un verre d’eau. Magie, ça fonctionne[_]! Par contre, vous buvez la tasse[_]!".

Ça n’a l’air de rien, mais vous voilà capable d’associer à n’importe quelle commande du joueur les règles de votre choix sans qu’Inform vienne vous bousculer avec son fonctionnement traditionnel.

Ici, plus vous avez d’actions, plus il faudra écrire de conditions dans une règle qui finira par devenir gigantesque. Si cela vous dérange, il est possible d’organiser son code avec des tableaux contenant les commandes et les règles associées (chap. 16) ou un livre de règles, voire une activité (chap. 18 et 19).

On va un peu plus loin ? Maintenant, on veut que la commande « plouf X » ajoute 2 à X, X devant être un nombre.

[Ces variables servent à exploiter la commande du joueur après son analyse.]
TxtChoix is a text variable.
NumChoix is a number variable.
ChoixAvecNombre is a truth state variable.

After reading a command:
	[Analyse de la commande du joueur]
	si la player's command correspond à "[number]":
		maintenant NumChoix est le number understood;
		maintenant TxtChoix est "";
	sinon:
		maintenant TxtChoix est la player's command en minucscule;
		si la player's command contient "[number]":
			maintenant NumChoix est le number understood;
			maintenant ChoixAvecNombre est vrai;
		sinon:
			maintenant ChoixAvecNombre est faux;
	[Traitement spécifique des commandes]
	si TxtChoix correspond au texte "plouf":
		suivre l' ActionPlouf rule;
		rejeter la commande du joueur;
	si TxtChoix correspond au texte "aller", ne pas prendre de décision;
	[Traitement par défaut]
	dire "Le joueur a tapé[_]: «[_][player's command][_]».";
	rejeter la commande du joueur.

This is the ActionPlouf rule:
	si ChoixAvecNombre est vrai:
		dire "Plouf change [NumChoix] en [NumChoix + 2], c'est magique[_]!";
	sinon:
		dire "Plouf n'a rien à changer.".

Peu à peu, vous rédigez votre propre analyseur syntaxique. En procédant ainsi, vous pouvez plier Inform à votre imagination, mais en vous privant de son comportement par défaut vous vous privez aussi de certaines commodités. Pondre un système quasiment de A à Z ne se fera pas sans de nombreuses lignes de code.

Il reste que rédiger son propre analyseur syntaxique n’est pas une mince affaire. Si vous voyez que votre code devient trop complexe à gérer, il vous faudra peut-être bien y repenser.

Achever la métamorphose

Vous contrôlez tout, tout sauf un petit truc. Oui, quelque chose est encore hors de votre pouvoir. Pour bien vous en rendre compte, ajoutons quelques éléments à notre projet.

Le Labo est un endroit.
La description est "Un labo bleu.".

Le Labo2 est un endroit.
La description est "Un labo rouge.".
Le Labo2 est à l'ouest du Labo.

Testez ! Déplacez-vous avec les commandes « aller ouest » et « aller est ». Inform se permet encore de présenter les lieux à sa façon. On va arranger ça et, pour ce faire, il faut remplacer l’action looking qui s’exécute automatiquement dès que le joueur pénètre dans une room.

Instead of looking:
	essayer de displaying.

L’action displaying n’existe pas encore. On peut donc la créer en toute liberté.

Displaying is an action applying to nothing.

Carry out displaying:
	dire "Nom du lieu[_]: [location du player][à la ligne]Description du lieu[_]: [description de la location du player]".

Testez ! Voyez comme le monde apparaît selon la manière prévue. Notez que vous n’utiliserez peut-être même plus les endroits dans votre système, tout dépendra de la manière dont vous le conceptualisez. Mais si vous vous en servez encore, l’action looking était importante à aborder. Si une autre action déjà existante vous pause problème, faite-lui subir le même sort, remplacez-la par une de votre création.

Il également possible de désactiver toutes les règles de l’action looking et d’ajouter ses propres Carry out looking. Ce serait plus « propre », mais cela implique de bien comprendre le fonctionnement de l’action d’origine, d’aller chercher les règles d’origine dans les règles standards… Utiliser une règle instead convient très bien dans la plupart des cas.

Conclusion

Avec cet ensemble d’astuces, vous devriez être capable de créer des jeux textuels sans contrainte, si ce n’est celle de devoir bien réfléchir à votre système sous peine d’aboutir à quelque chose de bancal.