lundi 27 septembre 2010

16 - Inventaire du Marchand - Achat d'Objets

Une fois que le marchand a fini son bavardage, il dévoile au Héros la liste des objets qu'il met en vente.
Le marchand propose un objet de chaque type : Une armure, un bandeau, une épée, un bouclier, un anneau, une paire de bottes, un morceau de viande, une potion, et un parchemin permettant d'apprendre un sort optionnel.

La puissance de chacun des équipements est tirée au sort entre deux valeurs ; cette fourchette de valeurs dépend de l'étage actuel, comme c'était le cas pour les trésors, mis à part qu'ici le maximum possède une valeur moindre : Ainsi une Épée trouvée dans un trésor à l'étage -18 donnera entre +12 et +22 Attaque, alorsqu'une Épée vendue par un marchand à ce même étage donnera seulement entre +12 et +16 Attaque.
En outre, si la puissance tirée au sort n'est multiple ni de 3, ni de 4, ni de 5, alors elle est diminuée de 1 jusqu'à ce qu'elle soit multiple d'au moins un de ces trois nombres.

La nature des deux objets de soin est déterminée par tirage au sort de la même manière que lorsqu'on les trouve dans des bourses : En fonction de l'étage, le pourcentage d'obtention de chaque type d'objet est différent (par exemple à l'étage -56 il y a 80% de chances de trouver une Viande+50 et 20% de chances de trouver une Viande+200).

Le parchemin de sort, pour finir, est lié lui aussi à l'étage actuel : Entre les étages 10 et 99 le marchand proposera le sort "Provoke" (provoquer), entre les étages 100 et 999 il proposera le sort "EnemHeal" (soin ennemi), etc.

Une fois la nature des objets vendus déterminée, il faut définir leur prix de vente. Pour les objets de type consommable et parchemin, ce prix est fixe ; en revanche pour les équipements, je dois prendre en compte le prix de revente de l'ancien équipement :
  • Pour les armures, le prix de vente est égal au bonus de PV ;
  • Pour les bandeaux, le prix de vente est égal au bonus de PM x 12 ;
  • Pour les autres pièces d'équipement, le prix de vente est égal au bonus de stat x 10 ;
  • Le marchand rachète le vieil équipement du Héros 1/4 de son prix de vente (arrondi en dessous).
Le prix de vente réel est donc égal au prix de vente moins le prix de rachat du vieil équipement ; ce prix ne peut pas être inférieur à 1 pièce d'or (si c'est le cas, je lui impose de prendre la valeur 1).

Exemple : Le marchand vend une armure +112 PV (prix de vente : 112 pièces d'or) ; Le Héros porte une armure +98 PV (prix neuf : 97 pièces d'or, prix de revente : 24 pièces d'or) ; le prix annoncé par le marchand ne sera donc pas 112 mais 112-24=88 pièces d'or.


Maintenant que je connais l'inventaire du marchand, je dois le communiquer au joueur ; pour ce faire j'ai créé un Clip appelé "cadre_shop" qui rassemble les diverses icones des objets vendus et possède plusieurs textes dynamiques (pour afficher les stats et les prix des objets vendus). Les objets susceptibles d'intéresser le Héros ont leur prix indiqué en bleu, les objets ayant des stats inférieures aux stats actuelles ont leur prix indiqué en rouge.

Je retire certains objets de la vente :
  • Les objets qui sont identiques à ceux déjà équipés par le Héros ;
  • Les objets de soin que le Héros possède déjà en 9 exemplaires ;
  • Les parchemins de sorts que le Héros a déjà appris.
Ces objets sont recouverts par un Clip portant la mention "Sold Out" et leur achat est impossible.


L'étape suivante consiste à permettre au joueur de sélectionner un objet et de l'acheter : J'ai créé un Clip représentant le curseur de sélection (4 triangles roses qui clignotent) et j'ai fait en sorte qu'on puisse le faire se déplacer d'une icone à une autre par simple pression sur une des 4 directions ; un fois l'objet choisi, une pression sur la touche "Entrée" permet de valider l'achat (à condition que le Héros possède suffisamment d'argent) : l'inventaire est alors modifié en conséquence, une sauvegarde automatique est effectuée, et l'affichage des objets vendus est actualisé (ajout d'étiquettes Sold Out si nécessaire).


Une fois la création du marchand terminée, j'ai procédé à quelques réglages afin que les joueurs ne deviennent pas trop riches trop rapidement : J'ai ainsi divisé par 2 les sommes trouvées dans les trésors, et grandement augmenté le prix des objets de soin. Mais il se peut que je modifie une nouvelle fois ces valeurs (dans un sens ou dans l'autre) une fois les combats contre les monstres implémentés...

samedi 25 septembre 2010

15 - Dialogue avec un PNJ

En dehors des trésors et des ennemis, il existe autre chose que le Héros peut trouver dans le Donjon : Des PNJ (Personnages Non Joueurs).

À l'origine je pensais utiliser différents types de PNJ :
  • Des marchands auprès de qui le Héros peut améliorer son équipement et s'approvisionner en objets de soin ;
  • Des vieux sages qui donnent des conseils quant à la bonne utilisation des différents sorts ;
  • Des aventuriers qui donnent des conseils sur la façon de battre les monstres.
Mais après réflexion, j'ai décidé de tout regrouper en un seul et même PNJ : Le marchand.


Quand le Héros entre en contact avec un marchand, il y a d'abord une phase de dialogue avant que le joueur ait accès à la liste des objets vendus ; pour chaque environnement du jeu, il existe 3 dialogues différents : En général il y a un message concernant le sort qui vient d'être appris lors du dernier Level Up, un message concernant le sort qui peut être acheté auprès du marchand, et le troisième concerne l'aventure au sens large (textes d'ambiance renforçant le background, mécaniques du jeu). Un tirage au sort détermine quel texte sera affiché.

Comme le marchand ne peut pas être rencontré dans la première zone, cela fait donc 18 textes au total, que j'avais rédigé un jour avant de me lancer dans la programmation ; je les ai donc intégré au jeu, en tenant compte des limitations de la fenêtre de texte : Celle-ci affiche en effet 6 lignes de 20 caractères, soit 120 caractères en tout (moins qu'un tweet !).

