Jason
PkPower déjame poner tildes en mi nick ¬¬
Introducción Parte 2 | Proyecto de Decompilación Pokémon R/S/+
Hola, este es un tutorial en el que les comentaré un par de cosas sobre cómo funciona el lenguaje C y lo que he visto acerca de la ROM. El título es porque pretendo que sea una continuación de la introducción creada por @Lunos.
¿Qué es C?
Es un lenguaje de programación de mediano nivel (pues tiene acceso a estructuras tanto de alto (variables, ciclos, condicionales, etc) como de bajo nivel (ASM)).
Es un lenguaje compilado: esto quiere decir que hay un programa que transforma el texto que nosotros escribimos en un archivo binario ejecutable por la máquina. En este caso una GBA (o un emulador), que cuenta con un bonito procesador ARM7.
El Rom Hacking tradicional toma la ROM (el archivo .gba) que es lo que se obtiene como archivo ejecutable luego de compilar el código, para modificar este. En cambio, en disassembly nosotros tenemos acceso directo al código que produce el archivo, de modo que en lugar de trabajar con el hexadecimal lo hacemos en un entendible inglés, cambiando las imagenes directamente, etc. No hay offsets, no hay que repuntear, no hay que escribir rutinas en ASM, no nos tenemos que preocupar por el largo de alguna rutina de scripting (cuya sintaxis es casi la misma que en GBA, solo que muchas cosas tienen nombres. En vez de ser 0x05 ahora es MSGBOX_YESNO, por poner un ejemplo).
Todas las FLAGS y VARIABLES que se usan en scripts tienen sus nombres, por lo que el acceso es más sencillo. Nombres descriptivos, además, te ayudarán a saber para qué son sin mucho esfuerzo.
Compilación de la ROM
Es imprescindible que lean y sigan el tutorial de Lunos antes de continuar. Dicho esto, empezamos:
Cuando entran a la carpeta del pokéruby/pokéemmerald/pokered verán:
Muchas carpetas, archivos con un . al inicio del nombre, archivos .sh, archivos.txt, archivos .md, archivos .sha1, archivos .mk y un archivo sin extensión: Makefile.
Los archivos con un . al inicio del nombre son casi todos relacionados con el manejo del repositorio de GitHub, son importantes en caso de que salga una nueva "versión" del proyecto y quieran aplicar los cambios a su código.
Los archivos .sh son scripts de la consola, no los toquen.
Los archivos .txt son archivos de texto. No los toquen.
Los archivos .sha1 son los que usan los de pret para saber si hicieron algo mal o no, ya que compara la rom que ellos compilaron con la original que están descompilando y su resultado debe ser igual. No tocar si no saben lo que hacen.
Los archivos .md son también del repositorio de github, son archivos de texto con un formato algo similar al BBCode que usamos en el foro. Déjenlos como están.
Los archivos .mk son los que junto al Makefile dicen al compilador con qué características deben realizar la compilación de la ROM, para que recibamos un .gba y no cualquier cosa. Ahora explicaré dos de ellos: config.mk y Makefile.
config.mk:
Este archivo tiene algunas configuraciones relacionadas con la compilación. Lo primero que vemos son las opciones predeterminadas, lo que compilará cygwin si no le decimos nada más que "make".
En concreto: Pokémon Ruby 1.0 en Inglés, sin las cosas de Debug y Sí comparará la ROM obtenida con el .sha1 en cuestón. Todo lo que está más abajo tiene que ver con cómo aplica estas opciones por defecto.
¿Quieren que deje de revisar si la suma sha1 coincide? Pongan el COMPARE en 0.
¿Quieren compilar por defecto pokémon zafiro? Cambien GAME_VERSION ?= RUBY por GAME_VERSION ?= SAPPHIRE.
¿Quieren que por defecto les compile la segunda revisión? (Los 1.2) Pongan GAME_REVISION en 2.
El resto no es necesario (ni recomendado sin saber) que lo toquen.
Makefile:
Si tuviéramos que compilar la rom escribiendo todo en la terminal de cygwin64, entonces sería un proceso extremadamente engorroso. El archivo Makefile se encarga de evitar esto, haciendo que con un simple "make" (y alguna opción más, si queremos), todo ocurra.
Lo primero que vemos es que "invoca" al devkitpro y luego lee el archivo config.mk.
A continuación lo que hace es setear muchos parámetros que no debemos tocar.
Luego encontramos
Ese es el nombre de la rom (archivo .gba) que obtendremos tras compilar.
Más abajo tenemos más definiciones de parámetros.
Luego, veremos que hay cosas seguidas de un ':'. Esas son las distintas opciones que podemos manejar de forma simple desde la terminal, con comandos como "make", "make clean", "make tools" decimos al compilador qué queremos que haga. Y sí, cerca de la línea 162 tenemos los nombres que Lunos nos comentó: "make ruby", "make ruby_rev1", "make ruby_rev2", etc.
Eso es todo lo que puedo y considero necesario contarles acerca de estos archivos. Hice un tutorial hace poco sobre cómo agregar una nueva opción al compilador: "make wclean".
Para trabajar en la ROM:
Para trabajar en la ROM, o mejor dicho en su código fuente y recursos, necesitaremos algunas herramientas básicas:
1. editor de código: necesitaremos un editor de texto plano, puede ser notepad++, sublime text 3, brackets, atom, vscode, o el que deseen, pero editores como Microsoft Word NO SIRVEN.
2. porymap: asumo que querrán modificar los mapas y eventos, así que esta herramienta es ya imprescindible. No tanto para los eventos, pues se pueden editar manualmente en sus archivos, pero sí los mapas. Además puede editar los tilesets y expandirlos con un par de botones, en caso de ser necesario.
3. PokerubyRegionMapEditor: esta es una herramienta que encontré y sirve para editar el worldmap de pokéruby.
4. PokerubyMapRenamer: esta es una herramienta que hice yo. Porymap de momento no permite cambiar el nombre a los mapas que, si creamos uno nuevo, recibe un nombre por defecto. Dado esto creé esta herramienta que permite cambiar el nombre de un mapa de manera sencilla (de lo contrario habría muchos archivos involucrados). Dentro de poco (en cuanto termine de darle más opciones y quizás una interfaz gráfica) lo subiré en la sección de aportes.
5. Character Maker Pro: como podrán ver, algunos tutoriales que tienen que ver con recursos gráficos requieren esta herramienta para trabajar las paletas.
Modificando cosas de la ROM:
Esto daría para varios tutoriales y se escaparían del objetivo de este, por lo que solo me limitaré a explicar qué son algunas cosas.
1. Archivos .c y archivos .h:
El lenguaje C tiene estas dos extensiones como extensiones por defecto, los archivos .c tienen el código en sí, mientras que los .h tienen lo que podríamos decir "el encabezado" de los archivos .c. Si desde un .c importamos el .h de otro, todo el código del .c también vendrá y lo podremos utilizar.
2. Preprocesador:
Por todos lados está lleno de cosas del estilo
"#define NOMBRE_EN_MAYUSCULAS algun_numero"
y similares, esto en realidad es algo que nos permite realizar operaciones sobre el código antes de compilarlo. En el caso de los "define", lo que hacemos es crear nombres para cosas que serán sustituídas por sus valores antes de empezar a compilar, veamos un ejemplo:
Cuando queramos compilar esto, el preprocesador reemplazará todos los sitios donde aparece NUM por un 3, dejando el código como:
A continuación les dejo un par de ejemplos de ejecución del programa que creé.
3. FLAGS y VARS:
Esto es importante que lo tengan en cuenta:
En la estructura que controla alguna de la data relacionada al guardado de la partida (SaveBlock1, instanciada como gSaveBlock1), las variables para scripting se definen como arrays de enteros sin signo. Las variables son de 16 bits y las flags son de 8. La capacidad de estos arrays están definidos por las "variables" del preprocesador FLAGS_COUNT y VARS_COUNT en el mismo archivo (include/global.h).
Las flags, sin embargo, siguen siendo de un bit gracias a las operaciones bitwise.
En include/constants/vars.h e include/constants/flags.h están definidos los nombres del preprocesador para estas variables y flags, al que se le asigna su posición dentro del array que les corresponda.
Para cambiar los nombres de las variables y flags deben hacerlo con cuidado, pues son referenciadas por los archivos en data/maps/nombre_mapa/events.inc y data/maps/nombre_mapa/scripts.inc como mínimo. Algunas también están referenciadas por data/event_scripts.s, que contiene lo que me parecen ser "scripts globales", utilizables por cualquier mapa. Lamentablemente no he investigado sobre el funcionamiento del compilador para los scripts.
Algunas flags y variables son limpiadas al reunirse ciertas condiciones, no he podido determinar cuáles son estas para muchos casos. Abriré un tema de investigación al respecto... pronto. Es importante saber si hay algún error en el manejo de las flags que impida utilizar apropiadamente algunas de sus posiciones o algo parecido, pues muchas no están definidas, lo que me parece curioso cuanto menos. Cuando intenté cambiar la posición de la flag de sistema a una adyacente para el poder correr, tuve el problema de que se reseteaba al cambiar de mapa.
4. Scripteando, edición de mapas y eventos con porymap:
Salvo por eliminar un mapa, cambiar su nombre y los puntos de respawn, pory ofrece un control total sobre los mapas. Podemos cambiar su tileset, cambiar tamaños, tipos, música, agregar o quitar eventos y configurarlos, etc. Tampoco ofrece la posibilidad de modificar los pokémon salvajes de una zona.
En include/constants/region_map_sections.h pueden crear referencias a nuevos lugares, que se usarán para mostrar el nombre del mapa en pantalla cuando entren a él y lo referente a la aparición de la carita del jugador y los nombres de los lugares en el worldmap. Ya traeré un tuto sobre esto... pronto.
En data/maps pueden acceder a los archivos de los mapas relacionados con los eventos y scripts. La sintaxis es muy similar a la del RH tradicional y diría que es incluso más simple. Pueden abrir el archivo de scripts en porymap con un botón una vez están en la pestaña de eventos de dicho mapa.
Porymap también permite la edición de tilesets: un tile está en realidad compuesto por dos capas de 4 minitiles cada una, con la capacidad de tener transparencias. Gracias a esto podemos pasar bajo un árbol y sobre el pasto sin problemas. También nos permite crear variaciones para muchos de nuestros tiles, por ejemplo, hacer que bajo la copa de un árbol haya agua en vez de pasto o hierba alta.
El control de las conexiones entre mapas es bastante intuitivo. También permite crear conexiones para buceo, sin embargo no eliminarlas, puede que aún no esté implementado.
Misceláneo:
Si usan git:
Algunos archivos requieren LF y otros CRLF, de no hacer esto al pullear y pushear esto se puede romper y arreglarlo sería horrible. Tuve que reiniciar mi proyecto a causa de esto, es mejor que git no realice conversión alguna.
Ediciones diferentes:
El preprocesador es también el que controla esto, detecta si están compilando zafiro o rubí para añadir unos u otros pokémon salvajes, cambiar la carátula, etc. También hace lo mismo con las revisiones y bugfixes. Finalmente esto es también lo que hace para los distintos idiomas.
¿No sabes programar?:
Aprende eso primero, no queda bien que recomiende mi propia escuela pero hice una de python que enseña a programar. Úsala si quieres aprender. Python es un lenguaje bastante amigable y aprender a programar es universal, luego queda tratar con los asuntos específicos de cada lenguaje.
Hola, este es un tutorial en el que les comentaré un par de cosas sobre cómo funciona el lenguaje C y lo que he visto acerca de la ROM. El título es porque pretendo que sea una continuación de la introducción creada por @Lunos.
¿Qué es C?
Es un lenguaje de programación de mediano nivel (pues tiene acceso a estructuras tanto de alto (variables, ciclos, condicionales, etc) como de bajo nivel (ASM)).
Nota: "nivel" no hace referencia a su dificultad, sino a qué tan parecido es al lenguaje humano. Alto nivel: muy parecido. Bajo nivel: muy distinto.
Es un lenguaje compilado: esto quiere decir que hay un programa que transforma el texto que nosotros escribimos en un archivo binario ejecutable por la máquina. En este caso una GBA (o un emulador), que cuenta con un bonito procesador ARM7.
El Rom Hacking tradicional toma la ROM (el archivo .gba) que es lo que se obtiene como archivo ejecutable luego de compilar el código, para modificar este. En cambio, en disassembly nosotros tenemos acceso directo al código que produce el archivo, de modo que en lugar de trabajar con el hexadecimal lo hacemos en un entendible inglés, cambiando las imagenes directamente, etc. No hay offsets, no hay que repuntear, no hay que escribir rutinas en ASM, no nos tenemos que preocupar por el largo de alguna rutina de scripting (cuya sintaxis es casi la misma que en GBA, solo que muchas cosas tienen nombres. En vez de ser 0x05 ahora es MSGBOX_YESNO, por poner un ejemplo).
Todas las FLAGS y VARIABLES que se usan en scripts tienen sus nombres, por lo que el acceso es más sencillo. Nombres descriptivos, además, te ayudarán a saber para qué son sin mucho esfuerzo.
Compilación de la ROM
Es imprescindible que lean y sigan el tutorial de Lunos antes de continuar. Dicho esto, empezamos:
Cuando entran a la carpeta del pokéruby/pokéemmerald/pokered verán:
Muchas carpetas, archivos con un . al inicio del nombre, archivos .sh, archivos.txt, archivos .md, archivos .sha1, archivos .mk y un archivo sin extensión: Makefile.
Los archivos con un . al inicio del nombre son casi todos relacionados con el manejo del repositorio de GitHub, son importantes en caso de que salga una nueva "versión" del proyecto y quieran aplicar los cambios a su código.
Los archivos .sh son scripts de la consola, no los toquen.
Los archivos .txt son archivos de texto. No los toquen.
Los archivos .sha1 son los que usan los de pret para saber si hicieron algo mal o no, ya que compara la rom que ellos compilaron con la original que están descompilando y su resultado debe ser igual. No tocar si no saben lo que hacen.
Los archivos .md son también del repositorio de github, son archivos de texto con un formato algo similar al BBCode que usamos en el foro. Déjenlos como están.
Los archivos .mk son los que junto al Makefile dicen al compilador con qué características deben realizar la compilación de la ROM, para que recibamos un .gba y no cualquier cosa. Ahora explicaré dos de ellos: config.mk y Makefile.
config.mk:
Este archivo tiene algunas configuraciones relacionadas con la compilación. Lo primero que vemos son las opciones predeterminadas, lo que compilará cygwin si no le decimos nada más que "make".
En concreto: Pokémon Ruby 1.0 en Inglés, sin las cosas de Debug y Sí comparará la ROM obtenida con el .sha1 en cuestón. Todo lo que está más abajo tiene que ver con cómo aplica estas opciones por defecto.
¿Quieren que deje de revisar si la suma sha1 coincide? Pongan el COMPARE en 0.
¿Quieren compilar por defecto pokémon zafiro? Cambien GAME_VERSION ?= RUBY por GAME_VERSION ?= SAPPHIRE.
¿Quieren que por defecto les compile la segunda revisión? (Los 1.2) Pongan GAME_REVISION en 2.
El resto no es necesario (ni recomendado sin saber) que lo toquen.
Makefile:
Si tuviéramos que compilar la rom escribiendo todo en la terminal de cygwin64, entonces sería un proceso extremadamente engorroso. El archivo Makefile se encarga de evitar esto, haciendo que con un simple "make" (y alguna opción más, si queremos), todo ocurra.
Lo primero que vemos es que "invoca" al devkitpro y luego lee el archivo config.mk.
A continuación lo que hace es setear muchos parámetros que no debemos tocar.
Luego encontramos
Código:
#### Files ####
ROM := poke$(BUILD_NAME).gba
Más abajo tenemos más definiciones de parámetros.
Luego, veremos que hay cosas seguidas de un ':'. Esas son las distintas opciones que podemos manejar de forma simple desde la terminal, con comandos como "make", "make clean", "make tools" decimos al compilador qué queremos que haga. Y sí, cerca de la línea 162 tenemos los nombres que Lunos nos comentó: "make ruby", "make ruby_rev1", "make ruby_rev2", etc.
Eso es todo lo que puedo y considero necesario contarles acerca de estos archivos. Hice un tutorial hace poco sobre cómo agregar una nueva opción al compilador: "make wclean".
Para trabajar en la ROM:
Para trabajar en la ROM, o mejor dicho en su código fuente y recursos, necesitaremos algunas herramientas básicas:
1. editor de código: necesitaremos un editor de texto plano, puede ser notepad++, sublime text 3, brackets, atom, vscode, o el que deseen, pero editores como Microsoft Word NO SIRVEN.
2. porymap: asumo que querrán modificar los mapas y eventos, así que esta herramienta es ya imprescindible. No tanto para los eventos, pues se pueden editar manualmente en sus archivos, pero sí los mapas. Además puede editar los tilesets y expandirlos con un par de botones, en caso de ser necesario.
3. PokerubyRegionMapEditor: esta es una herramienta que encontré y sirve para editar el worldmap de pokéruby.
4. PokerubyMapRenamer: esta es una herramienta que hice yo. Porymap de momento no permite cambiar el nombre a los mapas que, si creamos uno nuevo, recibe un nombre por defecto. Dado esto creé esta herramienta que permite cambiar el nombre de un mapa de manera sencilla (de lo contrario habría muchos archivos involucrados). Dentro de poco (en cuanto termine de darle más opciones y quizás una interfaz gráfica) lo subiré en la sección de aportes.
5. Character Maker Pro: como podrán ver, algunos tutoriales que tienen que ver con recursos gráficos requieren esta herramienta para trabajar las paletas.
Modificando cosas de la ROM:
Esto daría para varios tutoriales y se escaparían del objetivo de este, por lo que solo me limitaré a explicar qué son algunas cosas.
1. Archivos .c y archivos .h:
El lenguaje C tiene estas dos extensiones como extensiones por defecto, los archivos .c tienen el código en sí, mientras que los .h tienen lo que podríamos decir "el encabezado" de los archivos .c. Si desde un .c importamos el .h de otro, todo el código del .c también vendrá y lo podremos utilizar.
2. Preprocesador:
Por todos lados está lleno de cosas del estilo
"#define NOMBRE_EN_MAYUSCULAS algun_numero"
y similares, esto en realidad es algo que nos permite realizar operaciones sobre el código antes de compilarlo. En el caso de los "define", lo que hacemos es crear nombres para cosas que serán sustituídas por sus valores antes de empezar a compilar, veamos un ejemplo:
Código:
#include <stdio.h> //importa la librería de input output de C
#define NUM 3
int main()
{
int a = 4;
int b;
int c;
int resultado;
printf("Ingrese dos números:\n"); //imprime en pantalla
scanf("%i %i", &b, &c); //recibe datos del usuario
resultado = a + b + c + NUM;
printf("El resultado es %i\n", resultado);
return 0; //todo terminó bien
}
Cuando queramos compilar esto, el preprocesador reemplazará todos los sitios donde aparece NUM por un 3, dejando el código como:
Código:
#include <stdio.h> /*esto también se elimina pero trae todo el código de la librería hacia acá*/
int main()
{
int a = 4;
int b;
int c;
int resultado;
printf("Ingrese dos números:\n");
scanf("%i %i", &b, &c);
resultado = a + b + c + 3;
printf("El resultado es %i\n", resultado);
return 0;
}
A continuación les dejo un par de ejemplos de ejecución del programa que creé.
3. FLAGS y VARS:
Esto es importante que lo tengan en cuenta:
En la estructura que controla alguna de la data relacionada al guardado de la partida (SaveBlock1, instanciada como gSaveBlock1), las variables para scripting se definen como arrays de enteros sin signo. Las variables son de 16 bits y las flags son de 8. La capacidad de estos arrays están definidos por las "variables" del preprocesador FLAGS_COUNT y VARS_COUNT en el mismo archivo (include/global.h).
Las flags, sin embargo, siguen siendo de un bit gracias a las operaciones bitwise.
En include/constants/vars.h e include/constants/flags.h están definidos los nombres del preprocesador para estas variables y flags, al que se le asigna su posición dentro del array que les corresponda.
Para cambiar los nombres de las variables y flags deben hacerlo con cuidado, pues son referenciadas por los archivos en data/maps/nombre_mapa/events.inc y data/maps/nombre_mapa/scripts.inc como mínimo. Algunas también están referenciadas por data/event_scripts.s, que contiene lo que me parecen ser "scripts globales", utilizables por cualquier mapa. Lamentablemente no he investigado sobre el funcionamiento del compilador para los scripts.
Algunas flags y variables son limpiadas al reunirse ciertas condiciones, no he podido determinar cuáles son estas para muchos casos. Abriré un tema de investigación al respecto... pronto. Es importante saber si hay algún error en el manejo de las flags que impida utilizar apropiadamente algunas de sus posiciones o algo parecido, pues muchas no están definidas, lo que me parece curioso cuanto menos. Cuando intenté cambiar la posición de la flag de sistema a una adyacente para el poder correr, tuve el problema de que se reseteaba al cambiar de mapa.
4. Scripteando, edición de mapas y eventos con porymap:
Salvo por eliminar un mapa, cambiar su nombre y los puntos de respawn, pory ofrece un control total sobre los mapas. Podemos cambiar su tileset, cambiar tamaños, tipos, música, agregar o quitar eventos y configurarlos, etc. Tampoco ofrece la posibilidad de modificar los pokémon salvajes de una zona.
En include/constants/region_map_sections.h pueden crear referencias a nuevos lugares, que se usarán para mostrar el nombre del mapa en pantalla cuando entren a él y lo referente a la aparición de la carita del jugador y los nombres de los lugares en el worldmap. Ya traeré un tuto sobre esto... pronto.
En data/maps pueden acceder a los archivos de los mapas relacionados con los eventos y scripts. La sintaxis es muy similar a la del RH tradicional y diría que es incluso más simple. Pueden abrir el archivo de scripts en porymap con un botón una vez están en la pestaña de eventos de dicho mapa.
Porymap también permite la edición de tilesets: un tile está en realidad compuesto por dos capas de 4 minitiles cada una, con la capacidad de tener transparencias. Gracias a esto podemos pasar bajo un árbol y sobre el pasto sin problemas. También nos permite crear variaciones para muchos de nuestros tiles, por ejemplo, hacer que bajo la copa de un árbol haya agua en vez de pasto o hierba alta.
El control de las conexiones entre mapas es bastante intuitivo. También permite crear conexiones para buceo, sin embargo no eliminarlas, puede que aún no esté implementado.
Misceláneo:
Si usan git:
Código:
git config --global core.autocrlf=false
Ediciones diferentes:
El preprocesador es también el que controla esto, detecta si están compilando zafiro o rubí para añadir unos u otros pokémon salvajes, cambiar la carátula, etc. También hace lo mismo con las revisiones y bugfixes. Finalmente esto es también lo que hace para los distintos idiomas.
¿No sabes programar?:
Aprende eso primero, no queda bien que recomiende mi propia escuela pero hice una de python que enseña a programar. Úsala si quieres aprender. Python es un lenguaje bastante amigable y aprender a programar es universal, luego queda tratar con los asuntos específicos de cada lenguaje.
Última edición: