pitch: Como nasceu o port nativo de Dungeon & Dragons: Shadow of Mistara (CPS-2 / "ddsom")
Introdução
- repositório: aqui
Dungeons & Dragons: Shadow over Mystara ("ddsom" no catálogo de ROMs) é um beat-'em-up de até quatro jogadores lançado pela Capcom em 1996 na placa arcade CPS-2. O projeto ddsom-recomp é um port totalmente nativo para Windows (e, pela base compartilhada, também macOS/Linux): em vez de emular a placa, ele traduz o código original do arcade para C/C++ nativo e o compila num executável comum. O resultado roda como qualquer programa Windows — sem camada de emulação, sem tradutor em tempo de execução.
Este texto explica, com base no próprio repositório público, como esse port foi construído: do hardware da placa CPS-2 ao pipeline de recompilação, à organização dos arquivos e ao modo de jogar.
Aviso de direitos autorais: o repositório não contém a ROM do jogo nem a chave de descriptografia (
ddsom.key, 20 bytes). Você fornece esses arquivos a partir de uma placa que você é dono. O projeto distribui apenas código recompilado, ferramentas e documentação, sob licença GPL-3.0-only.
1. O conceito: recompilação estática, não emulação
A diferença central entre este port e um emulador (como o MAME) está em quando e como o código do arcade vira código executável na sua máquina.
- Emulação (por instrução): a cada ciclo, o emulador lê uma instrução da CPU do arcade (aqui, o Motorola 68000), decodifica-a e a executa através de uma função genérica em C. Há uma interpretação contínua: o programa original nunca vira código da sua CPU, ele é "simulado" instrução por instrução.
- Recompilação estática (ahead-of-time): uma ferramenta analisa o programa do arcade antes de rodar e gera, função por função, código C/C++ equivalente que a sua CPU executa diretamente. O que era um bloco de instruções 68000 vira uma função
native_*.cppcompilada ao lado do resto do programa.
Como o código nativo é executado direto pelo processador, evita-se a sobrecarga do laço de interpretação. Os ganhos práticos citados no projeto são: baixa latência, possibilidade de alta resolução / alta taxa de atualização, e uma interface (menu/HUD) em texto real (widgets de UI verdadeiros, acessíveis a leitores de tela) em vez do texto rasterizado da tela do arcade.
Importante: ainda existe um interpreter na árvore, mas ele serve apenas como fallback para blocos ainda não traduzidos e para os modos de verificação (check / interp / blocks). No ddsom, um check que compara o código traduzido contra o interpretador reporta 0,000% de instruções no interpretador — ou seja, todo o código foi traduzido e roda nativamente.
2. O hardware CPS-2 por trás do jogo
Para entender o que foi recompilado, vale lembrar a composição da placa:
| Componente | Função no arcade |
|---|---|
| Motorola 68000 (CPU principal) | Roda a lógica do jogo — controle, física, inimigos, estados de tela. É o programa que vira native_*.cpp. |
| Z80 (CPU de som) | Controla a placa de som, incluindo o chip QSound da Capcom (áudio espacial). Seu programa é traduzido por separado (z80_*.cpp). |
| Chips custom da CPS-2 | Geram vídeo (sprites/objetos, scroll, paleta, rowscroll, prioridade) e cuidam de proteção/descriptografia. O que o programa "espera" da placa é reimplementado em C++ no port, não emulado. |
O ponto-chave: a lógica do jogo vive no 68000 (e a música/efeitos no Z80). Tudo o que essas CPUs esperam da placa — vídeo, QSound, registradores da CPU de som, memória de configurações (EEPROM) — é código escrito para o projeto em port/, machine/, video/ e sound/. Não há fontes de emulador linkadas ao binário (uma busca na árvore não encontra código de MAME; as únicas referências a "MAME" são comentários que checam o CRC32 de cada arquivo de ROM contra src/mame/capcom/cps2.cpp).
3. A base: o toolkit cps2recomp
O ddsom-recomp não reinventa a roda: ele é o cps2recomp (de Tommy McLeroy, tmcleroy/cps2recomp, GPL-3.0) com o jogo ddsom pré-configurado. O cps2recomp é um toolkit que já portou diversos jogos CPS-2 (e CPS-1), todos num único launcher.
O repositório ohackercego/ddsom-recomp é um fork/derivado achatado ("flattened"): em vez de ter o toolkit num subdiretório cps2recomp/ e os jogos como irmãos, tudo mora na raiz do repositório — o toolkit completo, com as ferramentas, o código-fonte gerado e o executável pré-compilado para ddsom. A versão atual é 0.4.0-beta.3.
Como o toolkit é compartilhado, uma correção ou recurso feito na base alcança todos os jogos; cada jogo só adiciona sua definição e o "cola" específico recompilado.
4. O pipeline: como o port foi produzido
O processo de transformar a ROM num .exe nativo tem estas etapas (conforme tools/, runtime/ e CMakeLists.txt):
- Extração e leitura da ROM criptografada. A CPS-2 armazena seu programa criptografado; o toolkit lê o ROM set
ddsom(EUA, revisão 950101, 22 arquivos) usandomachine/cps2crypt.cpp(derivado do MAME, BSD-3-Clause). A descriptografia exige addsom.key(20 bytes) — tanto na compilação quanto na execução. Sem a chave válida, o build falha e o jogo se recusa a iniciar; não há modo "sem chave". - Descoberta do código ("explore"). Um passo roda o jogo em made-up play para encontrar quais blocos de código existem e onde estão. No cps2recomp isso é o alvo
make GAME=ddsom explore. - Recompilação do 68000 → C++.
tools/recomp.pytraduz o programa 68000 emwork/ddsom/gen/native_*.cpp(um arquivo por grupo de blocos). É esse o "código nativo" de fato — milhares de arquivos gerados que você quase nunca precisa tocar. - Recompilação do Z80 (som) → C++.
tools/recompz80.pyfaz o equivalente para o programa de som, gerandowork/ddsom/gen/z80_*.cpp. - Reimplementação do hardware da placa. O que o programa espera da placa é escrito do zero em C++:
machine/— cola da máquina CPS-2 recompilada:cps2crypt,eeprom,kabuki(CPS-1),m68k,romset, placa de som.video/esound/— backends nativos de vídeo e áudio QSound/Z80.port/— frontend SDL3:main.cpp, menu, HUD, apresentação, shaders.runtime/— o runtime de recompilação (recomp.cpp,recomp_z80.cpp), estado da placa/jogo,native.h.
- Linkagem. O
CMakeLists.txtaglobagen/native_*.cppegen/z80_*.cppe os compila junto com o frontend e a máquina emadd_executable(ddsom ...). Sem o código traduzido, o binário ainda compila e roda tudo no interpretador; com ele, roda nativo. - Verificação. O alvo
ddsom-checkroda o código traduzido lado a lado com o interpretador e compara; no ddsom o resultado é 0,000% de instruções no interpretador — cobertura de tradução total.
O runtime/state.h serializa toda a máquina (CPU, RAM, QSound, EEPROM) para save states — o mesmo estado que uma futura netcode de rollback retrocederia.
5. Organização do repositório
Tudo na raiz (layout achatado). Os caminhos relevantes:
| Caminho | O que é |
|---|---|
games/ddsom/ | Definição do jogo: game.cfg (ROM set + CRC32), src/ (cola específico recompilado: board.cpp, cases.cpp, ddsom.h, game.cpp) e o README.md com controles e FAQ. |
work/ddsom/ | Código nativo recompilado (native_*.cpp, z80_*.cpp) + logs de análise. É a tradução real do programa original. |
build/ddsom/ddsom.exe | Executável Windows nativo pré-compilado (~21 MB, runtime C++ estaticamente linkado). Ao lado: SDL3.dll, zlib1.dll, libiconv-2.dll. |
port/, machine/, video/, sound/, runtime/, recomp-common/ | Frontend SDL3, máquina CPS-2, backends, runtime e infraestrutura compartilhada. |
tools/ | Ferramental de recomp: recomp.py, recompz80.py, audit.sh, graft.py, empacotamento de release. |
docs/framework-README.md | README do toolkit original (design e build). |
Jogar.bat | Atalho que lança o jogo apontando para rom\ddsom. |
Makefile, CMakeLists.txt, build.mk | Sistema de build. |
Detalhe de engenharia: o CMakeLists.txt original do toolkit assume GAME=vampire_savior e um layout de pastas irmãs. Como o ddsom-recomp é achatado, é preciso passar o game id e os caminhos in-repo explicitamente (usando caminhos nativos C:/... — caminhos MSYS /c/... não são entendidos pelo cmake nativo):
# a partir da raiz do repositório, com o toolchain UCRT64 (gcc, cmake, ninja) no PATH
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DGAME=ddsom \
-DGAME_DIR="C:/caminho/para/o/repo/games/ddsom" \
-DWORK_DIR="C:/caminho/para/o/repo/work/ddsom"
cmake --build build --target ddsom
O ddsom.exe compilado cai em build/. Copie SDL3.dll, zlib1.dll e libiconv-2.dll do bin/ do seu toolchain para junto dele antes de rodar.
6. Construção a partir do código (resumo)
Requisitos (opcional — só se quiser reconstruir): toolchain C++20, CMake, Ninja e bibliotecas de desenvolvimento SDL3 (≥ 3.4.16) + ZLIB. No Windows, o build documentado usa o shell MSYS2 UCRT64 com mingw-w64-ucrt-x86_64-{gcc,cmake,ninja,python,sdl3,zlib} (o libiconv vem junto do toolchain UCRT64). O executável enviado já está linkado estaticamente contra libgcc/libstdc++, precisando apenas das três DLLs citadas.
7. Como jogar
O repositório já traz o executável pronto. O fluxo é:
-
Tenha o ROM set
ddsom(EUA, 950101, 22 arquivos) mais suaddsom.key. -
Coloque os 22 arquivos de ROM e a
ddsom.keyjuntos numa pasta — por padrãorom/ddsom/(ignorada pelo Git via.gitignore):rom/ddsom/ ddsom.03, ddsom.04, … ddsomu.13, ddsomu.14 … (22 arquivos) ddsom.key -
Rode
Jogar.bat(na raiz do repositório). Ele executa:build\ddsom\ddsom.exe --rom "%~dp0rom\ddsom"Ou rode manualmente:
build\ddsom\ddsom.exe --rom <pasta-ou-zip-do-rom>. A chave é lida do mesmo lugar automaticamente. O--romaceita uma pasta dos arquivos ou o zip. O set é sempre só lido, nunca escrito.
Observação honesta: o próprio
games/ddsom/README.mddescreve o projeto como beta — o código foi verificado instrução a instrução e roda seus primeiros cenários em made-up play, mas "ninguém o jogou à mão ainda". O autor do port reporta que o executável roda ("funcionou!"), e ocheckconfirma 100% de tradução nativa; ainda assim, espere arestas ásperas em estágios menos exercitados.
8. Controles
Quatro jogadores, cada um com seu teclado ou gamepad. Tudo remapeável por jogador na página Controllers do launcher. Padrões (do games/ddsom/README.md):
| Jogador | Mover | Attack | Jump | Magic | Start | Coin |
|---|---|---|---|---|---|---|
| 1 | Setas | A | S | D | Enter | Left Shift |
| 2 | 6 4 3 5 (cima/baixo/esq/dir) | Z | X | C | 2 | 1 |
| 3 | NumPad 8 2 4 6 | O | P | ; | 8 | 7 |
| 4 | T G F H (cima/baixo/esq/dir) | V | B | N | 0 | 9 |
Em qualquer gamepad SDL: o D-pad (ou analógico esquerdo) move; Oeste (X) = Attack, Sul (A) = Jump, Leste (B) = Magic; Start = Start, Back = Coin. Aceita até quatro gamepads ou qualquer mistura de gamepad e teclado.
Menu in-game: Esc ou F1 (no gamepad, o clique do analógico esquerdo, ou Start + Select juntos) — save states, velocidade, pausa, frame advance, cheats e todos os recursos.
9. Recursos além do arcade
Porque é um programa nativo e não a placa, o port adiciona opções que o arcade não tem (cada uma uma chave própria, desligada por padrão salvo indicado):
- Quatro jogadores simultâneos (configuração nativa da placa, ligada no modo Enhanced).
- Pure vs. Enhanced: Pure joga exatamente como a placa; Enhanced (padrão) adiciona free play e jogadores extras.
- Start em estágio qualquer, Score attack, Attract mode, Stage viewer e Character viewer.
- Rapid fire, cheats (vida/continues/tempo infinitos), custom soundtrack (seus arquivos
.ogg/.flac/.mp3/.wavno lugar da música da placa). - Imagem do seu jeito (pixels nítidos ou suaves; 4:3, pixels quadrados ou tela cheia), run-ahead (tira 1–2 frames de input lag) e arcade timing (modelo ciclo-a-ciclo da placa, checado em
docs/TIMING.md). - Configurações de operadora da placa e o test menu original.
10. Limitações e status
- Beta. Cobertura de tradução é total (0% no interpretador), mas nem todos os estágios foram jogados à mão; podem haver bugs pontuais.
- ROM e chave não inclusos, por direitos autorais. Você precisa ser dono da placa e fornecer o set
ddsom(950101) +ddsom.key. - O launcher e a verificação de checksum recusam regiões/revisões diferentes — cada port é feito daquele programa específico, e seus recursos usam endereços encontrados nele.
- Multiplataforma na base (macOS/Linux/Windows), mas o executável pré-compilado enviado no repositório é o Windows.
Conclusão
O ddsom-recomp é um exemplo prático de recompilação estática de arcade: em vez de simular a CPS-2 instrução por instrução, ele extrai o programa 68000 (e o Z80 de som) da ROM criptografada, traduz cada bloco para C/C++ nativo com tools/recomp.py/recompz80.py, reimplementa o que o jogo espera da placa (vídeo, QSound, EEPROM, entradas) em torno do SDL3, e linka tudo num ddsom.exe que roda direto no Windows. A verificação instrução a instrução confirma tradução completa (0,000% no interpretador), e o repositório entrega o executável pronto junto de um Jogar.bat — bastando você prover, legalmente, a ROM e a chave. O resultado é um port nativo, de baixa latência e com controles e recursos que a placa original nunca teve.