Il m'a donc fallu découper ces textes sur plusieurs pages, et reformuler certaines phrases pour qu'elles rentrent dans la fenêtre ; j'ai aussi mis certains mots-clé en avant en utilisant mes 2 variables "bleu" et "blanc". Au final, il y a donc pas mal de différences entre les textes d'origine et ceux qui seront visibles au cours du jeu.

jeudi 23 septembre 2010

14 - Level Up après ouverture d'un coffre

Comme je l'ai dit dans mon billet précédent, le score du Héros augmente de 1 chaque fois qu'il s'empare du trésor situé à l'extrême gauche de l'étage.
Si le score du Héros dépasse un certain seuil, son niveau augmente et il apprend un nouveau sort :

mardi 21 septembre 2010

13 - Sauvegarde Automatique - Changement d'Étage

Souvenez-vous : Il y a quelques semaines, lorsque je me suis lancé dans la programmation de ce jeu, ma première action a consisté à mettre au point les fichiers de sauvegarde.
Maintenant que les stats et l'inventaire du Héros peuvent être modifiés grâce aux trésors, il est temps que je mette à profit l'existence de ces fichiers afin de garder une trace de toutes ces modifications.
J'ai donc créé une fonction "autoSave" qui est appelée à chaque fois que le Héros ramasse un trésor et qui garde en mémoire la majorité des variables du jeu (stats, inventaire, High Score... ).

Je me suis ensuite occupé du changement d'étage : Quand le Héros s'empare du contenu du coffre situé à l'extrême gauche de l'étage, son score augmente de 1 et il est téléporté à l'entrée de l'étage suivant ; si son nouveau score est supérieur au High Score, je met ce dernier à jour et effectue une sauvegarde automatique.

lundi 20 septembre 2010

12 - Fenêtres de Textes - Modification de l'Inventaire - Choix

Une fois que le contenu du trésor a été tiré au sort, il faut transmettre cette information au joueur ; pour ce faire, j'utilise une fenêtre de texte au design une fois de plus rétro (texte blanc sur fond noir, cadre blanc pixelisé). À l'intérieur du Clip "fenêtre de texte" se trouve un objet "Texte dynamique", c'est à dire un texte que je peux modifier en fonction du message que je souhaite afficher.

Au moment d'effectuer mes recherches graphiques, j'ai opté pour une typo pixelisée appelée "Small Fonts" ; le problème c'est que cette typo est au format .fon, alors que SWISH Max utilise le format .ttf : J'ai donc dû chercher une typo TrueType qui, une fois l'option "police pixelisée" activée, ressemblerait suffisamment à "Small Fonts". Et fort heureusement parmi toutes les polices installées sur mon ordi il y en a une qui répond à ce critère : "Franklin Gothic Medium". La seule différence notable est la présence d'une barre sous le 1.

