Rom Hack & Fan Game

Trouver l'offset d'une image et sa palette

Combien de fois avez-vous eu besoin de modifier une image dont vous ne connaissez ni l'offset de l'image, ni de sa palette. Dans cette situation on se tourne dans un premier temps vers l'index de tiles et si on n'y trouve pas notre bonheur on se tape alors les 1XXX images de UnLz-GBA en espérant le trouver.
Mais cette méthode est souvent longue et parfois sans résultat. Alors comment faire pour retrouver l'image recherché dans ce cas la? Et bien ce tuto devrait vous apportez une solution dans la plupart des cas.
Je suis sur qu'à première vus vous vous dites que ce tuto est bien trop long pour apporter une solution viable, mais c'est parce-que j'ai pris soin de bien expliqué chaque chose. Une fois assimilé, retrouver une image et sa palette se fais en 3 minutes chrono.

Les nombres précédé d'un '#' sont en hexadécimal, sinon il sont en décimal.
Les bases de l'hexadécimal sont requises pour comprendre le tuto, mais rassurez vous, savoir que #A = 10, #B = 11, etc devrait suffire.

Les outils nécessaires

Les outils nécessaires vont ici énormément nous simplifier la tache, nous donnant presque directement la solution.
Le premier est VisualBoyAdvance, et oui votre fameux émulateur va ici beaucoup nous aider.
Votre éditeur Hexadécimal.
On utilisera aussi Namless Sprite Editor (NSE) pour visualiser et vérifier nos résultats.

Le stockage des données

On va commencer par une bonne dose de de théorie, car il est nécessaire que vous compreniez comment sont stocké les images et les palettes dans la ROM. (pour les couleurs c'est moins important mais de toute manières c'est simple à comprendre)

Les couleurs

Comme vous le savez les palettes sont composé 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 :

Code couleur en hexa

Vous êtes tous habitués à coder vos couleurs selon 3 composantes qui sont RVB. En général vous utilisez votre petit logiciel graphique pour faire varier les valeurs du rouge, du vert, et du bleu de 0 à 255. Chaque composante est alors codée sur 8 bit, soit 24 bits pour coder une seul couleur.

Et bien il en est de même pour vos jeux Pokémon (et tous les jeux GBA), sauf qu'au lieu de coder les couleurs sur 24 bits, la console n'utilise que 16 bits (2 octets) pour limiter la place que prend une couleur (16 bits ça fait quand même 32 768 couleurs possibles).
Comme on a 16 bits pour coder 3 composantes, cela fait 5 bits pour chaque composante (16/3 = 5), leurs valeurs peuvent donc varier de 0 à 31.
Il est possible de trouver la valeur d'une composante codée sur 5 bits en connaissent celle codée sur 24 bits en divisant par 8. (car 255/31 = 8). Autre chose, sur GBA les composantes ne sont pas dans le même ordre, c'est à dire qu'au lieu d'avoir RVB on a BVR.

Je sens que je vous perds déjà, mais un exemple est toujours le bienvenu. Imaginons que je veux retrouver la valeur hexadécimale de la couleur qui se trouve sur l'image au dessus. Je connais ses composantes qui sont: R = 88, V = 176, B = 48 (codé sur 8 bits par composante).
Je divise par 8 pour obtenir les valeurs codées sur 5 bits par composante. J'obtiens R = 11, V = 22, B = 6.
Je convertis en binaire: R = 01011, V = 10110, B = 00110.

Remarque : pour ceux qui ne savent pas faire une conversion Décimal->Binaire vous pouvez utiliser la calculatrice Windows en mode programmeur. (Affichage->Programmeur)

Il me suffit alors de les mettre dans l'ordre BVR pour obtenir la valeur correspondant à ma couleur, codée sur 16 bits. Soit 001 1010 1100 1011, et si on convertit en hexadécimal, on retrouve bien le #1ACB que l'on pouvait voir sur l'image.

Remarque : les plus perspicaces d'entre vous auront remarqué que 5 * 3 = 15 bits, donc 15 bits suffisent pour coder une couleur, mais la console est capable de lire uniquement des paquets de 8 bits (1 octet), il faut donc utiliser 16 bits pour coder une couleur. Il reste alors 1 bit qui n'a pas d'utilité, pas à ma connaissance en tous cas, et de ce qu'est j'ai pu observer il est toujours à 0.

Exercice : pour être sur que vous ayez compris je vous propose un petit exercice, essayez de le faire sans vous basez 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, elle sont en little-ediant (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-ediant).

