Substituição da Fonte de um jogo

Iniciado por kuroi, Abril 10, 2018, 15:20:35 PM

tópico anterior - próximo tópico

0 Membros e 1 Visitante estão vendo este tópico.

kuroi

Boa tarde, senhores!

Nos últimos dias, surgiu em meio aos meus estudos de Romhacking, uma dúvida que para mim já era recorrente em jogos da plataforma Sega Genesis (Mega Drive), mas que eu não tinha muitos recursos técnicos para poder elaborá-la...

Esta dúvida me surgiu quando eu estava traduzindo a rom do Langrisser II para Megadrive. Na época eu me deparei com uma característica gráfica um tanto "incomum" no Romhacking nacional...
Primeiramente eu tentei abrir a rom no editor Tile Layer Pro a fim de encontrar a fonte do jogo.
Depois de alguns segundos de busca eu a encontrei no Offset: 00006200 (como segue na imagem abaixo):



Ótimo. Agora seria só uma questão de editar a fonte a fim de adicionar os acentos e os caracteres especiais para que eu possa iniciar o meu Romhacking gráfico! PORÉM, aí que surgiu a minha dúvida...

Por se tratar de uma tradução já feita pelo grupo gringo "MIJET" em cima de uma versão original Japonesa de um jogo de Mega Drive, subintende-se que a antiga fonte que estava alocada no endereço 00006200 seria das duas uma:

1- Uma fonte em japonês composta de Hiraganas e Katakanas
OU
2- Dados aleatórios que não necessariamente fazem parte da fonte do jogo e que foram usados para "receber a colagem" da fonte nova

Para sanar esta dúvida eu busquei a rom original do Langrisser II, dei uma olhada no tal Offset 00006200 e o resultado foi o seguinte:



Ou seja, o Offset em questão estava vazio!

Com base nos dados apresentados acima, minha dúvida consiste em: Na maioria dos jogos de Mega Drive que eu tentei fazer o mínimo de edição, eu não fui capaz de encontrar a fonte original do jogo alocada da ROM original. Porém, em jogos já editados por algum Romhacker, como é o caso do Langrisser II, eu consigo vê-la de modo tão nítido que parece até que ela foi "colada" dentro da rom... Haveria aí algum tal procedimento que permita o redirecionamento da fonte de um determinado jogo para um outro lugar da memória que, posteriormente seria lido pelo emulador durante a execução da rom?

Ou em outras palavras, seria possível a substituição da fonte de um jogo por outra? E se sim, como seria feito este procedimento?

Até mais!!
君の夢が叶うのは誰かの影じゃないぜ。
風の強い日を選んで走ってきた。

tvtoon

Sim, mas é preciso verificar as características da fonte (fixa, variável, largura, altura, tamanho) além de conhecimento sobre como o jogo carrega, ou seja, uma boa profundidade do código em questão.

A princípio, pode-se simplesmente procurar o endereço do início da fonte, para praticar empirismo, mas não é trivial como pode-se achar: o que você pensa ser o início da fonte não é o que o jogo sabe, além de sempre ser bom estar atento aos bancos de memória da ROOM.

denim

Respondendo de forma simples, é só alterar o ponteiro para o gráfico da fonte.

Pode ser fácil de fazer, mas pode ser complicado... Tudo depende do jogo....

Anime_World

Monte a fonte e entre no canal do discord @kuroi. Eu coloco ela pra vc!  :charuto:
nonononono

kuroi

Olá a todos!

Primeiramente eu peço desculpas pela demora na resposta, mas é que estava meio enrolado no trabalho... rsrsrs

Bom, mas a questão é a seguinte: o jogo que eu pretendo traduzir editando a fonte (que até então está um mistério pra mim...) é um RPG antigo da plataforma Mega Drive chamado Traysia (Minato no Toreija, na versão japonesa).

Esse jogo não possui nenhuma compressão textual e utiliza a tabela ASCII para expressar os textos, portanto não há muitos empecilhos para que possa ser feito um Romhacking do mesmo. O meu único problema neste jogo mesmo é a impossibilidade de editar a fonte...

Certa vez eu tentei rodar o jogo usando o debugger do Gens, porém, por não conhecer muita coisa de Assembly de Mega Drive eu acabei ficando no zero a zero...

Anime_World, se eu te passar a ROM na qual eu estou trabalhando, você consegue inserir a fonte e me mostrar onde e como ela deve ser inserida? Vou te mandar uma MP hoje à noite.

Assim que eu conseguir dar um jeito na fonte deste game, eu começarei a compilar o Dumper/Inserter que eu fiz pra ele... me aguardem!!

Até mais!!
君の夢が叶うのは誰かの影じゃないぜ。
風の強い日を選んで走ってきた。

Anime_World

#5
Agora que sei que jogo é, facilita pra ajudar. Porém provavelmente você não conseguiu editar a fonte por isso:


:toligado:

