El parche

Ciento treinta entradas, 1.396 bytes, ninguna fuera de la tabla y ninguna desplazada: cada parche mide exactamente lo mismo que lo que sustituye, así que ninguna dirección del juego se mueve.

Son dos cosas de origen distinto: 27 entradas escritas a mano —548 bytes de código, punteros y texto— y 103 que salen solas de los lienzos —848 bytes, los 122 tiles del mapa repintados—. Byte a byte: 848 de tiles, 376 de texto, 137 de código nuevo, 23 de ganchos y trampolines, 10 de punteros y 2 sueltos —el tope del bucle de siembra y el papel del texto—. La herramienta no distingue entre unas y otras: todas llevan los bytes que esperan encontrar y todas miden lo mismo que lo que sustituyen.

La tabla

direcciónbloquebytesqué
0x7FD1medio1el tope del bucle de siembra, 0x78 → 0x00
0x708Amedio3trampolín a la rutina de los valores
0x6600medio76MUESTRA_LOS_VALORES
0x664Cmedio61la siembra por bando, el dibujo por bando y el plazo
0x7FC9medio5gancho de la siembra
0x770Amedio10gancho del dibujo
0x6F77medio5gancho del anillo
0x763Fmedio1el papel del texto, 0x78 → 0x70
0x7DE6medio9Habil → Firme, en su propio hueco
0x6689medio25 Virtuoso, Valiente y Fuerte
0x6FF0, 0x701F, 0x7036medio2 cada unolos tres punteros de esos adjetivos
0x66A2medio64las cuatro frases enteras de la última línea de la ficha
0x7074, 0x707Amedio2 cada unoel puntero de esa lista y su columna
0x7A79…0x7BC7medio180los diez toponimos del mapa
0x6BA5medio9Brand III → Bardo III
0x7D07medio45las razas en plural
0x7D3Amedio44las razas en singular
0x9E02…0xA280alto848los 122 tiles repintados, en 103 entradas

Las direcciones son de ejecución. El bloque «medio» corre desde 0x5E00 y el «alto» desde 0x9E00. Los diez toponimos son ocho entradas: siete sueltas —0x7A79, 0x7B28, 0x7B34, 0x7B4B, 0x7B5D, 0x7B7F y 0x7BC7— y una de 112 bytes que reescribe de una vez el tramo de nueve registros que empieza en 0x7AA1, porque ahí Rivendell encoge una letra para prestársela a Dale, y encoger un registro corre todos los de detrás.

Los cuatro formatos de texto

Nada se desplaza, así que el sitio de cada cadena manda. Y aprieta distinto según dónde viva:

La cuarta lista, la de la última línea de la ficha (0x7D6A), se mudó entera a 0x66A2. La línea se componía con una plantilla más la palabra de la lista y ahora cada entrada trae la frase completa, escrita desde la columna 0: era la única forma de que Aliado a la Sociedad pasara a Aliado a la Comunidad sin tocar las otras tres.

Cómo se aplica

El desensamblado no se toca. Se parte de los cuerpos que make extract saca de tu cinta (work/*.raw, los mismos bytes sin la envoltura del formato Spectrum), se les aplica la tabla de tools/parchea.py y se vuelve a montar la cinta reenvolviendo cada bloque con su bandera delante y su XOR detrás.

Cada entrada de la tabla lleva los bytes que espera encontrar. Si no están, make parche aborta: no es esa cinta. Y al terminar se comprueba que, fuera de los rangos de la tabla, el cuerpo es idéntico al original.

Dónde vive el código nuevo

Los 137 bytes de código nuevo —76 de la rutina de los valores y 61 de la segunda tanda— están escritos encima del motor del altavoz del ZX Spectrum, en 0x6600-0x6688. Detrás van 89 bytes más que ya no son código sino texto: los tres adjetivos largos (0x6689-0x66A1) y las cuatro frases de la última línea de la ficha (0x66A2-0x66E1).

Ese motor lo trajo la conversión entero y no lo llama nadie: ni una instrucción de los cinco listados apunta a 0x6600, y los cuatro sitios que piden un efecto de sonido llaman a 0x65FF, que es un ret pelado. Del PSG del MSX sólo se escriben dos registros, el 7 y el 14, y los dos son para leer el joystick. Este juego es mudo, y su silencio nos deja 276 bytes de sitio, de los que el parche gasta 226 y deja 50 libres. Hay una prueba que comprueba que ninguna entrada se sale de ese tramo ni pisa a otra.

Los gráficos, en tres PNG

Todos los dibujos del bloque alto se editan con un editor de imágenes. Están en src/parche/, a tamaño real y sin separación: un píxel del PNG es un píxel del juego.

lienzoqué llevadónde vivetamaño
tiles_del_mapa.pnglos 128 tiles del mapa, de 8 × 80x9E00128 × 64
sprites_de_batalla.pnglos 176 sprites de batalla, de 16 × 8 con máscara0xA2E8176 × 128
fuente.pnglos 128 caracteres, de 8 × 80xC800128 × 64

Se repinta lo que se quiera y make parche hace el resto: compara los lienzos con la cinta y cada dibujo que haya cambiado sale solo como una entrada más de la tabla, del grupo graficos, con su orig y su nuevo de la misma longitud, igual que las escritas a mano. Si no se tocan, no aparece ni una entrada de más.

Hoy salen de ahí 122 de los 128 tiles, repintados: 103 entradas y 848 bytes, más de la mitad del parche. Los seis que no se mueven son el 97 al 102, a los que sólo les cambió el fondo —el blanco del ZX y el del MSX son el mismo color 15, así que el dibujo que vuelve es byte a byte el que había—. El Ojo de Sauron está ahora en ese grupo: eran 36 bytes escritos a mano y se dibuja en el lienzo como todo lo demás.

ordenqué hace
make graficosdice qué dibujos cambian respecto a la cinta, sin montar nada
make parchelos convierte en entradas del parche y arma la cinta
make lienzosrehace los PNG desde la cinta, o sea que se lleva por delante lo que esté dibujado encima; hay que insistirle con --rehaz

Cómo se pinta cada hoja

Lo que no se toca

Un dibujo que se vea exactamente igual que el de la cinta se devuelve con sus bytes de siempre, sin recodificar. Por eso abrir un PNG y guardarlo sin cambiar nada no mueve un solo byte, ni siquiera en los que no se pueden reconstruir mirando la imagen: un tile con tinta blanca sobre papel blanco lleva ocho bytes de dibujo escondidos debajo, y otro tanto uno que sea negro sobre negro. Sin esa regla, cada ida y vuelta ensuciaría el parche con cambios que nadie ha pedido —y es lo que hoy deja fuera del parche a los tiles 97 a 102—.

La paleta de cada hoja va dentro del PNG, así que un editor en modo indexado la ofrece hecha. Si aun así entra un color de fuera —por trabajar en color verdadero, por ejemplo—, se toma el más parecido y se avisa por pantalla de cuál era, cuántos píxeles y por qué color se ha cambiado.

El IPS

make ips saca war_parche.ips: 1.718 bytes en 39 registros, con sólo lo que cambia. Comprobado en el sitio —y en las pruebas— que aplicado sobre war.tsx devuelve la cinta parcheada byte a byte.

Se reparte eso, no el juego.

Las comprobaciones

make test son 79, y no son de adorno. Entre ellas: