Hola a todos. Viendo el interés por convertir juegos de disco a cartuchos de GX4000, pensé en preparar un breve tutorial/FAQ (bueno, en mi cabeza empezó siendo breve) detallando los métodos que utilizo. Y una aclaración: solo llevo poco tiempo haciendo esto y voy aprendiendo sobre la marcha, así que por favor no os toméis nada de lo que diga como palabra sagrada; para nada soy un experto en el hardware de Amstrad. Sin embargo, disfruto muchísimo aprendiendo sobre esta máquina antigua y poniéndome a prueba; puede ser un pasatiempo muy gratificante y adictivo.
Cuando decidí probar suerte por primera vez, leí este buen artículo del fanzine de CPC: https://www.cpcwiki.eu/imgs/6/6f/CPC_Fanzine_-_GX4000_conversion.pdf
Ese artículo tiene mucha información útil que me sirvió para empezar, y tuve la gran suerte de que el primer juego que elegí convertir, Dynamite Dan, era adecuado para la conversión usando los métodos descritos. Desafortunadamente, hay varias situaciones que el artículo no menciona y, de hecho, la mayoría de los juegos que he convertido desde entonces no se podrían convertir con los métodos de ese artículo.
El artículo describe cómo usar un editor hexadecimal para modificar directamente un archivo de disco y hacer cambios a nivel de bytes en el código del juego. Esto solo funciona en situaciones donde el programa no está ni comprimido ni encriptado. En la mayoría de los juegos que intentéis convertir, el archivo de disco con el que empecéis estará «crackeado», y a los crackers les chifla encriptar y (sobre todo) comprimir sus trabajos. Aunque con formas rudimentarias de encriptación (a menudo usando simples algoritmos XOR) se puede trabajar hacia atrás para averiguar cómo deberían ser los bytes en el disco (yo hice esto con Shogun), es muy laborioso y requiere una concentración e historial de notas enormes. No es un camino que recomiende.
¿Por qué suele ser necesario empezar con una versión crackeada en lugar de una versión comercial? En muchos casos, los juegos de disco cargan datos desde el disco en algún momento, aunque solo sea una pantalla de carga. Muchos juegos grandes cargan cada nivel individualmente. A menudo, los juegos comerciales accedían directamente al controlador de disquetera en lugar de hacerlo a través de la ROM de AMSDOS. Tan pronto como un juego hace esto, no se puede convertir con nocart, por lo que no funcionará en la GX4000. Los crackers a menudo cogían juegos comerciales y reemplazaban el acceso directo a la disquetera por llamadas al firmware de AMSDOS, ya que esto permitía eludir la protección contra copia, etc. Por lo tanto, las versiones crackeadas a menudo funcionarán con nocart tal cual.
Hay dos formas fiables de comprobar si el archivo .dsk que tenéis utiliza el firmware o no. Primero, cargadlo en WinAPE e id al menú «Edit disk». Haced clic en «Show system files». Si veis múltiples archivos, lo más probable es que funcione con nocart tal cual, ya que está usando archivos estándar de AMSDOS con encabezados estándar. Para confirmarlo, podéis ejecutar el juego en WinAPE y establecer un punto de interrupción (breakpoint) en el FDC (controlador de disquetera) a través de Debug → Breakpoints → Input/Output → Add → FDC Data. Cuando el depurador se detenga cuando el juego intente cargar datos, echad un vistazo a la parte inferior del depurador y ved si la casilla de «Upper ROM» está marcada. Si lo está, es buena señal, significa que se está utilizando AMSDOS.
Debo aclarar que no he probado absolutamente todos los emuladores que existen, pero de los que he probado, WinAPE es con diferencia el mejor para hacer cualquier tipo de desarrollo, a pesar de tener un par de pequeños detalles que me encantaría cambiar.
Así pues, convertí un par de juegos utilizando el método de edición manual del archivo .dsk (con un editor hexadecimal, HxD), pero me pareció frustrante porque era muy difícil llevar un seguimiento de los cambios realizados, y si metías la pata en un solo byte podías volver al punto de partida o quedar en un estado indeterminado. Como programador de profesión, estoy acostumbrado a usar control de versiones como git para poder dividir todos mis cambios en pequeños commits y ver siempre un historial con notas de lo que he hecho.
Así que con el siguiente juego que convertí, decidí experimentar con un método alternativo que resultó ser un éxito, y es el método que he utilizado con cada juego que he convertido desde entonces.
Empiezo con un proyecto en blanco de CPCTelera. Posiblemente os suene esta excelente herramienta, es un compilador de C para Amstrad que genera un archivo .dsk. Hay muchísima documentación si la buscáis en Google.
Ahora hay dos posibilidades con cualquier juego dado: que los archivos estén comprimidos o no. Para averiguarlo, ejecutad el juego (el juego real donde estáis jugando) y pausad su ejecución en cualquier momento con F7. En el depurador veréis la dirección de la instrucción actual (PC) con los bytes de código de operación (opcode) a la derecha. Abrid el archivo .dsk en un editor hexadecimal y buscad ese puñado de bytes a partir del punto donde pausasteis. Si los encontráis en el archivo .dsk y todo coincide, genial, probablemente los binarios no estén comprimidos y podéis saltar al siguiente paso.
Si están comprimidos, es un poco más complicado, ya que necesitáis localizar el punto exacto donde termina la descompresión y se lanza el juego. La forma más fácil de hacer esto es ejecutar el juego (por ejemplo, run "disc") y establecer previamente un punto de interrupción en WinAPE en la dirección de inicio real. Podéis encontrarla en el editor de disco haciendo clic derecho en un archivo, seleccionando «Properties» y mirando en Exec Address.
Ahora hablaré sobre el uso de la IA para comentar y anotar el desensamblado, que es la herramienta más útil de la caja. Hacer esto a mano es posible, pero es una tarea enorme, lenta y frustrante; realmente no es viable si tenéis un trabajo, familia o cualquier otro pasatiempo. Así que una vez que estéis pausados en algún lugar al principio o dentro de la rutina de descompresión, desplazaos por el depurador, normalmente hacia adelante en la memoria, durante unos 0x1000 bytes. Por lo general, hasta que veáis un «RET», aunque la dirección final no es crucial ya que podéis tomar más código después. Haced Shift+clic para seleccionar ese bloque de instrucciones, luego clic derecho y «Disassemble». Solo dadle a OK en el diálogo. Pulsad F3 para mostrar el ensamblador si no ha aparecido. Ahora tenéis el código fuente, pero en un formato muy crudo, que es básicamente inútil si no se divide en rutinas y se comenta a fondo.
Una vez que tengáis el ensamblador en bruto de WinAPE, copiadlo y pegadlo en un nuevo archivo dentro de vuestro proyecto (empezad una nueva carpeta/proyecto de git para cada juego que convirtáis). Yo uso una convención de nombres como «JuegoZ0x1000-0x2000.raw.asm». Luego, usad una herramienta de IA con un prompt específico para convertir esto en algo legible. ¡No hace falta gastar dinero en herramientas de IA! Las gratuitas son perfectamente adecuadas. Las que yo uso son Opencode y Freebuff, ambas ofrecen una variedad de modelos que podéis usar de forma totalmente gratuita. Son extremadamente fáciles de configurar y usar. Elegid el modelo más potente disponible en su configuración máxima (preguntad a la IA si no estáis seguros de cuál es el mejor). Incluyo a continuación el prompt que utilizo; podéis ponerlo en un archivo y copiarlo/pegarlo o indicarle a la herramienta de IA el archivo y vuestro archivo .asm:
«For the z80 code block at (rueda de ruta de archivo), designed to run on the Amstrad CPC, add inline comments showing high-level functions and separate into subroutines, with a header for each major/minor subroutine describing its purpose. Alter any labels to be more descriptive, but retain the address at the end of the label. At the top of the file add a summary comment with a bullet point list of the major functions contained within. Output the commented disassembly as a single block without dropping any instructions or data into a new file beside the existing. Try to identify any areas that are actually data and not code where possible. Refer to the firmware manual here if necessary for ROM calls etc: https://www.cantrell.org.uk/david/tech/cpc/cpc-firmware/firmware.pdf»
Una vez que la IA haya hecho su trabajo, tendréis algo con suerte comprensible que podréis analizar. Si ha hecho un mal trabajo, o las rutinas no parecen relevantes para la descompresión y el lanzamiento del juego, simplemente tomad otra sección de memoria y repetid el proceso, o probad con otro modelo de IA alternativo.
Con suerte veréis algo como descomprimir datos, y luego JP 0xXXXX para lanzar realmente el juego (o su pantalla de título). En mi experiencia, casi siempre hay una sentencia JP XXXXX que es el punto de entrada a lo que habría estado en el juego comercial. A menudo es un número redondo como 0x100 o 0x500, ya que a los desarrolladores les gusta elegir números redondos. Otra alternativa para encontrar el punto de entrada es ejecutar la versión comercial real y ver dónde se inicia examinando las propiedades del archivo en el disco.
Una vez que tengáis el punto de entrada del juego (lo cual es trivial si no tenéis una versión comprimida/encriptada), podéis volcar el contenido de la RAM poniendo un punto de interrupción en esta dirección.
Bueno, esto se está haciendo mucho más largo de lo que pretendía, así que si a alguien le interesa saber más, ¡decídmelo y seguiré escribiendo abajo o lo moveré a un artículo en la wiki!