Fiction-interactive.fr

Tutoriels ink

Liste des articles :

Une introduction au langage ink – Nathanaël Marion

Faire varier ce qui est montré au joueur avec ink – Nathanaël Marion

Faire varier les choix proposés avec ink – Nathanaël Marion

Organiser son code ink – Nathanaël Marion

Tresser son histoire avec ink – Nathanaël Marion

Ink et les variables – Nathanaël Marion

Des fonctions avec ink – Nathanaël Marion

Ink et les tunnels – Nathanaël Marion

Les fils, une fonctionnalité avancée de ink – Nathanaël Marion

Premiers pas avec les listes ink – Nathanaël Marion

Personnaliser l’apparence de son histoire ink – Nathanaël Marion

Cet ebook compile des tutoriels parus sur le site http://www.fiction-interactive.fr, centrés sur le logiciel ink.

On parle uniquement de technique ici ; nous vous conseillons de l’accompagner de notre ebook sur la conception de jeux !

Nous publions un article sur la fiction interactive, et plus largement les narrations non-linéaires, tous les vendredis de septembre à juin.

Si ces articles vous ont plu, n’hésitez pas à :

parler de http://www.fiction-interactive.fr autour de vous ;

nous rejoindre sur notre serveur Discord ;

faire un don à notre compte paypal (paypal@fiction-interactive.fr), qui servira à couvrir nos frais d’hébergement et à proposer des prix pour notre concours annuel.

Une introduction au langage ink

Nathanaël Marion

ink est un langage permettant d’écrire facilement des histoires à embranchements avec beaucoup d’options et de parties qui se réunissent. En voici une brève introduction.

C’est quoi, ink ?

Comme écrit ci-dessus, ink permet d’écrire des histoires interactives, du style « livre dont vous êtes le héros », ou bien des dialogues interactifs. Le langage a été conçu pour être très lisible et pour que l’on puisse s’y retrouver aisément. Si vous n’aimez pas Twine (*tousse* comme moi *tousse*), alors ink est peut-être fait pour vous.

Cependant, bien qu’il est possible d’obtenir une page web contenant votre histoire jouable en ligne avec ce langage, ink a tout d’abord été conçu pour pouvoir s’intégrer dans d’autres moteurs de jeu (notamment Unity).

Ainsi, les créateurs de ink, inkle, l’ont utilisé pour leurs jeux, tels que 80 days ou Sorcery!, qui ont été acclamés par la critique. Plus récemment, Enterre-moi, mon amour, écrit avec ink, a beaucoup fait parler de lui. De nombreuses autres personnes utilisent ink, par exemple pour écrire les dialogues de leurs jeux.

Nous ne verrons pas comment utiliser ink dans un autre moteur de jeu ici. Nous l’utiliserons pour écrire des histoires purement textuelles, afin de découvrir ce langage.

Installation

Pour écrire avec ink, le plus facile est d’utiliser le logiciel Inky. Il nous permettra d’écrire notre histoire dans la moitié gauche d’une fenêtre et de la tester dans sa moitié droite (un peu comme dans Inform 7).

Téléchargeons donc Inky à cette adresse (faites défiler jusqu’à « Downloads »). Le logiciel fonctionne avec Windows, macOS et Linux, vous n’aurez donc vraisemblablement pas de problème.

Bien qu’Inky est très pratique pour tester un projet ink, il vous est possible d’utiliser votre éditeur de texte préféré pour la rédaction. Une coloration syntaxique est disponible pour Sublime Text ainsi que pour Atom.
Si vous n’avez pas tout compris de cette note, ce n’est pas grave ; utilisez simplement Inky ! 😉

Commençons notre histoire

Rien de plus simple pour afficher du texte : il suffit de l’écrire. Ouvrons Inky et tapons quelque chose dans la partie gauche de la fenêtre :

Un léger choc et l'engin se stabilise. Vous avez enfin atteint votre destination.

Vous consultez l'ordinateur de bord.

Le texte apparaît instantanément dans la partie droite, où l’histoire est jouée. Bien évidemment, il n’y a pour l’instant rien à tester. Remédions à cela.

Des choix

Pour proposer des choix au joueur, il suffit d’écrire une ligne commençant par une astérisque pour chaque choix. Ajoutons ce qui suit après notre introduction :

*  Vous vérifiez les résultats de l'analyse atmosphérique.

*  Vous consultez une carte topographique des alentours.

*  Vous ouvrez les portes et sortez.

Cliquons sur la double flèche en haut à droite de la fenêtre rembobiner l’histoire et voilà, nous pouvons voir trois options offertes au joueur. Cliquons sur l’une d’elles et… Inky nous avertit d’un problème : le jeu ne sais pas quoi faire après qu’une option est sélectionnée.

Tout d’abord, nous pouvons afficher une réponse quand le joueur clique sur un choix. Il suffit d’écrire du texte sous la ligne correspondant à ce choix.

*  Vous vérifiez les résultats de l'analyse atmosphérique.

 L'air est respirable sur cette lune.

*  Vous consultez une carte topographique des alentours.

 Le relief est accidenté. Il sera difficile de se déplacer.

*  Vous ouvrez les portes et sortez.

 Il vous faudra bien trouver l'origine du signal.

Cependant, cela n’est pas suffisant. Il faut dire où doit aller l’histoire. Il nous faudra donc la structurer.

Des nœuds

Une histoire ink est organisée en ce qui est appelé des nœuds. Pour en créer un, il suffit d’écrire une ligne comme suit :

=== atterrissage ===

Elle doit commencer par deux ou plus signes « égal » et son nom ne doit contenir que des lettres (sans diacritiques), des chiffres, et des tirets bas. Il ne peut en particulier pas contenir d’espaces.

Les nœuds sont un peu comme des marque-pages : il est possible de sauter instantanément depuis n’importe quel endroit vers n’importe quel nœud en écrivant :

-> atterrissage

Cela s’appelle une divert arrow, littéralement une « flèche de déviation ».

Restructurons notre petite histoire ; il faut que tous les choix que nous avons créés auparavant mènent de nouveau vers la même liste de choix, sauf si on sort, auquel cas on est dirigé vers un autre nœud.

Une dernière chose : ink n’aime pas les bouts qui ne mène nulle part. Il faut rediriger l’histoire vers un nœud après chaque choix. Il est également possible d’utiliser la déviation spéciale -> END pour indiquer que la fin de l’histoire est atteinte.

C’est fait ? Voici ce que ça peut donner :

// On affiche l'introduction.

Un léger choc et l'engin se stabilise. Vous avez enfin atteint votre destination.

Vous consultez l'ordinateur de bord.

-> atterrissage

// On va vers atterrissage, car ce n'est pas automatique.

=== atterrissage ===

*  Vous vérifiez les résultats de l'analyse atmosphérique.

 L'air est respirable sur cette lune.

 -> atterrissage // On revient.

*  Vous consultez une carte topographique des alentours.

 Le relief est accidenté. Il sera difficile de se déplacer.

 -> atterrissage // On revient.

*  Vous ouvrez les portes et sortez.

 Il vous faudra bien trouver l'origine du signal.

 -> sortie // On va vers sortie.

=== sortie ===

Vous posez un pied à l'extérieur.

<em>À suivre…</em>

-> END // On termine l'histoire.

(Ce qui est après les double barres obliques est un commentaire : une petite note faites à vous même mais qui ne sera pas lue par ink. Les <em> sont de l’HTML pour mettre le texte en italique.)

Si vous avez testé, vous aurez remarqué qu’un choix ne peut pas être sélectionné plusieurs fois. Si l’histoire rencontre une option qui a déjà été choisie par le joueur plus tôt, alors elle ne l’affiche pas. Cela est en général ce qui est voulu, mais il reste possible de forcer un choix à réapparaître en remplaçant l’astérisque par un signe « plus » (+)

Rendre les options plus dynamiques

Vous avez sûrement vu que lorsqu’un choix est sélectionné, son texte réapparaît immédiatement. Il est possible de modifier cela. Considérons le code suivant :

« Bonjour, vous dit l'ordinateur de bord.

*  — Bonjour[. »], » répondez-vous.

 -> atterrissage

Notons la présence des crochets dans le texte de l’option. Ce qui est avant les crochets est affiché à la fois dans l’option et dans le texte qui en résulte. Ce qui est dans les crochets est affiché seulement dans le choix et ce qui est après, seulement dans le texte qui en résulte.

Le plus simple pour comprendre est de le tester.

Ceci permet d’écrire des choix dont le texte ne se réaffiche pas quand on le choisit :

*  [Sortir]

Cette fonctionnalité d’ink est vraiment très utile pour les dialogues, afin d’afficher les incises quand il le faut.

Exporter son histoire

Voilà, les bases d’ink sont là, vous avez raconté ce qui arrivait à notre protagoniste, il ne reste plus qu’à partager notre histoire au reste du monde !

Le plus simple est de l’exporter en page web. Pour cela, allons dans le menu File > Export for web... pour obtenir une page, qu’il vous sera possible de mettre sur votre site internet par exemple.

De plus, vous pouvez indiquer un titre et un auteur à votre histoire en écrivant au tout début de votre source :

# author: Nathanaël Marion

# title: Le Signal perdu

Inky écrira ces informations au début de votre histoire quand vous l’exporterez en page web.

Si vous avez des connaissances en HTML, en CSS ou en JavaScript, vous pourrez modifier l’apparence de votre jeu. Sinon, l’apparence de base suffit amplement.

Et après ?

Avec ce que nous avons vu, il est possible d’écrire un livre dont vous êtes le héros basique. Cependant, ink est bien plus puissant que cela. Il est possible de compter le nombre de fois qu’un passage a été visité, de garder en mémoire des valeurs (l’argent du joueur, ses points de vie, s’il a rencontré telle personne, etc.), d’écrire des fonctions…

Une autre grande fonctionnalité d’ink est de pouvoir écrire une liste de choix qui n’affectent pas directement l’histoire et qui mènent tous vers le même passage. Il serait possible de rediriger vers un autre nœud après chaque choix (comme nous l’avons fait avec -> atterrissage), mais ink fournit une option plus élégante, qui permettra de rendre la source très lisible.

Mais tout cela, ce sera pour une prochaine fois !

Faire varier ce qui est montré au joueur avec ink

Nathanaël Marion

La semaine dernière, nous avons vu comment créer une histoire simple avec ink. Cependant, les fictions interactives étant en général non linéaires, il est possible qu’elles présentent plusieurs fois le même passage au cours d’une partie.

Aujourd’hui, nous allons voir comment faire varier le texte montré au joueur, afin de rendre les passages plus dynamiques.

Les listes de texte

Si le joueur est amené à visiter un passage plusieurs fois, il peut être intéressant de faire varier le texte pour moins l’ennuyer.

Il est possible de proposer plusieurs choix dans une liste, et ink fera le choix approprié en fonction du type de la liste. Une liste est écrite entre des accolades ({ et }) et chacun de ses éléments est séparé par une barre vertical (| — attention, ce n’est pas la lettre « L » !)

Voyons sans plus tarder les différents types de liste.

Les séquences

