BattleShip-Remix
BattleShip-Remix is a native PC and Switch port of Smash Remix 2.0.1 for Super Smash Bros. N64.
- Type: PC port
- Game: Smash Remix
- Runs on Windows, Linux, macOS and Android
- By lucasliet
- Latest release v2.0.1-port.10, 2026-11-10
- Source: https://github.com/lucasliet/BattleShip-remix
README
BattleShip-Remix
Warning
This is a community fork of BattleShip that ports Smash Remix. It is not made, endorsed or supported by the BattleShip author, the Smash Remix team or the Harbour Masters. Please do not open issues on their repositories or ask for help in their channels for anything you hit while building or playing this fork: report it on this repository's issue tracker.
BattleShip-Remix is a native PC and Switch port of Smash Remix 2.0.1, the Super Smash Bros. (N64) mod, built on the BattleShip port. BattleShip turns the VetriTheRetri/ssb-decomp-re decompilation into a native program with libultraship (rendering, audio, input) and Torch (asset extraction). This fork rewrites the Remix's MIPS assembly as C on top of that decompilation, so the Remix runs as native code instead of patches on an emulated ROM.
What the port covers:
- every Remix 2.0.1 fighter (97 fighter ids, including the Remix clones, Polygons and bosses), stage, hazard and custom item;
- the Remix modes: Remix 1P, All-Star, Multi-Man, Cruel, Home-Run Contest, Bonus 3, King of the Hill, Smashketball, Tag Team, Stamina, Tug of War, 12-Character Battle, the Remix Training mode;
- the Remix menus and screens: the character select panel and its options, the Remix settings and toggles (in the port menu), Character Data, Sound Test, Gallery, credits, results and Match Stats;
- the Remix audio banks (music and voices) and the CPU AI changes.
The few places where the port deliberately behaves differently from the assembly are listed in docs/remix/deviations.md. The Remix screens are authored for 4:3: the optional Widescreen setting only widens battle scenes, and menus stretch.
Releases ship macOS (Apple Silicon, .dmg and .zip), Linux (x86_64 AppImage), Windows (x64 .zip), Nintendo Switch (homebrew .zip with the .nro), Android (arm64 .apk) and PlayStation 5 (homebrew title folder) packages, and the built-in updater of every platform installs from the package of its platform (on macOS the in-game update uses the .zip, the .dmg is for the first install). On Windows the updater only announces a new release and opens its page: download the zip and extract it into the game folder, replacing the old files. The vanilla BattleShip build (US Super Smash Bros.) still compiles from the same tree with -DSSB64_VERSION=us.
No copyrighted assets are included in this repository
None of Nintendo's assets (code, textures, audio, models, text, ROM data), and no Smash Remix ROM data, are checked into this repo or distributed with builds. Every byte of game data is extracted on the first run from ROMs that you supply. If you do not own a legal copy of Super Smash Bros. for the Nintendo 64, you cannot build or run this project.
The Remix needs only the Smash Remix 2.0.1 ROM, made from your own US ROM with the Smash Remix web patcher or the patch from the Smash Remix releases. A release asks for it on the first launch; a source build reads it from the repository root:
| File | ROM | SHA-1 | MD5 |
|---|---|---|---|
baserom.remix.z64 | Smash Remix 2.0.1 (internal name SMASH REMIX, game code NALE) | 13716381ed5e29be2606e0f4724b18fd00789d04 | 2b2d6b295106c54216b7fc7a2f14346e |
The US ROM the patch is applied to is Super Smash Bros. NTSC-U v1.0 (NALE, SHA-1 e2929e10fccc0aa84e5776227e798abc07cedabf, MD5 f7c52568a31aadf26e14dc2b6416b2ed). A source build can also take it as baserom.us.z64 (optional: dev-only stage images and the Remix source assembly script).
The vanilla builds need only their own ROM: US as above, or JP (Nintendo All-Star! Dairantou Smash Brothers v1.0, NALJ, SHA-1 4b71f0e01878696733eefa9c80d11c147ecb4984, MD5 66db457b130d31a286a23d6e4dd9726e) with -DSSB64_VERSION=jp. A dump that does not match the hashes for its version will not work.
PlayStation 5
The PS5 build is a native homebrew title (PPSA99264, built with ps5-payload-dev's SDK and ps5-opengl) for a
jailbroken console with ShadowMountPlus. Unzip the release's BattleShip-Remix-ps5-PPSA99264.zip to /data/homebrew/
(or an external drive) and copy your baserom.remix.z64 into PPSA99264/; the first launch extracts
BattleShip-Remix.o2r there. Everything the game writes (archive, saves, settings, logs/) stays in that folder.
L3+R3 opens the port menu. Build steps: docs/remix/build_and_roms.md.
Nintendo Switch
The Switch build is a homebrew .nro (libnx). The console does not read the ROM: BattleShip-Remix.o2r is the one the desktop build
extracted from your ROM, copied to the SD card. Folder layout on the SD card:
sdmc:/switch/BattleShip-Remix/
├── BattleShip-Remix.nro
├── BattleShip-Remix.o2r (from your desktop build)
├── BattleShip-Remix.o2r.recipe (from your desktop build)
├── f3d.o2r
├── config.yml
├── gamecontrollerdb.txt
├── README.txt
└── assets/
- Launch it from the Homebrew Menu in full-memory mode (hold R while opening an installed game, or use a forwarder). Applet mode does not have enough memory.
- Always copy
BattleShip-Remix.o2randBattleShip-Remix.o2r.recipetogether, from a desktop build of the same release as the.nro. The game compares the recipe in the.recipefile with the one inside the.nroand refuses to start on a mismatch (or if the.recipeis missing). Some releases keep the same recipe, so an older.o2rcan still work; when it does not, the error screen shows both recipes. After an update that changes the asset pipeline, extract again with the new desktop build and copy both files again. - The in-game updater (About menu, or the popup at start-up) downloads
BattleShip-Remix-switch.zip, replaces the.nroright away and stages the other files of the zip in anupdate-pending/folder next to it; they are moved into place the next time the game boots. YourBattleShip-Remix.o2rand.recipeare never touched, so after a release that changes the asset pipeline copy a freshly extracted pair again. If applying the staged files fails, the error screen names the file: deleteupdate-pending/or reinstall from the zip. - The game writes
ssb64.logandlogs/BattleShip-Remix.lognext to the.nro, both overwritten on every launch; attach them to any Switch bug report. Quit the game from inside it rather than from the HOME menu: HOME kills the process and the end of the logs is lost. - Hi-res texture packs are off by default on the Switch (About menu to turn them on): the console cannot hold a whole pack in memory, and a pack that keeps missing the cache decodes textures while you play, which shows up as stutter when many new things appear on screen.
- Build and packaging steps:
docs/remix/build_and_roms.md.
How the Remix port was done and validated
- Plan and history:
docs/remix/ROADMAP.md, milestone by milestone, with the evidence of each task. - Method:
docs/remix/porting_guide.md(reading the Remix source, resolving addresses, the hook convention for vanilla code) anddocs/remix/architecture.md. - Patch audit: every
OS.patch_startof the Remix source (2007), its 80 directoriginwrites and its 988 character-table patches were mapped to the decomp function they land in (tools/audit_remix_patches.py) and compared with the port by hand. Each gap got a ledger ID and was closed with a test (docs/remix/patch_audit.md,docs/remix/patch_audit_scopes.md);docs/remix/parity.mdis the per-file summary. - Tests: unit tests for the pure rules (
tests/remix/), headless in-game smoke tests driven by input scripts (theremix-smoke-testsskill in.claude/skills/: VS matches, special-move matrices, stage and item sweeps, CSS and mode flows, audio dumps), and screen comparisons against the real Remix ROM in a reference emulator (docs/remix/notes/i8_reference_emulator.md). - Reference docs:
docs/remix/README.mdindexes how each Remix subsystem works and how the port implements it.
Features
Everything below comes from BattleShip and is toggleable in-game from the ESC menu. The Remix adds its own settings pages (Remix, Gameplay, Music, Stage and Pokemon) to the same menu.
Input enhancements (per-player)
- Disable Tap Jump
- C-Stick Smash
- D-Pad to Jump
- NRage analog-stick remap with customizable per-axis ranges
Gameplay & match options
- Classic Co-op — play the originally single-player Classic mode with 2-player local co-op, with an optional friendly-fire toggle
- Z-Cancel assists — Auto Z-Cancel and Flash on Failed Z-Cancel (L-cancel practice aids)
- Competitive ruleset — one-click tournament rules, plus neutral spawns on Dream Land
- Disable Stage Hazards
- Hitbox view — visualize hitboxes / hurtboxes / collision
- Boot straight to the VS character-select screen, Skip Results Screen, Force CPU Level 9
- Unlocks — unlock everything, or individual characters (Captain Falcon, Jigglypuff, Luigi, Ness) and features (Mushroom Kingdom, Item Switch menu, Sound Test)
Audio
- Music shuffler — randomize stage BGM
- Music selection screen — pick the track per stage
- Independent Master / Music / Sound / Voice volume sliders
Rendering (powered by libultraship / Fast3D)
- Internal resolution scaling, MSAA anti-aliasing, three-point texture filtering
- Optional widescreen for battle scenes, including ultrawide resolutions (menus stretch; off by default on the Switch)
- Renderer backend selection (OpenGL / Metal / Direct3D), VSync, windowed-fullscreen, multi-window
- Post-process shader support with an in-app shader-pack downloader
Textures & mods
- Hi-res texture packs on desktop, Android, Switch and PS5 (opt-in on Android and Switch, read in place straight out of a
.zip). Download GhostlyDark's pack from evilgames.eu. - Native C mod support — write mods in C, compiled at runtime (TinyCC), with hot-reload, function detours, and a documented engine/fighter event catalog. See
docs/modding.md. (Desktop only; scripting is disabled on Android.)
Controls
- Controller and rumble support powered by SDL2, with plug-and-play routing for up to 4 pads
- Native Raphnet adapter support up to 4 channels through hidapi
- Native GameCube adapter support (WUP-028 and compatible clones) over libusb, driven directly rather than through SDL — all 4 adapter ports, hotplug, and fully remappable like any other device. Each adapter port feeds the matching player by default and can be reassigned to any player. (Desktop only. On Windows the adapter must be bound to the WinUSB driver.)
- Per-controller configuration UI and a bundled
gamecontrollerdb.txtmapping database
Platform & quality-of-life
- Runs natively on macOS (Apple Silicon), Linux, Windows, Android, Nintendo Switch and PlayStation 5
- First-run ROM-extraction wizard, built-in update checker/downloader, and Discord Rich Presence
Rollback netcode & online play
Work in progress.
About the BattleShip port
BattleShip, the port this fork builds on, was created by JRickey. From its author:
This is a project that I started and developed alone with Claude until the v0.3-beta release. It took a little over a month of night and day work to get to the first beta release, and a massive 4 day long sprint working all day resolving bugs from v0.3-beta to v0.7-beta. As of now, this is no longer a pure AI project. Many people have offered their time playtesting, their knowledge of the game, or their experience with modding or competitive play; to bring improvements, bug fixes, new feature suggestions, and additions. Without them, the project would not be what it is today.
If you find anything that you would like to see improved, create an issue on Github. I'll fix it.
This port was started when the original decomp was 96% complete code only. The remaining 4% was the internal debug menu and Libultra functions that aren't necessary to port the game. The relocatable data was also not decompiled at the time. The port was designed with this in mind, and it is why certain design decisions had to have been made. I like to move fast, obviously.
This project uses a heavily modified LibUltraShip and Torch, those two modules obviously don't work with every n64 game out of the box and a lot of game specific things needed to be implemented. The original game is quite unique and uses rendering techniques and n64 hardware tricks in ways other LUS projects did not need to account for.
This is a passion project for me. Not out of nostalgia, but to actually make something. I don't have too much nostalgia for the original game, considering I didn't own a copy as a kid, but I remember playing it at a friend's house a handful of times. What motivates me to work on this is because I can. Because it's hard, because it hasn't been done before (at least not open source). It's required a ton of my personal time, even using AI. It's forced me to get creative, to design custom tools, to force the agents into certain boxes.
People may not like it because I used AI, and that's okay. I'm not going to argue with your opinion or try to say that my way is the correct way of doing things. It works for me and that's what matters to me. My code is open source, it's free, it's MIT Licensed, and everyone can learn from it. That's what should matter to you.
I hope you enjoy the project.
Building
The Remix build (ROMs, assets, desktop, Switch, Android and PS5) is described in docs/remix/build_and_roms.md. The generic BattleShip steps (including Windows) are in BUILDING.md.
Architecture
The port has three layers and they are kept deliberately separate:
┌──────────────────────────────────────────────────────────────┐
│ decompiled game code (decomp/src/) │
│ Unmodified C produced by the decomp project. Talks to the │
│ N64 the same way the original ROM did: GBI display lists, │
│ ALSeqPlayer audio, OS threads, OSContPad input. │
├──────────────────────────────────────────────────────────────┤
│ port layer (port/) │
│ Modern C++ glue. Translates N64-shaped APIs into LUS calls, │
│ fixes endianness on freshly-loaded data, owns Ship::Context │
│ and the resource factories, and quarantines every change │
│ the decomp doesn't need to know about. │
├──────────────────────────────────────────────────────────────┤
│ libultraship (libultraship/) │
│ PC-native runtime: Fast3D renderer (OpenGL / Metal / D3D), │
│ SDL2 input, miniaudio output, OTR/O2R resource manager, │
│ ImGui overlay. │
└──────────────────────────────────────────────────────────────┘
Asset pipeline
The ROM is never read at runtime. Torch walks it with the YAMLs under yamls/<version>/ and emits the game archive (BattleShip-Remix.o2r for the Remix, BattleShip.o2r for vanilla) — a zip-format archive of typed resources (textures, sequences, sample banks, animations, reloc files). A release does this on the first launch from the ROM you supply; a source build does it during the build. At launch, libultraship's resource manager mounts the archive + f3d.o2r and the port code requests resources by path. A .recipe file next to the archive records which Torch revision, config.yml and YAMLs produced it, so the game re-extracts when they change. This is the same pipeline used by Ship of Harkinian, Starship, SpaghettiKart, etc.
The relocatable-data files (fighter tables, item tables, effects, sprites) are SSB64-specific and required custom factories on the Torch side and a custom loader (port/resource/RelocFileFactory.cpp) on the runtime side.
Build-time codegen
A small amount of generated code lives outside the source tree (gitignored) and is regenerated on every build from tools/reloc_data_symbols.us.txt:
include/reloc_data.h— extern declarations for every relocatable symbolyamls/us/reloc_*.yml— Torch extraction configsport/resource/RelocFileTable.cpp— the runtime symbol table
If you ever see "undefined reference to dFooBarReloc" you regenerated the table without rebuilding, or vice versa.
Code conventions
#ifdef PORT — what it is and what it isn't
Every meaningful change to a decomp source file is wrapped in #ifdef PORT / #else / #endif. The discipline this enforces:
- The original decomp code path stays intact and compilable under the IDO toolchain on a real N64 build. This is non-negotiable — if it ever stops being true, upstreaming improvements back to the decomp project becomes impossible.
- The PORT branch is allowed to be ugly — an explicit endian conversion, a struct rewrite, a function shim — as long as the contract it presents to the rest of the file is the same as the N64 branch.
- Reloc tokens vs. raw pointers: a field declared
u32under#ifdef PORTwhere the N64 branch declaredT*is a reloc token, not a raw pointer. Resolving it requiresPORT_RESOLVE(token). Assigning a real pointer with(uintptr_t)ptrwill silently truncate on LP64 — wrap post-load writes inPORT_REGISTER.
Decomp preservation: behavior, not bytes
The repo follows a single principle for changes to decomp/src/:
Accuracy to game behavior > accuracy to ROM bytes.
That means IDO idioms that encode original N64 semantics — odd casts, goto flow, deliberate temporaries — are load-bearing and stay. But compiler-compat shims (warning suppressions, permissive flags, header shortcuts) that mask real bugs on modern LP64 toolchains do not survive. The most expensive lesson of the project was that -Wno-implicit-function-declaration was silently truncating 64-bit pointer returns to 32-bit int in dozens of places. The shim is gone; the real declarations are in.
Naming prefixes
The decomp uses two-letter module prefixes throughout. Knowing them makes the source tree navigable:
| Prefix | Meaning |
|---|---|
ft | Fighter (ftMario, ftKirby, ftFox, …) |
it | Item (itAttribute, itManager) |
wp | Weapon |
ef | Effect / particle |
gm | Game mode |
gr | Stage (ground) |
mp | Map / collision |
mn | Menu |
sc | Scene |
sy | System (engine internals) |
sf | Saved-state / save file |
db | Debug |
cm | Camera |
lb | Library (low-level utilities) |
obj | GObj / DObj / OMObj — game-object wrappers |
Endianness handling
The N64 is big-endian; PC targets are little-endian. The port handles this in three layers:
- Gross byteswap at load —
lbRelocLoadAndRelocFilebyteswaps relocatable files word-by-word during load. - *Per-struct fixups