
Ms. Pac-Man (Tengen) (mspacmanrecomp)
Port nativo de Ms. Pac-Man (Tengen) (mspacmanrecomp) para PC.
Ms. Pac-Man (Tengen) (mspacmanrecomp)
Port nativo basado en su ficha de origen.
README del repositorio
Ms. Pac-Man (Tengen, Genesis) static recompilation
Tengen's 1991 Genesis Ms. Pac-Man, recompiled to native code with segagenesisrecomp. The headline feature is a vertical full-maze view: every maze type (Arcade, Mini, Big, Strange) is shown in full, HUD included, with no forced scrolling. On top of that: RetroArch shader presets through librashader, rewind, save states, preemptive frames (one frame less input lag), fast forward, pause and frame advance, rebindable shortcuts, and the recomp-ui launcher and in-game menu.
Download
Builds for Windows (x64, x86, ARM64) and Linux (x86_64, aarch64; a tarball or
an AppImage) are on the
Releases page.
Extract one and run MsPacManRecomp.exe / MsPacManRecomp; the launcher asks
for the ROM on the first start.
No ROM is included. You need your own Ms. Pac-Man (USA, Europe) Genesis ROM,
the No-Intro dump Ms. Pac-Man (USA, Europe).md: SHA-256
87f3c75fea5c4e105163a3b6d4467527fdc3fcc4b8e385155067719b98b2be7c (CRC32
AF041BE6). The launcher reads "ROM verified" under the box art and enables
PLAY only for that file; any other file reads "ROM not recognized" and does
not start. The code was recompiled from that exact ROM.
Layout
| Path | What |
|---|---|
CMakeLists.txt | Game build (recompiler → generated C → MsPacManRecomp) |
segagenesisrecomp/ | Recompiler and runtime (submodule: fork of mstan/segagenesisrecomp, branch mspacman); the GL frontend is runner/frontend/ |
recomp-ui/ | Launcher and in-game menu (submodule: fork of RetroPortingToolKit/recomp-ui, branch shantae) |
game/game.toml | Recompiler config for this ROM |
game/mspacman_spec.c | Game hooks: interrupt model and save-state resume points (see below) |
game/mspacman_video.c | Full-maze view renderer |
game/mspacman.bin | The ROM: you supply it; never committed |
assets/boxart.tga | Launcher box art (cut from the title screen) |
cmake/default_settings.cmake | First-run settings.ini in a build dir (full-maze view on) |
release/settings.ini | The same defaults, shipped in every release |
tools/check_startup.py | 600 frames through the game loop and the GL frontend in a hidden window: no interpreter fallback, no dispatch miss |
tools/check_states.py | Preemptive frames against none, and a save state loaded by another process, compared by machine-state hash |
tools/build_librashader.sh | Build librashader.dll (OpenGL runtime; x64, or x86/arm64 when named) and stage the slang-shaders presets |
third_party/librashader/ | Its output: the x64 DLL, windows-<arch>/librashader.dll, shaders/, and patches/ applied to the librashader source; linux-<arch>/librashader.so from tools/build_linux.sh |
tools/build_windows.sh, tools/windows/ | Windows releases for x64, x86 and ARM64 (below): pinned msys2 libraries, CMake toolchain, DLL staging, packaging, checks |
third_party/windows/ | The pinned msys2 packages and the x86/ARM64 sysroots unpacked from them (tools/windows/bootstrap.sh) |
tools/build_linux.sh, tools/linux/ | Linux releases for x86_64 and aarch64 (below): toolchain bootstrap, CMake toolchain, packaging, checks |
LICENSE, THIRD-PARTY-LICENSES.md | This project's license (PolyForm Noncommercial 1.0.0) and the components the releases carry |
Build and run
The recompiler and the Windows build run on Windows with
MSYS2 installed at C:\msys64, plus Git and Python
3.11+:
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2 mingw-w64-x86_64-angleproject
git clone --recursive https://github.com/vibecodekun/mspacmanrecomp.git
cd mspacmanrecomp
cp "/path/to/Ms. Pac-Man (USA, Europe).md" game/mspacman.bin
bash tools/build_windows.sh x64 --no-package # recompiler -> build/x64/generated/mspac -> build/x64/MsPacManRecomp.exe
Already cloned without --recursive? Run git submodule update --init --recursive.
The generated 68000 translation is built at -O1 (it is large and flat), the
runtime and the game adapter, which run every scanline, at -O2. Generated C
lives only in build/x64/generated/mspac/ and is regenerated whenever the ROM,
game/game.toml or the recompiler changes. build_windows.sh builds
librashader.dll first (Rust needed; --no-librashader skips it, and the game
then runs without shader presets).
Run build/x64/MsPacManRecomp.exe. The launcher has controller setup (3/6-button,
keyboard or pad, rebinding), Settings, and Mods → Full maze view (on/off,
and Canvas: All mazes = one 360-line canvas, Per maze = height follows each
maze). Tick "Skip launcher on boot" to go straight into the game next time.
Passing a ROM path skips the launcher and allows overrides:
--widescreen off (original scrolling view), --widescreen fit,
--widescreen stage.
Only the ROM the build was recompiled from starts: the launcher checks its SHA-256 (the line under the box art and the PLAY button follow it), and the runtime checks size, CRC32 and SHA-256 again at boot, which is what stops a wrong ROM when "Skip launcher on boot" is on (a "Wrong ROM" box, then the launcher).
Full-maze view
Full-view heights: Mini 264, Strange 304–312, Arcade 312, Big 360 lines (native is 224). Title, menus and intermissions are shown at native size.
The game draws each whole maze into a 256×512 plane when the maze loads, and
all scrolling is one camera word ($FF000E) copied to VSRAM each V-blank.
Sprites are kept in screen space and re-based by the game when the camera
moves. So the renderer locks the camera at the top of the playfield, draws
the planes from VRAM, and shifts each sprite by game camera − locked camera.
Game logic is untouched. The view verifies itself every frame: the 224 rows
the hardware raster produced must reappear unchanged in the tall frame (TCP
command mspac_view, see below). Shader presets get the tall frame too.
The frontend
The game presents through the runtime's GL frontend
(segagenesisrecomp/runner/frontend/), a port of the one in the
Shantae recomp: OpenGL ES 3.1
through ANGLE (over Direct3D 11) on Windows and the system's OpenGL on Linux.
A PC whose driver has no OpenGL ES gets the engine's plain SDL picture and
the overlay menu instead.
- Esc, or a controller's Guide/Home button, opens the in-game menu: settings, the full-maze view, shader presets, save states, Restart Game, Return to Launcher and Quit. F10 opens the full settings window.
- Shortcuts (all rebindable in the settings window, Advanced → Controls):
Tab hold fast forward,
`fast forward on/off, R hold rewind, F5/F8 save/load state, F6/F7 state slot, P pause, O advance one frame, F1 overlay, F9 mute, F11 fullscreen. On a controller, the right trigger fast forwards and the left one rewinds. Settings are saved inruntime_prefs.ini. - Rewind keeps compressed snapshots (differences against the previous one) in a buffer of 16 MB and up; its size, and how many frames apart the snapshots are, are in the settings window's Advanced → Display.
- Preemptive Frames (1 by default, Advanced → Display) is RetroArch's
preemptive frames (
runahead.c,preempt_run): a ring keeps the state from before each of the last N frames; when the input changes, the oldest is loaded and those frames run again with the new input, silently, before the next frame is shown. The game sees each press N frames sooner and is otherwise unchanged;tools/check_states.pychecks that a press a frame late with one preemptive frame plays exactly as a press on time. - Save states (
MSPAC.state1…, beside the game) can be made during play, not on the title or demo screens: see the interrupt model below for why. A state file holds the whole machine, the game's fiber included, as the runtime's rollback snapshot, so it loads in any later run of the same build.tools/check_states.pysaves one, loads it in another process and compares the machine state 600 frames later. - Fast forward has its own speeds and frame skip for the hold and the toggle, with sound sped up, muted or left at normal pitch.
Shader presets (librashader)
RetroArch .slangp presets (CRT, LCD, scalers, Mega Bezel...) run through
librashader. Set it up once:
bash tools/build_librashader.sh # needs Rust (cargo); ~2 min the first time
The script clones librashader 0.12.0 into third_party/librashader/checkout
the first time (LIBRASHADER_SRC points it at a checkout of your own instead),
exports that checkout without modifying it, applies
third_party/librashader/patches/, builds the OpenGL runtime only, and copies
the checkout's slang-shaders collection. The build then stages librashader.dll
and shaders/ next to MsPacManRecomp.exe. Without them the game runs as
before. The DLL links the C and C++ runtimes in (crt-static), so players need
no Visual C++ Redistributable.
In game: Esc → Shader presets, or the settings window's Shader Presets
(librashader) section. Pick a preset (the filter box takes words such as
crt or geom), tune its parameters, and Reset All to go back. Edit
Preset changes how a preset is set up, the way RetroArch's Shader menu does
(passes, filters, scales, formats; Save Preset writes
shader_presets/<name>.slangp). A preset that has not loaded before is first
compiled in a hidden child process while the game keeps running, so one that
crashes the driver's compiler cannot take the game down; compiled programs are
cached in shader_cache/. GENESIS_SHADER_PRESET overrides the preset for one
run.
third_party/librashader/patches/ makes librashader's GLSL ES output work
under ANGLE:
| Patch | Fixes |
|---|---|
| 0001 | History copies used a blit ANGLE rejects; presets reading previous frames read black |
| 0002 | Integer varyings need flat on the vertex side in GLSL ES (crt-yah, ntsc-blastem) |
| 0003 | ANGLE's D3D translator cannot write global arrays-of-arrays constants; they are assigned in main() instead (crt-hyllian, crt-sony-megatron, crt-nobody, dithering) |
| 0004 | Quoted preset values end at the closing quote, as in RetroArch ("../..//x", "true"") |
| 0005 | RelaxedPrecision is dropped, working around a SPIRV-Cross GLSL ES bug (simple-crt) |
Windows (x64, x86 and ARM64)
bash tools/build_windows.sh # all three -> dist/windows/ (or name x64, x86, arm64)
bash tools/windows/check.sh # imports, startup and state checks
- x64 builds in
build/x64with msys2's mingw64 GCC and runs the recompiler; the other two compile its generated C (GENESIS_PREGENERATED_DIR), so they need neither the recompiler for their arch nor the ROM. - x86 (32-bit) builds in
build/x86with msys2's mingw32 GCC (pacman -S mingw-w64-i686-gcc). - ARM64 builds in
build/arm64with mingw64's clang and lld cross-compiling toaarch64-w64-mingw32against msys2's clangarm64 runtime (libc++, compiler-rt, UCRT). - The game fiber's context switch (minicoro) had none for 32-bit Windows or
Windows on ARM; this build adds both, keeping the thread information block's
stack bounds, SEH chain and fiber data per fiber as minicoro's Win64 switch
does (
runner/external/minicoro/minicoro.h). - SDL2, ANGLE and the ARM64 runtime come from msys2 packages pinned by SHA-256
in
tools/windows/bootstrap.sh, unpacked intothird_party/windows/($MSPAC_WINDOWS_CACHE, no spaces); nothing is installed into msys2. librashader.dllistools/build_librashader.sh <arch>'s, through Rust's MSVC targets (Visual Studio's x86 and ARM64 C++ tools).tools/windows/dlls.shfollows the imports of the exe and oflibrashader.dll: each build dir gets the DLLs it needs beside the exe, the zip carries exactly those, and the build fails if one is missing or is another arch's.dist/windows/mspacman-recomp-<version>-windows-<arch>.zipis a folder withMsPacManRecomp.exe, its DLLs,assets/,shaders/, the defaultsettings.iniandtools/windows/README-windows.txt. Packaging is an allowlist and refuses anything that looks like a ROM, a state or arom.cfg.<version>is$MSPAC_VERSION, or the project version.tools/windows/check.shchecks every build withtools/windows/check_imports.py(each module is the arch's, and every function imported from a DLL beside the exe is exported by it), then runstools/check_startup.py(through ANGLE, and again on SDL's dummy driver for the no-GL fallback) andtools/check_states.pyon each build this PC can run: x64 and x86 on an x64 PC; ARM64 needs an ARM64 PC.
Linux (x86_64 and aarch64)
tools/build_linux.sh builds the Linux releases from the x64 build's generated
C, in WSL (Ubuntu) or on any Debian/Ubuntu machine:
wsl bash tools/build_linux.sh # both arches -> dist/linux/ (x86_64 or aarch64 for one)
wsl bash tools/linux/check.sh # startup and state checks
The first run fetches its toolchain into ~/.cache/mspacman-linux
(tools/linux/bootstrap.sh, $MSPAC_LINUX_CACHE moves it; nothing needs
root): Zig as the C/C++ cross compiler, CMake and Ninja, each arch's Ubuntu
24.04 X11/Wayland/audio/GL headers and libraries through an unprivileged apt,
SDL2 built static, Rust and cargo-zigbuild for librashader, Debian 10's
libraries for the checks, and appimagetool. The toolchain is the Shantae
recomp's, so the two can share one cache.
- The binaries target glibc 2.28 (Zig's glibc stubs), so they run on Debian
10+, Ubuntu 20.04+, RHEL 8+, Fedora, Arch, SteamOS, Raspberry Pi OS 64-bit
and so on. SDL2 and the C++ runtime (libc++) are linked in; at start they
load only glibc and
libGL.so.1. X11, Wayland (with libdecor), KMSDRM, PipeWire, PulseAudio, ALSA, udev and D-Bus are opened at run time when the system has them.build_linux.shfails a binary that needs a newer glibc symbol. librashader.sois built fromthird_party/librashader/srcwith cargo-zigbuild intothird_party/librashader/linux-<arch>/, and the game finds it beside itself through its RUNPATH ($ORIGIN).dist/linux/mspacman-recomp-<version>-linux-<arch>.tar.gzis a folder that runs from anywhere writable and keeps its state inside it;MsPacMan_Recomp-<version>-<arch>.AppImagekeeps its state beside the .AppImage. The tarball carriestools/linux/README-linux.txt.tools/linux/check.shrunstools/check_startup.pyandtools/check_states.pyon the host, and the startup check again on Debian 10's glibc 2.28 (aarch64 through qemu-user).
Interrupt model
All gameplay runs inside the V-blank interrupt. The main program only unmasks
interrupts in two BRA * idle loops ($0008F6, $00F76E), and the handler
can run for many frames or discard its own exception frame and continue as
main-program code. game/mspacman_spec.c therefore takes IRQ6 on the game
fiber from those idle loops (see the comment at the top of that file).
This decides where a save state can be taken. A state file must be loadable by a later run, so it cannot hold the fiber's native stack; it is only written when the fiber is parked in the driver's idle wait, where the machine state alone says how to resume. During play the V-blank handler can run across a frame boundary, so a save holds the next interrupt until the tick ends. The title and demo screens run as main-program code that never returns to that wait, so states are refused there with a message (rewind and preemptive frames keep the fiber in memory and work everywhere).
Sound
The Z80 sound driver times its music off the YM2612's Timer A (it polls
the status flag at Z80 $014D). The runner's synchronous YM status model
originally implemented only Timer B, so the driver never ticked and the game
was silent; Timer A now lives beside it in runner/video/genesis_bus.c.
Debugging
Dev builds include the TCP debug server (GEN_ENABLE_TRACE, on by default;
the release scripts turn it off):
cmake -G Ninja -S . -B build/dev && ninja -C build/dev
Put a debug.ini containing port=4382 next to the exe to enable it, then
e.g.:
python segagenesisrecomp\tools\tcp_cmd.py 4382 "{\"id\":1,\"cmd\":\"mspac_view\"}"
After every run, dispatch_misses.toml next to the exe should list no
functions (tools/check_startup.py fails on any).
License
This project's own code is licensed under the PolyForm Noncommercial License 1.0.0, the same as the segagenesisrecomp engine. The submodules and the libraries the releases carry keep their own licenses; see THIRD-PARTY-LICENSES.md.
Ms. Pac-Man is a trademark of Bandai Namco Entertainment. This project contains no ROM; the box art and screenshot are captures of the game running. It is not affiliated with or endorsed by Bandai Namco, Tengen, or Sega.
Comentarios (0)
Inicia sesión para dejar un comentario.
Sé el primero en comentar sobre este juego.
