[NES] Might Final Fight-Ponteiros de diálogos

Iniciado por Ingram, Maio 29, 2023, 22:55:29 PM

tópico anterior - próximo tópico

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

Ingram

Olá. Há algum tempo que não estou ativo em romhacking, e estou a tentar aprender um pouco mais sobre a NES. Na verdade já fiz alguns hacks para NES (principalmente para amigos) mas já passaram alguns anos e regressar não está a ser fáci.

Especificamente, queria fazer algumas modificações ao Mighty Final Fight. Não penso que sejam modificações difíceis em si (especialmente para hackers mais avançados9, mas simplesmente não estou a conseguir encontrar os valores necessários. Mais especificamente, estou a tentar encontrar o seguinte:

1) Bytes que definem a velocidade das personagens em movimento. Mesmo sem recorrer a debuggers, é possível encontrar alguns valores relativos às personagens mediante comparação direta entre, por exemplo, valores afetados por Game Genie e um ROM normal (ou até fazer uso de mapas de RAM). Porém, não consegui ainda encontrar nada relativo a velocidade. O intuito é descobrir uma tabela que contenha os valores dos "atributos" das personagens. Eu já encontrei valores que definem a força dos ataques, por exemplo, mas nada relativo à velocidade.

2) Os pointers de diálogo. Este é o caso mais "bicudo" porque penso que é a primeira vez que não estou a conseguir encontrar pointers de NES. Além de que também são usados 5 bytes extra antes do diálogo, e não estou a conseguir perceber se os pointers estarão direcionados para eles também. Exemplo:



No ROM (da versão norte-americana) isto encontra-se em:
9D81 (com header) / 9D71 (sem header): 35 00 02 02 02
9D86/76: 17 14 17 78 17 14 17 2B 00 18 00 10 1C 00 23 17 21 10 22 17 14 21 2C FF (diálogo indicado acima).

Na primeira linha de código, os 5 bytes precedem sempre "blocos" de diálogo (ou seja, nao é usado sempre que há um diálogo, mas é usado onde o jogo define blocos distintos de texto). O valor $35 define o som a usar ao imprimir cada letra no ecrã; ainda não consegui definir os outros quatro valores (presumo que apontem para a localização das letras no ROM, mas ainda não validei isso). A segunda linha pertence ao diálogo em si. $17 = H, $14 = E, $78 = -, etc. $FF termina uma sequência e passa à próxima ($FE não é apresentado mas é usado para novas linhas ou espaçamento).

Ou a instrução é indireta, ou algo me está a passar ao lado, mas após múltiplas tentativas simplesmente não consigo encontrar os pointers para o texto. Também não ajuda ter sido necessário adicionar uma header ao jogo, porque estou a usar o Mesen, e o emulador consegue ler ROMs sem header, mas exige uma sempre que é feita uma modificação, por isso os cálculos também poderão estar errados. Além disso, apenas sei que cada bloco de texto está claramente "à espera" de encontrar apenas texto, porque tentar reapontar com comandos JMP não resulta.

Gostaria de saber se alguém me pode ajudar a encontrar estes valores sendo que o mais interessante seria entender o que o jogo está a fazer com o texto (eu sei que a Capcom costumava implementar coisas de um modo um pouco estranho nos seus jogos, e pode ser um desses casos). Por outro lado, ter noção dos atributos das personagens também seria curioso (para hacks mais generalistas).

Obrigado!

Anime_World

#1
A melhor forma de encontrar ponteiros no NES é através do Debugger, você pode usar o Mesen para isso.
De toda a forma, antes de tudo é preciso entender como os endereços são dividos em bancos. Caso contrário você irá encontrar diversos valores iguais espalhados pela rom e terá de vir testando um a um pra saber qual é o ponteiro. No geral fiz uma lista de coisas importantes a se considerar:

1 - NES é little endian, portanto você terá que inverter o par de bytes (word).
2 - É preciso saber se a ROM possui ou não header. Caso possuir header é necessário subtrair o valor dele do par de bytes (no caso do NES o valor do header é 0x10)
3 - É preciso saber como funcionam os bancos para calcular o valor do ponteiro corretamente. No geral é o endereço dividido pelo tamanho do banco.

nonononono

Ingram

Olá Anime_World, obrigado pelos lembretes!

Posso dizer que usei o debugger no texto da introdução, e penso que encontrei os valores necessários para modificações (os primeiros testes foram positivos, pelo menos, em termos de modificar onde o texto começa a ser lido e até que bloco de texto usar).

Porém, mesmo com o debugger ativo (tive de alternar entre o do Mesen e do FCEUX), ainda sinto alguma dificuldade com o texto restante. Passo a explicar: o primeiro diálogo do Trasher surge em 0x9D86 no ROM, sendo que este valor é "errado" por causa da header.

Portanto para propósitos de debugging, inseri o breakpoint quando o offset 0x9D76 (9D86 - 10) fosse lido/executado. Assim que o diálogo começa, o Mesen aponta para o seguinte conjunto de instruções, cujo local no ROM pode ser visto com o editor de memória:



O FCEUX estrutura o código de uma maneira um pouco mais inteligível para mim:

> 00993D: B1 0C     LDA ($0C),Y @ $9D76 = #$17
  00993F: C9 F9     CMP #$F9
  009941: D0 03     BNE $9936
  009943: 4C D6 99  JMP $99D6
  009946: C9 FA     CMP #$FA
  009948: D0 03     BNE $993D
  00994A: 4C D1 9A  JMP $9AD1
  00994D: C9 FB     CMP #$FB
  00994F: D0 03     BNE $9944
  009951: 4C D9 9A  JMP $9AD9
  009954: C9 FC     CMP #$FC
  009956: D0 03     BNE $994B
  009958: 4C 18 9B  JMP $9B18
  00995B: C9 FD     CMP #$FD
  00995D: D0 03     BNE $9952
  00995F: 4C A4 9B  JMP $9BA4
  009962: C9 FE     CMP #$FE
  009964: D0 03     BNE $9959
  009966: 4C 7E 9B  JMP $9B7E
  009969: C9 FF     CMP #$FF
  00996B: D0 03     BNE $9960
  00996D: 4C 9B 99  JMP $999B
  009970: 9D 83 07  STA $0783,X @ $0783 = #$00


Mas não consigo encontrar um valor que se assemelhe a um pointer (pelo menos a que esteja habituado). No texto de introdução, os valores que até agora percebi serem responsáveis não estão juntos, no sentido em que os bytes responsáveis estão afastados por vários outros bytes. Até pode estar a acontecer o mesmo aqui, mas..... :/


Anime_World

#3
A tabela de ponteiros:


Os ponteiro é esses dois bytes destacados em azul mais escuro. Juntos eles formam o par de bytes 0x9D71.

Basicamente tu tem o endereço 0x9D86
Subtraindo o header temos 0x9D76
Desse endereço temos que subtrair 0x5 bytes, portanto: 0x9D76-0x5=0x9D71

Depois o par de bytes do endereço é separado: $9D e $71
o primeiro valor é inserido na tabela de ponteiros e o segundo também com um intervalo de 79 bytes entre um e outro.

A primeira parte da tabela começa em 0xA4FD e a segunda parte em 0xA54C

Como cheguei a essa conclusão? Simples, lendo o código da rotina:


991C  LDA $A54C,Y   # Carrega o valor de 0xA54C no registrador A, valor=0x71
991F  STA $0C       # Salva o valor no endereço 0xC da RAM
9921  LDA $A4FD,Y   # Carrega o valor de 0xA4FD no registrador A, valor=0x9d
9924  STA $0D       # Salva o valor no endereço 0xD da RAM

9926  LDY $AA       # Carrega o valor do endereço da RAM 0xAA no registrador Y, valor=0x0
9928  INY           # Incrementa Y em 1, valor=0x1
9929  INY           # Incrementa Y em 1, valor=0x2
992A  INY           # Incrementa Y em 1, valor=0x3
992B  INY           # Incrementa Y em 1, valor=0x4
992C  INY           # Incrementa Y em 1, valor=0x5 (Lembra do 0x5 que subtraimos?)

992D  LDA ($0C),Y   # Carrega no registrador A o valor que salvamos no endereço $0C da RAM
                    # Depois soma ao valor no registrador Y (0x5), o valor no registrador A (0x9D71)
nonononono

Ingram

Olá Anime_World - obrigado pela ajuda! :)

Já percebi o que estava a fazer de errado, e até me sinto mal por isso - esqueci completamente a necessidade de ler o código anterior ao breakpoint (ou seja, estava a ler a partir do offset onde o Mesen estava a parar, e quando parava, apenas consultava os valores hexadecimais em torno dos bytes referenciados). Quando comecei a ler a resposta, não estava a perceber onde estavam os INY mencionados (que resultam no 0x5). Tenho de ser mais rigoroso na leitura do código.

Obrigado mais uma vez ^_^