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 !