Trouver l'offset d'une image et sa palette
Comment retrouver l'offset d'une image et de sa palette dans une ROM Pokémon GBA. Tuto pour hackeurs !
Les outils nécessaires
Les outils nécessaires vont ici énormément nous simplifier la tâche, nous donnant presque directement la solution. Le premier est [VisualBoyAdvance](http://vba.ngemu.com/downloads.shtml), et oui, votre fameux émulateur va ici beaucoup nous aider. Votre [éditeur Hexadécimal](http://mh-nexus.de/en/hxd/). On utilisera aussi [Namless Sprite Editor (NSE)](http://www.pokecommunity.com/showthread.php?t=253701) pour visualiser et vérifier nos résultats.Le stockage des données
On va commencer par une bonne dose de théorie, car il est nécessaire que vous compreniez comment sont stockées les images et les palettes dans la ROM. (pour les couleurs c'est moins important mais de toute manière c'est simple à comprendre)Les couleurs
Comme vous le savez, les palettes sont composées de couleurs, on va donc tenter de comprendre comment sont codées ces couleurs. Vous avez tous déjà créé vos propres palettes car celles par défaut ne vous convenaient pas, pour ça vous avez par exemple utilisez l'outil d'édition de palette du logiciel Advance-Map. Mais pour la plupart d'entre vous la valeur hexadécimale correspondant aux différentes couleurs était incompréhensible (je suis même persuadé que certains ne savent pas de quelle valeur je parle). Celle qui se trouve dans le coin en bas à gauche :
Exercice : pour être sûr que vous ayez compris je vous propose un petit exercice, essayez de le faire sans vous baser sur mon exemple, ce serait trop simple et montrerait juste que vous êtes capable de me copier comme un imbécile. La couleur à convertir est ce violet: R = 136, V = 56, B = 160.
En réalité les couleurs ne sont pas directement sous cette forme dans la ROM, elles sont en little-endian (inversé), on retrouvera donc notre couleur #1ACB sous la forme #CB1A dans la ROM. Mais quand la console "lit" la ROM, elle interprète la couleur comment étant #1ACB. Si vous voulez mieux comprendre pourquoi (Google -> little-endian). Remarque : le logiciel NSE donne directement les valeurs en little-endian (inversé).Les palettes
Il existe en GBA deux types de palettes, les palettes de 16 couleurs et les palettes de 256 couleurs. L'avantage d'avoir plusieurs types de palette est que l'une prend moins de place que l'autre et sûrement pour les performances. Car comme vous le savez maintenant chaque couleur a une taille de 2 octets, donc une palette en 16c a une taille de 32 octets alors qu'une palette en 256c a une taille de 512 octets, c'est radicalement différent. C'est pour ça que la plupart des images des jeux GBA utilisent les palettes 16c, les palettes 256c ne sont utilisées que quand c'est réellement nécessaire. Un point important à connaître est que la première couleur d'une palette correspond toujours à la transparence, il ne reste donc que 15 couleurs d'utilisables en plus de la transparence. Mais normalement vous le saviez déjà. La structure d'une palette dans la ROM est simple, il s'agit tout simplement d'une suite de couleurs codées sur 16 bits. Par exemple la palette du héros
est codée de la façon suivante dans la ROM :
```
F051 F521 1F4B 5B3A 0F21 0869 E73C 8E62AD14 BD7F D66A BF25 F81C 7F2F 771E 0000 ``` Et il en est de même pour une palette comportant 256 couleurs. Remarque : la plupart des logiciels ne gèrent pas les palettes 256c. À ma connaissance seul UnLz-GBA le fait, même si il semblerait que NSE 2 le fasse aussi. Mais pour que la console sache quelle couleur de la palette elle doit utiliser, on attribue un indice à chaque couleur, de #0 à #F. Ainsi la première couleur est à l'indice 0, la deuxième à l'indice 1, etc. Cette notion est vraiment importante car c'est là-dessus que tout reposera quand on cherchera nos images.
Exercice : Extrêmement simple mais on aura besoin de faire ce genre de chose pour retrouver une image, donc je veux être sûr que vous ayez compris. Je veux que dans la palette du héros (donnée au dessus) vous me donniez l'indice des couleurs D66A, E73C, et 771E. Mais aussi que vous me donniez les couleurs qui se trouvent aux indices 9, 3, et 4.
Remarque : certaines palettes n'ont pas exactement la même structure, je ne sais pas pourquoi mais elles sont composées de #00 tous les 8 octets. Ce qui donne ce genre de chose (les YYYY sont les couleurs) : ``` YYYY YYYY YYYY YYYY 00 YYYY YYYY YYYY YYYY 00 YYYY YYYY YYYY YYYY 00 YYYY YYYY YYYY YYYY ``` Mais heureusement ce genre de cas est rare. Autre chose à savoir qui nous sera utile pour la suite c'est que la console n'est capable d’utiliser qu'un certain nombre de palettes à la fois, 16 pour les sprites (numérotées de #0 à #F), et 16 autres pour les backgrounds (numérotées de #0 à #F).Les images
Tout comme pour les palettes il va falloir distinguer deux types d'images, celles qui utilisent une palette de 16 couleurs et celles qui utilisent une palette de 256 couleurs. J’expliquerais seulement celles qui utilisent 16 couleurs car ce sont les plus fréquentes mais aussi car celles en 256 couleurs sont bien souvent compressées pour prendre moins de place, donc savoir comment elles se structure ne nous aidera pas à les trouver. Remarque : il est possible que certaines images en 16 couleurs soient elles aussi compressées pour prendre moins de place, mais on sera quand même en mesure de les trouver. Comme vous le savez une image ne peut pas avoir n'importe quelles dimensions, il faut obligatoirement qu'elle soit un multiple de 8. On remarque d'ailleurs que la plupart des images sont en 1616, 1632, 3232, ou encore 6464. Je vous préviens, à partir de là il va falloir être extrêmement attentif, la compréhension de ce qui suit est essentiel pour retrouver une image mais c'est aussi la partie compliquée à comprendre de la théorie. La console n'est capable de charger que des carrés de 8*8, que l'on appelle bloc, une image est donc formée d'un ensemble de blocs. C'est aussi de cette façon qu'est structurée une image dans la ROM, par un ensemble de blocs mis les uns à la suite des autres. Certains me diront "Ok, mais ça change quoi ?". Et bien c'est totalement différent de si les informations étaient structurées ligne par ligne. Pour vous en convaincre regardez l'exemple suivant (dimension: 16*16):
Si l'information était structurée ligne par ligne j'aurais eu: 8 rouge, 8 bleu, 8 rouge, 8 bleu, ..., 8 vert, 8 blanc, 8 vert, 8 blanc, etc. Alors qu'en structurant l'information par bloc j’obtiens: 64 rouge, 64 bleu, 64 vert, 64 blanc. Maintenant que l'on sait comment est structurée une image observons comment est codé un pixel. C'est ici qu'on va avoir besoin des indices de la palette. La couleur d'un pixel est en fait définie par son indice, et l'image est uniquement composée d'indices. On a vu que l'indice peut varier entre #0 et #F, chaque octet correspond donc à deux pixels. Prenons cette image 88 (dimension: 88)
, et la palette suivante: Blanc Rouge Vert Bleu puis le reste Noir. Voilà comment serait codée l'image dans la ROM :
```
00 11 11 00 01 22 22 10 12 23 32 21 12 33 33 2112 33 33 21 12 23 32 21 01 22 22 10 00 11 11 00 ``` Mais les choses seraient trop belles si c'était vraiment aussi simple, en réalité il faut inverser les chiffres de chaque octet (en hexadécimal le A,B,C,D,E,F sont aussi des chiffres). Je n'en connais pas la raison mais c'est comme ça. Le bon code de l'image est donc celui-ci : ``` 00 11 11 00 10 22 22 01 21 32 23 12 21 33 33 12
21 33 33 12 21 32 23 12 10 22 22 01 00 11 11 00 ``` Je suis conscient que cette dernière partie théorique était plutôt compliquée à comprendre, n’hésitez surtout pas à la relire si certaines choses vous semblent flou.
Exercice : celui-ci sera plus complet que les premiers pour être sûr que vous maîtrisiez la chose. Vous allez devoir me refaire les données de l'image qui suit, en utilisant la palette en haut de l'image. Bon courage.

Si vous n'avez pas réussi, recommencez tranquillement à lire cette partie. Vous devez absolument réussir cet exercice car on en aura besoin à chaque fois que l'on voudra trouver une image.
On a enfin terminé avec la théorie, on va maintenant pouvoir mettre en pratique ce que je viens de vous apprendre. Si vous avez compris la partie théorique dans son intégralité la suite ne devrait pas vous poser de problème, sinon, je me répète, relisez la partie sur les palette et sur les images.Retrouver la palette
Avec ce que vous savez maintenant il existe plusieurs méthodes qui vous permettront de trouver la palette et l'image recherchée, mais VBA met à notre disposition des outils qui nous simplifient vraiment la tâche, alors pourquoi s'en priver. La première étape est donc d'ouvrir VBA et de faire en sorte que l'image que vous cherchez apparaisse à l'écran. À partir de là je vais distinguer deux cas d'images : les sprites et ce qui fait partie des backgrounds. Car les outils à utiliser ne sont pas tous à fait les mêmes. Remarque : au début vous aurez peut-être du mal à savoir si vous cherchez un sprite ou un élément du background mais avec l'habitude vous ferez facilement la différence. Et si vous ne trouvez pas votre élément avec un des outils c'est qu'il faut utilisez l'autre.Quel est le numéro de la palette: les sprites
Si l'image que vous cherchez est un sprite alors ouvrez le visualiseur d'OAM (Tools->OAM Viewer...). Et utilisez les flèches en haut à gauche pour retrouver votre sprite. Voilà ce que vous devriez obtenir :
Exercice : cette fois l’exercice sera de trouver le numéro de la palette de l'overworld du héros.
Quel est le numéro de la palette: les backgrounds
Si vous n'avez pas trouvé l'image recherchée dans le visualiseur OAM cela signifie qu'elle fait partie du background, et la méthode est quelque peu différente. Cette fois il va falloir utiliser le visualiseur de Map (Tools->Map Viewer...).
Exercice : vous devez trouver le numéro de la palette du Centre Pokémon (l’extérieur du bâtiment).
Rechercher la palette dans la mémoire
Maintenant que l'on connaît le numéro de la palette en mémoire on va pouvoir la visualiser. Pour commencer ouvrez le visualiseur de palette (Tools->Palette Viewer...). Le menu suivant devrait s'ouvrir :
Rechercher la palette dans la ROM
Maintenant que l'on connaît la palette il ne reste plus qu'à trouver où elle se trouve dans la ROM. Pour ça on va refaire la palette sous sa forme hexadécimale, comme on l'a fait dans la partie théorique. Je met donc chaque couleur obtenue grâce au visualiseur de VBA les unes à la suite des autres pour obtenir ma palette. Par exemple la palette de la main (voir image plus haut) est : ``` 0000 5652 2D4A 7FFF 7FF9 76EB 668B 520A3DAA 2D4A 0000 7B7B 5A94 5652 3DCE 2D4A ``` Mais n'oubliez pas que dans la ROM les données de la palette sont en little-endian, il faut donc inverser la valeur de chaque couleurs, et voilà à quoi ressemble ma palette dans la ROM : ``` 0000 5256 4A2D FF7F F97F EB76 8B66 0A52
AA3D 4A2D 0000 7B7B 945A 5256 CE3D 4A2D ``` Maintenant qu'on a notre palette une simple recherche avec votre éditeur hexadécimal vous permettra de la retrouver. Cependant ce n'est pas la peine de lancer une recherche sur toute la palette, bien souvent 2-3 couleurs suffiront et cela permet de trouver aussi les palettes avec des 00 (voir dernière remarque de la partie théorie sur les palettes). Prenez quand même soin de vérifier que les autres couleurs coïncident. Par exemple, si je recherche "0000 5256 4A2D" dans la ROM je tombe tout de suite sur le bon résultat, à l'offset #3C8630. Remarque : vérifier bien que votre recherche ne donne qu'un seul résultat, il se peut que plusieurs palettes partagent les mêmes couleurs.
Exercice : vous devez retrouver à quel offset se trouve la palette du héros.
Vous voyez ? Une fois que l'on a compris le système, retrouver la palette est extrêmement simple et rapide. Remarque : le principe est le même avec les palettes en 256 couleurs.Retrouver l'image
Il est nécessaire d'avoir trouvé la palette avant de chercher l'image, qu'elle soit en 16 ou 256 couleurs, compressée ou non. Sinon vous n'avez aucune chance de la trouver avec cette méthode.Les images 16c non compressées
L'idée sera comme pour les palettes d'essayer d’imaginer à quoi ressemble l'image dans la ROM pour ensuite faire une recherche. Encore une fois VBA va énormément nous simplifier la tâche. La première chose à faire est d'ouvrir l'OAM Viewer ou le Map Viewer suivant votre image. Vous remarquerez que quand on clique sur une partie de l'image (dans le viewer) elle se retrouve affichée à un endroit, ce qui est affiché est en fait un bloc de 8*8 qui fait partie de notre image. Mais pour notre recherche seule une ou deux lignes suffisent. Et plus il y a de variations de couleurs dans ces lignes mieux c'est, donc faite en sorte de trouver les lignes les plus adaptées sur votre image. Pour moi ce sera la 2eme ligne de ce bloc : Remarque : il se peut que certaines images possèdent très peu de variations de couleurs, ce genre d'images donne beaucoup de résultats lors de la recherche, elles vous obligeront donc à essayer différentes lignes pour la recherche voir même à utiliser plusieurs lignes à la fois. Une fois que vous avez identifié quelle ligne sera la plus appropriée il faut essayer de reproduire la façon dont elle serait codée dans la ROM. Pour ça cliquez sur le premier pixel de la ligne, les valeurs de ses composantes devraient s'afficher, il ne vous reste plus qu'à retrouver de quelle couleur il s'agit dans la palette et à noter son index, souvenez vous, on a fait ça dans un des exercices que j'ai donné dans la partie théorique. Pour la deuxième ligne de la main j’obtiens donc ceci: ``` 2B 33 B2 CC ``` Mais je vous rappelle que dans la ROM, pour les images chaque chiffre d'un octet est inversé. Au final la ligne que j'ai choisis devrait donc ressembler à ça dans la ROM : ``` B2 33 2B CC ``` Ensuite il vous suffit de faire une recherche avec votre éditeur hexadécimal, prenez soin de vérifier que le résultat obtenu est le bon avec NSE, et si ce n'est pas le cas vérifier si il n'y a pas d'autres résultats à votre recherche. J'ai obtenu un seul résultat pour la ligne que j'ai choisis, et il se trouve à l'offset: #3CCB50. Si j'ouvre NSE et que je vais à l'offset que je viens de trouver, j'observe effectivement un bout de la main :
Exercice : cet exercice va être le plus difficile de ce tuto (sans compter l’exercice qui se trouve tous à la fin) mais je suis sûr que vous y arriverez. Vous allez devoir retrouver l'offset de l'image du truc qui montre qu'un Pokémon porte un objet (visible dans le menu Pokémon). Pour ça il faudra utiliser l'OAM viewer et non le Map Viewer, et la palette est de l'image est la numéro #0.
Les images 256c ou compressées
Pour ce genre d'images il n'y a pas de miracle, soit vous la trouvez dans UnlZ-GBA, ou alors vous allez devoir tâtonner. Pour cette méthode on va avoir besoin de l'offset de notre palette, et on va cherchez le pointeur qui lui correspond. Pour ceux qui ne savent pas comment faire, commencez par inverser l'offset de la palette puis rajoutez 08 à la fin, par exemple pour la main vu plus haut : #3C8630 devient #30863C08. Et ensuite je lance une recherche pour #30863C08. Remarque : parfois le pointeur ne pointe pas directement sur la palette mais quelques octets plus tôt. Donc si la recherche ne donne pas de résultat essayez de prendre un offset un peu avant. Si vous regardez les données autour de votre résultat vous devriez voir qu'il y a d'autres pointeurs, et bien la méthode consiste à vérifier un par un chaque pointeur avec NSE, car souvent le pointeur de la palette et de l'image sont proche. Je ne vous donne pas d'exemple cette fois car la main qui me servait d'exemple jusqu’à présent ne suit pas cette règle.Exercice : la palette d'une des fenêtres de texte se trouve à l'offset #469244, à vous de retrouver son image avec cette méthode.
Exercice final
Maintenant vous avez tous les outils pour retrouver à peu près n'importe quelle image et sa palette. Mais je sens que vous manquez d'entrainement, un exercice complet est donc le meilleur moyen de s'entraîner et de vérifier que vous avez bien compris le tuto. Si vous n'y arrivez pas, ne regardez pas tout de suite la correction, faite une pause, relisez la partie qui vous fait défaut, puis ré-essayez.L'énoncé
Votre mission est de retrouver les offsets (palette et image) de la petite Poké Ball qui nous indique si on a déjà capturé un Pokémon ou non, c'est la même que celle qui indique combien de Pokémon il reste dans notre équipe et dans l'équipe adverse. Pour ceux qui ne voient toujours pas de quoi je parle, c'est celle-là :
Retrouvez la correction de chaque exercice sur le topic du forum.
Par Unifag

