|
|||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Sur Amiga, les menus de triche ("trainer") étaient essentiellement un menu enjolivé par un effet et une musique, qui permettait d'activer des options pour tricher dans un jeu : "Vies illimitées: On/Off", et ainsi de suite. Dans bien des cas, les triches ont pu être le seul moyen de parvenir à profiter totalement d'un jeu sans y passer trop de temps, vu la difficulté. Ne termine pas Shadow Of The Beast qui veut... Dans la continuité d'un programme d'hommages aux différentes figures de la scène, voici Scoopex "THREE", un menu de triche produit pour le fameux StingRay du glorieux groupe Scoopex. Après Scoopex "TWO" rendant hommage aux graphistes, un hommage aux déplombeurs, donc. Comme on pourra le constater, l'originalité a pris ici le pas sur la technique. Du moins en apparence, car en matière de programmation du matériel en assembleur sur Amiga, tout devient finalement assez technique rapidement ! Code, données et explications dans tout ce qui suit...
Cliquez ici pour télécharger l'archive contenant le code et les données du menu de triche. Précisons d'emblée deux choses pour éviter les déceptions :
Depuis le jour où j'ai fait la découverte émerveillée d'Ultima III: Exodus sur l'affichage CGA d'un PC1512, je voue une admiration sans bornes à Richard Garriott, dit "Lord British". Inutile de dire que cette admiration s'est renforcée avec la découverte, cette fois sur Amiga, de Ultima IV: Quest Of The Avatar puis de Ultima V: Warriors Of Destiny. Je ne peux contempler les cartes en tissus de ces jeux - oui, je ne suis pas un pirate : j'ai les originaux, môssieur ! - sans écraser une larme en souvenir des heures joyeuses passées à explorer les recoins de Britannia. C'est dire. Il m'a toujours semblé que le potentiel de ces jeux a été sous-estimé, tout particulièrement le quatrième opus. Enfin diable ! Ne présentait-il pas un caractère unique du fait qu'il contraignait le joueur à se plier à une éthique pour gagner ? Par la suite, je n'ai pas rencontré de jeux conçus de la sorte, et j'ai toujours pensé qu'un jour, le jeu vidéo en général trouverait son utilisation en tant qu'outil de propagande. D'ailleurs, j'avais développé ce propos dans un papier programmatique intitulé "Le jeu vidéo au service de la communication", dans lequel il faudrait que je me replonge. Ceci étant, c'était en 2001, avant que l'histoire ne montre que les réseaux sociaux constituent un vecteur bien plus facile à utiliser... Mais revenons à nos moutons. De toute cette série, c'est Ultima V qui a toujours eu ma préférence. Cela tient non seulement à la richesse du scénario élaboré par Richard Garriott, mais aussi à la beauté des graphismes produits par Denis Loubet et de Doug Wike : ![]() Ultima V sur Amiga Tout cela pour dire qu'il fallait rendre hommage à Ultima V avant de passer outre. Or, j'échange un jour avec le fameux StingRay du glorieux groupe Scoopex, et voici qu'il me propose de réaliser un menu de triche. Pour ceux qui l'ignorent, StingRay est l'un de ces brillants codeurs qui contribuent à la préservation du patrimoine de l'Amiga en reprenant méthodiquement les jeux pour en produire des versions qui peuvent être exécutées depuis un disque dur avec WHDLoad, avec menu de triche quand ils en étaient jusqu'alors dépourvus. Par exemple, Ultima V, pas plus tard qu'en avril 2018. Il faut disposer de l'original. Je cogite un instant, et il me vient l'idée d'un menu de triche pour le moins original, puisqu'il consisterait à doubler l'inévitable menu non pas d'un effet, mais de toute une animation à base de tuiles d'Ultima V. Il s'agirait de suivre un joueur qui se baladerait gentiment, avant que des streums lui tombent dessus. Là-dessus, il se ferait défoncer grave la gueule, et implorerait pitié pour être trainé par StingRay. Bam ! Il hériterait de la totale, et vêtu des pieds à la tête d'un matos de ouf, il mettrait une rouste aux affreux. C'est le pitch. L'idée plaît à StingRay pour son originalité, et je me lance dans la réalisation, avec d'autant plus d'intérêt que j'étais en train de développer un jeu à la Ultima à base de JavaScript et de WebGL - que je finirai bien par terminer un jour ? Du moins ce menu de triche m'aura-t-il déjà donné l'occasion de programmer tout un éditeur de cartes à base de tuiles, comme on le verra plus loin. Le menu Sur la base de l'expression des besoins de StingRay, le menu de triche peut proposer au joueur deux types de paramètres en pagaïe :
La petite difficulté était de permettre à StingRay de facilement rédiger le contenu des pages du menu. Le mieux était d'être aussi WYSIWYG que possible, et donc de lui permettre d'entrelacer des lignes de texte, des lignes de paramètres, mais aussi des lignes permettant de naviguer dans le menu : aller à l'éventuelle page précédente, à l'éventuelle page suivante, quitter le menu de triche. Pour cette raison, les lignes du menu sont déclarées dans les données sous la forme de structures :
Au démarrage du menu de triche, les données qui décrivent ainsi le menu se trouvent à l'adresse menuData. Elles sont interprétées par la routine _menuSetup, qui génère une représentation du menu facile à manipuler à l'adresse menuPages, sous la forme d'une suite de structures de données dans le détail de laquelle il est inutile de rentrer. En particulier, ces structures sont utilisées par la routine _menuPrintPage pour afficher le contenu d'une page. Une page du menu mobilise les plans de bits 5 et 6. Sur Amiga, le plan de bits 6 est particulier, car le bit 5 qu'il introduit dans le codage de l'indice de la couleur d'un pixel ne permet pas d'afficher ce pixel dans une couleur qui peut être contrôlée. Le matériel considère que les couleurs 32 à 63 sont nécessairement des versions "half-bright" - moitié moins lumineuses - des couleurs 00 à 31. Ce fonctionnement est idéal pour le menu, car cela permet de l'afficher sur un fond qui laisse entrevoir les plans de bits de la première scène cinématique ("cut scene") en semi-transparence sans avoir à intervenir dessus. ![]() Le menu gère les booléens et les entiers bornés (ou non) La souris De toutes les difficultés auxquelles le codeur du matériel de l'Amiga peut être confronté, la gestion de la souris est l'une des plus inattendues. C'est qu'autant il est simple de tester si le bouton gauche de la souris est pressé ou relâché - tester le bit 6 de $BFE001 -, autant il est ardu de tester la même chose pour le bouton droit. La lecture de cette section de l'Amiga Hardware Reference Manual permet de supposer que le bouton droit ne se gère pas comme le bouton gauche, car il n'est pas relié à une circuiterie du même genre : il est connecté à une broche analogique et non numérique. De fait, à la lecture de cette annexe, il apparaît que lire l'état du bouton droit sur cette broche ne consiste pas simplement tester un bit dans un registre. S'il est bien possible de tester le bit 10 (DATLY) de POTGOR, ce n'est qu'après avoir demandé au matériel de traiter la broche comme numérique. Pour cela, il faut écrire dans un autre registre, POTGO. D'où la séquence suivante :
L'annexe semble préciser qu'il faut en théorie attendre jusqu'à 300 ms entre les deux opérations. Toutefois, il n'apparaît pas que ce soit véritablement nécessaire. En tout cas, le code du menu de triche s'en dispense. Et pour suivre le mouvement de la souris ? Comme bien expliqué ici, déplacer la souris entraîne l'incrémentation d'un compteur quand elle est déplacée vers le haut, et la décrémentation du même compteur quand elle est déplacée vers le bas. Il s'agit d'un compteur 8 bits, dont la valeur peut être lue dans JOY0DAT quand la souris est branchée sur le port 1 - ce qui généralement le cas. Les précisions apportées ici permettent de comprendre qu'arrivé à saturation, le compteur reboucle. Le menu de triche en tient compte pour éviter de produire cet effet indésirable où le mouvement de la souris vers le bas est interprété comme un mouvement vers le haut, et inversement. Par exemple, suite à un mouvement vers le bas, le passage de -126 à -127 permettrait bien de détecter une variation de -1 du compteur, assimilée à un mouvement vers le bas en tant qu'elle est négative. Toutefois, au mouvement suivant toujours vers le bas, le passage de -127 à 0 du compteur conduirait à détecter une variation de +127, assimilée à un mouvement vers le haut, en tant que cette variation est positive. Dans le code du menu de triche, sachant que le compteur est lu à chaque trame - 1/50e de seconde -, et qu'un mouvement ne peut raisonnablement faire reboucler le compteur s'il démarre à 0, le compteur est réinitialisé à 0 à chaque fois qu'il est lu. Par ailleurs, un mouvement n'est détecté que si le compteur dépasse le seuil MENU_MOUSESENSITIVITY - qui en pratique est fixé au minimum. La réinitialisation s'effectue en écrivant dans un autre registre, JOY0TEST :
Il peut paraître curieux d'ignorer les deux bits de poids faible du compteur, car cela apparaît comme une perte de précision. C'est que comme expliqué ici, ces deux bits ont un comportement très particulier pour permettre de lire dans JOY0DAT aussi bien l'amplitude d'un mouvement de la souris, que la direction d'une poussée sur une manette. Par conséquent, le mieux est de les ignorer. Cliquez ici pour récupérer le code minimal permettant de prendre le contrôle du matériel pour afficher un écran sur un plan de bits, et exécuter une boucle qui teste la pression des boutons de la souris, les mouvements de cette dernière, et le relâchement d'une touche (Échap) pour quitter. Les scènes cinématiques ("cut scenes") Comme je l'ai mentionné, cela fait longtemps que j'essaie de produire un jeu à la Ultima en JavaScript et WebGL - mais "Je l'aurais un jour ! Je l'aurais !", c'est sûr. Ce projet personnel m'a donné l'occasion de développer pas mal d'outils - c'est d'ailleurs bien le problème, cette perpétuelle digression... -, et d'acquérir une très bonne connaissance de JavaScript et de certaines des API du navigateur, dont WebGL et Canvas. Partant, je savais que si je me lançais dans le développement d'un éditeur de Scènes cinématiques pour le menu de triche, je n'aurais aucune difficulté pour le terminer rapidement. Or, composer le décor et décrire l'animation d'une scène cinématique à l'aide de codes dans un éditeur de texte allait assurément vite se révéler d'autant plus fastidieux, que je n'étais pas du tout certain de la scène à créer, si bien qu'il faudrait très probablement me livrer à de nombreuses retouches. Bref, disposer d'un éditeur m'est vite apparu essentiel pour travailler confortablement. J'ai donc produit cela : Ce gentil petit éditeur permet de créer facilement une scène cinématique. A la base, il charge un fichier JSON - oubliez XML pour toujours -, qui contient simplement un tableau repérant les tuiles dans le fichier PNG qui les regroupe. Un exemple d'entrée :
Ce tableau permet de mettre à disposition les tuiles à déposer à la souris dans chaque trame de la scène. Pour simplifier la vie, l'éditeur est notamment doté des fonctionnalités suivantes :
Pour l'animation, il ne fallait pas chercher midi à quatorze heures : c'est du différentiel. Autrement dit, exception faite de la trame 0, une trame se réduit à la liste des tuiles qu'elle remplace dans la trame précédente. Cette technique permet de limiter la taille du fichier décrivant l'animation, mais aussi les opérations graphiques requises pour transformer une trame en la suivante. Par exemple, dans son format d'exportation DC.B, la trame 1 de la seconde scène se résume aux octets suivants :
Ce qui se lit ainsi. Il faut modifier deux tuiles :
La technique est économique, mais elle présente un inconvénient majeur lors de l'édition. En effet, une tuile n'est qu'une tuile, c'est-à-dire une instance d'une tuile d'une palette de tuiles, et non une instance d'une entité comme un personnage, un objet, ou un élément de décor, qui aurait une existence au-delà de la trame. Pour le dire autrement, une tuile est à une trame de la scène cinématique ce qu'un pixel est à une trame d'une animation : elle n'est rien de plus qu'une image, elle ne comporte aucune information autre que celle qu'il permet de l'afficher. Cela pose une difficulté particulière pour animer les entités que les tuiles représentent, car il n'y a aucun lien entre une instance de tuile dans une trame et l'entité qu'il représente - aucune information dans l'instance y renvoie. Par conséquent, il est impossible de dire automatiquement - c'est-à-dire dans le code - si une tuile en (x0, y0) dans la trame N représente la même entité qu'une tuile en (x1, y1) dans la trame N+1, voire en (x0, y0) dans cette trame. Quand bien même c'est un dragon qui est représenté aux deux positions dans les trames, comment affirmer que c'est le même dragon ? Partant, comment dire que l'image du dragon dans la trame N+1 doit être l'image de l'animation d'un dragon qui suit celle utilisée dans la trame N dans cette animation ? L'animation des tuiles ne pouvant être déduite de celle des entités qu'elles représentent, cela fait qu'à chaque trame, il faut modifier à la main la tuile représentant l'entité pour produire l'animation de l'entité en question. C'est assez lourd. De plus, si jamais une trame est supprimée ou insérée, il faut modifier à la main les tuiles représentant cette entité dans toutes les trames suivantes, sinon la continuité de l'animation de l'entité est rompue. Et cela, pour toutes les entités. Autant dire qu'il vaut mieux n'animer les entités entre les trames qu'à la fin, une fois que la liste des trames qui composent la scène est définitive. Il est clair qu'au regard de cette contrainte, créer les scènes par animation différentielle sans éditeur aurait été un pur cauchemar. Sur la manière dont une scène est jouée en assembleur, quelques précisions. Il n'y a pas de double tampon mémoire, pour deux raisons. Tout d'abord, il est pénible de gérer le double tampon mémoire quand il s'agit de jouer du différentiel : à chaque trame, il faut faire progresser la trame que contient le tampon courant de deux trames dans la scène et non d'une. Ensuite, ce n'est pas la modification de quelques tuiles qui va conduire à ce que le raster rattrape le processeur, produisant le scintillement que le double tampon mémoire permet d'éviter, comme je l'ai expliqué ici. La seule partie un peu délicate du code, et sans doute la plus longue, est la routine _drawText, qui affiche le texte dans une bulle positionnée par rapport à un angle d'une tuile désigné dans les données de la trame, sur le modèle suivant :
Ce qui se lit ainsi : afficher une chaîne de 24 caractères - comprenant éventuellement des retours à la ligne - par rapport à un angle de la tuile (9, 14). L'angle, et la position de la bulle par rapport à cet angle, est 1. Il y a quatre valeurs possibles : ![]() Positionnement d'une bulle de texte par rapport à une tuile C'est ici que le code devient un peu subtil, car la bulle n'est pas dessinée dans les plans de bits. Elle est dessinée dans le plan de bits de sprites qui sont accolés pour former un super-sprite. Pourquoi ? Parce que c'est drôle, et parce que cela permet d'éviter d'avoir à gérer de la restauration. Pour ne pas s'emmerder outre-mesure, la bulle est tout de même dessinée dans des mini-plans de bits hors écran, et le contenu de ces mini-plans de bits est ensuite recopié, colonne de seize pixels par colonne de seize pixels, dans les plans de bits des sprites utilisés. Il aurait été beaucoup trop pénible que le code traçant le cadre, remplissant le fond et écrivant les caractères, fasse de sauts des plans de bits d'un sprite à ceux d'un autre sprite tous les seize pixels... Comme expliqué ici, le matériel de l'Amiga 500 peut afficher huit sprites en quatre couleurs, dont une transparente, d'une largeur de seize pixels et sur toute la hauteur de l'écran. Ainsi, la largeur maximale d'une bulle est de 16*8=128 pixels, ce qui fait quinze caractères en police 8x8 par ligne, quatre pixels étant réservés de part et d'autre pour le bord de la bulle. Cela suffit amplement pour les besoins du menu de triche : les personnages ne déclament pas du Dostoïevski. La bannière La bannière est affichée durant la seconde scène exclusivement. Y défilent quelques messages qui n'ont rien de subliminal - on ne me fera pas le même procès qu'au générique du journal de 20 heures sur Antenne 2 en son temps ! ![]() La bannière, et dump Trump the dumb !
...que la fin de l'animation de la bannière conduit à désactiver :
Les instructions précédentes tapent dans la liste Copper, où elles modifient la valeur qu'une instruction MOVE écrit dans le registre BPLCON0, lequel permet de notamment de contrôler le nombre de plans de bits affichés. Tout le code de gestion de la bannière a été factorisé pour resservir en d'autres occasions. Ainsi, il adopte un modèle avec lequel ceux qui ont lu le code de Scoopex "TWO" sont désormais familiers, à savoir :
La transition L'animation cyclique de carrés déphasés, c'est un peu une marque de fabrique. J'ai utilisé cet effet dans presque toutes mes cracktros à l'époque, non seulement parce que je trouvais cela élégant, mais aussi et surtout parce que je ne pouvais recourir aux services d'un graphiste. Quand on ne sait pas dessiner, mieux vaut faire simple : c'est toute ma théorie de la conception. Le menu de triche m'a donné l'occasion de recycler cet effet, que j'avais repris en 2016 quand je m'étais remis à programmer en assembleur le matériel de l'Amiga. L'idée était alors de produire un certain nombre d'effets, que j'assemblerai un jour dans une démo. Finalement, ils me servent petit à petit pour produire des productions plus modestes, mais des productions tout de même, comme ce menu de triche. Les cimetières sont plein de bien meilleurs codeurs qui seront ignorés à jamais, car ils n'ont jamais sorti quelque chose. Et du moins, ce code ne sera-t-il ainsi pas perdu pour tout le monde. L'effet est trivial. L'écran est découpé en carrés. Chaque carré est animé : en quelques images, ses dimensions se réduisent à presque rien. A chaque trame - ou plus selon la vitesse qu'on souhaite donner à l'effet -, l'animation de chaque carré progresse d'une image, rebouclant au début si besoin. L'astuce consiste à déphaser les animations des carrés, c'est-à-dire à les faire démarrer toujours à partir de la trame 0 - totalement vide -, mais à des instants différents. Cela permet de produire un motif général, comme ici où l'écran semble se gonfler et se dégonfler : ![]() Une animation cyclique de carrés déphasés Dans le menu de triche, l'effet permet de ménager une transition entre la fin de la seconde scène et sa reprise, histoire de marquer la fin : ![]() Une transition à la fin de la seconde scène Plus généralement, cet outil permet de générer ce type d'animation sur un certain nombre de plans de bits, et sous la forme de données RAW - les plans de bits d'une trame les uns après les autres -, ou RAWB - les plans de bits d'une trame entrelacés à chaque ligne. Les raisons d'être de ces formats ont été déjà été expliquées ici. Le motif produit par les animations déphasées des carrés a été élaboré dans un outil Excel, ici encore développé pour l'occasion. En associant une couleur à l'indice de la trame de départ de l'animation d'un carré, cet outil permet de se faire facilement une idée de ce que sera l'effet produit à l'échelle de l'écran : ![]() Conception des motifs du découpage dans Excel La condition d'arrêt de la transition est que tous les carrés soient opaques. Comme l'animation de chaque carré démarre avec ou sans retard sur celle de la transition, il est difficile de calculer à l'avance la durée totale de la transition, exprimée en trames. Elle dépend de nombreux paramètres. Le fichier cutter.s contient des commentaires qui donnent plus de détails sur l'algorithme et ce sujet. Tout comme le code de la bannière, celui de la transition a été factorisé pour resservir en d'autres occasions. Il est regroupé dans le fichier cutter.s :
La programmation d'un pilote du clavier sur Amiga n'est pas la chose la plus aisée. J'ai déjà exposé ici dans le détail comment s'y prendre pour simplement récupérer le code d'une touche pressée puis relâchée, non seulement par interruption, mais aussi par interrogation continuelle. Dans ce menu de triche, c'est la seconde solution qui est retenue. Le pilote gère les pressions suivies de relâchements des touches suivantes :
La raison, c'est que cela simplifie la gestion de la sortie de ces deux états de la scène. Plutôt que d'avoir à gérer un cas où il faut en sortir alors que ni la bannière ni la transition n'est en cours, un cas où la bannière est en cours, et un cas où la transition est en cours, il suffit de gérer le premier cas. C'est que sortir de la bannière ou de la transition implique une série d'opérations pour restaurer les plans de bits utilisés du menu en l'état. Mieux vaut s'épargner cette complication au prix d'une neutralisation du clavier que le joueur ne remarquera sans doute jamais, la bannière et la transition ne durant que peu de temps. Or, il ne suffit pas de ne plus appeler le pilote pour couper le clavier. En effet, chaque fois que le joueur presse et relâche une touche, le code de cette dernière s'accumule dans un tampon mémoire du matériel. Dès lors, lorsque le pilote est réactivé, il se met à gérer chaque touche dont le code se trouve dans le tampon mémoire. Cela peut produire cet effet particulièrement indésirable de prise en compte à retard de la pression suivie du relâchement d'une touche. Il faut donc vider ce tampon mémoire avant de réactiver le pilote. C'est le rôle de ce petit bout de code, factorisé dans une macro pour être répété facilement aux divers endroits où il s'avère nécessaire, c'est-à-dire durant l'animation de la bannière et la transition. En l'espèce :
La musique Suite à la publication d'une petite annonce sur Wanted pour trouver des comparses afin de produire ma série d'hommages, l'excellent JMD m'a contacté pour me proposer ses services de musicien. JMD est particulièrement versé dans l'art de la musique chip, comme chacun pourra le constater en écoutant quelques-unes de ses productions sur Bandcamp, ou plus exhaustivement AMP. D'ailleurs, quelle ne fut pas ma surprise de constater que dans la liste des jeux auxquels il a participé, on trouve Despot Dungeon, qui a toute l'apparence d'un jeu à la Ultima ! Grâce soit rendue à JMD, car je dois dire qu'il m'a composé un module aux petits oignons. Qu'on y songe : ce dernier comporte presque une dizaine de mélodies sur mesure, d'après les thèmes que je lui avais indiqués. Du travail de pro ! D'ailleurs, constatant la qualité du travail fourni, j'ai tout de suite regretté que le joueur ne puisse finalement qu'en écouter de brefs passages en regardant la scène cinématique. Comme le pilote du clavier était tout programmé, ne convenait-il pas de rajouter la possibilité de presser les touches numériques - pas celles du pavé, mais celles qui figurent au-dessus des caractères - pour écouter à volonté chacune des mélodies ? Aussitôt dit, aussitôt fait ! Il suffisait de rajouter quelques lignes. Le joueur est donc invité à presser les touches 1 à 8 pour écouter les divers morceaux dans leur intégralité. J'en profite pour saluer phx, toujours actif sur Amiga, pour la routine de lecture de modules ProTracker - retouchée à la marge par StingRay. On oublie toujours de le remercier, alors que sa routine doit être aussi utilisée dans les productions de la scène, que Forbid (). Frank Wille - car c'est lui - a donné cette entrevue en 2016. Elle permet de constater l'ampleur de sa contribution. Le texte défilant J'allais oublier le texte défilant ! Il serait dommage de ne pas l'évoquer, car il permet d'illustrer comment il est possible d'utiliser le Copper pour modifier la résolution de l'écran à n'importe quelle ligne de ce dernier. En effet, le texte défilant est en haute résolution (640x256) alors que tout le reste est en basse résolution (320x256). J'avais déjà programmé un texte défilant en haute résolution autrefois. En fait, il en apparaît un en bas de la première - si je me souviens bien - cracktro que j'ai produite : ![]() Texte défilant en haute résolution dans la cracktro de Flashback ![]() Changement de résolution dans la cracktro d'Ishar II
Les tableaux suivants permettent de s'y retrouver. Pour une amplitude de défilement donné, ils donnent la valeur des bits PFxH3-0 à écrire dans BPLCON1 et le décalage à écrire dans BPLxPTH/L, et de là la formule qui permet de trouver les valeurs des PFxH3-0 à partir de celle de l'amplitude : ![]()
La technique qui vient spontanément à l'esprit consiste à utiliser une bande dont la largeur est simplement accrue d'un caractère sur la droite. Dans cet exemple, l'écran fait trois caractères de large : ![]() Le fonctionnement du texte défilant en simple largeur Une meilleure solution consiste à utiliser une bande dont la largeur est accrue d'autant de caractères que la largeur de l'écran peut en afficher. Pour reprendre l'exemple précédent, la bande fait donc six caractères de large : ![]() Le fonctionnement du texte défilant en double largeur La combinaison du défilement matériel et de la bande de double largeur fait que dans le code du menu de triche, le bloc de mémoire utilisé pour afficher le texte défilant, scrollFrontBuffer, a une largeur de ((2*SCROLL_DX+16)>>3) octets, SCROLL_DX valant 640 pixels. La raison pour laquelle le défilement matériel nécessite seize pixels supplémentaires ne sera pas détaillée ici. C'est fort bien expliqué là, dans l'Amiga Hardware Reference Manual. Tout comme le code de la bannière et celui de la transition, celui de la transition a été factorisé pour resservir en d'autres occasions. Il est regroupé dans le fichier "scroll.s" :
La boucle principale A ce stade, il ne reste plus qu'à évoquer la boucle principale, tout particulièrement la manière dont les différentes parties du menu de triche s'enchaînent. La boucle est simplement une série de tests portant sur des drapeaux conservés dans un WORD à l'adresse mainState, qui reflète l'état dans lequel se trouve l'automate du programme à l'instant présent :
Lorsqu'une action doit provoquer un changer d'état de l'automate, elle efface et/ou positionne certains drapeaux. Par exemple, lorsque le menu est affiché - ce qui est l'état de démarrage -, les drapeaux STATE_CUTSCENE_RUNNING, STATE_KEYBOARD_RUNNING, STATE_MENU_RUNNING. Lors d'une itération de la boucle principale, chaque drapeau est testé et donne lieu à l'exécution d'un bout code associé. Ainsi, dans le cas précédent :
Somme toute, la structure de la boucle principale n'est qu'une imbrication de "switch". Une autre solution aurait été de créer une table de pointeurs de routines, et de limiter la boucle principale à des manipulations sur cette table, tout le code étant autrement factorisé dans les routines en question. Toutefois, sachant qu'il n'y avait somme toute que peu de code, j'ai préféré ne pas pousser jusque-là. Et voilà ! Non compressé, le menu de triche pèse 91 852 ko. C'est énorme pour un menu de triche. Fort heureusement, un problème de ce type peut être géré sur Amiga grâce à un "cruncher", c'est-à-dire un programme qui peut en compresser un autre, produisant un exécutable contenant tout ce qu'il faut pour décompresser cette version compressée une fois qu'elle a été chargée en mémoire. En l'espèce, c'est l'excellent Crunch-Mania qui a été retenu, étant aussi élégant qu'efficace. Ce compresseur s'est plié en quatre, ou plutôt il est parvenu à plier en quatre le menu de triche, produisant un exécutable de seulement... 26 416 ko ! Sans doute, cela reste très conséquent pour un menu de triche, mais cela permet de l'utiliser pour de nombreux jeux qui n'occupent pas l'intégralité des 880 ko d'une disquette. ![]() Crunch-Mania pour pliant le menu de triche en quatre A bientôt pour la prochaine ? Ce devrait être un hommage aux administrateurs système sous la forme d'une BBS-intro pour le groupe Desire. Je dois bien cela à Ramon B5 pour m'avoir sauvé la mise sur Scoopex "TWO". Et le lot de tuiles ? Pour recréer le lot de tuiles, par exemple à partir de celui d'Ultima V que vous trouverez ici, commencez par produire un PNG de 4x21 tuiles. Composez alors votre lot de tuiles selon ce modèle : ![]() Chargez ensuite l'outil BOBsConverter.html qui se trouve dans le répertoire "tools". Attention ! Veillez bien à placer votre PNG dans le répertoire avant d'utiliser l'outil, car les contraintes de sécurité du navigateur vous interdiront de charger un fichier PNG depuis un autre endroit que ce répertoire. Dans l'outil, chargez votre fichier PNG. Ce dernier doit s'afficher dans "Input". Sélectionnez le format RAWB, puis cliquez sur "Convert!". Le résultat de la conversion doit s'afficher dans "Output". Copiez-collez le code qui apparaît dans la fenêtre "Data" dans un fichier. Chargez ce fichier dans ASM-One, assemblez-le avec la commande "A", puis enregistrez le binaire qui en résulte dans un fichier "tiles.rawb" avec la commande Workbench en spécifiant "start" et "end" comme libellés de départ et de fin.
|