segunda-feira, 5 de setembro de 2022

O Panfleto Pitfall! para Commodore64 no MSX

Inspirado por um colega do grupo MSX Brasil (Facebook), analisei com mais cuidado um vídeo postado no canal do Youtube "8-bit Show and Tell" sobre um panfleto publicado pela Actvision nos anos 80 contendo uma listagem de um programa para o Commodore 64. O programa é relativamente simples, mas como é assinado pelo próprio David Crane (autor de clássicos do Atari 2600 como Pitfall! e Decathlon), concordei com o colega que ele merecia uma versão para MSX.

 

Panfleto publicado pela Actvision em 1984

 

O programa do panfleto está em BASIC, mas tem uma certa quantidade de dados (linhas DATA) referentes à imagem do Harry na tela e também um pouco de código de máquina. Resulta na animação do personagem Pitfall Harry correndo olimpicamente pela tela, desparecendo no lado direito e reaparecendo no lado esquerdo. Ele para quando a tecla de espaço é pressionada.

A maior curiosidade talvez seja o fato de que mesmo que o programa BASIC seja parado ("break"), o personagem continua a correr pela tela. Isto porque existe uma rotina em linguagem de máquina ligada à interrupção do sistema.

 



Os sprites no MSX

Não foi muito difícil replicar o programa no MSX. Na realidade eu não desassemblei o programa original, apenas reproduzi seu comportamento no MSX. 

Entretanto, não sem algumas adaptações. O chip gráfico do Commodore 64 tem capacidade de produzir sprites multicoloridos, de até três cores, que é o caso daqueles usados no programa original. O MSX não tem essa capacidade, pois os sprites possuem apenas uma cor. A única maneira de contornar essa situação é sobrepondo sprites de cores variadas para obter o mesmo resultado.

Assim, os 6 sprites coloridos no Commodore 64 (5 representando a corrida e 1 do Harry parado) viraram 18 sprites no MSX. A tarefa de desenhá-los e de gerar os dados correspondentes foi bastante facilitada pelo aplicativo web chamado TinySprite, de autoria do Rafael Janone. Depois, no MSX, eu só tive o trabalho de converter os dados de hexadecimal para decimal e assim diminuir o tempo de carregamento dos dados.

Outro detalhe (que francamente não sei como funciona no Commodore 64) é que o Harry desaparece ao poucos do lado direito e reaparece, também aos poucos no lado esquerdo da tela. Ocorre que a resolução horizontal (eixo x) do MSX é de 256 pixels. No MSX-BASIC o efeito de um sprite aparecer gradualmente na margem esquerda da tela é obtido com valores negativos no eixo x do sprite, de modo que quando o valor 0 é atingido, o sprite já aparece por completo na margem esquerda. 

Entretanto, em linguagem de máquina o eixo x é representado por apenas um byte e, sendo assim, este pode assumir valores de 0 a 255, que são todos considerados como positivos pelo VDP. Para que o sprite inicie no eixo x antes do início da margem esquerda, é necessário setar o bit 7, chamado early clock, do quarto byte de atributos do sprite (que também contém sua cor). Isso irá localizar o sprite 32 pixels para dentro da margem esquerda. Não é o fim do mundo, mas esse procedimento demanda que o programador preveja manualmente quando o early clock deve ser setado ou zerado e, ainda, que se faça o devido ajuste no valor do eixo x no programa assembly.

A rotina de interrupção

Atrelei o programinha em assembly ao gancho do sistema (H.TIMI). Isso faz com que a animação do Harry seja atualizada 60 vezes por segundo no caso das máquinas PAL-M e NTSC (60Hz de frequência vertical) e 50 vezes por segundo no caso das máquinas PAL-G/PAL-N (50Hz). Como resultado, assim como no programa original, o personagem continua correndo pela tela mesmo com a interrupção do programa BASIC pelo usuário com um Control+Stop (break). 

Entretanto, uma diferença é que no caso do Commodore 64 o sprite pode ser programado para aparecer debaixo das letras que estão na tela. Já no MSX isso simplesmente não é possível, uma vez os planos dos sprites sempre sobrepõem o plano no qual os caracteres são impressos por definição do hardware (VDP). O Harry no MSX só pode correr por sobre o texto, nunca sob ele.