Logo olhando com mais calma... vc encontra em fonte 0xE0000



Se ela é lida em bits e renderizada na VRAM de acordo com o texto. Tirem suas próprias conclusões =)

nonononono

kuroi

Bom dia, Anime_World!

Então, cara... Não sei se é porque eu sou muito Noob, mas é que eu não consegui visualizar a fonte do mesmo jeito que você não...

De certo modo, eu consegui perceber que o Offset da fonte é exatamente 0xE078F, como você indicou, porém os meus gráficos estão bem mais embaralhados do que os que você mostrou aí no seu post... Acredito que seja alguma coisa que eu esteja fazendo de errado no Tile Molester ou porque a minha rom, apesar de também ser a versão americana, não possui a extensão .gen e sim .Bin...

Enfim, não sei exatamente o que pode estar acontecendo...

Até mais!!
君の夢が叶うのは誰かの影じゃないぜ。
風の強い日を選んで走ってきた。

Anime_World

Citação de: kuroi online Abril 18, 2018, 06:41:11 AM
Bom dia, Anime_World!

Então, cara... Não sei se é porque eu sou muito Noob, mas é que eu não consegui visualizar a fonte do mesmo jeito que você não...

De certo modo, eu consegui perceber que o Offset da fonte é exatamente 0xE078F, como você indicou, porém os meus gráficos estão bem mais embaralhados do que os que você mostrou aí no seu post... Acredito que seja alguma coisa que eu esteja fazendo de errado no Tile Molester ou porque a minha rom, apesar de também ser a versão americana, não possui a extensão .gen e sim .Bin...

Enfim, não sei exatamente o que pode estar acontecendo...

Até mais!!

A fonte tem uma leve compressão. Você vai ter q descomprimir ela nesse endereço, editar, recomprimir e inserir novamente.
nonononono

kuroi

Eu andei procurando tutoriais por aí e essa compressão que você mencionou seria a Nemesis?

Até mais!!
君の夢が叶うのは誰かの影じゃないぜ。
風の強い日を選んで走ってきた。

Anime_World

#9
Citação de: kuroi online Abril 23, 2018, 14:18:39 PM
Eu andei procurando tutoriais por aí e essa compressão que você mencionou seria a Nemesis?

Até mais!!

Não... você vai ter q criar o decompressor, é uma compressão simples de dicionário específica desse jogo. Portanto, não adianta procurar por ai que você não vai encontrar ferramentas prontas.

Vou tentar explicar como ela funciona:

Rotina principal:
1 - Cria-se um buffer preenchido apenas de valores 0x11
2 - Posiciona-se o cursor no offset da rom: 0xe097e
3 - Lê 3 bytes da rom e separa eles em A,B,C
4 - Seta o contador como 3 e vai pro modelo m1
5 - Avança 0x1C bytes no buffer
7 - Seta o contador como 3 e vai pro modelo m2
8 - Retorna 0x1C bytes no buffer
10 - Seta o contador como 7 e vai pro modelo m3
11 - Avança 0x1C bytes no buffer
12 - Seta o contador como 7 e vai pro modelo m3
13 - Retorna 0x1C bytes no buffer
14 - Volta pro passo 4 até finalizar a decompressão


Modelo 1:

1. Le o byte da posição atual do buffer e armazena
2. Seta o status como 0
3. Se primeiro bit do byte A (byte &0x80) for 0 vai pro passo 6
4. Se o status for 0 vai pro passo 4.1; se for 1 vai pro passo 4.2
4.1. Com o byte armazenado do buffer executa a operação bitwise ( (buffer &0xF) | 0x11 ) e grava na posição atual do buffer
4.2. Com o byte armazenado do buffer executa a operação bitwise ( (buffer &0xF0) | 0x1 ) e grava na posição atual do buffer
5. Vai pro passo 8
6. Se o status for 0 vai pro passo 6.1, se o status for 1 vai pro passo 6.2
6.1. Com o byte armazenado do buffer executa a operação bitwise ( (buffer &0xF0) | 0xF ) e grava na posição atual do buffer
6.2. Com o byte armazenado do buffer executa a operação bitwise ( (buffer &0xF) | 0xF0 ) e grava na posição atual do buffer
7. Vai pro passo 8
8. Movimenta os bits do byte A 1 bit para a esquerda (byte << 1)
9. Alterna o status (Se for 1 passa pra 0, se for 0 passa pra 1)
10. Se já leu todos os 8 bits do byte A vai pro passo 11, se não leu volta pro passo 3
11. Avança o cursor do buffer 1 byte
12. Decrementa (-1) o contador; Se for igual a 0 volta pra rotina principal


Modelo 2:

Mesma coisa do modelo 1 porém usando o byte B


Modelo 3:

Com os bytes B e C formando um par executa o modelo 1
nonononono

kuroi

Certo. Deixa eu ver se eu entendi...

Para que as minhas dúvidas fiquem mais organizadas, eu vou separar os tópicos:

Primeiramente você me disse eu teria que criar um "buffer" composto só de 0x11, certo?
Mas isso significa que eu poderia interpretá-lo como um "array" de "n" posições, sendo que "n" seja o número total de Bytes da fonte que será descomprimida, ou eu deveria interpretá-lo como um espaço que guarda as 8 linhas que compõem um Tile da fonte descomprimida?

Pelo que eu entendi do algoritmo que você me passou acima, convertendo em bits todos os passos, eu teria:

1 - Ler a ROM e armazenar três Bytes da mesma a partir do endereço 0xe097e

Os Bytes que eu armazenei nas variáveis A, B e C são:

A=F8 -> 11111000

B=08 -> 00001000

C=40 -> 01000000

Os próximos 5 Bytes a seguir, eu só coloquei aqui pra completar o Tile...

A=82 -> 10000010

B=08 -> 00001000

C=20 -> 00100000

A=82 -> 10000010

B=08 -> 00001000

Portanto, o Tile lido seria:

11111000
00001000
01000000
10000010
00001000
00100000
10000010
00001000

2- Com os três Bytes armazenados nas variáveis A, B e C, eu acredito que eu tenha que avançar mais três Bytes da ROM, para que a próxima Iteração da leitura seja feita a partir do quarto Byte. Neste passo, você disse que o fluxo de dados deve ser alterado para a rotina "m1".

3- Na rotina "m1", eu leio a posição atual do "buffer" (que no meu caso é 0x11???) e armazeno em uma variável.

4- Depois devo setar o valor zero em uma variável chamada Status.

5- Neste ponto será feita uma operação bitwise & que servirá para verificar se o primeiro bit do Byte atual do Buffer é igual a zero, portanto teremos:

valor do buffer atual= 0x11 -> 00010001

valor que será usado para verificar via bitwise= 0x80 -> 11110000

Portanto teremos:

11111000 &
10000000
------------------
10000000 -> 0x80

6- Depois temos que verificar se o valor do status é igual a zero. Neste caso é, portanto:

((0x11 & 0xF0) | 0x0F)

00010001  &
11110000
------------------
00010000  |
00001111
------------------
00011111 -> 0x1F

Com isso, o Byte que era 0xF8 na ROM, passa agora a ser: 0x1F. Ou seja:

Isso:
0xF8 = 11111000

Passa a ser isso:
0x1F = 00011111

Na primeira linha do primeiro tile da Fonte descomprimida, claro...

8- Depois disso, o seu algoritmo diz que os bits do Byte armazenado no buffer devem ser deslocados 1 bit para a esquerda, portanto eu teria:

00011111 << 00111110 -> 0x3E

9- Depois tenho que alternar o valor do Status (se for zero, transformar em um. Se for um, transformar em zero)

10- Incrementar um Byte ao Buffer, para que o próximo Byte seja gravado no buffer + 1

11- Decrementa o contador em -1 e volta à rotina principal

Bom, eu acredito que me enrolei no meio do algoritmo e acabei não entendendo muita coisa no fim das contas... Estou escrevendo um programa em C que lê a ROM a partir do ponto em que você indicou no algoritmo, retira os Bytes da fonte, realiza os cálculos necessários e grava os Bytes descomprimidos em um novo arquivo binário. A partir daí eu posso editá-lo e posteriormente comprimí-lo novamente.
Essa seria uma boa forma de se proceder para a descompressão e compressão dessa fonte?

Até mais!!
君の夢が叶うのは誰かの影じゃないぜ。
風の強い日を選んで走ってきた。

Anime_World

#11
Bom, vamos lá.
O Buffer nada mais é um arquivo na memória de tamanho 0xFFFF.
Como você vai fazer isso... se é com array ou outra coisa. Fica a seu gosto.

o Buffer recebe um byte fill de 0x11, ou seja, é todo preenchido com valores 0x11.

Quanto a rotina principal ficaria algo assim em python:

        if (int((byte&0x80) >> 7) == 0):
            if (mirror%2 == 0):
                output.write((buf&0xF)|0x10)
            else:
                output.write((buf&0xF0)|0x1)
        else:
            if (mirror%2 == 0):
                output.write((buf&0xF)|0xF0)
            else:
                output.write((buf&0xF0)|0xF)
        mirror+=1
        byte=byte<<1
        if (mirror%2 == 0):
            output.seek(0x1)


Quanto a forma como proceder, sim, está é uma boa forma. Você pode extrair a fonte e manter as rotinas originais de leitura e escrita na RAM. Além de adicionar os caracteres a mais que você precisa.

Detalhe que não adianta apenas você aplicar a mascara 0x80 pra ler o primeiro bit, você tem q adicionar o bitshift pra direita de 7.
Isso no caso de ser apenas 1 byte de controle, quando for dois a coisa muda. Pra (byte&0x8000) >> 15
nonononono