Remarque : le logiciel NSE donne directement les valeurs en little-ediant (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 surement pour les performances. Car comme vous le savez maintenant chaque couleurs à une taille de 2 octets, donc une palette en 16c à une taille de 32 octets alors qu'une palette en 256c à une taille de 512 octets, c'est radicalement différent. C'est pour ça que la plupart des images des jeux GBA utilise les palettes 16c, les palette 256c ne sont utilisé que quand c'est réellement nécessaire.

Un point important à connaitre est que la première couleur d'une palette correspond toujours à la transparence, il ne reste donc que 15 couleurs d'utilisable 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 tous 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 8E62
AD14 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ère pas les palettes 256c. A 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 se genre de chose pour retrouver une image, donc je veux être sur que vous ayez compris. Je veux que dans la palette du hero (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 non pas exactement la même structure, je ne sais pas pourquoi mais elle sont composé 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 heuresement 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 (numeroté de #0 à #F), et 16 autres pour les backgrounds (numeroté de #0 à #F).

Les images

Tout comme pour les palettes il va falloir distinguer deux types d'images, celle qui utilise une palette de 16 couleurs et celle qui utilise une palette de 256 couleurs.
J’expliquerais seulement celle qui utilise 16 couleurs car ce sont les plus fréquentes mais aussi car celle en 256 couleurs sont bien souvent compressé pour prendre moins de place, donc savoir comment elle 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 quelle dimensions, il faut obligatoirement qu'elle sois un multiple de 8. On remarque d'ailleurs que la plus part des images sont en 16*16, 16*32, 32*32, ou encore 64*64.

Je vous préviens, à partir de la il va falloir être extrêmement attentif, la compréhension de se qui suis est essentiel pour retrouver une image mais c'est aussi la partie compliqué à comprendre de la théorie.

La console n'est capable de chargez que des carrés de 8*8, que l'on appelle bloc, une image est donc formée d'un ensemble de bloc. C'est aussi de cette façon qu'est structurée une image dans la ROM, par un ensemble de bloc mis les un à la suite des autres.
Certains me dirons "Ok, mais sa change quoi?". Et bien c'est totalement différent de si les informations était structurée ligne par ligne. Pour vous en convaincre regardez l'exemple suivant (dimension: 16*16): Image à blocs structurés
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 sais comment est structuré une image observons comment est codée un pixel. C'est ici qu'on va avoir besoin des indices de la palette. La couleurs d'un pixel est en faite définie par sont indice, et l'image est uniquement composé d'indices. On à vu que l'indice peut varié entre #0 et #F, chaque octet correspond donc à deux pixels. Prenons cette image 8*8 (dimension: 8*8) Rond de couleurs comme exemple, et la palette suivante: Blanc Rouge Vert Bleu puis le reste Noir. Voila comment serait codée l'image dans la ROM :

00 11 11 00 01 22 22 10 12 23 32 21 12 33 33 21
12 33 33 21 12 23 32 21 01 22 22 10 00 11 11 00

Mais les choses serait 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é à 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 sur que vous maitrisiez la chose. Vous allez devoir me refaire les données de l'image qui suis, en utilisant la palette en haut de l'image. Bon courage.

Image à reproduire pour l'exercice 3

Si vous n'avez pas réussi, recommencez tranquillement à lire cette partie. Vous devez absolument réussir cette 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 posez 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 simplifie vraiment la tache, 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.

A partir de la je vais distinguer deux cas d'images: les sprites et ce qui fais partie des backgrounds. Car les outils à utilisez ne sont pas tous à fais 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 ferrez 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.

Quelle 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. Voila ce que vous devriez obtenir :

OAM Viewer

Remarque : tous les outils de VBA possèdent une case "Automatic update", si vous ne l'activez pas les informations affichées resterons celle qui était en mémoire quand vous avez ouvert l'outil, donc si vous voulez que les outils s'actualise en même temps que vous jouez il faut cochez cette case.

Observez maintenant les informations affichées, on remarque une ligne "Pal:", et bien il s'agit du numéro de la palette en mémoire que votre sprite utilise (0 dans l'exemple ci-dessus), retenez-le. Vous pouvez fermer cette outil, on en aura pas besoin dans l'immédiat.
Si vous avez trouvez votre image dans le visualiseur OAM alors vous pouvez passé directement à la partie: "rechercher la palette dans la mémoire".

Exercice : cette fois l’exercice sera de trouvez le numéro de la palette de l'overworld du héros.

Quelle 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...).

Map Viewer de VBA

Dans la fenêtre qui s'ouvre on peut voir sur la gauche qu'il y à 4 backgrounds différents , trouvez celui sur le-quelle se trouve votre image.
Comme pour les OAM on retrouve écrit "Palette: ", mais attention, cette fois, contrairement aux sprites il ne faut pas prendre directement la valeur donné.

Une petite explication s’impose : rappelez-vous que les images sont composées de blocs de 8*8. Et pour les sprites, la palette utilisée est la même pour tous les blocs. Mais en revanche pour les background chaque bloc peut utiliser une palette différente (parmi les 16 en mémoire).

Pour en revenir à notre background vous devez donc cliquer sur une partie de l'image recherchée pour avoir la palette qui lui correspond, retenez le numéro de la palette.

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 connait 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 :

Palette Viewer

On se retrouve avec 2 groupes de 16 palettes (souvenez vous je vous avez dit qu'il y à 16 palettes pour les backgrounds, et 16 palettes pour les sprites).
Les palettes qui vous concerne dépendent de l'image que vous avez choisis, donc si c'est un sprites il faudra regarder les palettes appelées "Sprite" (à droite) et si votre image fais partie du background il faudra regarder les palettes appelées "Background" (à gauche).

Les palettes sont rangées dans l'ordre (de #0 à #F), vous ne devriez donc pas avoir trop de problème pour retrouver celle de votre image.
Remarque : vous pouvez voire la valeur d'une couleur en cliquant dessus.

Rechercher la palette dans la ROM

Maintenant que l'on connais 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écimal, comme on l'a fais dans la partie théorique. Je met donc chaque couleur obtenu grâce au visualiseur de VBA les une à 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 520A
3DAA 2D4A 0000 7B7B 5A94 5652 3DCE 2D4A

Mais n'oubliez pas que dans la ROM les données de la palette sont en little-ediant, il faut donc inverser la valeur de chaque couleurs, et voila à 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 suffirons 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 tous 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 à quelle 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, quel 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 un fois VBA va énormément nous simplifier la tache. 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 faite un bloc de 8*8 qui fais partie de notre image. Mais pour notre recherche seul une ou deux lignes suffisent. Et plus il y à 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 certaine images possèdent très peu de variations de couleurs, ce genre d'images donne beaucoup de résultats lors de la recherche, elle vous obligerons 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és 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 à notée sont 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 devrai donc ressembler à sa dans la ROM :

B2 33 2B CC

Ensuite il vous suffit de faire un 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 à 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 :

Un bout de la main s'affiche sur NSE.

Cependant votre image n'est pas celle que vous vouliez obtenir, mais c'est normal, l'offset que vous avez trouvé est celui de la ligne que vous avez utilisé, et non celui où commence votre image, vous devez donc essayer par tâtonnement quelques offsets se trouvant avant jusqu'à obtenir le bon.
On peut aussi obtenir le bon offset par le calcul. Pour sa aidez vous du fais que 1 ligne = #4 octets et un bloc = #20 octets.
Moi je préfère le faire par le calcul, je trouve sa plus rapide. Avant la ligne que j'ai choisis se trouvais donc 1 ligne et 9 blocs.
Le calcul que je doit faire est donc:
#3CCB50 - #1*#4 - #9*#20 = #3CCB50 - #128 = #3CCB50 - #124 = #3CCA2C
La main de mon exemple commencés donc à l'offset #3CCA2C.

Exercice : cette exercice va être le plus difficile de ce tuto (sans compter l’exercice qui se trouve tous à la fin) mais je suis sur 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 à pas de miracle, soit vous la trouvez dans UnlZ-GBA, ou alors vous allez devoir tâtonnez.
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 quelque 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 à 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 son proche. Je ne vous donne pas d'exemple cette fois car la main qui me servais d'exemple jusqu’à présent ne suis pas cette règle.

Exercice : la palette d'une des fenêtres de texte se trouve à l'offset #469244, à vous de retrouver sont 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'entrainer et de vérifier que vous avez bien compris le tuto. Si vous n'y arrivez, 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-la :

Retrouvez l'image et la palette de la Poké Ball qui sert d'indice de capture.

Je ne donne pas d'autres indications, cette fois c'est vraiment à vous de tous faire de A à Z. Bonne chance.

Retrouvez la correction de chaque exercice sur le topic du forum.

Par Unifag

Par Loris