Cómo funciona

La maquinaria: de dónde salió el sitio, cómo se escribe el texto y por qué los textos se generan en vez de escribirse a mano.

Trabajo en curso: mira Lo que falta.

La cadena

src/parche_en/parche.txt         definiciones que se pueden leer
        |  construye_parche_en.py
        v
work/parche_en/*.asm             los bloques, ya en ensamblador
        |  parchea.py            empalmados en una copia del listado,
        v                        ensamblados y comparados con el original
work/mahjong_en.rom              la ROM traducida
        |  ips.py
        v
parche/mahjong_en.ips            lo único que se distribuye

El último paso se comprueba, no se supone: ips.py check aplica el parche al original y exige que salga la ROM que se acaba de construir, byte a byte.

De dónde salió el sitio

El texto de la mesa vive en el hueco de las fichas. Cada ficha son seis caracteres, dos de ancho por tres de alto, y las hileras caen a caballo de dos tercios de pantalla. En el tercio de en medio se ve la fila de abajo de las fichas de arriba y la de arriba de las de abajo — la fila del medio de cada ficha no se dibuja nunca ahí.

Y ahí es donde el cartucho escribe sus rótulos. Cruzando la tabla de fichas con las tablas de nombres de 124 volcados de memoria de vídeo: de las 97 celdas que usa la barra, 56 son exactamente el par central de alguna ficha. El mismo número de celda es media ficha en un tercio y un kanji en otro.

Contando lo que gastó la primera fase, lo que hay que conservar (la barra cian de la caja, el cursor del menú) y las doce letras del alfabeto de la barra que ningún rótulo usa, el presupuesto quedó en 49 celdas.

Dos letras por celda

Con letras de 8×8 la caja de mensajes se queda en siete caracteres por línea y no cabe lo que dice el japonés. Antes de escribir nada se presupuestaron tres formas:

celdas que pideveredicto
8×8, una letra por celda26cabe, pero 7 caracteres por línea
3×7, dos letras por celda49cabe, 14 caracteres por línea
5px, «carácter y medio»66no cabe

La de en medio gana y la última pierde por lo mismo: con dos letras por celda el coste es una celda por cada PAR DISTINTO de letras; con carácter y medio las letras caen a caballo de dos celdas, casi todas son únicas y la cuenta se dispara. El cálculo no necesita la fuente — una celda queda determinada por qué trozos de letra caen dentro y con qué desplazamiento.

Dos consecuencias, y las dos mordieron:

Ahora mismo la cuenta es de 49 pares distintos para 49 celdas, sin nada de margen.

Cuando un bloque no cabe en su hueco

A menudo. El inglés es más largo que la katakana, y un bloque comprimido con letras dentro comprime peor.

El generador lo resuelve con reubica=RUTINA: el bloque se va a la zona libre del final del cartucho y se reapunta el ld hl que lo carga. Los bloques llevan su destino de VRAM dentro, así que da igual desde dónde se lean. Hicieron falta dos variantes:

La zona libre son los 8.219 bytes de 0xFF del final del cartucho (0x9FE5-0xBFFF), de los que el parche gasta 8.049 —quedan 170, medidos como los 0xFF que siguen al final—. Lo que eso supone: que el chip original tuviera esos 8 KB grabables. En emulador y en flashcart —que es como se juega— funciona seguro.

Hay además una válvula de escape que conviene conocer: las celdas 0x08, 0x09 y 0x0A del bloque sin comprimir de 0x92E3 son copias byte a byte de 0x0C, 0x0D y 0x0E. Como ese bloque va sin comprimir, meter letras ahí no cuesta tamaño — que es lo que te salva cuando un bloque comprimido se pasa de su hueco por unos pocos bytes.

El generador

src/parche_en/parche.txt es el parche entero en forma legible. La sintaxis completa está en el docstring de construye_parche_en.py; las formas que conoce son:

secciónqué escribe
[patrones] / [colores]formas de carácter y colores, con reubica=
[formatoA] / [formatoB]los dos formatos de lista de dibujo del cartucho
[codigo]una sustitución de instrucción con nombre, línea a línea
[libre]declara la zona libre
[asmlibre]código nuevo al final de ella, con las etiquetas resueltas por el ensamblador
[diapositiva]una lista de formato A nueva — así se escribe una pantalla del tutorial
[tilesnuevos]saca fichas de un bloque comprimido, las recomprime en otra dirección y reescribe la tabla de fichas, para poder seguir pidiéndolas por su nombre

Más los destinos crudos @0xDIR y el token <glifo@fuente>, para escribir directamente en las tablas de patrones y colores del VDP, y la orden fichas, que saca los dibujos de la propia tabla del cartucho.

Tres generadores son dueños de sus secciones de parche.txt y son la fuente de verdad de ellas: los dos repartidores de dígrafos y el troceador del logo. Esas secciones se regeneran, no se editan.

Leer la pantalla, no el parche

La construcción demuestra que la ROM es la que se pidió. No puede demostrar que la pantalla esté bien, y una vez no lo estuvo: mira la banda cian.

make pantallas cierra ese agujero. Vuelca las pantallas del cartucho original y las del parcheado y las compara celda a celda, con una regla que no adivina nada:

Si una celda dibuja el mismo número de celda en las dos versiones, y el dibujo antes no se veía y ahora sí, se ha escrito una letra dentro del mobiliario.

Lo que distingue el mobiliario de una traducción normal es justo eso. Cuando el parche traduce un rótulo reescribe la lista, así que en esa celda acaba habiendo otro número. El mueble se queda con el suyo, porque nadie lo ha tocado: lo único que ha cambiado es el dibujo de debajo.

Una excepción, comprobada a mano y escrita dentro de la herramienta: el logo del título, cuyo lienzo de 54 celdas se redibuja a propósito.