• Publicado el 26/12/2016 Esto es un post en el blog de: Jesús Alonso Abad @kencho Offline Bio: Apasionado de los videojuegos (desarrollarlos), intentando abrirme paso en la industria poco a poco. Ir a su perfil completo

    Hacking the Dragons (2)

    (Continúa desde la parte 1)

    Uno de los problemas de los controles de este juego es que los bloqueos sólo se pueden realizar si el botón de bloqueo se pulsa fuera de otras acciones como un puñetazo, etc. Esto hace casi imposible que inmediatamente después de lanzar un golpe, pases a un estado defensivo. Vamos a solucionar eso.

    Localizar el segmento de RAM del personaje
    La SNES tiene un área de RAM de trabajo (WRAM) en las direcciones comprendidas entre 7E:0000 y 7F:FFFF. Es aquí donde el juego almacena los datos de las entidades del juego (entre otras cosas), como son los personajes, enemigos, armas… Para los personajes utiliza segmentos de 256 bytes, con la forma 7E:nn00 y 7E:nnFF. Mi consejo antes de empezar es limpiar la pantalla de enemigos (¡sin avanzar por el escenario!) para poder probar cosas a gusto. Hay que ir inspeccionando en el mapa de memoria cada uno de estos segmentos para ver si cambian cuando (y sólo cuando) nosotros hacemos algo como dar un puñetazo o saltar. Atentos, porque estos segmentos cambian de sitio según los necesita el juego cuando crea una nueva entidad. Por ejemplo, en un emulador estoy inspeccionando 7E:0Cxx y en otro 7E:11xx. Lo único que interesa son los desplazamientos dentro de estos segmentos.

    Una vez localizado este segmento, podréis ver que los bytes del 7E:nn44 al 7E:nn48 cambian cuando se pulsa algo en el mando. Las direcciones 44 y 45 son una copia de las lecturas directas del mando. De ellas dos, se copia en 46 el estado de los 4 botones de la SNES A, B, X e Y (cada bit es un botón). 47 es una copia interna de 46, y 48 usa los mismos bits que 46, pero sólo de los que se han pulsado en este frame. Esto lo he sacado a base de observar y un poco de ingeniería inversa. Con saber que el 46 tiene el bit con valor 04 cuando está pulsado el bloqueo (B), y que el 48 lo tiene cuando se acaba de pulsar, es suficiente para lo que queremos.

    Localizar el código que comprueba esta pulsación
    Lo que haremos será ver qué hace una lectura de el byte 7E:nn48 cuando éste valga 04. En bsnes, añadiremos un breakpoint inspeccionando esa dirección (en mi caso, 1148, sin el 7e del principio; la razón es un poco larga aquí), indicando como valor 4 y marcando la casilla R. En cuanto pulsemos el botón B hará una parada en el primer punto que lo inspeccione. Debería tener esta pinta:
    059edf lda $48 [001148] A:1101 ... D:1100 …
    El primer valor es la dirección de la instrucción que ha hecho la lectura, 059edf. Después viene la instrucción desensamblada, lda $48. [001148] es la dirección sobre la que se acaba de trabajar (hay que sumar el 7e0000 para tener la dirección real). Después, el valor actual del registro A (a donde se leerá el valor de 7e1148) y el D (que define el desplazamiento en la zeropage). Básicamente esta instrucción, lda $48, lo que hace es cargar en el registro A lo que haya en D+48.
    Se hace varias veces por frame, así que tendremos que ver cuál es la que nos interesa. Si en el debugger pulsamos a step, avanzará una instrucción. En el primer caso será and #$02, que hace un AND lógico entre el parámetro, 02, y el registro A, 1104. No nos interesa, así que damos a run para ir al siguiente breakpoint, y a step para ver qué valor está buscando, hasta que busque un 04.
    059f4f lda $48 [001148] A:1100 ...
    059f51 and #$04 A:1104 …
    Luego aquí lee el valor en 7E:nn48 para ver si en este frame se ha pulsado el botón de bloqueo. Como lo que nos interesa es que detecte si está pulsado, y no sólo si se acaba de pulsar, tenemos que cambiar el parámetro de 059f4f para que lea el 46 en lugar del 48. Desde no$sns, en el panel de desensamblado, vamos a la dirección 059f4f (botón derecho > Goto…) y editamos la instrucción (botón derecho > Change instruction) para cambiar de lda 48 a lda 46

    Ahora podemos ver que si para el momento en que acabemos de dar un golpe, tenemos pulsado el bloqueo, pasa directamente a ese estado.

    Aplicar en la rom
    Ahora sólo queda modificar definitivamente la rom. Abrimos la rom con un editor hexadecimal. Usando Lunar Address autodetectamos el tipo de rom y escribimos en la dirección SNES el valor 059f4f y nos dirá la posición en el fichero (en mi caso, 029f4f). Vamos a esa dirección en el editor hexadecimal y deberíamos encontrar A5 48 (el opcode LDA, y su parámetro, 48). Modificamos ese 48 por el 46 (se pueden ver los nuevos bytes en no$sns, a la izquierda de la instrucción), y guardamos con otro nombre la rom. Esa es nuestra rom parcheada.

    Crear el parche
    Ahora con Lunar IPS creamos el parche, primero cargando la rom original y después la modificada. Ahora podemos parchear la original con este parche, sin necesidad de aplicar todos los demás cambios que hagamos.



    Ha sido un poco espeso hoy. Más en el siguiente ;)
    3
Loader
Arriba