Tables de caractères et recherche relative

De T.R.A.F - Wiki
Aller à : navigation, rechercher

Introduction

Le but de ce document est d'être informatif à propos de l'utilisation des tables de caractères et de la recherche relative. Le Guide de la Traduction essaie de ne pas trop rentrer dans les détails du pourquoi et du comment afin de ne pas être une trop grosse machine à gaz. Cette annexe s'attache donc aux détails concernant les raisons de l'utilisation de ces fonctions, en particulier pour la traduction des jeux qui tournaient sur les consoles 8 et 16 bits.

Vous devez garder à l'esprit que nous traitons des ROMs dont les données ne sont pas compressées (en tout cas pour ce qui concerne la partie "textes du jeu"). Nous vous recommendons également, avant toute chose, la lecture des annexes sur l'hexadécimal et l'introduction aux graphismes.

La table de caractères

Des 0 et des 1

Pour résumer, en taillant dans la masse, sachez qu'une machine électronique telle un ordinateur fonctionne en interprêtant des 1 et de 0, des "oui" et des "non". Si vous vous souvenez de vos cours d'électronique, une diode ne laisse passer le courant que s'il va dans un certain sens ; donc, s'il va dans le bon sens, c'est "oui", s'il va dans le mauvais, c'est "non". La complexité des données permet alors de tout mettre sous la forme d'une suite de 1 et de 0. C'est ce qu'on appelle le langage binaire. Histoire de ne pas s'embêter avec de longues chaînes de 1 et de 0 lorsqu'on explore un fichier, on réuni tout cela sous forme hexadécimale avec 1111 1111 = FF ; c'est plus court, non ?

L'interprétation des données

En gros l'éditeur hexadécimal permet de vous donner l'interprétation de cette suite de 0 et de 1 sous la forme commune "hexadécimale". Des suites d'octets se promènent joyeusement un peu partout pour notre plus grand bonheur (euh). Pour en revenir à nos histoires d'interprétations de données, il est évident qu'un jeu, lorsqu'il souhaite afficher du texte, va interpréter la suite de données propre à chaque caractère affiché. Les programmeurs du jeu doivent donc choisir la manière dont est codé chaque caractère. En général, le plus convénient est de coder lesdites lettres sur un seul octet (soit 8 bits - 256 caractères). Les américains pourraient très bien coder sur 7 bits (128 caractères), la norme ASCII (American Standard Code for Information Interchange) ayant été réalisée sur ce modèle. Nous, Européens, avec nos lettres accentuées diverses et variées, aurions tendance à choisir l'ASCII dit "étendu" sur 8 bits (soit un octet) pour plus de confort. Les langues asiatiques comme le Japonais et le Chinois qui peuvent posséder 60 000 caractères seront plutôt codées sur deux octets (16 bits - 65 536 caractères).

Bref, sachez qu'au final, très rares sont les jeux dont les lettres sont codées sur moins d'un octet. Par souci de simplicité, lorsqu'on n'est pas trop pressé par la place disponible dans le jeu, les caractères seront soit codés sur un octet, soit sur deux octets.

L'exemple "Hello world"

Revenons-en à la question principale de cette section. Lorsqu'une fonction d'affichage de dialogue est utilisée par le jeu, la machine sait donc qu'un certain octet est associé à une certaine lettre, ce qui lui permet, par exemple, d'afficher un magnifique "Hello world" ($48 $65 $6C $6C $6F $20 $77 $6F $72 $6C $64 en ASCII). Si on nous mettait un "$48 $65 $6C $6C $6F $20 $77 $6F $72 $6C $64" sous les yeux, nous serions bien incapables, de prime abords de savoir ce que cela signifie (je ne parle pas des geeks). Par contre, si on nous pose la table d'équivalence suivante :

  _=20
  H=48
  d=64
  e=65
  l=6C
  o=6F
  r=72
  w=77

nous serions plus à même de décrypter rapidement le message dans un langage que nous comprenons !

Eh bien la table de caractère sert tout simplement à cela : lorsque vous allez extraire le texte de votre ROM dans un fichier texte, il faut que vous puissiez lire le texte dans un langage "humain". La table de caractères permet au programme d'extraction d'associer directement les octets connus aux lettres. Ainsi, au lieu d'avoir "$48 $65 $6C $6C $6F $20 $77 $6F $72 $6C $64", vous aurez "Hello world" au moment de l'extraction du texte.

Il en sera de même au moment de l'insertion : il faut bien retransformer le langage "humain" en langage "machine", non ?

La recherche relative

Qu'est-ce qu'une recherche relative ?