J'ai donc utilisé cette typo pour l'affichage des stats. Et je comptais bien l'utiliser aussi pour afficher les divers messages du jeu, sauf que...


Il est possible d'intégrer des balises HTML au sein d'un objet "texte dynamique" en activant l'option adéquate. Cela permet de modifier l'apparence de certains éléments du texte (mots en gras, en italique, soulignés, changement de taille ou de couleur), et de mettre ainsi certains mots en avant.
Il se trouve que j'ai justement envie que, lorsque le joueur reçoit le message "Vous avez trouvé une Épée +50 ATT, voulez-vous l'équiper ?", l'expression "Épée +50 ATT" ne soit pas écrite en blanc mais en bleu.

Le changement de couleur se fait à l'aide de la balise <font color ="#B0BCF9"></font>, sauf que je ne peux pas utiliser de guillemets tels quels car ils servent à marquer le début et la fin d'une chaîne de caractères ; je suis donc obligé d'utiliser le code ASCII du caractère guillemet à la place : chr(34).

message = "Le début est en blanc <font color=" add chr(34) add "#B0BCF9" add chr(34) add ">puis en bleu</font> et de nouveau en blanc !";
monTexteDynamique.text = message;

edit : suite à une remarque judicieuse de Fitz (voir les commentaires), j'ai découvert une autre façon d'intégrer des guillemets à ma chaîne sans pour autant passer par le code ASCII : Il me suffit juste de marquer le début et la fin de la chaîne avec des apostrophes et non des guillemets !
Le code ci-dessus aurait en fait pu être remplacé par :
message = 'Le début est en blanc <font color="#B0BCF9">puis en bleu</font> et de nouveau en blanc !';
monTexteDynamique.text = message;


Pour me simplifier la vie, je me suis créé une variable "bleu" et une variable "blanc" qui me permettent de changer de couleur facilement ; la variable "bleu" correspond en fait à la balise d'ouverture <font color ="#B0BCF9"> tandis que la variable "blanc" correspond à la balise de fermeture </font> :

bleu = "<font color=" add chr(34) add "#B0BCF9" add chr(34) add ">";
blanc = "</font>";
message = "Le début est en blanc " add bleu add "puis en bleu" add blanc add " et de nouveau en blanc !";
monTexteDynamique.text = message;

Le problème, c'est que l'activation des balises HTML a pour conséquence la désactivation de l'option "typo pixelisée" : Mon texte est certes multicolore, mais devient par la même occasion tout lisse !

J'ai donc dû me mettre en quête d'une typo qui soit pixelisée d'origine afin de pouvoir utiliser les balises HTML sans risque de lissage. Et mon choix s'est porté sur Apple ][ (une typo gratuite créée par Ivan Rood), même si l'espacement entre les caractères est plus important ; j'apprécie le fait que chaque caractère occupe un espace de taille identique, ça fait encore plus "vieux jeu 8-bits".

J'ai donc ma fenêtre de texte et ma typo, il me suffit juste d'afficher tout ça au moment adéquat et de modifier mon texte dynamique en fonction du message que je souhaite afficher ; cela donne à peu près ceci :

Une simple pression sur "Entrée" ferme la fenêtre de texte et permet au jeu de reprendre son cours.

Évidemment ce n'est pas tout de dire qu'une Potion+30 a été trouvée : Il faut aussi que l'inventaire soit modifié en conséquence, et que l'affichage soit actualisé pour témoigner de cette modification (ce qui est le cas sur le screen ci-dessus).


Pour les objets que le Héros peut équiper, les choses sont légèrement différentes : Le joueur a le choix entre équiper l'objet trouvé et jeter l'ancien, ou garder l'ancien et jeter le nouveau.
Ce choix s'effectue via un curseur qui se déplace lorsqu'on appuie sur les touches "Gauche" ou "Droite" et qui sélectionne deux cadres ("Yes" et "No") ; par défaut le curseur pointe sur la réponse qui privilégie le bonus de stat le plus important : Si le Héros ramasse une Épée +10 alors qu'il a une Épée +30, c'est la réponse "No" qui sera sélectionnée dès le départ.

Dans l'exemple de la capture d'écran ci-dessus, si le joueur appuie sur "Entrée", la stat "Attaque" (représentée par l'icone Épée) passera de 8 à 9 et l'Épée +8 sera jetée : Le coût en pièces d'or de cette Épée jetée sera ajoutée au "Junk" (l'icone Poubelle en haut à droite du cadre ITEMS) ; le Héros pourra par la suite convertir son Junk en pièces d'or s'il rencontre un marchand qui lui rachète ses objets inutiles.