GBA | Hex / Mapping | Investigando los tileblock (Con aplicaciones)
Gracias a éste error me propuse a investigar los tileblocks con HxD y ver si había forma. Lo que he logrado básicamente es entender como A-Map guarda los tileblocks en formato .bvd, como los inserta, como funciona el changeamount, como funciona el código interno de los tileblocks, y cómo los inserta.Hace 2 semanas mientras mapeaba me di cuenta de que había cometido un error. Como ya sabréis los mapas están formados por 2 tileblocks (“pizarra de bloques”). El primer tileblock empieza desde el bloque 0 y el segundo desde el bloque 640 (0x280 en hex). Entonces cierto día me di cuenta de que cierto tileblock lo había construido desde 0x250, no desde 0x280. Entonces me pregunté ¿Habrá alguna forma de desplazar estos bloques entre 0x250 y 0x280 a 0x280?
En base a esto he pensado y probado varias utilidades de cómo, en base a éste conocimiento, lo podemos aplicar a nuestros hacks. Entre estas funciones las más útiles son: empezar desde un tileblock en blanco, poner en 0 los bytes de comportamiento y de fondo de los bloques, desplazar bloques, cambiar la paleta de un grupo de bloques, entre otros […]
Este post lo he estructurado en tres partes; (1) un glosario para entender todo los términos que vamos a usar de cara a la parte 2 y 3, (2) un apartado que agrupa toda la investigación y (3) la aplicaciones que esta investigación tiene en nuestro campo.
* * *
Dicho esto empecemos:
GLOSARIO
Tilesets:
Tileset: Es el conjunto de tiles usado para crear bloques del tileblock. Cada tile mide 8x8 pixeles.Tileset primario: Existen dos, el 0 (exteriores) y el 12 (interiores). Estos tilesets miden 128x320 píxeles, es decir, están formados por 640 tiles (0x280).
Tileset secundario. Son los otros tilesets restantes (ejemplos de ellos son PUEBLO PALETA o el MT.MOON). Estos tilesets miden 128x192 píxeles, es decir, están formados por 384 tiles (0x180).
Tileset de A-Map: Está formado por dos tileset, un tileset primario seguido de un tileset secundario. En suma 640+384, mide 1024 tiles (0x400). El primer tile del tileset primario se ubica en 0x0 y el último en el 0x27F entonces el tileset secundario empieza en 0x280 y termina con el tile 0x3FF.
Paletas:
Paleta: Es el conjunto de 16 colores asignables a un tile. Una paleta tiene 16 colores, dónde el primero actúa de transparencia. Ocupa 32 bytes de la ROM (2 bytes x 16 colores).Paletas de la 0 a la 7: Cada tileblock primario tiene estas 8 paletas asignadas y son usables para el tileblock secundario.
Paletas de la 8 a la 12: Cada tileblock secundario tiene estas 5 paletas asignadas y son propias de cada tileblock, es decir, no deberían usarse para el primario.
Tileblocks:
Bloques: Conjuntos de 8 tiles del tileset que forman parte del Tileblock. Los mapas se crean en base a distribuir estos bloques por el mapa. Cada bloque tiene una capa inferior de 4 tiles y una capa superior de 4 tiles. A su vez, cada tile del bloque tiene asignado una paleta y un tipo de giro. Tileblock: Es un conjunto de bloques usado para mapear nuestros mapas. Cada tileblock está asociado a un tileset. (Es decir, si nuestro mapa tiene el tileset 2 también tendrá el tileblock 2 asignado.)
Tileblock primario: Está definido por el tileset primario. Está formado por 640 bloques (0x280) siendo el 0x0 su primer bloque y el 0x27F el último.
Tileblock secundario: Está definido principalmente por el tileset secundario pese a que también puede usar tiles del tileset primario para formar sus bloques. A diferencia del primario, la cantidad de bloques es variable. El máximo número de bloques es de 384 bloques (0x180).
Tileblock de A-Map: Está formado por 2 tileblocks uno que actúa como primario y seguido de otro que actúa como secundario. El primer bloque del tileblock secundario es el 0x280 y su último, (en el caso de que mida 384 bloques), 0x3FF. En total mide un máximo de 1024 bloques.
INVESTIGACIÓN
A raíz de investigar los cambios de la ROM y los propios tileblocks mediante hex. He llegado a estos procedimientos y resultados:
Lo que hace la cadena es registrar cada tile por su ubicación en el tileset. En el ejemplo, el bloque 0x047 está insertado en el offset 0x2ADC24 y el primer tile por el que está formado es el 0x003.
Abierto la rom en hex vemos que ahí aparece el 1r Tile, pero como 03 10. ¿Por qué? Sencillo. Se debe al formato de los bytes que definen como se han asignado los tiles al bloque. A estas altura ya debes saber que en A-Map puedes decidir 3 cosas acerca de cómo montar un tile del bloque: la ubicación del tile, la paleta del tile y la orientación del tile.
En nuestro ejemplo, el primer tile del bloque se forma a partir del tile 0x003 de nuestro tileset, la paleta 0x1 y sin ningún tipo de giro. Para entender como esto pasa escribirse como 0x0310 he investigado y he descubierto esto:
El valor del par de bytes de cada tile viene definido de la suma de 3 pasos y su permutación:
Lo interesante de esto es que te hace entender el porqué hay un límite de 1024 tiles (0x3FF último tile). Éste límite viene dado por que es el máximo que pueden hacer contando los giros integrados en el código.
¿Entonces y si usamos paletas superiores (13 en adelante)? En dicho caso se asignarán las paletas background de la consola, es decir, las que trabajan de fondo para diálogos, menús, etc. Pese a ello, es algo interesante de toquetear. Como ya sabemos si abrimos en VBA nuestro ROM con la opción de Tools>Palete View y Map View podemos ver nuestros tiles y sus paletas. Para hacer un ejemplo de qué pasa si usamos otra paleta he usado el mismo tile del ejemplo y le he asignado la paleta 15 (0xF).
¿Curioso no? He asignado la paleta 15 a un tile. Por cierto, en A-Map todos los tiles con paletas asignadas superiores a 0xC se verán en negro dado que A-Map no las abre además de que estás paletas son móviles (las carga la rom durante el juego, no son para tilesets).
* * *
Segunda cadena de valores
La segunda cadena de valores, va seguida tras la primera cadena y está formada por los comportamientos-byte y los fondo-byte solamente. Es más sencillo de entender que la primera cadena ya que conservan el mismo orden uno detrás de otro. Es decir, por cada bloque tendremos 4 bytes, 2 de comportamiento seguidos de 2 de fondo uno detrás del otro bloque tras bloque.
Si cogemos éste ejemplo vemos que la rom lo escribe conservando el mismo orden:
Y así para cada bloque, uno detrás de otro.
Siempre que queremos pasar un tileblock de una rom a otra lo que hacemos es guardar el tileblock mediante la opción del Editor de Bloques>Blocks>GuardarTileset (pone tileset, pero se refiere al tileblock del que hemos ido hablando) y después cargarlo en una nueva dirección (repunteamos).
El archivo.bvd que creamos se verá así, por ejemplo:
Éste archivo.bvd lo que hace es guardar un registro del tileblock tal como es más unos parámetros para que pueda ser leído al cargase. Lo que vemos en azul es Código del tileblock. Pero aparte de ello vemos 4 bytes iniciales y 4 finales.
Hay dos casos normales en los que cargamos de nuevo un tileblock y nos obliga repuntearlo en una nueva dirección. Uno cuando cambiamos la cantidad de bloques y otro cuando cargamos un archivo.bvd.
Entonces, os preguntareis ¿Cómo hace la ROM para asignar cada bloque a un comportamiento/fondo? Sencillo, hace dos repunteos modificando dos punteros de una tabla de varios punteros (empieza en 0x2D4A98). Uno que apunta al principio del tileblock (1ra cadena) y otro que apunta a la 2nda cadena. De esta forma, parece ser que la ROM mide la longitud entre los distintos offset y asi saca la cantidad de bloques que hay en el tileblock. Dado esto, asigna cada bloque de la 1ra cadena a su función de la 2nda cadena.
Por cierto, si os preguntáis que pasa con el tileblock antiguo sabed que ocurre lo mismo que para los tileset. Al repuntear A-Map borra el tileblock antiguo rellenándolo de FF. Es decir, es seguro moverlo por la ROM y repuntear varias veces. Os lo digo para quitaros el miedo.
Análisis 1: Código del tileblock
El tileblock está formado por dos cadenas de valores hexadecimales uno detrás de otro. La primera cadena de valores define la forma de los bloques y la segunda cadena su comportamiento y fondo. Las investigaremos a continuación:Primera cadena de valores
La primera cadena está formada por grupos de 16 bytes (16 bytes por cada bloque). ¿Por qué 16? Sencillo. Los bloques se montan en base a 8 tiles, 4 tiles de la capa inferior y 4 de la capa superior. La cadena de bytes empieza por el primer tile de arriba a la izquierda de la capa inferior y termina con el último tile de la capa superior situado abajo en la derecha. De ésta forma:
Lo que hace la cadena es registrar cada tile por su ubicación en el tileset. En el ejemplo, el bloque 0x047 está insertado en el offset 0x2ADC24 y el primer tile por el que está formado es el 0x003.

