domingo, 29 de novembro de 2015

Convertendo jogos para uso com Paddles (5)

Pesquisa do(s) endereço(s) de memória que armazenam as coordenadas do personagem na tela

Recapitulando do artigo anterior, descobrimos que a função localizada no endereço 0x4f1c é responsável pela leitura dos comandos do jogador, seja via teclado ou via joystick. Também descobirmos que esta função recebe um parâmetro contido no registrador A.

Endereço: 0x4f1c

Função:   Le_controles

Entrada: A = 0xff -> Lê joystick 2 ou teclas 'Z' e 'C'
         A<> 0xff -> Lê joystick 1 ou setas direcionais

Retorno: A = Direção
         A = 
                7  1  3
                 \ | /
          (Z) 7 -- 0 -- 3 (C)
                 / | \      
                7  5  3
           
Agora precisamos rastrear os trechos do jogo que chamam e função 0x4f1c e ver o que acontece quando os valores 7 e 3 são retornados, o que corresponde aos comandos de 'esquerda' e 'direita' respectivamente.


Analisando a primeira chamada, a partir de 0x4cc3 temos que quando a chamada a 0x4f1c retorna 3, o endereço 0x4f03 é chamado

E quando a chamada a 0x4f1c retorna 7 o endereço 0x4f10 é chamado

Vamos então analisar estes dois endereços:


O que encontramos nesta chamada é um bom indício de que estamos perto, pois ambas as chamadas limitam o valor da variável contida em 0xd010. Para a direita o valor é limitado a 100 (0x64 em hexadecimal). Se o valor for menor do que 100 então o conteúdo da posição de memória em 0xd010 é incrementado. Já para a esquerda o valor é limitado a 10 (0x0A).

Em ambos os casos, caso a posição em oxd010 seja alterada a função salta para 0x4ddc. Vamos ver o que tem lá:


Em 0x4ddc acontece o seguinte:
- A posição em 0xd012 é incrementada com módulo 2. Isso talvez sirva para comandar o sprite do personagem conforme ele se movimenta, mas por enquanto não importa.
- A posição de memória em 0xd015 é zerada. Isso pode ser um flag ou algo assim.

Vamos voltar um pouco e retomar a pista do endereço de memória 0xd010 e ver onde este endereço é usado e como é usado:

Bom, este endereço é utilizado em 18 lugares! São dezesseis lugares a mais para pesquisar (dois nós já vimos). Isso fica para o próximo artigo.







sábado, 28 de novembro de 2015

Convertendo jogos para uso com Paddles (4)

Pesquisa das funções que fazem a leitura do teclado / joysticks (continuação)

Começamos nossa análise ao redor dos endereços onde a função GTSTK (Get Stick) é chamada.

    Line 2043: 4f37 cdd500    call    00d5h
    Line 2058: 4f49 cdd500    call    00d5h
    Line 2061: 4f4f cdd500    call    00d5h
    Line 4602: 6214 cdd500    call    00d5h


O objetivo é rastrear as referências a esta chamada. Queremos saber se a leitura do Joystick é feita no meio do loop do jogo, ou se é chamada a partir dele. Devemos seguir o código para trás e para a frente até chegar a um bloco estanque. No caso temos todo o bloco compreendido entre os endereços 0x4f1c e 0x4f5e.



Pesquisando então pelo endereço 0x4f10 achamos quatro chamadas:


 Precisamos analisar esta função e ver o que ela recebe de entrada e o que retorna de saída. As primeiras instruções mostram que se o registrador A for igual a 0xFF na entrada, a função desvia para 0x4f48.

Analisando a primeira parte da função (chamada com A!=255), vemos que a matriz de teclado também é lida (função SNSMAT - 0141h) pesquisando-se as teclas 'C' (row 3 bit 0)  e 'Z' (row 5 bit 7)

4f1f 3e05      ld      a,05h
4f21 cd4101    call    0141h
4f24 1607      ld      d,07h
4f26 cb7f      bit     7,a       Testa 'Z'
4f28 3e07      ld      a,07h     Retorna 7 (esquerda)
4f2a c8        ret     z

4f2b 3e03      ld      a,03h
4f2d cd4101    call    0141h
4f30 cb47      bit     0,a       Testa 'C'
4f32 3e03      ld      a,03h     Retorna 3 (direita)
4f34 c8        ret     z


Caso nenhuma destas teclas esteja pressionada, a rotina lê o Joystick 2. Caso o joystick 2 esteja em repouso, ou na posição 1 (cima) ou na posição 5 (baixo) a função retorna. Por outro lado, se o joystick estiver nas posições 2,3,4 (direita e diagonais) a função retorna o valor '3' (direita). Analogamente, se a posição for superior a 5 (6,7,8 - esquerda e diagonais) a função retorna o valor '7' (esquerda).

4f35 3e02      ld      a,02h
4f37 cdd500    call    00d5h
4f3a fe02      cp      02h              retorna se menor que 2
4f3c d8        ret     c

4f3d fe05      cp      05h              retorna se igual a 5
4f3f c8        ret     z

4f40 3803      jr      c,4f45h          ; (+03h)
4f42 3e07      ld      a,07h            retorna 7 (esquerda)
4f44 c9        ret

4f45 3e03      ld      a,03h            retorna 3 (direita)
4f47 c9        ret


Os valores 3 e 7 correspondem às posições direita e esquerda, respectivamente que são os mesmos que a função GTSTK retorna quando o joystick é acionado para a esquerda ou a direita.


Já o outro trecho de código lê o teclado e o joystick 1 e também retorna 3 ou 7 caso um destes dois dispositivos esteja nas posições direita/diagonais-direita ou esquerda/diagonais-esquerda.

4f45 3e03      ld      a,03h         Retorna 3 (direita)
4f47 c9        ret

4f48 af        xor     a             A=0, Direcionais teclado
4f49 cdd500    call    00d5h
4f4c f5        push    af
4f4d 3e01      ld      a,01h         A=1, Joystick 1
4f4f cdd500    call    00d5h
4f52 c1        pop     bc
4f53 b0        or      b
4f54 fe02      cp      02h
4f56 d8        ret     c

4f57 fe05      cp      05h
4f59 c8        ret     z

4f5a 38e9      jr      c,4f45h          ; (-17h)
4f5c 3e07      ld      a,07h         Retorna 7 (esquerda)
4f5e c9        ret



Este trecho inteiro é candidato a local para se instalar os patches, mas agora é preciso descobrir como o jogo transforma o resultado dos controles direcionais em coordenadas da personagem, que é o tema do próximo artigo.


Convertendo jogos para uso com Paddles (3)

Pesquisa das funções que fazem leitura do teclado / joysticks

O MSX só tem duas vias para comandos do usuário:  O Teclado e as Portas de Joystick. Sendo assim todos os jogos necessariamente têm que acessar estas vias. Para isso o jogo pode usar as rotinas da BIOS (recomendado) ou ler diretamente as portas de I/O. Para cada jogo precisamos descobrir o método ou os métodos utilizados.

Comecemos pelas rotinas da BIOS. Segundo o Livro Vermelho, temos:

ADDR. NAME   TO    FUNCTION
------------------------------------------------

00D5H GTSTCK 11EEH Get joystick status
00D8H GTTRIG 1253H Get trigger status

00DEH GTPDL  1273H Get paddle status
0141H SNSMAT 1452H Read row of keyboard matrix

A primeira rotina a ser procurada é a GTPDL (00DEH). Se o jogo a utiliza nosso trabalho está concluído. Mas infelizmente para o Penguin Wars ainda não foi dessa vez.


A próxima é a GTSTK (00d5h). Esta retornou em 4 endereços.

Em seguida leremos GTTRIG (00d8h). Também é chamada em 4 locais.

Por último SNSMAT (0141h). Novamente, a função é chamada 4 vezes
Estes endereços serão o ponto de partida para a pesquisa das funções que guardam a posição da personagem na tela. 

quarta-feira, 25 de novembro de 2015

Convertendo jogos para uso com Paddles (2)

Disassembly do Jogo

Existem várias ferramentas para desassemblar código de Z80, mas eu gosto de usar o DZ80. O jogo que eu escolhi para adaptar foi o Penguin Wars. A ROM de MSX deste jogo tem 32Kbytes e as configurações para o disassembly ficam como na figura abaixo:


Se tudo estiver certo, a listagem em assembly gerada deve começar no endereço 0x4000 e os dois primeiros caracteres devem ser 0x41 e 0x42






Convertendo jogos para uso com Paddles

Apesar do padrão MSX estabelecer um padrão para Paddles e tanto a BIOS quanto o BASIC terem suporte a eles, nenhum jogo que eu tenha notícia os utiliza. O único jogo que utiliza Paddles é o Arkanoid, porém este utiliza um padrão próprio, em vez de usar o padrão nativo.

Pois bem, a mecânica de jogo de alguns títulos utiliza somente movimentos laterais e são ótimos candidatos a adaptações para uso de Paddles. Um exemplo é o Galaga.

Lá pelos idos de 1990 eu construí um Paddle para o MSX seguindo as especificações do Livro Vermelho do MSX. Na falta de jogos que o utilizassem eu consegui desassemblar justamente o Galaga de forma a convertê-lo para o uso de Paddles. Naquela época eu ainda usava fitas cassete e tinha que me utilizar de programas que eu mesmo escrevia de forma a poder fazer a adaptação. Como todo o processo era muito trabalhoso eu nunca me aventurei a converter nenhum outro jogo. Hoje em dia com emuladores, desassembladores, etc esta tarefa é um pouco mais facilitada mas mesmo assim não é trivial, uma vez que cada jogo, mesmo da mesma desenvolvedora, funciona de maneira diferente na hora de ler as interfaces com o usuário (teclado, joysticks).

Mas de uma maneira geral a adaptação segue os seguintes passos:

- Disassembly do jogo
- pesquisa das funções que fazem leitura do teclado / joysticks
- pesquisa do(s) endereço(s) de memória que armazenam as coordenadas do personagem na tela
- Inclusão das chamadas de leitura do paddle em substituição às funções de tratamento de teclado e mouse.
- criação de um arquivo de 'patch' para carregamento do jogo com ou sem a modificação.