Déplacer des textes dans une autre bank - SNES

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

Note : Ce tutorial va être basé sur la rom "Dragon Ball Z - Super Saiya Densetsu (J) (V1.1)".

Souvent, les banks où se trouvent le texte ne contiennent pas uniquement du texte mais aussi les tables de pointeurs 16-bits, ainsi que du code pour le jeu.

Le but de cette manipulation est de déplacer la table de pointeurs et les textes d'une bank donnée dans une nouvelle bank vide ajoutée à la rom (en utilisant "LunarExpander" pour agrandir la rom), ce qui va permettre d'utiliser tout l'espace disponible dans cette nouvelle bank (ou presque, disons entre 95 et 99% de l'espace disponible, car il faut compter la place que va prendre la table de pointeurs, qu'on déplace en même temps).


Il nous faut connaître divers informations :

  • L'adresse de début et fin de la table de pointeurs (0x30000-0x302DB).
  • L'adresse de début et fin du texte (0x302DC-0x35108).

Tout d'abord, on lance donc "LunarExpand" pour agrandir la rom sans se casser la tête à le faire manuellement. La rom originale fait 1 Mo (8M bits), on va la passer à 1,5 Mo (12 Mbits), sachant qu'on pourra toujours l'agrandir de nouveau plus tard si nécessaire.

On choisit donc "12 Mbit (1.5 MB)", on clique sur "Apply to Rom...", on choisit la rom sur laquelle on veut effectuer la modification, et hop, la rom est agrandie.

On va ensuite dumper le script principal de façon classique, personnellement j'utilise "Hareng-Tool", ce qui donne ceci dans mon cas comme ligne de commande :

extraire("Dragon Ball Z - Super Saiya Densetsu (J) (V1.1).smc", "Dragon Ball Z - Super Saiya Densetsu (J) (V1.1).tbl", "Dragon Ball Z - Super Saiya Densetsu (J) (V1.1)_Script_Principal.txt", 0x302DC, 0x35108, 0x30000, 366, 2, "X+$8000", little_endian)

Ce qui me donne un dump tout ce qu'il y a de plus classique, dont voici un extrait :

[PT0001]
[Kame Sennin]
「いやいや おまえたちが コンビを[nl]
くむとはのう‥‥。[nl]
これなら かてるかもしれんぞい!」
[Pause]
[Kame Sennin]
「しっかりやってこいよ![nl]
しぬでないぞっ!!」[End]
[PT0002]
[Bulma]
「ゴハンくんのぼうしに ドラゴンボール[nl]
がついてたわよね!?[nl]
ドラゴンレーダーをつかえば ばしょが[nl]
わかるんじゃない!?」[End]
[PT0003]
[Kulilin A]
「オレがいっても ゴクウたちの やくに[nl]
たてそうもないな‥‥」
[Pause]
[Kulilin A]
「ゴクウ!しぬなよ[!!]」[End]
[PT0004]
[Kulilin A]
「いや‥その‥‥[nl]
ピッ‥ピッコロも・な!?」
[Pause]
[Kulilin A]
「ホラ これもってけよ」[End]
[PT0005]
[Piccolo A]
「‥‥‥‥‥。」[End]

Il faut ensuite une ligne de commande fonctionnelle pour réinsérer le dump en question, ce qui donne ceci dans mon cas :

inserer("Dragon Ball Z - Super Saiya Densetsu (J) (V1.1).smc", "Dragon Ball Z - Super Saiya Densetsu (J) (V1.1).tbl", "Dragon Ball Z - Super Saiya Densetsu (J) (J) (V1.1)_Script_Principal.txt", 0x302DC, 0x35108, 0x30000, 366, 2, "X+$8000", little_endian)

Ce que j'ai l'habitude de faire, pour être sûr que ma réinsertion fonctionne parfaitement, c'est de réinsérer le script original dumpé sans modifications (cf la ligne de commande au dessus) et ensuite de comparer la rom originale et la rom dans laquelle j'ai réinséré le dump. Si la réinsertion fonctionne parfaitement, les deux roms doivent toujours être identique après la réinsertion du dump original.


Maintenant, comment déplacer la table de pointeurs et les textes ?

En fait, pour que le jeu puisse accéder à la table de pointeurs, et donc aux textes, il faut bien qu'il sache où se trouve la table de pointeurs en question, et pour cela, le jeu lit un pointeur. Sachant qu'il y a plusieurs tables de pointeurs/textes dans différentes banks, il faut que le jeu connaisse l'adresse exacte, et pour cela, il lit donc un pointeur 24-bits.

Ce pointeur 24-bits pointe sur le début de la table de pointeur, il faut donc le trouver. Une fois trouvé, il "suffira" de modifier les adresses dans la commande de réinsertion pour réinsérer la table de pointeurs/les textes dans une nouvelle bank (vide) avec "Hareng-Tool", puis de modifier ce pointeur 24-bits pour qu'il pointe vers cette nouvelle bank.


Pour calculer facilement les pointeurs au format SNES (qui est différent du format classique), j'utilise "LunarAdress".

Petite explication à propos des différences entre les adresses SNES et celles que l'on appelle "PC" (celles qu'on utilise dans un éditeur hexadécimal, par exemple "0x32DBC") :

La SNES ne reconnait pas l'adresse 0x32DBC. Pour "elle", cette adresse équivaut à 0x06ADBC ("06" étant le n° de bank et le reste étant l'adresse dans la bank en question).

Pour utiliser "LunarAdress", rien de plus simple. Il suffit de cliquer sur "Auto-Detect Type", de choisir la rom en question, et le logiciel choisira automatiquement le bon mode. Vous entrez ensuite l'adresse PC (hexadécimal dans le cadre en bas à gauche, "03:2DBC" (vous pouvez effacer les deux points, le logiciel n'en tient pas compte) et vous obtenez à droite "06:ADBC").

Il faut donc, en premier lieu, trouver le pointeur 24-bits de la table de pointeurs originale.

On connait l'adresse de début de la table de pointeurs, 0x30000, on demande à "LunarAdress" de faire la conversion en adresse SNES, ce qui donne "06:8000".

On sait que les pointeurs SNES sont en "little endian" donc il faut inverser notre résultat, ce qui donne : "0080:06" (je conserve les deux points dans ce tutorial pour bien séparer l'adresse du n° de bank mais en réalité, on s'en fiche).


Maintenant, le but du jeu est de chercher "008006", sachant que selon les jeux (ou même dans un même jeu), on peut avoir le pointeur 24-bits en deux morceaux, la partie adresse à un endroit donné, et l'octet de la bank dans les alentours,

On cherche donc chaque occurence de "008006" dans la rom. Pour vérifier si c'est la bonne occurence, il y a une méthode simple.

La table de pointeurs est composée de pointeurs 16-bits (2 octets). Si l'on remplace"008006" par"028006" et que l'on a trouvé la bonne occurence, le dialogue affiché devrait être différent (la modification ci-dessus indique au jeu que la table de pointeurs comme 2 octets plus loin, ce qui signifie que tous les textes vont être décalés d'un pointeur, et donc le dialogue de base devrait soit afficher un autre dialogue, soit ne rien afficher/bugger s'il s'avère que le dialogue en question était lié au dernier pointeur, mais ce cas est plutôt improbable. Dans notre cas, il y a une probabilité sur 366 que ce soit le cas vu qu'il y a 366 pointeurs).

La première occurence de "008006" se trouve à 0x2B78E. On modifie en "028006" et on vérifie dans le jeu si le dialogue choisi au début a changé (dans mon cas, le premier dialogue de Bulma).

Le dialogue n'a pas changé, ce n'est donc pas la bonne adresse, je continue donc ma recherche dans la rom.

L'occurence suivante de "008006" se trouve à 0x38F1C. On modifie en "028006" et on vérifie dans le jeu si le dialogue choisi au début a changé.

Oh, le dialogue a changé :-) Le portrait de Bulma s'est transformé en portrait de Krilin et le texte en lui-même est également différent. Cela signifie que c'est bien le pointeur 24-bits de la table de pointeurs que l'on a trouvé.


Maintenant, on va réinsérer notre dump (fait au début de ce tutorial) dans une nouvelle bank vide.

La première bank vide se trouvant dans la partie agrandie de la rom se trouve à 0x100000. Comme la rom est une "low-rom", chaque bank fait 0x8000 et donc elle se termine à 0x107FFF. La bank suivante commence à 0x108000 et se termine à 10FFFF. Celle qui suit commence à 0x110000 et se termine à 0x117FFF, etc...

(Note : Si votre rom est une "high-rom", il faut savoir que chaque bank d'une rom "high-rom" fait 0x10000. La première bank vide commencerait donc à 0x100000 et se terminerait à 0x10FFFF. La bank suivante commencerait à 0x110000 et se terminerait à 0x11FFFF. Celle qui suit commencerait à 0x120000 et se terminerait à 0x12FFFF, etc...)

Donc, je disais, on va réinsérer notre dump dans la première (nouvelle) bank vide, donc 0x100000.

On modifie notre ligne de commande d'insertion du début, en tenant compte du changement de plusieurs adresses :

  • L'adresse de début de la table de pointeurs qui était 0x30000 devient 0x100000 (début de la première bank vide).
  • L'adresse de début du script principal qui était 0x302DC devient 0x1002DC.
  • L'adresse de fin du script principal qui était 0x35108 devient l'adresse de fin de bank (vu qu'on veut utiliser l'espace libre disponible dans la bank entière), ce qui donne donc 0x107FFF.

Voici donc la nouvelle ligne de commande pour l'insertion du dump du script principal :

inserer("Dragon Ball Z - Super Saiya Densetsu (J) (V1.1).smc", "Dragon Ball Z - Super Saiya Densetsu (J) (V1.1).tbl", "Dragon Ball Z - Super Saiya Densetsu (J) (J) (V1.1)_Script_Principal.txt", 0x1002DC, 0x107FFF, 0x100000, 366, 2, "X+$8000", little_endian)

(Note : La table de pointeurs originale débutant à 0x30000, il est facile de faire la correspondance avec les nouvelles adresses. Cependant, si le début de la table de pointeurs n'est pas un chiffre rond et ne correspond pas à la base de l'adresse nouvelle bank (ici 0x30000/0x100000), ça peut vite être galère donc il y a un petit truc. Si vous convertissez "2DC" de 0x1002DC en décimal, cela vous donne "732", qui divisé par deux vous donne "366", ce qui coincide évidemment avec le nombre de pointeurs. Pour trouver la nouvelle adresse de début du texte dans votre nouvelle bank, il suffit donc de prendre le nombre de pointeurs de la table de pointeurs, "366", le multiplier par 2 (pointeurs 16-bits, 2 octets par pointeur), ce qui donne "732" puis de le convertir en héxadécimal, ce qui donne "2DC". Il suffit ensuite de prendre l'adresse de début de la nouvelle bank (qui sera également l'adresse de début de la table de pointeurs déplacée), ici 0x100000 et d'y ajouter "2DC", ce qui donne "0x1002DC").

(Note 2 : Selon le calcul des pointeurs, il est possible que le "X+$8000" doive être modifié. Pour la bank 0x100000, il n'y a pas besoin, c'est facile à voir, les pointeurs sont de la forme xx82xx83 etc... Si par contre, par exemple, votre formule de base est "X+$0" et que les pointeurs deviennent de la forme xx02XX03, il faudra modifier le "X+$0" en "X+$8000" (même si la formule avec "X+$0" fonctionne sur la bank original). Le jeu étant une "low-rom", le deuxième octet des pointeurs (qui est le premier en l'inversant, "little endian) ne peut pas être en dessous de "80" vu qu'une bank de "low-rom" commence à "00:8000" (en adresse SNES).


Une fois le dump réinséré ce qui réinsère donc la table de pointeurs et le texte dans la nouvelle bank vide, à 0x100000, il reste à modifier le pointeur 24-bits de la table de pointeurs.

(Note : Petite astuce qui permet d'être sûr que vos modifications sont fonctionnelles et que le jeu n'utilise plus l'ancienne table de pointeurs/les anciens textes : Effacer les données de la rom compris entre 0x30000 et 0x35108 (remplacer tous les octets par des "00". De cette façon, vous effacez l'ancienne table des pointeurs/les anciens textes et vous serez sûrs que si, suite à vos modifications, le texte est fonctionnel dans le jeu, c'est que le jeu utilise bien la table de pointeurs/les textes déplacés dans la nouvelle bank).

Il faut donc calculer le pointeur 24-bits de la nouvelle table de pointeurs. Elle commence à "0x100000", ce qui donne "20:8000" en adresse SNES. Il faut évidemment inverser cette adresse ("little endian") ce qui donne : "0080:20".

On retourne donc à 0x38F1C et on remplace "028006" (vu qu'on avait modifié "008006" en "028006") par "008020".

Bingo, le texte original de Bulma s'affiche de nouveau :-)

Vous avez donc déplacé avec succès la table de pointeurs/le script principal dans une nouvelle bank, ce qui vous octroie "12023 octets" supplémentaire pour la traduction du script principal (ce qui équivaut à 60% d'espace libre en plus). Sur les textes annexes, le gain est bien plus spectaculaie, respectivement "245%", "448%", "2655%" et "3097%" par banks différentes contenant du texte annexe.


Je vais rapidement aborder le cas du pointeur 24-bits en deux morceaux, mais sans trop détailler, c'est quasiment la même méthode que celle décrite juste avant.

Les noms de personnages/ennemis et certains messages de combat sont dans une autre bank, et il y a aussi une table de pointeurs classique, à l'adresse 0x12B66, ce qui donne "02:AB66" en adresse SNES, et en inversant ("little endian") "66AB:02".

Tout d'abord, on dumpe les textes de la bank en question avec "Hareng-Tool" dans notre cas.

Cependant, rechercher "66AB02" ne donne aucun résultat dans la rom.

Le truc est alors de chercher uniquement la partie relative à l'adresse dans la bank, donc ici "66AB", et de refaire la même méthode, décaler tous les pointeurs, ce qui donne "68AB.

On recherche donc chaque "66AB" et on remplace par "68AB", puis on teste dans le jeu, jusqu'à ce que l'un des messages de cette bank change dans le jeu.

Ici, on est un peu chanceux car la première occurence de "66AB", à 0xBC18 est la bonne. En la remplaçant par "68AB", ça modifie bien des textes (dans notre cas, un nom de personnage).


Il ne reste plus qu'à trouver l'octet de la bank, ce qui est un peu plus "compliqué" (mais pas tant que ça).

On va directement réinsérer le dump fait précédemment dans une nouvelle bank vide, ici "0x108000" pour l'adresse de la nouvelle table de pointeurs, "0x10FFFF" pour l'adresse de fin des textes, et pour l'adresse de début des textes, utilisez la méthode que j'ai expliqué plus haut (nombre de pointeurs x2, converti en hexadécimal et additionné à l'adresse de la nouvelle table de pointeurs).

Ensuite, effacez la table de pointeurs/le texte original (ici, entre 0x12B66 et 0x12E9A) contenu dans la rom. Comme expliqué dans le premier exemple, ça permettra lors des tests d'être sûr que vous avez trouvé (ou pas) l'octet de la bank.

Tant qu'on y est, on peut déjà modifier la partie "adresse" du pointeur 24-bits (à 0xBC18), donc la nouvelle table de pointeurs se trouve à 0x108000, ce qui donne "21:8000" en adresse SNES et en inversant ("little endian") "0080:21". On remplace donc "66AB" par "0080" à 0xBC18.

Donc, pour finir, on recherche toujours l'octet de la bank pour le modifier. L'adresse de la table de pointeurs originale était 0x12B66, ce qui donne "02:AB66" en adrese SNES. L'octet de la bank originale est donc "02". On va donc chercher aux alentours (en général, avant le "66AB) et tester de remplacer les "02" que l'on trouvera par "21" (l'octet de la nouvelle bank). Si le texte apparaît, bingo, c'est la bonne adresse, sinon on remet le "02" et on teste le précédent, etc...

Il y a un "02" en 0xBC10, on le remplace en "21", et on teste dans le jeu. Non, le texte est toujours bousillé, donc ce n'est pas le bon. On remet le "02" et on cherche un autre "02" encore avant.

Il y a un autre "02" en "0xBC0E". On le remplace en "21" et on reteste dans le jeu. Oh, le texte original s'affiche de nouveau correctement, c'est donc bien l'octet de la bank que l'on recherchait.

(Note : L'octet de la bank aurait aussi pu être après le "66AB". Cependant, il n'est jamais très loin de l'adresse en question, donc le plus rapide pour commencer est de se limiter à 5 occurences avant et après l'adresse (ici le "66AB") et si vous ne trouvez rien de concluant, élargissez à 10, puis 15, etc... jusqu'à trouver le bon).

Nos table de pointeurs/textes sont donc déplacés et fonctionnels, même si dans ce cas le pointeur 24-bits n'était pas en un bloc.


La technique expliquée dans ce tutorial a des limites. Elle ne sert à rien si le jeu que vous désirez traduire contient déjà des banks entièrement remplis de texte (si vous avez une bank où il n'y a que les pointeurs et le texte, vous aurez beau changer de bank, vous ne gagnerez pas de place). Dans ce cas, il faut passer par l'ASM et programmer une routine de pointeurs 24-bits pour pouvoir dispatcher le texte dans différentes banks.

Elle ne fonctionnera pas non plus si le jeu a des données compressées, et si le pointeur 24-bits (ou tout du moins, l'octet de la bank) se trouve dans ces données compressées, sauf si évidemment vous avez de quoi décompresser/recompresser les données en question (c'est visiblement le cas de "Chrono Trigger").

(Note : Si cette technique ne fonctionne pas, il se peut que, parfois, un numéro de bank puisse être utilisé pour plusieurs données. Donc si on ne déplace qu'une seule donnée et qu'on modifie le numéro de bank, les autres données ne fonctionneront plus).