O que mais não ficou igual

Uma das coisas que mais me chamou atenção no vídeo do "8-bit Show and Tell" foi que o programa BASIC era interrompido e então o comando LIST era executado e o Harry continuava a correr sob a listagem do programa.

Infelizmente, não consegui fazer que esse efeito funcionasse a contento no MSX. No meu programa, tudo está bem quando comandos simples são executados, como um PRINT ou algo assim. Entretanto, se diversos comandos PRINT ou mesmo um único LIST é executado de modo que ocorra um scroll da tela, a memória de vídeo (VRAM) é afetada e coisas estranhas aparecem na tela. Os comandos CLS e SCREEN também não funcionam como deveriam, esculhambando a tela com lixo da VRAM.

Quebrei bastante a cabeça tentando evitar a corrupção da memória de vídeo na execução desses comandos enquanto o Harry corria pela tela e cheguei a conclusão que não há forma simples de evitar que as rotinas do BIOS utilizadas pelos comandos do MSX-BASIC conflitem com o programinha do Pitfall. É que essas rotinas acessam os registros do VDP de forma mais intensa e acabam colidindo como acesso do programa do Pitfall ao VDP e à VRAM (60 vezes por segundo) gerando lixo na memória de vídeo. 

Pela mesma razão, alterar as cores dos sprites do Harry enquanto ele está em movimento também acarretam a corrupção da memória de vídeo, estragando um pouco a brincadeira (update 20.09.22: modifiquei a rotina em linguagem de máquina e agora é muito raro que haja corrupção na memória de vídeo utilizando os pokes para alteração das cores do Harry).

Assim, eu me dei por satisfeito e deixei o programa como está (e no fim ponho a culpa no hardware... rs).

Para quem quiser tentar, as cores da roupa podem ser trocadas para azul, por exemplo, com POKE &HE0C9,4. É esse último valor "4" que contém o código da cor, que pode ser de 0 a 15. 

A cor do cabelo/cinto/sapatos e a cor da pele do Harry também podem ser mudados alterando-se o valor dos endereços &HE0C1 e &HE0C5 respectivamente, usando o mesmo critério descrito acima. Por exemplo, POKE &HE0C5,6:POKE &HEC1,10 deixa o Harry com pele "morena" e cabelos louros. 

O programa

Enquanto o programa BASIC estiver sendo executado, a tecla ESPAÇO (na realidade, qualquer tecla) faz com que o Harry pare por um instante. Esta é a única interação que o usuário pode ter com o personagem. Isto está no programa original, mas provavelmente minha implementação de como isso é feito é diferente (eu utilizei uma flag para que o BASIC indique ao programa assembly que uma tecla foi pressionada).

Após interromper o programa BASIC com Control+Stop, o Harry continua correndo até que o usuário comande GOTO 180, que irá desligar a rotina de interrupção, colocando um C9 (opcode RET) no início do gancho do sistema H.TIMI. O correto mesmo seria que a rotina original do gancho do sistema fosse salva e depois recuperada. Mas como isso não funcionaria se o programa fosse iniciado novamente com RUN (porque o gacho já alterado seria salvo), optei por uma solução menos elaborada (displicente, talvez, mas funcional).

Como explicado anteriormente, os endereços &HE0C1, &hE0C5 e &HE0C9 podem ser alterados com o comando POKE para mudar as cores do Harry.

Disponibilizo no link abaixo a imagem de disco contendo o programa BASIC para MSX, com comentários delimitando os blocos e, ainda, a rotina assembly responsável pela animação do Harry, no formato do MegaAssembler em que foi criado. Este está sem comentários, pelo que peço desculpas. Incluí ainda, no pacote zip, a listagem do programa assembly em formato texto.

Download (update 20.09.22)


Relógio BCD para o TK85 no ZX Assembler da Artic

Um relógio BCD (binary-coded decimal) mostra os dígitos decimais em formato binário. Cada dígito decimal das horas, minutos e segundos está ...