Abierto la rom en hex vemos que ahí aparece el 1r Tile, pero como 03 10. ¿Por qué? Sencillo. Se debe al formato de los bytes que definen como se han asignado los tiles al bloque. A estas altura ya debes saber que en A-Map puedes decidir 3 cosas acerca de cómo montar un tile del bloque: la ubicación del tile, la paleta del tile y la orientación del tile.
En nuestro ejemplo, el primer tile del bloque se forma a partir del tile 0x003 de nuestro tileset, la paleta 0x1 y sin ningún tipo de giro. Para entender como esto pasa escribirse como 0x0310 he investigado y he descubierto esto:
El valor del par de bytes de cada tile viene definido de la suma de 3 pasos y su permutación:
- La dirección de nuestro tile en el tileset.
En nuestro caso, 0x0003 - La paleta asignada corresponde a 0x1000 x el número de la paleta.
Al ser la paleta 1, se suma 0x1000, el anterior 0x0003 + 0x1000 pasa a ser 0x1003. - El giro en los ejes X e Y. Si el giro es en el eje X se suma 0x400, si es en el eje Y 0x800 y si es en ambos 0xC00.
Al no tener ningún giro se queda como 0x1003. - Permutar la suma para obtener el valor en hex de nuestro tile.
Giramos 0x1003 y obtenemos 0x0310.
Lo interesante de esto es que te hace entender el porqué hay un límite de 1024 tiles (0x3FF último tile). Éste límite viene dado por que es el máximo que pueden hacer contando los giros integrados en el código.
* * *
¿Entonces y si usamos paletas superiores (13 en adelante)? En dicho caso se asignarán las paletas background de la consola, es decir, las que trabajan de fondo para diálogos, menús, etc. Pese a ello, es algo interesante de toquetear. Como ya sabemos si abrimos en VBA nuestro ROM con la opción de Tools>Palete View y Map View podemos ver nuestros tiles y sus paletas. Para hacer un ejemplo de qué pasa si usamos otra paleta he usado el mismo tile del ejemplo y le he asignado la paleta 15 (0xF).

¿Curioso no? He asignado la paleta 15 a un tile. Por cierto, en A-Map todos los tiles con paletas asignadas superiores a 0xC se verán en negro dado que A-Map no las abre además de que estás paletas son móviles (las carga la rom durante el juego, no son para tilesets).
* * *
Segunda cadena de valores
La segunda cadena de valores, va seguida tras la primera cadena y está formada por los comportamientos-byte y los fondo-byte solamente. Es más sencillo de entender que la primera cadena ya que conservan el mismo orden uno detrás de otro. Es decir, por cada bloque tendremos 4 bytes, 2 de comportamiento seguidos de 2 de fondo uno detrás del otro bloque tras bloque.

* * *
Análisis 2: Guardado de los tileblocks en archivos .bvd
Análisis 2: Guardado de los tileblocks en archivos .bvd
Siempre que queremos pasar un tileblock de una rom a otra lo que hacemos es guardar el tileblock mediante la opción del Editor de Bloques>Blocks>GuardarTileset (pone tileset, pero se refiere al tileblock del que hemos ido hablando) y después cargarlo en una nueva dirección (repunteamos).
El archivo.bvd que creamos se verá así, por ejemplo:

Éste archivo.bvd lo que hace es guardar un registro del tileblock tal como es más unos parámetros para que pueda ser leído al cargase. Lo que vemos en azul es Código del tileblock. Pero aparte de ello vemos 4 bytes iniciales y 4 finales.
- Los 2 primeros bytes indican la cantidad de bloques. 0x1800 es 0x0018 que equivale a 25 bloques. Si hubieran el máximo de bloques, 384, tendríamos 0x0180 obteniendo el código 8001. En el caso de los tileblocks primarios, contienen 640 bloques por lo que tenemos 0x0280 bloques obteniendo el código 8002.
- El 3er y 4to byte no tienen una función aparente, son simples bytes de 00.
- Los últimos 4 bytes sirven para que A-Map identifique la base. En nuestro ejemplo: FRLG.
* * *
Análisis 3: Cargado de los tileblocks en la rom
Hay dos casos normales en los que cargamos de nuevo un tileblock y nos obliga repuntearlo en una nueva dirección. Uno cuando cambiamos la cantidad de bloques y otro cuando cargamos un archivo.bvd.
- En el primer caso lo que hará será una réplica de nuestro tileblock desde el offset del a nueva dirección pero añadiendo a nuestra cadena de código los nuevos bloques al final de cada cadena por orden. (Recordemos: 16 bytes para la forma y 4 para las funciones, un total de 20 bytes para cada nuevo bloque. Al ser bloques nuevos tendrán valor 00)
- En el segundo caso, lo que hará será insertar tal cual el archivo.bvd quitando los 4 bytes iniciales y finales propios del archivo. Ya que la ROM lo lee tal cual, sin especificar los bloques ni la base de antemano.
Entonces, os preguntareis ¿Cómo hace la ROM para asignar cada bloque a un comportamiento/fondo? Sencillo, hace dos repunteos modificando dos punteros de una tabla de varios punteros (empieza en 0x2D4A98). Uno que apunta al principio del tileblock (1ra cadena) y otro que apunta a la 2nda cadena. De esta forma, parece ser que la ROM mide la longitud entre los distintos offset y asi saca la cantidad de bloques que hay en el tileblock. Dado esto, asigna cada bloque de la 1ra cadena a su función de la 2nda cadena.
Por cierto, si os preguntáis que pasa con el tileblock antiguo sabed que ocurre lo mismo que para los tileset. Al repuntear A-Map borra el tileblock antiguo rellenándolo de FF. Es decir, es seguro moverlo por la ROM y repuntear varias veces. Os lo digo para quitaros el miedo.
APLICACIONES
Si habéis seguido la investigación habréis entendido las aplicaciones que puede llega a tener, yo destaco éstas:
Empezar desde un tileblock en blanco y sin comportamientos
Llegados a este punto creo que esto es lo más útil. Normalmente cuando empezamos editamos el tileblock modificando bloques, pero es algo muy molesto ya que a veces nos olvidamos de quitar algún tile o comportamiento antiguo. Lo que recomiendo es limpiar el tileblock ya que normalmente no querrás usar algo del tileblock antiguo. Para ello, guárdalo como archivo.bvd y usa la función de relleno de HxD (Edición>Rellenar Selección>Valores Hexadecimales) y pones 0, exceptuando los primeros y últimos 4 byes del archivo.bvd.
¡Listo! ¡Ya tienes un tileblock vacío listo para editar!
Yo por lo general recomiendo empezar a usar esto con frecuencia ya que agiliza mucho las cosas.
Desplazar bloques, mover o borrar
Imagínate que por error empiezas a montar tu tileblock en 0x250 en lugar de 0x280. Deseas montar tu tileblock de la misma forma desde 0x280 ¿Qué haces? Sencillo, guardas ambos tileblocks y copias los bloques deseados (Os recuerdo que os dan el offset de cada bloque en el Editor de Bloques y que cada bloque son 16 bytes (0xF))
¡Listo! ¡Tan fácil como copiar y pegar! De esta forma nos ahorramos tener que rehacer bloque a bloque.
Editar la paleta de una selección de bloques
En ciertos casos usaremos un tileblock para una estructura de dos paletas. Como ejemplo, imaginad una cueva, pero está cueva tiene dos tonalidades, una gris y otra marrón. Imaginad que habéis hecho el tileblock de la cueva en su versión marrón y ahora queréis su versión gris en el mismo tileblock ¿Qué hacéis? Si lo queréis en el mismo tileblock solamente copiad los bloques a continuación para que conserven el orden que habéis decidido para la cueva marrón y cambia la paleta de éstos nuevos bloques.
¿Cómo cambio la paleta? Sencillo, modificando los bytes de los tiles de la primera cadena. Si os acordáis una parte del byte definía la paleta. Solo tenéis que establecer un punto de partid y final y cambiar ese byte por la paleta que queréis.
Modificarlo con HxD no solo hará más rápido vuestra tarea sino que hará más difícil que cometáis un error. (En HxD se os marcan los cambios antes de grabarlos)
¡Y eso es todo! Me he entretenido mucho investigando por mi cuenta, redactando todo y organizándolo a mi manera. Creo que es algo muy interesante de saber y que servirá tanto a los más nuevos como a los que ya llevamos algunos años en esto.
He intentado explicarlo de forma que se entienda fácilmente pero quizás me haya descuidado reforzar alguna explicación. Si tenéis alguna duda no dudéis en comentarla por aquí, si veis que algo no cuadra también podéis comentarlo.
En todo caso, es un placer y espero que lo disfrutéis de la misma forma que yo. En mi opinión, trabajar con los tileblocks de ésta forma agiliza y facilita mucho las cosas.
~Un abrazo.
Tutoriales relacionados:
Última edición: