MMX Zero History — recompilación de Mega Man X3 con historia, jefes y cápsulas propias, en español chileno. Linux, Windows, macOS y Android.
  • C 37.9%
  • Python 35.8%
  • Java 12.3%
  • Shell 10.2%
  • PowerShell 2.8%
  • Other 1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Daniel Rojas 7859e862ba v0.0.6: el guion entra al juego
Hasta la 0.0.5 el proyecto aplicaba un solo parche al cartucho: el nombre
interno. El guion, los jefes y las cápsulas seguían siendo documentación.

Esta versión escribe el guion completo sobre la imagen del jugador, en
memoria, y lo verifica.

Cómo se pudo
------------
X3 guarda su script como ASCII plano con saltos 0x80 0x80 y comandos de un
byte entre páginas. No hay tabla de glifos que adivinar para el texto latino.
Cada página es un tramo imprimible de largo fijo, así que reemplazarla no
mueve ni un puntero: el formato del cartucho es el contrato.

Pipeline
--------
  content/story_es.txt     guion en chileno, un beat por línea
  tools/build_story.py     lee el dump, mide las páginas, empaqueta
  src/x3_story_data.c      generado: nuestro texto + direcciones + largos
  src/x3_story.c           aplica tras verificar el SHA-256 de la imagen

Tres invariantes, cada una con test:
 - misma longitud de página que el tramo original (nada se mueve);
 - sólo ASCII imprimible y 0x80 (un control pisado rompería la página);
 - ninguna línea de más de 22 columnas: el motor no envuelve texto y la
   tercera línea de la caja va centrada, donde 28 columnas ya se cortan.

Cobertura: intro (20 páginas), Acto I (24), ocho cápsulas, Acto II/III
(26 + 87), tablas de cast/jefes/armas/stats y los rótulos del título.

Verificado en el motor real
---------------------------
 - [mmx] historia: 227/227 pagina(s) aplicadas sobre el ROM en memoria
 - el prólogo y los diálogos salen en la caja de texto del juego;
 - el menú del título dice EMPEZAR / CLAVE / OPCIONES;
 - con un dump distinto no se escribe un byte y el log lo dice;
 - 5000 frames sin fallos con ambos overlays activos (historia + contenido).

Lo que NO cambia: sprites, mapas, música del SPC y lógica de los jefes. La
historia se cuenta con los personajes y escenarios que el cartucho ya tiene.
2026-10-27 21:31:35 -03:00
.github/workflows v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
android v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
assets/audio MMX Zero History 0.0.1 — Bóveda Ω 2026-10-27 16:57:50 -03:00
content v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
docs v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
mods/preloaded/packages/megaman-x3.enhancement.widescreen/1.0.0 v0.0.2: 16:9 en todas las versiones, APK Android y assets 16:9 2026-10-27 18:00:11 -03:00
recomp Preserve X3 generation hooks and update framework dependencies (#3) 2026-10-18 13:01:47 -07:00
recomp-ui@0546fbcb01 Preserve X3 generation hooks and update framework dependencies (#3) 2026-10-18 13:01:47 -07:00
snesrecomp@f68aa0fe8e Use the validated Windows setup analyzer dependency staging 2026-10-18 13:21:55 -07:00
src v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
symbols Preserve X3 generation hooks and update framework dependencies (#3) 2026-10-18 13:01:47 -07:00
third_party Preserve X3 generation hooks and update framework dependencies (#3) 2026-10-18 13:01:47 -07:00
tools v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
.gitignore v0.0.5: aplicar contenido al ROM, no sólo documentarlo 2026-10-27 20:22:49 -03:00
.gitmodules Import pinned DiztinGUIsh annotations for Mega Man X3 2026-10-09 11:13:49 -07:00
CMakeLists.txt v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
framework_pins.txt Use the validated Windows setup analyzer dependency staging 2026-10-18 13:21:55 -07:00
keybinds.ini Initial scaffold: Mega Man X3 (USA) static recompilation 2026-07-26 13:58:58 -07:00
LICENSE Declare PolyForm Noncommercial 1.0.0 2026-09-09 13:47:52 -07:00
README.md v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
RELEASE_NOTES_v0.0.1.md MMX Zero History 0.0.1 — Bóveda Ω 2026-10-27 16:57:50 -03:00
RELEASE_NOTES_v0.0.2.md v0.0.2: 16:9 en todas las versiones, APK Android y assets 16:9 2026-10-27 18:00:11 -03:00
RELEASE_NOTES_v0.0.3.md v0.0.3: la app Android deja de cerrarse al abrir 2026-10-27 19:15:52 -03:00
RELEASE_NOTES_v0.0.4.md v0.0.4: decir en la app qué cambia esta build y qué no 2026-10-27 20:04:37 -03:00
RELEASE_NOTES_v0.0.5.md v0.0.5: aplicar contenido al ROM, no sólo documentarlo 2026-10-27 20:22:49 -03:00
RELEASE_NOTES_v0.0.6.md v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00
rom_identity.txt Preserve X3 generation hooks and update framework dependencies (#3) 2026-10-18 13:01:47 -07:00
VERSION v0.0.6: el guion entra al juego 2026-10-27 21:31:35 -03:00

MMX Zero History

MMX Zero History

Recompilación nativa de Mega Man X3 (USA) con identidad, historia, jefes, cápsulas y banda sonora propias, en español chileno, para Linux, Windows, macOS y Android.

La historia que Zero nunca alcanzó a contar.

Desktop host

Qué es esto

Un fork de MegamanX3SNESRecomp que conserva el motor (ejecución LLE del 65816 con cobertura AOT encima, Cx4 emulado por instrucción) y le cambia todo lo que se puede cambiar sin tocar el cartucho: nombre, identidad visual, línea narrativa, guion, diseño de jefes y cápsulas, banda sonora original, controles táctiles y CI multiplataforma.

Qué no es esto

No es un ROM hack. No trae sprites nuevos de jefes, mapas nuevos, música insertada en el SPC ni el texto del juego traducido dentro del cartucho. Eso es un proyecto de meses y está especificado, no implementado.

Lo que hay acá es todo el andamiaje alrededor de eso más el motor real compilando. La línea exacta entre "funciona" y "está escrito" está en docs/ESTADO.md, sin adornos.

Qué ves cuando jugás

Esto es lo que cambia de verdad al abrir el juego, y es todo:

  • El nombre: la app es MMX Zero History, con icono y placa de arranque propios.

  • El campo 16:9 (342×224): HUD anclado a los lados, columnas nuevas de BG1 y BG2, ventanas de activación y dibujo de enemigos ensanchadas. Se apaga desde config.ini (Widescreen = 0).

  • El diagnóstico: la pantalla de entrada de Android muestra la versión de la build y el campo que el motor eligió, leídos de native.log.

  • El guion (desde la 0.0.6): el prólogo de la Bóveda Ω, los diálogos, los textos de las ocho cápsulas, el final y los nombres de los ocho mavericks con sus stats y sus armas, todo en chileno y dibujado por la caja de texto del propio juego. El menú del título dice EMPEZAR / CLAVE / OPCIONES.

Y esto es lo que no cambia todavía: los sprites de los jefes, los mapas nuevos y la banda sonora no están dentro del juego. Si abrís el APK y ves los jefes originales de Mega Man X3 con los nombres nuevos, es el comportamiento esperado de esta versión, no un fallo de instalación: la historia se cuenta con los personajes y los escenarios que el cartucho ya tiene.

El guion se aplica al ROM (lo que se puede verificar)

Desde la 0.0.6 el guion entra al juego. tools/build_story.py lee tu dump, localiza las páginas de texto del cartucho y empaqueta content/story_es.txt en ellas sin mover un puntero; src/x3_story.c las aplica sobre la copia en memoria, sólo después de comprobar el SHA-256.

adb shell cat /sdcard/Android/data/cl.zerohistory.mmx/files/native.log | grep historia
# [mmx] historia: 227/227 pagina(s) aplicadas sobre el ROM en memoria

Desde la 0.0.5 hay además una tabla de contenido propia, content/zerohistory.toml, que el motor aplica sobre la copia en memoria de tu dump después de verificar su identidad:

adb shell cat /sdcard/Android/data/cl.zerohistory.mmx/files/native.log | grep contenido
# [mmx] contenido: tabla content/zerohistory.toml, idioma es, 1 parche(s) de ROM, 0 de VRAM
# [mmx] contenido: 1/1 parche(s) de ROM aplicados

Cada parche va guardado por contenido (source_hex): si los bytes del destino no son los del cartucho original, no se aplica nada y el log lo dice. Tu archivo nunca se modifica. Para una copia parcheada en disco:

python3 tools/x3_content_patch.py --check mmx3.sfc
python3 tools/x3_content_patch.py --apply mmx3.sfc

Hoy el parche incluido es la identidad interna del cartucho (cabecera LoROM, 0x7FC0), el único campo cuya posición fija la especificación del formato. El resto —guion, jefes, mapas, música— necesita direcciones y glifos derivados del dump real; el mecanismo está listo y esperando esos datos. El detalle completo, con el formato y las reglas, está en docs/CONTENIDO.md.

El ROM

Tenés que poner tu propio dump, legalmente obtenido. Nada derivado del ROM se versiona en este repositorio.

  • archivo: mmx3.sfc en la raíz del repo
  • tamaño: 2 MiB, sin cabecera
  • CRC32: 0xFA0FE671
  • SHA-256: 65b03268afac296330e8ff8d60dd0825879e13ed658b37713c034a3bd074f1d7

Una cabecera de copiador SMC de 512 bytes se descarta automáticamente, tanto en el recompilador como en el launcher. Verificalo con:

python3 tools/verify_rom.py mmx3.sfc

La historia

Años después de Doppler, una excavación bajo Atacama abre la Bóveda Ω: el archivo personal del Dr. Wily, todavía en línea. Adentro no hay un robot, hay un eco — la voz y el criterio de Wily, grabados para seguir dando órdenes después de muerto. Y lo que el eco quiere no es conquistar el mundo: es terminar un trabajo que quedó a medias y recuperar a Zero.

Para eso reactiva ocho revisiones de la unidad W-00, el nombre de fábrica de Zero. Cada jefe carga un fragmento cifrado de su pasado. X baja a las ocho zonas y, por cada jefe que cae, una memoria vuelve a su lugar.

La historia no se cuenta en una cinemática: se cuenta en pedazos, y el pedazo que importa es el último — Wily construyó a Zero para matar a Mega Man, y Zero alcanzó a intentarlo.

Línea de tiempo

  • Biblia narrativa completa: docs/HISTORIA.md
  • Guion de todas las cinemáticas, en chileno: docs/GUION.md
  • Tres finales según cuántos fragmentos juntaste

Los ocho mavericks

Ocho revisiones W más el jefe final, con anillo de debilidades cerrado: ningún orden de etapas deja al jugador sin respuesta.

  • W-01 — Cóndor Cobalto, Cordillera de los Andes · Ala Cobalto
  • W-02 — Salitre Sierpe, Desierto de Atacama · Salmuera
  • W-03 — Glaciar Grifo, Campo de Hielo Sur · Aliento Blanco
  • W-04 — Víbora Caldor, Volcán Caldor · Erupción
  • W-05 — Marea Mantis, Fiordos de Chiloé · Ola Cortante
  • W-06 — Jabalí Alerce, Selva Valdiviana · Astilla
  • W-07 — Búho Reloj, Puerto del Reloj · Segundero
  • W-08 — Puma Chatarra, Desarmadero Wily · Imán Puma
  • Ω — Cero-Ω y el Eco de Wily, Bóveda Ω

Mapa de etapas

Patrones de ataque, fases y drops en docs/MAVERICKS.md.

16:9 en todas las versiones

Desde la 0.0.2 el campo de juego es 16:9 en Linux, Windows, macOS y Android. El motor renderiza 342×224 píxeles reales —el máximo que cabe con la relación de píxel 7:6 de SNES— y rellena las columnas nuevas con los tiles auténticos de BG1 y BG2; el HUD del jugador se ancla a la izquierda y el del jefe a la derecha. El paquete megaman-x3.enhancement.widescreen viene habilitado por defecto y se puede apagar desde el launcher (Mods → Widescreen).

Los assets, la placa de arranque y el icono se rediseñaron en 16:9 (1920×1080). En Android el modo es inmersivo de borde a borde, con layoutInDisplayCutoutMode = shortEdges; en pantallas 19.5:9 o 20:9 la imagen sigue siendo 16:9 centrada, no estirada, y los controles táctiles se miden en unidades del lado corto para seguir cuadrados en cualquier relación de aspecto.

El campo se topa en 342 px (tools/test_display_width.sh): es la configuración que el port midió, así que una pantalla más ancha que 16:9 agrega barras en vez de inventar columnas sin validar.

Cápsulas errantes

Ninguna cápsula tiene posición fija. Cada etapa tiene tres nichos autorados, todos alcanzables con el equipo base; cada partida elige uno por etapa y reparte los ocho contenidos al azar.

Cápsulas errantes

El reparto es determinista y verificable — publicado como semilla en el select de etapas:

$ python3 tools/capsule_shuffle.py --mode speedrun
semilla 00000000
  W-01 condor_cobalto   nicho 3  -> Casco      (rompe bloques)
  W-02 salitre_sierpe   nicho 2  -> Núcleo 01  (fragmento de memoria)
  W-03 glaciar_grifo    nicho 1  -> Núcleo 02  (fragmento de memoria)
  ...

$ python3 tools/capsule_shuffle.py --mode historia --slot 1
semilla CC0D3F32
  ...

Modos: Historia (semilla por perfil/slot/partida), Speedrun (semilla fija 0) y Caos (semilla nueva cada vez). Contrato completo en docs/CAPSULAS.md; pruebas con python3 tools/test_capsule_shuffle.py.

Música

Doce pistas originales a 32 kHz mono, generadas desde código: el tema de la Bóveda, el select de etapas, las ocho etapas, la Bóveda Ω y el tema de Zero. Misma familia de timbres que un juego de SNES (dos pulsos, triángulo, ruido), melodías y progresiones nuevas.

python3 tools/make_soundtrack.py          # renderiza las doce
python3 tools/make_soundtrack.py --list   # tempo, compás y mood

Escuchalas en assets/audio/. Diseño y camino de integración al motor en docs/MUSICA.md.

Plataformas y controles

  • Linux / Windows / macOS — host de escritorio SDL2, con soporte real de mando por SDL_GameController (Xbox, DualShock, 8BitDo) y teclado remapeable en keybinds.ini.
  • Android — APK arm64-v8a con controles táctiles (D-pad, rombo SNES, hombros, start), auto-ocultado al conectar un mando y geometría cuadrada en cualquier aspecto.

Android

APK de Android

Cada release publica MMXZeroHistory-android-arm64-v8a.apk (y un build x86_64 para emuladores). Es un host LLE sin código derivado del ROM: el binario no trae el juego, lo carga desde tu dump.

  1. Instalá el APK (Android 7.0+).
  2. Abrí la app. La primera pantalla pide el cartucho.
  3. Tocá Elegir mi mmx3.sfc y elegí tu dump con el selector del sistema. Se copia a la carpeta de la app, se verifica el SHA-256 y se descarta la cabecera de copiador si la trae.
  4. La app arranca el motor con el campo 16:9.

El botón Historia y jefes abre la Bóveda Ω, los ocho mavericks con su arma, el anillo de debilidades y las reglas de las cápsulas: ese contenido vive en la app, no en el cartucho.

Historia y jefes en Android

Pantalla de entrada en Android: ROM verificado, build y campo 16:9

Para capturar una pantalla de juego —la etapa 1, por ejemplo— con tu dump ya cargado:

tools/capture_android.sh docs/img/android-etapa-1.png

Desde la 0.0.3 la app no se cierra al abrir: si falta el ROM (o no es el dump correcto) lo dice en pantalla, y si el motor se corta después de arrancar muestra el final de native.log en vez de desaparecer.

El APK se compila, se firma y se ejecuta en un emulador x86_64 del repo (SDK 34, Android 14): la pantalla de entrada queda estable, el importador rechaza un archivo con SHA-256 equivocado y el motor llega a first frame simulated con un dump presente. Lo que no se pudo verificar es una partida real: hace falta un dump legal de Mega Man X3 (USA), que este repositorio no incluye.

La capa táctil se dibuja con geometría 16:9 y produce la máscara de botones, pero el envío al guest sigue pendiente porque el estado del pad es privado del host: para jugar hoy hace falta un mando Bluetooth. La receta completa está en docs/ANDROID.md.

La lógica táctil sí está probada en el escritorio (17 pruebas: dos dedos a la vez, dos dedos en el mismo botón, latcheo al deslizar, saturación de la tabla de dedos, espejado exacto y teclas cuadradas en 16:9, 19.5:9, 20:9 y 4:3):

bash tools/test_touch_controls.sh
bash tools/test_display_width.sh

El APK se construye con:

bash tools/build_android.sh arm64-v8a

Build

git submodule update --init --recursive
cp /ruta/a/tu/dump mmx3.sfc
python3 tools/verify_rom.py mmx3.sfc
bash tools/regen.sh --no-tests          # emite src/gen/*.c + recomp/funcs.h
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSNESRECOMP_SDL_BACKEND=SDL2
cmake --build build --target MegaManX3SNESRecomp

Para depurar con el servidor TCP de 4384 y los anillos de observabilidad, configurá con -DSNESRECOMP_ENABLE_TRACE=ON.

Sin ROM se puede compilar igual el setup host, que es lo que corre CI:

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DSNESRECOMP_SETUP_HOST=ON
cmake --build build --target MegaManX3SNESRecomp

Integración continua

  • build.yml — pruebas (cápsulas + táctil) y compilación del host de escritorio en Linux. Es el gate real.
  • rom-build.yml — manual. Compila el binario jugable en Linux, Windows y macOS leyendo tu ROM desde el secreto MMX3_ROM_BASE64, que nunca entra al repositorio. Verifica el SHA-256 antes de aceptar el archivo.
  • android.yml — manual. Compila el APK de un ABI concreto con tools/build_android.sh y lo deja como artefacto. No necesita el ROM.
  • release.yml — al empujar una etiqueta v*, publica los paquetes de las tres plataformas de escritorio, el APK de Android, arte, banda sonora y el aviso de ROM.

Estado de cada uno al publicar la 0.0.2:

  • Desktop host (Linux): verde — pruebas + compilación, corrida real en CI.
  • Release: publica los tres .zip de escritorio y el APK arm64-v8a, con el catálogo de mods incluido para que el 16:9 viaje activo.
  • Android: tools/build_android.sh compiló el APK en esta máquina con SDK 34 / NDK r27 y lo firmó; el workflow Android corre el mismo paso.
  • rom-build: escrito, nunca corrido (necesita el secreto con tu ROM).

Estado

Lo que corre hoy, lo que está escrito y lo que no existe (sprites, mapas, música insertada, traducción dentro del cartucho) está separado explícitamente en docs/ESTADO.md. Si algo de este README suena a que el juego nuevo ya está adentro del cartucho, leé ese archivo.

Créditos y licencia

  • Motor: snesrecomp y recomp-ui, con el port original de mstan.
  • Emulación del Cx4: adaptada de ares (ISC), vía snesrecomp.
  • Anotaciones de desensamblado: bogaa/dizProjects.
  • Todo el contenido nuevo de Zero History —historia, guion, diseño, arte, banda sonora y código— es original de este repositorio.
  • Licencia del código: PolyForm Noncommercial 1.0.0 (ver LICENSE). El ROM de Mega Man X3 y cualquier dato extraído de él no se distribuyen acá y no están licenciados para redistribución.

Documentación técnica heredada del port original: docs/WIDESCREEN.md, docs/SAVE_STATES.md, docs/CX4.md, docs/COVERAGE_2026-10-18.md.