La recherche dite "relative" permet de retrouver du texte en testant une suite de caractères dont l'espacement entre les valeurs est identique à l'espacement entre celles de la chaîne de caractères initialement recherchée. Par exemple, si vous cherchez "ABCDEF" (en mode 8 bits, c'est-à-dire que chaque lettre est codée par un seul octet), les suites d'octets recherchées seront :

  $00 $01 $02 $03 $04
  $01 $02 $03 $04 $05
  $02 $03 $04 $05 $06
  ...
  $FA $FB $FC $FD $FE
  $FB $FC $FD $FE $FF

De cette manière, vous pourrez trouver la valeur initiale du "A" et en déduire toutes les lettres qui suivent. Les logiciels de recherche relative reposent sur le principe bien évident que l'alphabet est complet et qu'il n'existe que sous la forme "ABCDEF...XYZ", c'est-à-dire avec A comme première lettre de l'alphabet, B la deuxième, C la troisième, ..., Y la vingt-cinquième et Z la vingt-sixième. Il en va de même pour les minuscules et pour les chiffres. Si la police de caractères utilisée par le jeu est incomplète ou brouillée (par exemple avec F comme première lettre de l'alphabet et M comme vingt-sixième lettre), la recherche relative ne fonctionnera tout simplement pas (en tout cas, pas de manière directe).

Pourquoi une recherche relative ?

Si vous écrivez un document texte et que vous ouvrez ce dernier avec un éditeur hexadécimal standard, vous verrez le texte s'afficher en clair et remarquerez que les lettres ont les valeurs hexadécimales suivantes : A = 41 et a = 61. Rien de plus normal. C'est ce que l'on appelle, je le rappelle, le standard ASCII dont la base est reprise par la plupart des standards internationaux (UTF-8, ISO 8859, SHIFT JIS, etc.). Pourtant, lorsqu'on ouvre un jeu 8 ou 16 bits, les textes sont invisibles à l'éditeur hexadécimal. A ne vaut plus $41 et a ne vaut plus $61. Alors pourquoi le standard ASCII n'est-il en général pas respecté alors que le ZX Spectrum de 1982 (par exemple), en faisait déjà usage (l'ASCII ayant été créé en 1961, tout de même) ? Deux phénomènes en sont essentiellement à l'origine : la transposition des jeux japonais en anglais et une histoire de place.

L'absence de standards : un début d'explication

En lisant les paragraphes précédents, on peut effectivement se demander pourquoi les programmeurs n'ont-ils tout simplement pas utilisé des polices standardisées ? Cela nous aurait grandement facilité le travail, n'est-ce pas ? Ceci dit, on pourrait également poser la question dans l'autre sens : pourquoi devraient-ils utiliser des standards puisque, contrairement aux ordinateurs, il n'y a pas de relation d'échanges entre machines ?

Essayons d'y voir un peu plus clair.

Le manque de place

Pour ce qui concerne les jeux 8 et 16 bits, il faut savoir qu'une police de 1 BPP 8x8 (l'une des polices les plus légères - sachant que, sur Super NES, on pouvait aller jusqu'à du 4 BPP 16x16), il fallait 8 octets par lettre (non compressée - et 128 octets maximum par caractère sur Super NES ; autant te dire qu'on ne le voit pas souvent... pour ne pas dire jamais). Fréquemment, on retrouvait du 2 BPP 8x8 (soit 16 octets par caractère).

Bref, comme il faut mettre cette police en mémoire graphique afin de l'afficher à l'écran, une font de 224 caractères ASCII (le standard de départ, l'ASCII 7 bits, utilisait 95 caractères ; dans notre cas, on s'intéresse à l'ASCII étendu 8 bits puisqu'on code classiquement une lettre sur un octet) occupait au minimum 1 792 octets... Ce serait deux fois plus avec un simple font 2 BPP 8x8, et quatre fois plus avec une 1 BPP 16x16, soit 7 168 octets, ce qui occupe une bonne partie de l'espace mémoire de la NES qui fait entre 4 ko et 16 ko : il ne faut pas oublier que cette mémoire est aussi utilisée pour les sprites, par exemple, ou d'autres choses plus obscures pour le commun des mortels (le but, ici, étant de vulgariser le problème). Pour aérer, on peut revenir à un minimum de 70 caractères (majuscules/minuscules sans accents, chiffres et signes de ponctuation) pour tout faire rentrer alors que dans le second cas, ça devient très juste. Il fallait alors trouver de la place. Et la seule manière d'y parvenir était par exemple de limiter la police de caractères, ce qui était le plus simple. Il faut savoir que l'octet coûtait très cher à l'époque (une ROM NES pouvait peser 256 ko) à cause de l'électronique utilisée.

Les plus malins d'entre vous (et les puristes) pourront objecter que cette histoire de manque de place ne rend pas nécessaire l'utilisation d'une table de caractères différente des standards : il suffit en effet juste de couper les caractères qui n'intéressent personne au bon endroit, même lorsque la police finit par être partielle (absence de certaines lettres de l'alphabet). En résumé, le problème de place n'est certainement pas le "problème" majeur même s'il doit contribuer à le complexifier.

Puisqu'il en est ainsi, regardons ailleurs.

Les programmeurs font ce qu'ils veulent

A l'époque des 8 et 16 bits, la suprématie du Japon ne fait aucun doute. La plupart des jeux sortent d'abord au pays du soleil levant avant que nous, pauvres occidentaux, puissions jouir des restes. Comparons deux ROMs d'un même jeu. Prenons Gargoyle's Quest II - The Demon Darkness et sa version japonaise Reddo Ariimaa II ("Red Arremar II" dans le GoodNES). Dans un jeu japonais qui utilise une font 8x8, il faut faire usage des hiragana et des katakana mais pas des kanji. En effet, les kanji sont en général des caractères complexes que l'on a déjà bien du mal à dessiner dans une police 16x16 et, si vous vous souvenez du petit laïus sur les histoire de place, il était hors de question de mettre quelque 2000 caractères dans notre ROM. D'ailleurs, au-delà de 256 caractères, il faut coder chaque lettre sur deux octets (dans le cas d'une "compression par limitation de bits", on encodera sur 9, 10 ou 11 bits, voire davantage mais le script n'apparaîtra pas en clair dans l'héditeur hexadécimal, même après une recherche relative qui, elle, ne s'effectue qu'en 8 ou 16 bits).

Bref. Si on ne garde que nos hiragana et katakana avec leur ponctuation, chiffres et signes divers, on arrive à environ 120 caractères. L'utilisation de caractères latins étant rare, il est fréquent de ne pas retrouver nos lettres dans leur police de caractères ou juste partiellement. C'est justement ce qui se passe avec la ROM japonaise que nous avons prise en exemple. Notez également l'illustration de l'utilisation d'une partie de l'espace pour autre chose que des caractères (des graphismes qui seront utilisés dans une tilemap). Ici, "par souci de place", on n'utilise que 128 caractères en 1BPP 8x8, de $00 à $7F. Vous remarquez comme il ne reste pas une once de place dans la ROM japonaise (les derniers caractères étant occupés par des bords de cadre destinés aux dialogues et quelques signes divers) ?

Ah mais qu'à ce la ne tienne ! Les Occidentaux n'ont que 70 à 80 caractères à faire rentrer ! Oui mais... puis-je respecter les valeurs hexadécimales du standard ASCII ? On pourrait, effectivement : la lettre ayant la valeur la plus élevée est z = 7A. Dans notre cas, manque de bol, le 7A est occupé par une tile utilisée dans le dessin des cadres de dialogue. Au vu de ce que l'on retrouve, au final, dans la ROM américaine, on aurait pu déplacer les cadres autre part et garder le standard ASCII (d'ailleurs, vous remarquerez que les programmeurs en ont gardé l'agencement : A = 01 et a = 21 ; ils s sont tout juste décalés de $40... ou presque - voir plus bas).

Alors pourquoi ne pas l'avoir fait ? Les programmeurs US ont dû insérer une toute nouvelle police de caractères et trifouiller le code du jeu pour associer chacun de ces caractères à une valeur hexadécimale bien précise : le travail est le même quelle que soit la valeur des caractères, ASCII ou autre. Le temps étant de l'argent, pourquoi diable iraient-ils toucher aux cadres sachant que cela leur ferait du travail en plus avec des tests supplémentaires et le risque (somme toute minime) de tout faire planter ? Simplement pour respecter un standard ? Aucun intérêt ! Ils n'ont même pas touché au "LV" et, pire, ont laissé les chiffres là où ils étaient, ce qui a eu pour résultat de scinder la police de minuscules en deux ! Enfin, ils se sont contentés du strict minimum dans l'utilisation des caractères.

Conclusion

Le cas "Gargoyle's Quest II" est loin d'être isolé. Par ailleurs, quelle est l'importance de l'utilisation d'un standard pour ce type de jeu, à cette époque ? Même pour les jeux développés par des occidentaux, il était fréquent d'insérer les caractères à l'arrache pour une raison ou une autre (souvent "en tête" de la mémoire, suivant ce qui était chargé par ailleurs). Au final, on se retrouve donc avec des jeux dont les caractères ne possèdent aucune "standardisation" de leur valeur. D'où l'étape souvent nécessaire de la recherche relative.

Aujourd'hui, c'est beaucoup moins le cas (voire pas du tout) : les jeux disposent de tellement d'espace (une police UTF-8 japonaise possède tout ce qu'il faut de caractères latins pour localiser le jeu où l'on veut) et les kits de développement prémachent tellement le travail de ce côté-là qu'il n'est absolument pas nécessaire de se prendre la tête sur l'allocation des caractères en mémoire. Sur PlayStation/Saturn (CD, environ cent fois plus de place qu'une ROM Super NES) ou Nintendo 64 (cartouche, environ 10 fois plus de place qu'une ROM Super NES), on peut éventuellement avoir affaire à des tables de caractères qui ne respectent pas les standards.

De toute façon, au final, vous devrez quand même construire votre table de caractères dans un fichier texte, qu'elle soit ASCII ou pas, afin que votre logiciels d'extraction puisse correctement interpréter les données !