Quand ink rencontre une liste de base pour la première fois, il va afficher son premier élément ; lors de la deuxième fois, son deuxième élément et ainsi de suite jusqu’au dernier. Ensuite, ce sera toujours le dernier élément qui sera affiché. Par exemple :

Vous vous réveillez en sursaut.

-> attente

=== attente ===

{Le maudit téléphone sonne|Le téléphone sonne une deuxième fois|Le téléphone sonne encore|L'autre a raccroché. Vous pouvez enfin vous rendormir. -> END}.

+  [Attendre]

 Vous attendez dans le noir.

 -> attente

*  [Vous lever et jeter l'appareil par la fenêtre]

 Vous vous levez et vous emparez de l'appareil démoniaque. Enfin le calme.

 -> END

Ici, à chaque fois qu’on est dévié vers attente, le texte sera différent. La première fois, ce sera « Le maudit téléphone sonne », puis ce sera « Le téléphone sonne une deuxième fois » et ainsi de suite. Le dernier élément de la liste contient une déviation, donc si le joueur attend suffisamment longtemps, le jeu va arriver à une fin. Cela est une fonctionnalité intéressante des listes : elles peuvent faire varier du texte, mais aussi influer sur le cours de l’histoire.

(Et n’oubliez pas, le « plus » est là pour indiquer que l’on peut choisir l’option plusieurs fois. Si on avait mis une astérisque, il n’aurait pas été possible d’attendre plus d’une fois.)

Les cycles

Un cycle est une liste qui va afficher ses élément les uns à la suite des autres, mais ne s’arrêtera pas au dernier et recommencera au début. Pour signaler qu’une liste est un cycle, il faut utiliser le symbole &. Exemple :

Aujourd'hui, nous sommes le {&lundi|mardi|mercredi|jeudi|vendredi|samedi|dimanche}.

Notez bien l’esperluette après l’accolade ouvrante !

À usage unique

Les listes marquées d’un point d’exclamation ne seront parcourues qu’une seule fois. Ensuite, rien ne sera affiché. Cela revient donc au même qu’une séquence dont le dernier élément est vide.

Il y a un flash. {!Vous ne vous y attendiez pas et vous sursautez.|Vous vous y attendiez et vous ne réagissez donc pas.|Vous ne réagirez plus désormais.}

Les listes aléatoires

Les listes marquées par un tilde afficheront choisiront l’élément à afficher de manière totalement aléatoire.

Vous lancez la pièce. {~Pile|Face} !

Quelques caractéristiques des listes

Les listes peuvent contenir des éléments vides. Cela peut permettre de « compter » le nombre de fois qu’un passage est visité.

Vous continuez d'avancer à l'aveuglette.{|||| Vous tombez dans un précipice ! -> END}

Ici, il ne se passera rien les quatre premières fois, mais la cinquième fois sera fatale.

Il est également possible d’imbriquer des listes. Les règles suivies sont exactement les même, mais cela devient un peu plus difficile à lire.

Vous lancez {&le dé et obtenez {~1|2|3|4|5|6}|la pièce et tombez sur {~pile|face}} !

On lancera alternativement le dé et la pièce, et le résultat de chacun sera aléatoire.

Les conditions

Enfin, il est possible de n’afficher du texte que sous certaines conditions. La condition la plus simple à tester est si le joueur a visité ou non un nœud.

La syntaxe est très similaire à celle des listes. Un exemple sera peut-être plus parlant.

Vous essayez de vous remémorer le code secret. {lecture_memo: Ah oui, c'était 222-830.|Malheureusement, il vous échappe. Où aviez-vous mis votre mémo ?}

Ce qui suit l’accolade ouvrante est le nom d’un nœud suivi d’un deux-points. Ce qui est écrit après ne sera affiché que si le joueur a visité le nœud correspondant au cours de la partie (ici, s’il a lu sa note). Nous pouvons, si nous le souhaitons, ajouter une barre verticale suivi d’un autre texte, qui sera lui affiché si le nœud n’a pas été visité.

Il est bien sûr possible de faire varier selon d’autres conditions (argent du joueur, points de vie, inventaire…) mais il faudra pour cela voir la notion de variable, alors ce sera pour une prochaine fois.

Et comme pour les listes, il est possible d’imbriquer les conditions.

La prochaine fois

La prochaine fois, nous verrons comment faire varier les choix qui sont proposés au joueur. C’est très similaire à ce que nous avons vu dans cet article, alors ce ne sera pas bien compliqué !

Faire varier les choix proposés avec ink

Nathanaël Marion

Un rappel : les choix ne sont disponibles qu’une seule fois par défaut

Commençons par un rappel.

Si notre histoire mène le joueur plusieurs fois dans le même nœud et lui réaffiche une liste de choix, n’oubliez pas que les options que le joueur a déjà sélectionnées lors de ses précédents passages ne lui seront pas montrées de nouveau. Pour remédier à cela, il suffit de remplacer l’astérisque par un symbole « plus ».

Considérons cet exemple. Trouvez-vous le problème ?

Vous vous tenez devant le bureau de votre rival de toujours. Le document secret doit bien se trouver quelque part.

-> bureau

=== bureau ===

*  [Regarder dans la paperasse]

 Vous fouillez la pile de papier. Rien.

 -> bureau

*  [Ouvrir le tiroir du haut]

 Vous ouvrez le premier tiroir. Après une rapide inspection, vous ne trouvez que des factures.

 -> bureau

*  [Ouvrir le tiroir du bas]

 Vous ouvrez le second tiroir, qui se révèle être vide.

 -> bureau

Quand le joueur n’a plus le choix

Si vous avez convenablement testé l’exemple, vous aurez remarqué qu’une erreur a lieu quand tous les choix ont été faits. C’est normal, car ink ne sait plus où aller ensuite.

Il est alors possible d’ajouter un choix de secours (« fallback choice ») : il s’agit d’une option qui ne sera jamais proposée au joueur mais qu’ink sélectionnera automatiquement si tout le reste a déjà été choisi.

Pour cela, il faut créer un choix sans texte, avec comme seul contenu une flèche de déviation. Si la flèche est suivie par le nom d’un nœud, alors on sera dévié vers ce nœud ; s’il n’y a que la flèche, alors il est possible d’écrire une réponse, comme pour un choix normal.

Vous vous tenez devant le bureau de votre rival de toujours. Le document secret doit bien se trouver quelque part.

-> bureau

=== bureau ===

*  [Regarder dans la paperasse]

 Vous fouillez la pile de papier. Rien.

 -> bureau

*  [Ouvrir le tiroir du haut]

 Vous ouvrez le premier tiroir. Après une rapide inspection, vous ne trouvez que des factures.

 -> bureau

*  [Ouvrir le tiroir du bas]

 Vous ouvrez le second tiroir, qui se révèle être vide.

 -> bureau

*  -> a_suivre

=== a_suivre ===

Vous entendez des pas dans le couloir. Votre rival revient ! Vous vous enfuyez par la fenêtre. Tant pis pour le document !

À suivre…

-> END

Ce qui est équivalent à :

Vous vous tenez devant le bureau de votre rival de toujours. Le document secret doit bien se trouver quelque part.

-> bureau

=== bureau ===

*  [Regarder dans la paperasse]

 Vous fouillez la pile de papier. Rien.

 -> bureau

*  [Ouvrir le tiroir du haut]

 Vous ouvrez le premier tiroir. Après une rapide inspection, vous ne trouvez que des factures.

 -> bureau

*  [Ouvrir le tiroir du bas]

 Vous ouvrez le second tiroir, qui se révèle être vide.

 -> bureau

 // Notez la déviation vide.

*  ->

 Vous entendez des pas dans le couloir. Votre rival revient ! Vous vous enfuyez par la fenêtre. Tant pis pour le document !

 À suivre…

 -> END

N’hésitez pas à tester pour bien comprendre.

Notez que cette option de secours n’échappe pas à la règle : si elle a déjà été déclenchée plus tôt car tous les autres choix avaient été épuisés, alors elle ne sera plus utilisable une seconde fois, et l’on se retrouvera avec la même erreur qu’auparavant. On peut remplacer l’astérisque par un plus, comme pour un choix normal, pour rendre l’option de secours réutilisable.

Des options conditionnelles

Comme pour du texte normal, il est possible de n’afficher des choix que sous certaines conditions. Le plus simple est de vérifier si le joueur est déjà passé — ou pas — dans un nœud particulier. Il faut pour cela mettre le nom du nœud entre accolades juste avant son texte. Si le nœud a été vu, le choix s’affichera, et vice-versa.

*  [Regarder dans la paperasse]

 // …

*  [Ouvrir le tiroir du haut]

 // …

*  [Ouvrir le tiroir du bas]

 // …

*  {apprendre_cachette} [Localiser le tiroir secret]

 // …

Ici, la dernière option ne sera affichée que si le nœud apprendre_cachette a été visité.

Pour vérifier si le nœud n’a pas été visité, il suffit de le précéder par not :

*  {not apprendre_cachette} [Essayer de trouver un emplacement secret, s'il y en a]

Enfin, il est possible de tester plusieurs conditions à la fois ; il faudra alors qu’elles soient toutes vraies pour que le choix soit montré.

*  {apprendre_cachette} {trouver_clef} [Utiliser la clef pour ouvrir le tiroir secret]

Il est bien sûr possible de faire des tests plus compliqué (sur l’argent du héros, ses points de vie…) mais il faudra pour cela utiliser des variables. Ce sera donc pour un prochain tutoriel.

La syntaxe pour des choix conditionnels est la même que pour les listes (voir le tutoriel précédent). Il possible d’insérer du texte qui varie dans le texte d’une option, mais pas au début, sinon ink confondra la liste avec une condition.

Conclusion

Avec ce que nous avons couvert jusqu’à maintenant, il est possible d’écrire des histoires assez complexes. La prochaine fois, nous verrons comment mieux organiser ce que nous avons écrit, avant de passer aux fonctionnalités avancées (mais les plus intéressantes !) d’ink.

Bonne écriture !

Organiser son code ink

Nathanaël Marion

Dans cet article, nous allons voir comment rendre un long projet écrit en ink plus clair.

Rien de bien excitant, donc, mais très pratique à savoir !

La colle

Quand nous écrivons du texte avec ink, les passages à la ligne se traduiront par de nouveaux paragraphes en jeu.

Ceci est le premier paragraphe.

Voici le second.

Et le troisième, même s'il n'y a pas de ligne vide avant.

Il est également possible de dévier depuis n’importe où. Il est donc possible de passer à un autre nœud au beau milieu d’une phrase.

Par exemple :

Bonjour, je -> deux

=== deux ===

tiens sur une -> trois

=== trois ===

seule ligne !

-> END

s’affichera comme ceci en jeu :

Bonjour, je tiens sur une seule ligne !

Toutes les déviations sont transparentes, ce qui fait que tout tient sur une seule ligne, comme si nous avions véritablement tout écrit sur la même ligne. Nous aurions obtenu plusieurs paragraphes si nous étions passés à la ligne avant l’une des flèches de déviation.

Il est cependant possible de forcer cet affichage en un seul paragraphe : la colle (« glue » en anglais). Pour mettre un peu de colle, rien de plus simple :

Bonjour, je <>

-> deux

=== deux ===

tiens sur une

-> trois

=== trois ===

<> seule ligne !

-> END

Notez que les flèches de déviations tiennent bien sur leur propres lignes ; pourtant, nous obtenons le même résultat qu’il y a un instant. En effet, le texte <> indique à ink de rassembler les textes de part et d’autre en un seul paragraphe. On peut aussi bien mettre de la colle à la fin de la première partie, ou au début de la seconde. Il est possible d’en mettre n’importe où, pas forcément avant une déviation. Et une fois que la colle est appliquée, impossible de l’enlever : s’il y a un <> à la fin d’une ligne, alors la ligne suivante n’aura aucun moyen de l’annuler.

Mais à quoi cela peut-il bien servir ?

Quand le texte devient compliqué, avec beaucoup de conditions à tester ou de listes dans une phrase par exemple, on peut rendre son texte plus clair en mettant chaque condition ou liste sur sa propre ligne et utiliser de la colle pour qu’elles soient remises ensemble à la lecture.

Une autre utilité peut être si une phrase ne commence pas de la même façon en fonction du chemin pour y parvenir.

Un appel au secours à l'extérieur. Pas de temps à perdre !

*  [Sortir.]

 J

 -> sortie

*  [D'abord chercher mon téléphone.]

 J'ai rapidement cherché mon téléphone.

 Je ne l'ai pas trouvé, alors j

 -> sortie

=== sortie ===

// On aura ou pas une majuscule en fonction de l'option choisie plus haut.

<>e me suis précipitée dehors.

-> END

De manière générale, il est possible d’obtenir le même effet en ne sautant pas de ligne avant les flèches ou en utilisant des conditions sur les nœuds visités, mais je trouve la colle plus lisible. À vous d’utiliser ce que vous préférez.

Écrire son histoire dans plusieurs fichiers

Si l’histoire devient imposante, il est possible de la séparer en plusieurs morceaux. Il nous faudra donc créer un fichier .ink par partie, avec un des fichiers considéré comme le principal (on peut choisir celui qu’on veut, mais il ne doit y en avoir qu’un seul).

Imaginons que nous ayons l’arborescence de fichiers suivante :

mon-projet

 chapitre1

 section1.ink

 section2.ink

 histoire.ink

 prologue.ink

Le fichier principal sera histoire.ink. Ce fichier peut contenir des nœuds et du texte, mais le mieux est de l’utiliser seulement pour toutes les initialisations requises par l’histoire : inclusions des fichiers, variables, fonctions…

Pour inclure des fichiers, il faut utiliser le mot INCLUDE suivi du chemin du fichier à inclure (ce qui est simplement son nom s’il se trouve au même endroit que le fichier principal).

Il n’est pas possible d’utiliser INCLUDE dans des fichiers eux-mêmes inclus ! C’est pour cela que le fichier faisant les inclusions est considéré comme le principal ; c’est lui qui rassemble les autres, et c’est lui que vous ouvrirez.

Pour notre structure, notre fichier histoire.ink pourrait ressembler à cela :

INCLUDE prologue.ink

INCLUDE chapitre1/section1.ink

INCLUDE chapitre1/section2.ink

// On commence l'histoire.

-> il_etait_une fois

Il ne faut pas oublier de dévier vers le début de l’histoire. Ici, nous aurons un nœud appelé il_etait_une_fois quelque part dans l’une des inclusions, n’importe laquelle. En effet, ink ne sépare pas les nœuds des différentes parties : tous les nœuds de tous les fichiers sont accessibles depuis n’importe quel endroit. À vous de vous débrouiller pour qu’ils aient chacun un nom unique et ce, dans l’histoire au complet.

Les mailles

Comme nous le savons bien, un projet ink est structuré en nœuds. Il se trouve que le langage permet d’avoir une organisation plus fine.

Considérons ceci :

=== jour_1 ===

= atterrissage

// …

= sortie

// …

=== nuit_1

= coucher

// …

= cauchemar

// …

Les nœuds sont indiqués par les lignes commençant par trois signes « égal ». La nouveauté est les lignes commençant par un seul signe « égal ». On appelle cela des stitches, littéralement des « points » (en couture) ou des « mailles » (en tricot).

Comme tous les autres termes ink, il n’y a pas de terme officiel en français. Vous pouvez choisir « stitch », « point » ou « maille », ou les utiliser indifféremment !

On peut considérer les mailles comme des subdivisions de nœuds. Si l’on dévie vers un nœud avec -> jour_1 (comme on l’a déjà fait), ink affichera le texte sous le nœud si celui-ci n’est pas suivi directement par une maille, sinon il déviera automatiquement vers la première maille du nœud (auquel cas c’est le texte sous la maille qui sera montré).

Pour dévier vers une maille, la syntaxe est la même, mais il faut indiquer l’« adresse » de la maille, de la forme -> nœud.maille ; plus concrètement, cela donnerait -> nuit_1.cauchemar par exemple. Le nœud peut-être omis si l’on dévie vers une maille contenue dans le nœud courant : -> cauchemar suffit si on écrit cela dans le nœud nuit_1 (ou dans l’une de ses mailles).

Ce système d’adresse permet d’avoir des mailles ayant le même nom, mais contenues dans des nœuds différents. On pourrait donc avoir une maille cauchemar dans le nœud nuit_1 et une autre maille cauchemar dans un autre nœud appelé nuit_2. N’oubliez pas de spécifier l’adresse d’une maille au complet lorsque vous voulez y accéder depuis un autre nœud. Enfin, une maille et un nœud ne peuvent pas partager le même nom.

Conclusion

Nous voilà arrivé à la fin. Vous possédez maintenant toutes les ressources nécessaires pour avoir un projet bien rangé.

La prochaine fois, nous verrons une fonctionnalité très puissante et très pratique d’ink. Ce sera plus intéressant !

Tresser son histoire avec ink

Nathanaël Marion

Jusqu’à maintenant, avec ink, nous avons pu proposer des choix au lecteur et dévier l’histoire vers d’autres passages, un peu à la manière des livres dont vous êtes le héros.

Mais n’avez-vous jamais trouvé qu’il était parfois fastidieux de créer de nouveau nœuds, simplement pour des choix anodins qui ne font que faire aller l’histoire de l’avant plutôt que de la scinder en plusieurs branches ?

C’est là que le tressage (« weave ») entre en jeu.

Les points de rassemblement

Imaginons que notre protagoniste s’est introduit par effraction dans un bâtiment. Pour faire monter la tension, on veut lui proposer des choix qui vont faire avancer l’histoire, sans pour autant avoir d’impact sur la progression immédiate du jeu. Chaque option doit donc amener vers le même passage.

Vous êtes devant la porte de votre cible. Tout sera simple et rapide. Vous entrez, vous récupérez le butin et vous ressorter.

*  Vous crochetez la serrure.

 Habile comme vous êtes, elle ne tient pas longtemps.

*  Vous enfoncez la porte.

 La porte est solide, mais elle finit par céder.

-  Vous effectuez quelques pas à l'intérieur. Vous êtes dans grand hall. Ce que vous cherchez doit être à l'étage.

*  Vous longez les murs jusqu'à l'escalier.

*  Vous allez directement vers l'escalier en traversant le hall.

-  Au moment où vous posez le pied sur la première marche, un bruit se fait entendre sur le côté.

À suivre…

-> END

Nous pouvons remarquer que les options ne dévient pas vers un nouveau nœud. De plus, un nouveau symbole a fait son apparition : -.

Les paragraphes commençant par un trait d’union sont des points de rassemblement. Quand un choix qui ne dévie pas est sélectionné, ink regarde si un point de rassemblement est présent après les choix. Si c’est le cas, l’histoire continue à partir de cet endroit.

Ici, que l’on enfonce la porte ou crochète la serrure, on entre. Ensuite, quelle que soit la façon dont on atteint l’escalier, un bruit s’élève. (Testez pour vous en convaincre !)

Et on pourrait recommencer, jusqu’à ce qu’un choix soit significatif et dévie vers un autre nœud. Avec cela, il est garanti que l’histoire ira de l’avant. Et si on veut qu’un choix ne mène pas vers le point de rassemblement, on peut toujours dévier vers un autre nœud, uniquement pour cette option.

Mais à quoi peuvent servir ces choix, en apparence inutile ? Ils peuvent servir à augmenter la tension, à faire croire au joueur qu’il influence le cours de l’histoire… Il est également possible de tester plus tard quels choix ont été pris, comme nous le verrons plus bas.

Imbriquer des options

Des sous-options

Attention, c’est là que ça devient un peu plus compliqué !

Il est possible de proposer des « sous-options » quand un choix a été fait.

Considérons ceci :

Devant vous se dresse le meuble que vous cherchez. Malheureusement, vous entendez des bruits à l'extérieur de la pièce. Vous n'aurez pas le temps de le fouiller en entier.

*  Vous partez sans prendre de risques.

*  Vous vérifiez l'étagère du haut.

*  Vous regardez l'étagère du milieu.

*  Vous cherchez sur l'étagère du bas.

-  Soudain, des pas se font entendre dans le couloir. Plus de temps à perdre. Vous vous enfuyez par la fenêtre alors que la poignée de la porte commence à tourner.

-> END

Comme indiqué dans le premier paragraphe de l’histoire, Il y aura forcément un moment où le protagoniste devra s’enfuir. C’est pour cela qu’il y a un point de rassemblement à la fin : l’histoire doit avancer.

Si le joueur fait un choix, nous aimerions que d’autres options soient proposées, pour affiner la fouille. Pour écrire ces sous-options, nous allons utiliser deux astérisques, comme ceci :

Devant vous se dresse le meuble que vous cherchez. Malheureusement, vous entendez des bruits à l'extérieur de la pièce. Vous n'aurez pas le temps de le fouiller en entier.

*  Vous partez sans prendre de risques.

*  Vous vérifiez l'étagère du haut.

 Elle est remplie d'objets hétéroclites.

 **  Vous fouillez le petit coffret.

 Il contient quelques cartes postales. Vous vous en emparez.

 **  Vous regardez à l'intérieur de l'horloge.

 Rien n'y semble caché. Vous décidez de la prendre avec vous, au cas où.

*  Vous regardez l'étagère du milieu.

*  Vous cherchez sur l'étagère du bas.

-  Soudain, des pas se font entendre dans le couloir. Plus de temps à perdre. Vous vous enfuyez par la fenêtre alors que la poignée de la porte commence à tourner.

-> END

Maintenant, si on fouille la première étagère, le message sous l’option apparaît, suivi de l’ensemble des sous-choix. Quand l’un d’eux est sélectionné, on passe au point de rassemblement à la fin.

Le fonctionnement est assez intuitif. Je vous conseille de tester le code ci-dessus pour vous assurer de bien comprendre. Après cela, vous pourrez essayer d’écrire le contenu des autres étagères !

Ce qui est important, c’est le nombre d’astérisques. L’indentation n’est pas nécessaire, même si elle est conseillée.

Des sous-points de rassemblement

Il est aussi possible d’imbriquer des sous-points de rassemblement. Ils fonctionnent de la même façon, si ce n’est qu’ils rassemblent après un sous-choix, plutôt qu’un choix principal. Pour en écrire, vous l’aurez deviné, il faut répéter le symbole -.

*  Vous vérifiez l'étagère du haut.

 Elle est remplie d'objets hétéroclites.

 **  Vous fouillez le petit coffret.

 Il contient quelques cartes postales. Vous vous en emparez.

 **  Vous regardez à l'intérieur de l'horloge.

 Rien n'y semble caché. Vous décidez de la prendre avec vous, au cas où.

 --  Vous vous apprêtez à continuer votre inspection.

*  Vous regardez l'étagère du milieu.

*  Vous cherchez sur l'étagère du bas.

-  Soudain, …

Ici, si on fouille la première étagère, les sous-options seront montrées. Quand l’une d’elle est sélectionnée, on continue au sous-point de rassemblement. Enfin, comme il n’y a plus de contenu sous le choix principal, on arrive au point de rassemblement final.

Il est possible de proposer d’autres sous-options après le point de rassemblement de second niveau, comme on l’avait fait pour l’entrée dans le bâtiment, mais pour les choix principaux :

*  Option 1

 **  Option 1.1

 **  Option 1.2

 --  Sous-point de rassemblement 1

 **  Option 1.1'

 **  Option 1.2'

 --  Sous-point de rassemblement 2

 // Et ainsi de suite.

*  Option 2

Il est également possible d’ajouter des options de troisième niveau, quand un option de deuxième niveau est sélectionnée, et de quatrième niveau… Pour cela, il suffit d’ajouter une astérisque à chaque fois. Bien sûr, ça peut commencer à devenir illisible, alors il vaut mieux dévier plutôt que de faire des choix de quarante-deuxième niveau.

Savoir quels choix ont été pris

Pour savoir par quel chemin est passé le joueur, il est possible de donner des noms aux différents choix :

*  (cartes_postales) Vous fouillez le petit coffret.

Il sera possible de tester, comme pour les nœuds et les mailles, si le joueur a sélectionné ce choix :

{cartes_postales: Vous vous assurez que les cartes sont bien dans votre poche.}

Pour faire référence à une option, il faut utiliser son adresse : nœud.maille.option. Le nœud n’est pas obligatoire si on écrit la condition dans le même nœud que le choix, et il en va de même pour la maille.

Avec cela, les choix du joueur, même s’il ne font qu’avancer l’histoire, pourront avoir des conséquences par la suite.

Enfin, sachez que si vous voulez mettre des conditions sur des choix, il faut les écrire après leur nom.

Un petit bonus : il est possible de dévier vers un choix. Cela le sélectionnera, comme si c’était le joueur qui l’avait choisi.

Il est possible de nommer les points de rassemblement de la même manière, si jamais le besoin s’en fait sentir. Cela peut servir à organiser plus finement son histoire, en ayant une subdivision plus précise que les mailles.

Conclusion

Le tressage — cette façon de proposer des choix puis de les rassembler —, est une fonctionnalité très puissante et très pratique d’ink. Je vous recommande fortement de vous y habituer, car elle devient très claire une fois que l’on s’y est fait.

En plus, cela vous garanti que votre histoire avancera, sans que vous n’ayez à vérifier tous les chemins possibles. Car une déviation est si vite oubliée !

Ink et les variables

Nathanaël Marion

Avec ce que nous avons appris jusqu’à maintenant, nous pouvons déjà écrire des histoires assez conséquentes. Cependant, elles restent assez statiques et nous ne savons pas encore comment garder certaines choses en mémoire. Nous allons remédier à cela dès maintenant.

Rappel : pour savoir si le joueur a vu un passage

Rappelons-nous : il est possible de d’afficher du texte ou de proposer un choix seulement si un certain passage a été vu ou une certaine option, sélectionnée.

Ce qui n’avait pas été dit, c’est qu’en fait, quand on tape le nom d’un nœud (ou d’une maille ou d’un choix) dans une condition, on ne teste pas si le joueur a vu ou non tel passage ; on teste combien de fois il a été vu (s’il a été vu 1 fois ou plus, la condition est vrai, fausse sinon).

Il est donc possible de faire des tests plus avancés :

{attente > 5: Vous en avez assez d'attendre, vous passez à l'action ! -> attaque}

Ici, le texte ne sera affiché que si le passage attente a été vu plus de cinq fois. Nous allons voir plus loin quels autres conditions peuvent être testées.

Créons des variables

Comme dans n’importe quel autre langage de programmation, il est possible de créer des variables dans ink. Une variable est une valeur que l’on veut sauvegarder pour pouvoir la récupérer plus tard : le score ou les pièces d’or du protagoniste, mais aussi s’il a obtenu un arc ou le nom de sa prochaine destination.

Pour déclarer une variable, il faut utiliser le mot-clef VAR suivi de son nom (sans espaces, comme pour les nœuds) et de sa valeur initiale. Un bon endroit pour faire cela est le début de son code, ou dans le fichier .ink principal.

VAR pieces = 9

VAR arc = false

VAR destination = "la crypte du Nécromancien"

On voit ici qu’une variable peut stocker différents types de valeurs : la première est un nombre, qui peut être décimal ou pas, positif ou négatif. La deuxième est un booléen, c’est-à-dire un type qui ne peut avoir que deux valeurs, true (vrai) ou false (faux). La dernière est une chaîne de caractère, c’est-à-dire du texte ; on la reconnaît grâce aux guillemets qui l’encadrent.

Il faut obligatoirement déclarer ses variables avant de pouvoir les utiliser, c’est pourquoi il vaut mieux le faire le plus tôt possible.

Affichons nos variables

Pour afficher la valeur de ses variables, rien de plus simple : il suffit de les écrire quelque part dans des accolades.

Vous possédez {pieces} pièces d'or et votre prochaine destination est {destination}.

Cela affichera, avec les valeurs données plus hauts :

Vous possédez 9 pièces d'or et votre prochaine destination est la crypte du Nécromancien.

Il est possible d’afficher le contenu de variables dans des options, mais attention : comme les accolades au début d’un choix déterminent sous quelles conditions il est visible, on ne peut pas afficher de variables au début du texte de l’option.

Modifions nos variables

Tout cela est bien beau, mais nos variables ne varient pour l’instant pas beaucoup. Il nous faut un moyen de les modifier en cours d’histoire.

Avec ink, quand on veut exécuter du code plutôt que simplement afficher du texte, il faut commencer la ligne par le symbole ~. On peut alors changer la valeur de ses variables.

Vous apercevez un scintillement dans l'herbe, plus loin.

*  [Allez voir.]

 ~ pieces = pieces + 7 // On gagne 7 pièces.

 Vous trouvez quelques pièces par terre !

Les différentes opérations possibles pour les nombres sont + (addition), - (soustraction), * (multiplication), / (division) et % (modulo, pour obtenir le reste de la division). De plus, il faut utiliser des nombres décimaux pour avoir un résultat non arrondi, (à prendre en compte surtout lors des divisions). Ainsi, 1/4 vaut 0, mais 1.0/4, 1/4.0 et 1.0/4.0 valent 0,25 chacun.

Additionner deux chaînes de caractères revient à les concaténer : "Bon" + "jour" donnera "Bonjour".

Il est bien évidemment possible de ne pas effectuer d’opération et d’assigner directement une valeur :

*  [Acheter l'arc pour 50 pièces d'or]

 ~ pieces = pieces - 50

 ~ arc = true

 Vous achetez un arc. Vous possédez maintenant {pieces} pièces.

Enfin, il existe des raccourcis pour les opérations communes :

// Chaque paire de lignes est équivalente.

~ pieces = pieces + 5

~ pieces += 5

~ pieces = pieces - 5

~ pieces -= 5

~ pieces = pieces + 1

~ pieces++

~ pieces = pieces - 1

~ pieces--

Testons nos variables

Enfin, la dernière chose utile à faire avec des variables est de les comparer. Par exemple, tout à l’heure, il aurait fallu vérifier si le joueur a assez de pièces pour acheter l’arc. C’est conditions peuvent se mettre aux mêmes endroits que lorsque l’on testait si un passage avait été visité.

Tout d’abord, on peut comparer deux valeurs entre elles :

x == y : x est égal à y ;

x != y : x est différent de y ;

x > y : x est plus grand que y ;

x >= y : x est plus grand ou égal à y ;

x < y : x est plus petit que y ;

x <= y : x est plus petit ou égal à y ;

x : x est différent de 0.

not x : x est égal à 0.

Ici, x et y peuvent être n’importe quoi : un nombre tapé directement, une variable, une opération entre plusieurs valeurs…

Attention, il s’agit bien de deux symboles = à la suite ! On utilise un seul symbole uniquement quand on veut donner une valeur à une variable !

Lorsque l’on teste un booléen, il suffit d’écrire son nom quand on veut qu’il soit vrai et le précéder de not quand on veut qu’il soit faux.

*  {arc} Vous utilisez votre arc.

*  {not arc} Vous n'avez malheureusement pas d'arc.

Il est aussi possible de combiner plusieurs conditions entre elles :

condition_1 and condition_2 ou condition_1 && condition_2 (au choix) : les deux conditions doivent être vraies ;

condition_1 or condition_2 ou condition_1 || condition_2 (au choix) : au moins une des deux conditions doit être vraie. Il s’agit du caractère « barre verticale » dans la deuxième forme.

Notre exemple de l’arc devient ainsi :

*  {pieces >= 50 and not arc}[Acheter l'arc pour 50 pièces d'or]

 ~ pieces -= 50

 ~ arc = true

 Vous achetez un arc.

*  {arc} [Vendre votre arc pour 35 pièces d'or.]

 ~ pieces += 35

 ~ arc = false

 Vous vendez votre arc.

- <> Vous possédez maintenant {pieces} pièces.

Pour effectuer plusieurs choses en fonction d’une certaine condition, que ce soit pour afficher du texte ou modifier plusieurs variables, il existe la syntaxe suivante :

{ condition:

 // Tout ce qui est ici se passera si la condition est vrai.

- else:

 // Tout ce qui est ici se passera si elle est fausse.

}

Ou, s’il doit arriver des choses différentes selon plusieurs conditions :

{

- condition_1:

 // La condition 1 est vrai.

- condition_2:

 // La condition 1 est fausse mais la deux est vraie (fonctionne comme un « sinon si »).

- condition_3

 // Les deux conditions précédentes sont fausses mais la troisième est vraie.

- else:

 // Toutes les conditions sont fausses.

}

Il est possible de faire ce que vous voulez sous chaque condition : afficher du texte, modifier des variables, même proposer des choix ! Je vous laisse expérimenter.

Conclusion

Ce tutoriel était assez théorique. Si vous avez déjà des notions d’autres langages de programmation, tout ce qui est ici doit être assez facile. Si ce n’est pas le cas, je vous conseille de bien vous habituer à ce que nous venons de voir, car il y a souvent besoin de garder en mémoire certaines choses dans des histoires interactives !

Des fonctions avec ink

Comme nous l’avons vu précédemment, ink possèdent certaines fonctionnalités de langages de programmation standards, comme les variables. Aujourd’hui, nous étudierons les fonctions. Si vous avez déjà un peu d’expérience en programmation, ce qui suit vous ne sera pas bien différent de ce que l’on peut faire dans d’autres langages.

Une fonction, qu’est-ce que c’est ?

Les fonctions vous rappellent peut-être de lointains cours de maths. En programmation, une fonction fonctionne de manière similaire : il s’agit d’une « machine » dans laquelle on insère des choses ; la machine les utilise pour accomplir une tâche et éventuellement vous donner un résultat.

Par exemple, on pourrait créer une fonction à laquelle on donne un nombre représentant les points de vie du protagoniste, et qui nous rend des mots décrivant son état de santé (0 donnerait « mort », 1 donnerait « mourant », 5 donnerait « en pleine forme », etc.).

Si ce n’est pas encore clair, lisez la suite !

Notre première fonction

Avec ink, les fonctions sont de simples nœuds, mais dont le nom est précédé par function. Cependant, il est interdit d’y inclure des mailles, des déviations ou des choix. On peut tout de même y mettre du texte, qui sera affiché quand la fonction sera appelée.

Voici un exemple très basique,  qui ne fait que montrer du texte :

=== function bonjour ===

Bonjour, le monde !

Il est d’usage d’écrire ses fonctions au début de sa source, ou dans un fichier séparé (il ne faudra pas oublier de l’inclure !).

Ensuite, il faut l’appeler. Pour ce faire, il suffit d’écrire le nom de la fonction, suivi de parenthèses, sur une ligne commençant par ~.

Nous allons dire bonjour avec une fonction.

~ bonjour()

Il est également possible d’appeler une fonction en plein milieu de texte, en la mettant entre accolades. Ceci est très pratique pour les fonctions renvoyant un résultat, comme nous allons le voir plus bas.

Avec des arguments

Une fonction peut prendre des arguments : il s’agit des choses qu’on lui donne pour travailler. Voyons par l’exemple :

VAR vie = 10

=== function blesser(degats) ===

// On blesse le protagoniste.

{ vie < degats:

 ~ vie = 0

- else:

 ~ vie -= degats

}

La nouveauté est les parenthèses après le nom. Elles vont contenir ce qui sera donné à la fonction. Dans cette fonction, le mot degats fera référence à ce que nous lui donneront lorsqu’elle sera appelée. Par exemple :

Le gobelin vous attaque !

~ blesser(3)

Ici, degats prendra la valeur 3 dans la fonction, et la variable vie sera donc diminuée de 3. On aurait pu mettre une autre valeur, ou même une variable  : ~ blesser(attaque_ennemie) diminuera la vie de la valeur stockée dans la variable attaque_ennemie !

On peut écrire une fonction demandant plusieurs arguments en les séparant par des virgules :

VAR vie = 10

VAR empoisonne = false

=== function blesser(degats, type) ===

// On blesse le protagoniste.

{ vie < degats:

 ~ vie = 0

- else:

 ~ vie -= degats

}

// Si le deuxième argument est la chaîne de caractère "poison", on met true dans la variable adéquate.

{ type == "poison":

 ~ empoisonne = true

}

Il suffira ensuite d’écrire :

// Attaque normale

Vous recevez un coup d'épée !

~ blesser(3, "normal")

// Attaque empoisonnée

Vous sentez une fléchette empoisonnée vous toucher !

~ blesser(3, "poison")

Renvoyer des valeurs

Enfin, une fonction peut nous redonner une valeur. Pour cela, il faut faut la terminer avec l’instruction ~ return valeur_a_renvoyer. Exemple simpliste :

=== function toujours_daccord ===

~ return true

Cette fonction va toujours redonner la valeur « vrai » (ce qui est assez inutile, mais c’est un exemple). Puisqu’elle renvoie un booléen, nous pourrons l’appeler à n’importe quel endroit où nous avons besoin d’une condition :

*  {toujours_daccord()} Je suis d'accord.

*  {not toujours_daccord()} Je ne serai jamais affiché car la fonction renverra toujours vrai.

Une fois que l’on a renvoyé une valeur avec ~ return, la fonction s’arrête et ce qui est après n’est pas exécuté.

Bien sûr, une fonction peut également renvoyer un nombre ou un texte. Si la fonction est appelée dans du texte, avec des accolades (et non avec une ligne commençant par un tilde), la valeur renvoyée est affichée (si une fonction ne renvoyant rien est écrite à la place, rien ne sera montré).

=== function min_en_h(x) ===

// Cette fonction convertit des minutes en heures et minutes.

~ return x / 60 + " h " + x % 60 + " min"

Et on pourra écrire :

729 minutes font {min_en_h(729)}.

On obtiendra :

729 minutes font 12 h 9 min.

(N’oubliez pas, une addition avec des chaînes de caractères les colle ensemble.)

Vous sentez-vous prêts à écrire la fonction décrite au tout début de cet article (celle qui convertit des points de vie en mots décrivant l’état du protagoniste) ? Essayez, puis regardez une solution possible ci-dessous. Il faudra que la fonction renvoie « mort » à 0 PV, « mourant » entre 1 et 3, « faible » entre 4 et 6 PV, « vigoureux » entre 7 et 9 PV et « en pleine forme » à 10 PV. N’hésitez pas à regarder l’article sur les variables si vous ne vous souvenez plus comment faire des conditions.

C’est bon ? Voici :

=== function decrire_PV(x) ===

{

- x == 0:

 ~ return "mort"

- x <= 3:

 ~ return "mourant"

- x <= 6:

 ~ return "faible"

- x <= 9:

 ~ return "vigoureux"

- else:

 ~ return "en pleine forme"

}

Des variables temporaires

Il est possible d’avoir des variables qui n’existent que le temps d’une fonction (ou d’un nœud). À chaque fois qu’elle est appelée, la variable est créée, puis elle est détruite quand on arrive à la fin de la fonction. Il faut utiliser le mot temp, comme ceci :

=== function ma_fonction ===

~ temp ma_variable_temporaire = 42

Elle est ensuite modifiée ou testée comme une variable normale.

L’intérêt ? Stocker une valeur de « travail », comme un genre de Post-it pour se souvenir de résultats intermédiaires pendant des calculs. Si vous n’en voyez pas trop l’utilité, ce n’est pas grave, vous n’en n’aurez de toute façon pas forcément besoin.

Finalement, à quoi sert tout cela ?

Si vous avez déjà programmé dans d’autres langages, le sujet de cet article devrait vous être familier et la question ne se pose alors peut-être pas. Dans le cas contraire, nous allons terminer cet article par donner quelques pistes d’utilisations pour des fonctions.

Elles peuvent être utile pour une tâche que l’on souhaite accomplir à des endroits différents de l’histoire. Par exemple, quand le protagoniste essaie de crocheter une serrure, on peut écrire une fonction ayant pour arguments le niveau de la compétence de crochetage, la difficulté de la serrure, etc. et qui renvoie vrai ou faux après avoir passé ces arguments dans une formule mathématique ; comme cela, pas besoin de réécrire cette formule à chaque fois que l’on veut déterminer si le joueur réussit à ouvrir une porte. La fonction pour blesser le joueur est un autre exemple.

Une fonction peut aussi être utilisée pour convertir des données. Celle qui transforme les minutes en heures ou celle qui décrit la santé du personnage en sont des exemples.

Enfin, elles peuvent servir à coder des opérations mathématiques qui ne sont pas incluses dans ink : puissances, factorielle…

Voilà ! Le sujet d’aujourd’hui ne sera pas forcément utile à tout le monde, mais cela nous donne un outil de plus pour écrire des histoires avec ink !

Ink et les tunnels

Nathanaël Marion

Aujourd’hui, nous allons nous attarder sur une fonctionnalité pratique d’ink, même si elle ne sera pas forcément utile à tout le monde : les tunnels. Il est tout à fait possible d’écrire une histoire sans et vous n’en aurez peut-être pas besoin, mais on ne sait jamais.

Et il reste possible de les utiliser pour expérimenter même si on aurait pu procéder autrement. C’est avec la pratique qu’on finit par savoir quand telle fonctionnalité est nécessaire.

Des nœuds à paramètres

Commençons toutefois par quelque chose qui n’a de prime abord pas de rapport avec les tunnels (nous verrons ensuite pourquoi).

Nous avons vu précédemment des nœuds spéciaux, les fonctions, qui pouvaient prendre des paramètres. Il se trouve que les nœuds normaux le peuvent aussi.

Comment irez-vous au travail aujourd'hui ?

*  [En voiture]

 -> travail("voiture")

*  [En bus]

 -> travail("bus")

*  [En métro]

 -> travail("métro")

=== travail(transport) ===

Vous vous rendez à votre travail en {transport}{transport == "voiture": <> et vous arrivez à destination malgré les embouteillages}.

Ici, il faut fournir une valeur entre parenthèses quand on dévie vers travail, car ce nœud demande un argument. On passe ici un texte mais, comme pour une fonction, on aurait pu utiliser un nombre ou un booléen. Le mot transport se comporte exactement comme un argument de fonction normal : on peut l’afficher, le comparer, même lui assigner une autre valeur à l’intérieur du nœud… et il n’est disponible qu’à l’intérieur de son passage. Les mailles aussi peuvent avoir des arguments.

Cela permet de réutiliser un même passage mais avec des variations en fonction de la façon dont on y arrive. Très pratique pour ne pas avoir à écrire plusieurs fois un passage identique excepté de petites différences.

On aurait pu utiliser une variable globale (chaque choix lui donne la valeur adéquate) et afficher cette variable, mais je trouve cette syntaxe plus claire. Et s’il n’y a qu’à cet endroit que le mode de transport affecte l’histoire, alors ça ne vaut peut être pas la peine de créer une variable globale accessible à toute l’histoire !

Garder une déviation en mémoire

Les variables peuvent, comme nous l’avons vu, stocker des textes, des nombres ou des booléens. Mais elles peuvent aussi stocker des déviations.

VAR epilogue = -> fin_malheureuse

-> intro

=== intro ===

*  Vous décidez de gagner.

 ~ epilogue = -> fin_heureuse

 -> intro

*  Finir maintenant.

 -> epilogue

=== fin_malheureuse ===

Vous avez perdu !

-> END

=== fin_heureuse ===

Vous avez gagné !

-> END

Ici, quand l’histoire rencontre -> epilogue, elle va chercher quelle déviation est stockée à l’intérieur de la variable, et elle sera déviée vers le nœud approprié. Initialement, la variable contient une déviation vers fin_malheureuse. Cependant, si le joueur a décidé de gagner, elle contiendra une déviation vers fin_heureuse.

Il ne faut pas oublier d’écrire la flèche quand on stocke une déviation ! En effet, le nom d’un nœud sans la flèche signifie le nombre de fois que celui-ci a été visité. Si l’on n’avait pas écrit la flèche à la première ligne, on aurait stocké le nombre 0 dans la variable (car le passage n’a jamais été visité à ce moment).

Cela peut être utile quand un passage ne doit pas mener au même endroit en fonction des choix précédents du joueur. Ici, il aurait été facile de mettre une condition plutôt qu’une variable (si le joueur a précédemment sélectionné l’option de gagner, alors aller vers la fin heureuse, sinon aller vers la fin malheureuse), mais dans une histoire complexe, il se peut que la fin (ou toute autre déviation) doivent changer en fonction d’éléments trop compliqués à exprimer par une condition.

Maintenant, combinons ce que nous venons d’apprendre et passons une déviation comme argument d’un passage. Attention cependant, il faut bien écrire la flèche même devant l’argument après le nom du nœud. Cela peut être pratique pour par exemple se souvenir de l’endroit d’où est fait la déviation. Un exemple sera peut-être plus parlant.

-> gare

=== gare ===

Quelle sera votre destination ?

*  [Paris]

 -> voyage(-> paris)

 // on dévie vers voyage, en donnant comme paramètre la déviation -> paris.

// Ci-dessous, il ne faut pas oublier la flèche.

=== voyage(-> destination) ===

Vous prenez place dans le train.

// Passage qui raconte les rencontres que fait le joueur, les événements du voyage, etc.

Enfin, vous arrivez à destination.

// On dévie vers la destination donnée en paramètre.

-> destination

=== paris ===

Vous êtes dans la capitale de la France.

Comme cela, il est facile d’ajouter de nouvelles destinations tout réutilisant le passage qui décrit le voyage, puisqu’on peut maintenant spécifier où aller après ledit voyage.

Enfonçons-nous sous terre

Et c’est là que les tunnels entrent en jeu. Imaginons que le voyage en train est assez complexe et possède de nombreux nœuds et mailles. Comme il faut garder en mémoire la destination, il faudrait à chaque fois passer la déviation en argument de chaque passage !

=== voyage(-> destination) ===

Vous prenez place dans le train.

Que faites-vous ?

*  [Manger]

 -> manger(-> destination)

*  [Dormir]

 -> dormir(-> destination)

= manger(-> destination)

Vous manger puis arrivez enfin à destination.

-> destination

= dormir(-> destination)

Vous dormez un moment. Quand vous vous réveillez, vous vous rendez-compte que vous êtes arrivés.

-> destination

C’est assez lourd. Une solution simple serait encore une fois d’utiliser une variable globale. Mais ce n’est pas la peine, car les créateurs d’ink ont pensé à cette situation et ont créé les tunnels.

Une tunnel est une déviation spéciale qui mène vers un passage qui, une fois terminé, nous ramène à l’endroit où l’on était au moment d’entrer dans le tunnel.

Pour entrer dans un tunnel, on ajoute une flèche à la fin d’une déviation : -> mon_tunnel ->. Cela signifie : « Rends-toi au nœud mon_tunnel puis reviens ici. »

Ici, mon_tunnel est simplement un nœud normal (ou une maille). Il se passera des choses à l’intérieur de ce nœud, qui contiendra éventuellement d’autres déviations, jusqu’à ce qu’on veuille sortir du tunnel. Dans ce cas, il suffira d’écrire deux flèches à la suite : ->->. Cela voudra dire qu’on souhaite revenir à l’endroit où on est entré dans le tunnel.

Notre exemple deviendrait alors :

-> gare

=== gare ===

Quelle sera votre destination ?

*  [Paris]

 // On entre dans le tunnel voyage.

 -> voyage ->

 // Puis on va à Paris.

 -> paris

=== voyage ===

Vous prenez place dans le train.

Que faites-vous ?

*  [Manger]

 -> manger

*  [Dormir]

 -> dormir

= manger

Vous manger puis arrivez enfin à destination.

// On sort du tunnel.

->->

= dormir

Vous dormez un moment. Quand vous vous réveillez, vous vous rendez compte que vous êtes arrivé.

// On sort du tunnel.

->->

=== paris ===

Vous êtes dans la capitale de la France.

Plus besoin de traîner un argument ! Les tunnels sont, je trouve, assez intuitifs, mais n’hésitez pas à bien tester l’exemple pour être certain que rien ne vous échappe. Ici, un cheminement possible serait gare, voyage, dormir, retour au milieu de gare, paris.

Entrer dans un tunnel, c’est comme faire pause dans l’histoire actuelle (le joueur décide de visiter des villes de France) pour passer momentanément à une sous-histoire (les rencontres du joueur dans le train).

Il faut bien vous assurer que le joueur va finir par rencontre un ->-> pour qu’il puisse sortir du tunnel. Et il faut aussi vous assurer que le joueur ne rencontre pas de double flèche alors qu’il n’est pas dans un tunnel.

Sachez également qu’il est possible d’enchaîner des tunnels et des déviations. On aurait donc pu écrire dans l’exemple ceci, sur une seule ligne : -> voyage -> paris. On pourrait même écrire, dans d’autres cas, -> tunnel_1 -> tunnel_2 -> tunnel_3 -> pour effectuer plusieurs tunnels à la suite.

Il est aussi possible d’entrer dans un second tunnel alors qu’on est déjà à l’intérieur d’un tunnel. On passerait donc à une sous-sous-histoire qui, quand elle sera terminée, reviendra à la première sous-histoire qui, quand elle sera terminée, reviendra à l’histoire principale. J’espère que c’est assez clair ! 🙂

Pour finir

Vous vous demandez peut-être maintenant l’intérêt de passer des arguments à un nœud si les tunnels existent. C’est toujours utile quand on veut passer un nombre ou un texte, comme dans le tout premier exemple. Pour le reste, tout dépend de votre histoire. Utilisez ce qui vous paraît le plus clair.

Enfin, comme dit au début, il est possible que vous n’ayez jamais besoin de ces fonctionnalités. Expérimentez quand même, car vous pourrez vous rendre compte qu’elles peuvent quand même servir !

Les fils, une fonctionnalité avancée d’ink

Nathanaël Marion

La dernière fois, nous avions parlé des tunnels, une fonctionnalité d’ink assez avancée, mais bien pratique quand on en a besoin. Le sujet d’aujourd’hui est similaire, bien qu’on puisse peut-être le considérer comme encore plus avancé. Mais n’ayons pas peur ! Les fils ne sont pas si compliqués, même s’il peut être difficile de leur trouver une utilisation de prime abord.

Que sont les fils ?

Un fil (thread en anglais) permet d’aller chercher du contenu ailleurs dans l’histoire afin de l’intégrer dans le nœud actuel. Pour en créer un, il faut utiliser une déviation vers la gauche : <- mon_fil.

Un petit exemple pour mettre tout cela au clair :

-> reveil

=== reveil ===

Quand je me suis réveillée ce jour-là, j'ai tout de suite su que quelque chose clochait.

// On crée un fil à cet endroit

<- fenetre

=== fenetre ===

Les volets avaient été ouverts et la lumière était différente.

*  Je me suis levée pour regarder par la fenêtre.

*  J'ai tiré les rideaux sans jeter un œil dehors.

En testant, nous nous rendons compte que le texte du nœud reveil est affiché, puis celui du nœud fenetre avec ses options. En effet, lorsque nous démarrons un fil, ink va chercher les texte et les options du passage indiqué pour l’intégrer au nœud actuel.

Mais pourquoi ne pas avoir écrit le texte de fenetre directement dans reveil ? Ici, ça aurait effectivement été plus facile, mais ça devient intéressant quand on utilise plusieurs fils à la fois.

-> reveil

=== reveil ===

Quand je me suis réveillée ce jour-là, j'ai tout de suite su que quelque chose clochait.

// Deux fils en même temps, cette fois-ci.

<- fenetre

<- musique

=== fenetre ===

Les volets avaient été ouverts et la lumière était différente.

*  Je me suis levée pour regarder par la fenêtre.

*  J'ai tiré les rideaux sans jeter un œil dehors.

=== musique ===

Une étrange musique s'échappait de la porte entrebâillée.

*  J'ai écouté la mélodie.

*  J'ai quitté la pièce.

Ici, nous récupérons le contenu de deux nœuds différents. Ink va procéder comme suit. Après avoir affiché l’introduction, ink va chercher le contenu du noeud fenetre pour afficher son texte et garder les choix qu’il propose en mémoire. Mais il ne va pas les montrer tout de suite ! Ink doit d’abord chercher le contenu du second fil, l’afficher et garder ses choix en mémoire. Quand tous les fils ont été parcouru, ink montre toutes les options qu’il a rencontré d’un coup.

Ici, on aura donc l’introduction, la ligne décrivant les volets, la ligne annonçant la mélodie, puis les quatre choix à la suite.

Ces choix n’ont rien de particulier autrement. Pour compléter l’exemple, on ajouterait des réponses et des diversions à chaque option, ou des points de rassemblement, afin de continuer l’histoire comme si de rien n’était.

Tout cela est bien beau, mais à quoi peut concrètement servir tout cela ?

De l’utilité des fils

Comme on vient de le voir, les fils permettent de récupérer du contenu ailleurs dans l’histoire pour les intégrer sur le champ. Chaque fil peut être vu comme une vision d’un futur possible (chaque futur étant représenté par un nœud) : on peut soit s’intéresser à la fenêtre, soit s’intéresser à la musique. Mais dès qu’un choix est sélectionné, c’est le futur auquel il appartient qui devient la réalité : si la protagoniste regarde à l’extérieur, alors c’est qu’elle a décidé de ne pas s’intéresser à la mélodie.

Les fils peuvent n’avoir qu’une utilité organisationnelle : plutôt que de mettre tout le texte et toutes les options dans un seul énorme nœud, on le casse en plusieurs petits morceaux. C’est ce que nous avons fait dans l’exemple plus tôt. En effet, rien ne nous aurait empêché d’écrire tout le contenu dans reveil.

Mais les fils deviennent véritablement utiles quand on veut le même contenu à plusieurs moments. Il peut s’agir de personnages se déplaçant à différents endroits, d’un ordinateur que le joueur peut consulter depuis divers emplacements…

=== couloir ===

La musique était un peu plus forte dans le couloir. Elle semblait venir du salon.

<- ecouter

*  Je suis allée dans le salon.

 -> salon

*  Je suis retournée dans ma chambre

 -> chambre

=== salon ===

La mélodie était forte ici, envoûtante, mais je ne parvenais pas à en localiser l'origine.

<- ecouter

*  J'ai cherché d'où venait la musique.

=== ecouter ===

*  J'ai fermé les yeux et me suis laissé emporter.

 J'ai eu la sensation de basculer. Quand j'ai rouvert les yeux…

 À suivre…

 -> END

Ici, il sera possible d’écouter l’hypnotisante musique partout, en plus des choix que chaque pièce offre. Le fil permet donc de récupérer l’option depuis des nœuds différents, sans avoir à réécrire plusieurs fois la même chose.

Encore mieux, comme avec des déviations normales, on peut passer des paramètres quand on crée un fil. Cela peut servir si l’on veut retourner à l’endroit d’où a été fait le fil :

=== foret ===

J'étais dans une étrange forêt.

// Ce point de rassemblement ne sert qu'à avoir un endroit vers lequel on peut dévier.

- (options)

// On crée un fil avec comme paramètre une déviation vers le point de rassemblement ci-dessus.

<- carte(-> options)

*  Les arbres étaient moins serrés, plus loin.

 -> clairiere

=== clairiere ===

Je me tenais dans une drôle de clairière

- (options)

<- carte(-> options)

*  J'ai exploré l'endroit.

=== carte(-> retour) ===

*  J'ai consulté l'étrange carte que j'avais trouvée.

// On revient vers l'endroit spécifié quand on crée un fil. On utilise un point de rassemblement pour que l'on soit sûr de revenir, même si le nœud a plusieurs options.

- -> retour

Le nœud carte prend comme argument une déviation ; quand on créé le fil, on fournit l’endroit vers lequel on veut revenir. Pour cela, nous utilisons des points de rassemblement que nous avons nommés et qui n’ont pas d’autres vocations que d’être la cible de déviation (lisez l’article dédié aux points de rassemblement pour vous rafraîchir la mémoire !). On aurait pu s’en passer et dévier vers les nœuds directement, mais cela aurait eu pour effet de répéter le texte du nœud, ce qui n’aurait pas forcément été souhaitable.

Interrompre un fil

Un fil cherche le contenu d’un nœud et ses options, mais il peut arriver que l’on veuille interrompre cette collecte. Par exemple, si la protagoniste ne possède pas la carte, on ne veut pas que les options pour la consulter soient visibles. On peut pour cela utiliser la déviation spéciale -> DONE, qui dit à ink d’interrompre le fil à cet endroit.

VAR possede_carte = true

=== carte ===

// Si on ne possède pas la carte, on coupe le fil et rien ne sera récupéré.

{not possede_carte: -> DONE}

// Sinon, on récupère les choix.

* J'ai consulté l'étrange carte que j'avais trouvée.

Si la variable est fausse, la condition coupe le fil avec -> DONE et tout contenu qui suit ne sera jamais récupéré. Le jeu n’affichera donc pas l’option dans ce cas-ci. Cela est plus pratique que de mettre une condition à chaque fois qu’on crée le fil (comme ceci : {possede_carte: <- carte}) car on n’a à le faire qu’à un seul endroit.

Conclusion

Et cela clôt cet article ! Nous avons fait un tour général des fils dans ink, mais n’hésitez pas à lire la documentation officielle pour plus d’exemples. Et surtout, expérimentez ! Votre histoire n’en n’a peut-être pas besoin, mais il n’y a qu’un moyen de le savoir.

Gardez simplement en tête qu’une fois que des fils sont en jeu, une histoire obtient une structure plus complexe, alors faites attention et ne perdez pas le fil ! (Oui, j’avoue, elle était facile.)

Premiers pas avec les listes ink

Nathanaël Marion

Ink est un excellent langage pour écrire des histoires, mais ce que nous avons vu jusqu’à maintenant nous permettrait difficilement de simuler un monde (par rapport à Inform 7, par exemple). Les listes ink ont été créé pour remédier à cela (au moins en partie, car ink reste principalement utilisé pour de la narration).

Il s’agit d’une récente fonctionnalité (et aussi la dernière qu’il nous reste à voir), et sûrement la plus complexe du langage (mais rien d’insurmontable !).

Notre première liste

Une liste dans ink est simplement une énumération de mots, que l’on crée avec le mot-clef LIST.

LIST emplacement = foret, plaine, desert, ocean

Le code ci-dessus crée une variable nommée emplacement, susceptible de contenir quatre valeurs différentes (foret, plaine, desert ou ocean). Il ne reste plus qu’à lui donner l’une de ces valeurs, quelque part au début de l’histoire. On peut bien évidemment la changer en cours de partie.

LIST emplacement = foret, plaine, desert, ocean

// La variable « emplacement » aura comme valeur « plaine ».

~ emplacement = plaine

*  [Voyager vers le désert]

 Votre prochaine destination : le désert.

 ~ emplacement = desert // On change l'emplacement, qui est maintenant le désert.

Et bien entendu, pour que tout cela puisse servir à quelque chose, on peut tester la valeur de la liste :

// On ne peut couper du bois qu'en forêt.

*  {emplacement == foret} [Couper du bois]

Et enfin, lorsque l’on déclare la liste, il est possible de mettre l’une des valeurs entre parenthèses pour indiquer que celle-ci est la valeur initiale. Si l’on écrit ceci :

LIST emplacement = foret, (plaine), desert, ocean

Alors il n’y a pas besoin d’initialiser la liste avec ~ emplacement = plaine, elle aura cette valeur dès le départ.

Quelques explications

Entrons maintenant plus en détails sur ce que nous venons de faire.

Le mot-clef LIST fait plusieurs choses à la fois. Il crée une variable (emplacement dans notre exemple), mais aussi les valeurs, représentées par des mots, qu’elle pourra avoir (comme ocean).

On aurait pu, dans ce cas-ci, se passer des listes et simplement représenter les endroits par des nombres ou du texte (1 pour la forêt et 2 pour la plaine, ou "forêt" pour la forêt et "plaine" pour la plaine). Cependant, utiliser une liste a beaucoup d’avantages, que nous verrons surtout dans de prochains articles. Disons qu’au moins, une liste nous permet de ne pas avoir à nous remémorer chaque nombre ou chaîne que l’on aurait pu utiliser à la place.

Un avertissement dédié aux programmeurs : les listes ink ne sont pas analogues aux listes que l’on peut trouver dans d’autres langages de programmation (comme le Python). Elles ne sont pas des tableaux pouvant contenir d’autres valeurs arbitraires comme des nombres ou des chaînes de caractères, mais des listes de valeurs possibles. Elles s’apparentent donc plus aux types énumérés (aussi appelées énumérations).

Réutiliser des listes

Dans notre premier exemple, nous avons créé une liste qui pouvait prendre comme valeurs divers endroits, afin de modéliser l’emplacement du joueur. Imaginons que nous voulons également modéliser l’emplacement de divers autres objets ou personnages. Faudra-t-il créer plusieurs listes ? La réponse est non. Comme écrit plus haut, en tapant LIST emplacement = foret, plaine..., nous créons à la fois une variable et une liste de valeurs possibles. Il ne nous reste donc plus qu’à créer d’autres variables contenant ces valeurs, sans avoir à recréer ces valeurs elles-mêmes !

C’est peut-être un peu confus ; voici un exemple.

// On crée la variable emplacement avec les valeurs qu'elle pourra contenir.

LIST emplacement = foret, (plaine), desert, ocean

// On crée d'autres variables qui contiendront des endroits.

VAR nemesis = foret

VAR dirigeable = desert

On dispose ici d’une liste de valeurs (foret, plaine, etc.) et de trois variables (emplacement qui contient plaine, nemesis qui contient foret et dirigeable qui contient desert). Et on peut faire la même chose que tout à l’heure avec ces trois variables : changer leur valeur et les tester.

Il est possible de créer des listes différentes avec des valeurs ayant le même nom :

LIST emplacement = foret, plaine, desert, ocean

LIST outil = tournevis, marteau, foret

VAR nemesis = foret

La troisième ligne va causer une erreur, car ink ne peut pas deviner s’il s’agit de la forêt définie dans la première liste ou du foret définie dans la deuxième liste. Pour résoudre cela, il faut préciser le nom que l’on a utilisé en créant la liste :

VAR nemesis = emplacement.foret

Ici, emplacement n’a pas de signification particulière. Il est simplement là pour indiquer à ink qu’il s’agit de l’emplacement foret, et non de l’outil foret. Si vous n’êtes par trop certain d’avoir compris, ou que vous voulez éviter ce genre d’ambiguïté, il vous suffit de ne pas utiliser de mots identiques pour les valeurs de listes.

Des listes comme des nombres

En vérité, l’ordre dans lequel on définit une liste est important. En effet, pour ink, les valeurs d’une liste sont équivalents à des nombres. Cela signifie qu’on peut les comparer comme des nombres ou les augmenter.

LIST jour = lundi, mardi, (mercredi), jeudi, vendredi, samedi, dimanche

-> routine

=== routine ===

Il est {jour}.

+  [attendre]

 { jour < dimanche:

 ~ jour++

 - else:

 ~ jour = lundi

 }

 -> routine

Cet exemple fait plusieurs choses :

Tout d’abord, on crée une liste pour les jours de la semaine, puis on dévie l’histoire.

Dans le nœud routine, on affiche d’abord le jour actuel (mercredi au début). Il va s’afficher en mot tel qu’on l’a défini. Voici un autre avantage par rapport à l’utilisation directe de nombres (1 pour lundi, 2 pour mardi, etc.).

C’est dans l’option que ça devient intéressant. Comme en interne ink considère les éléments d’une liste comme des nombres, on peut les comparer. Si jour est « inférieur » à dimanche (c’est-à-dire s’il est avant dimanche), alors on « incrémente » jour (on passe au jour suivant). Sinon, on revient à lundi. Attention, il faut avoir la condition, car incrémenter une liste quand on est à sa fin (dimanche ici) ne la fera pas revenir au début.

Il est bon de savoir qu’on peut si on le souhaite augmenter le jour d’un autre autre nombre pour faire avancer le temps plus vite (~ jour += 3) ou effectuer une soustraction pour remonter le temps.

Enfin, il est possible de convertir des valeurs en nombre et vice-versa.

Pour le premier, il faut utiliser la fonction LIST_VALUE, fournie par ink :

Nous somme le jour {LIST_VALUE(jeudi)}

Affichera « Nous sommes le jour 4 » (les listes commencent à 1). Cela peut parfois être utile, par exemple pour indiquer combien de jours il reste à la semaine :

Il reste {LIST_VALUE(dimanche) - LIST_VALUE(jour)} jours à la semaine.

Pour l’inverse, il faut utiliser le nom de la liste comme s’il s’agissait d’une fonction :

Le jour 3 est {jour(3)} // Ce sera mercredi.

Cela peut servir lorsque l’on veut faire des calculs compliqués, puis les convertir en une certaine valeur.

La fin ?

Il y a beaucoup de matière à appréhender dans cet article. La morale ici, c’est que les listes permettent d’avoir des variables pouvant prendre un certain nombre de valeurs nommées (que l’on pourra afficher et manipuler facilement), plutôt que d’utiliser des nombres ou des textes arbitraires.

Comme d’habitude, le mieux est d’expérimenter ! Si vous voyez que des variables simples comme des nombres ne suffisent pas à modéliser votre récit, alors il se peut que vous ayez besoin des listes.

Et c’est loin d’être la fin ! Les listes sont bien plus puissantes qu’elle ne le paraissent, mais ce sera pour un prochain tutoriel. Ce sera aussi plus compliqué, alors préparez-vous !

Personnaliser l’apparence de son histoire ink

Nathanaël Marion

Alors que je me reposais pendant les vacances, de nouvelles versions d’ink et d’Inky sont sorties. Parmi les nouveautés, une façon plus facile de personnaliser l’apparence de son histoire quand on l’exporte vers une page web.

Assurez-vous donc de télécharger la dernière version d’Inky (0.10 au moment de l’écriture de l’article) avant de continuer !

Avant de commencer, un petit mot pour ceux qui se débrouillent en HTML/CSS/JavaScript ou qui utilisent ink dans un autre moteur de jeu comme Unity : ce qui sera décrit ici n’est valable que pour l’exportation web de base d’Inky. Si vous utilisez votre propre HTML et JavaScript, alors modifier l’apparence se fera sans doute différemment en fonction de votre code. Cela va de même pour ceux qui utilisent Unity ou un autre moteur.

Une nouvelle notion : les étiquettes

Les étiquettes (« tags » en anglais) sont des informations que l’histoire donne au logiciel qui l’affiche (ici, notre page web) pour qu’il puisse effectuer quelque chose de spécial qu’on ne peut pas contrôler avec ink ; l’apparence, par exemple. Elles ne seront pas visibles par le joueur.

Une étiquette est indiquée avec le symbole #. On peut l’écrire à la fin de la ligne qui la concerne, ou juste au-dessus.

Cette ligne n'est pas étiquetée.

# une étiquette # une seconde étiquette

# une troisième

Cette ligne l'est. # une quatrième étiquette # et une cinquième

Cette ligne n'est pas étiquetée non plus.

Dans l’exemple ci-dessus, la seule ligne ayant des étiquettes — et elle les a toutes ici — est celle du milieu (si on ne compte pas lesdites étiquettes). Comme nous pouvons le voir, il est possible d’en mettre plusieurs pour un même paragraphe en les écrivant les unes après les autres, ou sur plusieurs lignes si on les place avant le contenu.

Si nous testons notre projet dans Inky, nous pouvons voir les étiquettes dans le panneau de droite au fur et à mesure de l’histoire, afin de nous assurer que tout fonctionne. Mais n’oubliez pas, elle ne seront pas visibles par le joueur !

Tout cela est bien beau, mais comme les étiquettes ne sont pas utilisables par ink directement, cela ne sert pour l’instant pas à grand-chose ! Heureusement pour nous, la page web exportée par Inky gère par défaut plusieurs étiquettes.

Le titre et l’auteur de l’histoire

Deux étiquettes peuvent être placées au tout début de l’histoire pour spécifier son titre et qui l’a écrite (vous !).

# title: Ma génialissime histoire

# author: Nathanaël Marion

La seule chose requise ici, c’est de commencer les étiquettes par title: et author:, et de les placer au tout début du fichier. N’oubliez pas de remplacer mon nom par le vôtre ! 😉

Une fois que c’est fait, allons dans le menu File > Export for web..., choisissons une destination et le nom du dossier qui contiendra l’histoire. Il ne reste plus qu’à ouvrir le fichier index.html ainsi créé avec un navigateur. Le titre et votre nom apparaît ! Il y a un problème cependant : il y a un petit « by » en anglais…

Pour cette raison, il vaut peut-être finalement mieux ne pas spécifier l’auteur avec une étiquette et directement modifier le fichier HTML. Supprimons l’étiquette, ouvrons donc encore une fois index.html, mais cette fois avec un éditeur de texte (Bloc-notes sur Windows ou TextEdit sur macOS peuvent faire l’affaire) et localisons la ligne suivante :

<h2 class="byline"></h2>

Ajoutons-y le nom pour qu’elle ressemble à ceci :

<h2 class="byline">par Nathanaël Marion</h2>

Il est aussi possible d’à la place modifier la ligne byline.innerHTML = "by "+splitTag.val; dans main.js pour remplacer le « by » par un « par ». Comme cela, on pourra garder l’étiquette author:, qui fonctionnera comme il faut. Simplement, modifier le JavaScript est (un tout petit peu) plus risqué si jamais on y ajoute par inadvertance des erreurs. À vous de choisir l’une ou l’autre des méthodes !

Nous avons à présent modifié un fichier provenant de l’exportation web. À cause de cela, il ne faut plus utiliser l’exportation web, car Inky remplacerait le fichier que nous venons de changer par celui par défaut ! Quand nous effectuerons une modification dans l’histoire, il faudra à la place utiliser l’option Export story.js only..., laisser le nom du fichier proposé et le sauver dans le dossier contenant l’exportation web (avec index.html et les autres). On confirme qu’il faut remplacer l’ancien et le tour et joué : nous avons mis à jour l’histoire sans toucher aux fichiers chargés de la présentation. C’est cela que nous devrons faire pour le reste de l’article.

Et n’oubliez pas, Inky ne prend pas en compte les étiquettes. Il faut exporter l’histoire et l’ouvrir dans un navigateur pour voir les effets décrits dans ce tutoriel !

Avoir un thème ténébreux (sombre)

Si le fond blanc par défaut de l’histoire vous fait mal aux yeux, il est possible d’utiliser un thème sombre. Il suffit d’ajouter cela au début, juste après l’étiquette du titre :

# theme: dark

Vous n’avez qu’à essayer pour voir. (N’oubliez pas, il faut utiliser Export story.js only... !) C’est tout ce qu’il y a à savoir ici. Nous verrons plus tard comment modifier plus finement les couleurs avec un peu de CSS.

Contrôler le flot du texte

Il est possible de vider l’écran du texte qui y a été affiché précédemment. Cela est très pratique lorsque l’on change de chapitre, par exemple. L’étiquette à utiliser est # CLEAR.

Chapitre 1 :

Tout avait commencé ainsi…

*  Ce livre est ennuyeux et vous sautez un chapitre.

# CLEAR

Chapitre 2 :

Et ce fut la fin.

Il faut faire attention : si l’on efface l’écran entre deux lignes, la première ne s’affichera jamais car elle sera effacée au moment même où elle sera montrée !

Ne faites donc

# CLEAR

pas cela !

Le mieux est d’effacer l’écran après un choix.

Il est aussi possible de réinitialiser l’histoire pour que le joueur puisse recommencer. Il faut cette fois-ci utiliser # RESTART :

Et ce fut la fin.

Voulez-vous relire l'histoire ?

*  Oui

 # RESTART

 -> END

*  Non

 Et ce fut véritablement la fin !

La même remarque que plus haut s’applique : le texte qui sera affiché après le # RESTART ne s’affichera jamais puisque l’histoire aura recommencé avant de l’atteindre. Il convient de tout de même écrire un -> END après l’étiquette pour qu’Inky ne se plaigne pas qu’il y a un bout de l’histoire sans véritable fin.

Pour finir cette section, un petit effet absolument totalement inutile, mais amusant : si on fait recommencer l’histoire dès le début, avant le premier choix, alors quand elle aura redémarré, elle atteindra d’emblée l’endroit où elle se réinitialise, ce qui la fera recommencer, ce qui… Oui, il en faut peu pour m’amuser.

Des images

Tout d’abord, allez chercher des images, n’importe lesquelles, sinon vous ne pourrez pas tester. Mettez-les dans le dossier contenant votre histoire exportée (celui qui contient index.html).

Pour afficher une image avec Inky, il faut écrire # IMAGE: monimage.png, où monimage.png doit être remplacé par le nom d’une des images que vous êtes allé chercher au paragraphe précédent.

Et alors, un énorme dragon cracheur de feu apparut !

# IMAGE: mechant-dragon.png

Passionnant. Vous tournez la page.

Il est possible de ranger les images dans un dossier à la place. Il faudra alors écrire (par exemple) # IMAGE: images/mechant-dragon.png, où le dossier images serait placé dans celui contenant l’histoire exportée. On peut bien sûr aller encore plus loin si on le souhaite et créer un dossier dragon dans le dossier images. On aurait alors # IMAGE: images/dragon/mechant-dragon.png, et ainsi de suite.

Modifier l’apparence de façon arbitraire

Alors là, nous allons mettre les mains dans le cambouis. Il est possible, en écrivant du CSS, de modifier l’apparence d’à peu près n’importe quoi dans l’histoire. Tout d’abord, il faut dire à ink de quel paragraphe nous souhaitons modifier l’apparence. Il faut pour cela utiliser l’étiquette # CLASS: suivi d’un mot tout en minuscules et ne contenant que des lettres, des chiffres et des traits d’union (pas d’espaces, notamment).

Cette ligne est normale et triste.

Mais cette ligne voit la vie en rose ! # CLASS: texte-joyeux

Et celle-ci ne voit rien.

La deuxième ligne possède maintenant un petit nom : texte-joyeux. Pour colorer texte-joyeux, il va falloir écrire du CSS. Ouvrons donc le fichier style.css, toujours à côté d’index.html. Ne nous préoccupons pas du contenu déjà présent. Allons à la fin et ajoutons ceci :

.texte-joyeux {

 color: pink;

}

Et si nous testons, nous verrons que la deuxième ligne voit véritablement la vie en rose.

Décortiquons ce que nous venons de faire. Tout d’abord, nous avons écrit le nom que nous avions utilisé dans l’étiquette, mais précédé d’un point. Nous avons ensuite ouvert une accolade et écrit le nom d’une propriété CSS (ici color), un deux-point, la valeur de la propriété (ici pink) et un point-virgule ; on peut écrire plusieurs propriétés si on le souhaite, puis on n’oublie pas de refermer l’accolade.

À partir de là, le merveilleux monde du CSS est à notre portée. Pour ne pas vous y perdre, prenez le temps de lire n’importe quel tutoriel de CSS. Tiens, par exemple, celui-ci et celui-là, provenant d’un site que vous devez connaître. Ça s’applique à Twine, mais à part les sélecteurs (pour nous, .texte-joyeux), le reste est le même. Vous aurez un petit aperçu des propriétés utilisables.

Il est également possible de modifier l’apparence par défaut du texte.

Pour modifier le titre principal et le nom de l’auteur, il faut utiliser h1 et h2, respectivement (sans point avant) :

h1 {

 color: red;

}

h2 {

 color: blue;

}

Vous pouvez soit modifier le CSS concernant ces deux éléments qui est déjà présent dans le fichier style.css, ou juste ajouter les règles ci-dessus à la fin du fichier CSS.

Pour modifier le texte normal, il faut utiliser p, et pour les choix, a. Par exemple :

p {

 font-size: 50px;

}

a {

 font-style: italic;

}

Bien sûr, mes exemples feront très moches. Le mieux est de savoir ce que l’on veut changer et de chercher la propriété CSS qui correspond. Prenez votre temps, lisez donc les deux tutoriels mentionnés plus haut, et n’hésitez pas à écrire un commentaire s’il y a quelque chose que vous n’arrivez pas.

Enfin, sachez qu’il est possible d’écrire directement de l’HTML dans l’histoire ink. Si l’on voulait rendre un seul mot joyeux plutôt que tout un paragraphe, il aurait été possible d’écrire :

Il y a <span class="texte-joyeux">deux mots</span> joyeux dans cette phrase !

Le CSS est le même que quand il s’agissait de tout le paragraphe. Et là, tout le monde de l’HTML s’ouvre à nous ! Mais ce sera sûrement pour une prochaine fois. Alors amusez-vous bien à apprendre du CSS pour l’instant !

Pour terminer cet article qui est déjà bien assez long, sachez qu’Inky propose un style par défaut pour le texte qui indique la fin de l’histoire. Il suffit d’utiliser le nom end :

Et c'est la fin ! Pour de vrai cette fois. # CLASS: end