Being the Smash Bros. fan that I am, I couldn’t resist the opportunity to interview Jack Rickey, the founder of BattleShip – the unofficial PC port of Super Smash Bros. 64. In it he walks us through the technical process of getting a port like this to work, addresses the controversy behind the use of AI-assisted programming tools, and makes an interesting note as far as what maintaining the Linux version has been like.

Note that some minor edits have been made throughout the interview for grammar purposes. Bold has been added by me. I also asked Jack to explain some of the technical terms he uses; these are explained at the bottom.

TL;DR:

  • Jack Rickey has a Bachelor’s in mathematics and works as a “trading analyst” in energy, and is married with two children
  • in addition to BattleShip, Jack also works on a decomp of Frogger’s Adventures - Temple of the Frog and a few other recomps for the GBA
  • inspiration for the PC port: after failure in assisting with the decompilation, Jack realized a PC port was still possible even though the decompilation isn’t 100% complete
  • the project name “BattleShip” came from “an idea someone had if a PC port was made” (BattleShip is not affiliated with Harbour Masters)
  • the original PC port didn’t use tools like LibUltraShip (LUS) and Torch; only later on were these implemented after a “sequence of failures” to make the PC port a reality, without making it look like a “LLM mess”
  • Jack reports that, out of the four platforms BattleShip currently supports, the Linux version was “tough to fix” and has “rougher stability problems” due to glibc’s heap allocation process
  • regarding AI for development: “I believe that software should be free, open-source, and abundant. If something doesn’t exist and I want it to exist, then I’ll make it and use any tools available to me to do so…people were concerned that because I used AI, I had no idea how the port actually worked and new enhancements or features would be impossible. But that’s just not the case and I’ve proved that”
  • despite some backlash from using AI-assisted tools, Jack mentions the overall reception has been “great”, and even some who initially dismissed it came back after he had fixed several issues and added new features
  • favorite games: Silent Hill 2, Chrono Trigger, Final Fantasy VI, Yakuza series, The Witcher 3, and the Resident Evil series
  • what we can look forward to: netcode support!
  • mentions that “it’s a good time to be a Linux fan” despite the development hurdles of getting BattleShip to work on it

Explain who you are and what you do.

My name is Jack Rickey, I’m 27 years old, I have a Bachelor’s degree in Mathematics and a Master’s in Quantitative Finance from the University of Maryland. Since graduating from my Master’s program in 2024, I’ve been working in energy as a trading analyst. My job is a combination of developing data ingestion pipelines that feed databases and building machine learning trading models, as well as specialized analysis for certain trading opportunities. I work with Python and SQL for backends and models, and then React/Typescript for the web apps which hold those models.

I have no formal training in computer science. I did take three semesters of object-oriented programming in my undergraduate program through the Department of Computer Science. This was in Java and these classes were very introductory; basically what a first year comp-sci student would take as part of a CS degree.

My graduate program was very focused on programming, specifically Python, and it’s “standard” libraries of pandas, matplotlib and scikit-learn, which differentiated it from a standard Master of Finance graduate degree. However, this style of programming is less programming, and more using Python as a programmatic interface to interact with C/C++ code without needing to scaffold C/C++ yourself.

Personally, I am married and have two children, a son who turns one year old this month, and a three-year-old daughter. I have a love of classic games, which stems from playing on emulators as a kid when I couldn’t afford new games. I have a really cool 27” Sony Trinitron TV that I have my retro consoles hooked up to with a component cable splitter.

Sony Trinitron TV setup

Aside from working on BattleShip, are you involved with any other community projects?

I’m working on a few projects now. A matching decompilation of Frogger’s Adventures - Temple of the Frog, a SLaDe (Small Language model Decompiler) 114m parameter model for GBA (agbcc) matching decompilation that anyone can run locally and for free (minus electricity), a static recompilation kit and runtime for the GBA, and three reference GBA recomps for the kit. [1]

The GBA was my childhood console as opposed to N64 or Smash, which I only ever played once at a friend’s house when I was a kid. I’ve been wanting to do stuff in the GBA/NDS scene for a while now, so all these projects started in sequence and are related to each other. I started on the matching decomp with LLM driven workflows and loops; so far it’s been pretty good, and I have ~700 functions matched. I have a loop to fully disassemble and map any given ROM and today’s frontier models are pretty good at matching functions. Not just matching, but building global structs, renaming functions and locals too. Full disassembly and mapping of an arbitrary GBA ROM cannot be done programmatically, then of course matching decompilation is a very difficult problem. Both of these are incredibly important for game preservation. There are quite a few completed and active decompilations in the scene, but the core economics of time invested mean that only the most popular and beloved games will get this treatment. I think that AI can close this gap. Some tools have been created – see Mizuchi by Bruno Macabeus – but the space is ripe.

In any case, from working on the decomp, I wondered how feasible it would be to train a local model on how to match functions using the agbcc compiler. [2] There is already work done on AI driven decompilation; the SLaDe model is not my architecture. I assembled and cleaned a nice dataset of 64k functions, then enriched with ~40k functions of synthetic data. I have been training, testing, and tuning for the past week on my home RTX 5070 Ti. The model works by seeding functions though M2C, a Ghidra-like tool for ARM/Thumb assembly, then compiling the M2C C output, checking diffs against the target, and recycling those diffs into another inference pass until a match. In a game unseen by the training, it was able to match 10.1% of functions, half by M2C on the initial pass, then the other half on recycling inputs. All the functions were small, so it’s not good enough for my hopes yet, but a real start. [3, 4, and 5]

GBA Recomp GUI

While this was training in the background, I started work on a static recompilation kit for the GBA as well. This statically recompiles the BIOS, the game code, and will boot 98% of the GBA library with no added symbols or mapping. Of course, this means that it will fall back to an interpreter if it panics, but maps and symbols can be provided to package a full portable static recomp executable. With this runtime, I’ve also added reimplementations of common sound libraries that are detected by signature at runtime. The three I have are M4A/MP2K, Rare in-house, and Gax. Sound quality is the GBA’s biggest weakness. I also provided a custom renderer that reconstructs the appearance of the GBA screen to the naked eye by recalculating the colors based on public colorimetry measurements of the GBA screen, and tuned to the user’s display. This is not a GLSL shader; it is an actual recalculation of the colors before they reach the player’s screen, dependent on what the color gamut and specifications of the screen they’re on. I’m really proud of this implementation and it looks fantastic on my MacBook Pro screen.

Repos are available here; open-source, always.

Metal Slug running on GBA Recomp

What inspired you to take on the process of creating a PC port for Smash 64?

I was in the mood to work on a project and I wanted to do something really hard. I work with AI a lot at my job and I felt like I wasn’t pushing it to the limit of what the models were really capable of. One day when I was scrolling Twitter/X, I saw that the Smash Bros. 64 decompilation was 96% complete. I thought at the time that this would be an interesting experiment to see how difficult decompilation with AI would be, and I was paying for the $200 Claude sub anyway and not using it fully, so I wanted to contribute. I ended up failing pretty hard. I thought that I had matches but I misunderstood the toolchain and macros and hadn’t matched at all. I was also just remote managing the Claude instances on my phone and when I got home for the day I was worn out, but so excited that I shared my fork only to be corrected.

This was a great experience. Nobody laughed at me, nobody made fun of me, no one told me to get lost or go do something else. In fact, the message I got back from the maintainer: MarioReincarnate, was “thanks for caring about my favorite game.” This was a failure, and to do things like this you have to love failure. It has to be your best friend. If you never fail at something you never learn. The harder the failure, the more embarrassing it is, the better.

So, I gave up on trying to assist the decomp and put my eyes on making the PC port. The work on trying to assist the decomp showed me that the functions that were unmatched were in the HAL Labs’ debug menu and libultra that shipped with the ROM and didn’t affect actual gameplay. A PC port wouldn’t need them. So I announced to the Discord that I was going to make a PC port instead, then disappeared for about a month and a half until I had something nice to show.

Brutally smashing a target in Target Test

What led to the name “BattleShip”?

It’s a Harbour Master’s-style port, but to be clear, I and the port are unaffiliated with them. I had been sharing some snippets of my progress, and the code was always public on my GitHub. During a discussion with some of the people I shared it with, the name came up as an idea someone had if a PC port was made. So later on when I published the initial release, I used it.

What has been the development process been like? Any pet peeves or things you wish you could have done better?

The first version of the port didn’t use Libultraship (LUS; a modern re-implementation of the N64 SDK) at all; instead it used Fast3D directly. Also no Torch (asset extractor); I was just reading directly from the ROM bytes. I got it to boot and the game to render, but couldn’t get in to the title screen, and there were plenty of rendering bugs. The first thing I saw was the Nintendo 64 screen, and it was swizzled. For those who don’t know, RAM on the N64 is severely constrained and textures have this swizzle compression pattern that is hardware-decoded in TMEM. [6]

TMEM sizzle on N64 logo This is the TMEM swizzle issue on full display. Basically reading a bitmap straight from ROM without deswizzling it gives you this.

I got a few messages from people about the port asking how I was doing it and suggesting to use Libultraship. I had played Ship of Harkinian (Zelda: OoT PC port) before and gave it some thought. When I wasn’t making any progress with the version of the port I had and felt lost, I decided to start over and do it with LUS and Torch.

After re-scaffolding and setting it all up again, the port looked the exact same. Every bug was still there. I kept at it, and once I figured out how to handle the de-swizzling and get the N64 logo to render correctly, I really got the confidence that the port was possible, and it was just a matter of putting in the work.

Like I said earlier, it was a sequence of failures. One thing I was really concerned about was accumulating per-bug fix-ups and creating tech debt instead of fixing the root architectural issue. So something I mandated in my CLAUDE.MD was to create a bug index, and whenever a bug was fixed, write a doc about it and save it in the docs folder. Nearly all the bugs fell under similar data processing patterns, and the fact that every data type: character animations, textures, bitmaps, moves, all have to be handled differently. So once a class was documented, I could design a single helper system that could handle multiple similar data types in one file. The helpers are agnostic to individual assets and can handle assets as a group.

Half-rendered trees in opening segment Un-deswizzled bitmap in the room background texture. Half-rendered trees because the pointer to them wasn’t handled and overran. Kirby has Samus’ mask because his struct is getting packed wrong by clang. Pikachu’s textures arent being clamped properly. And on top of it all, the N64 overscan is undefined, creating the purple border.

This architectural decision was how adding support for the Japanese ROM was trivial. Even though that version changed some character data, the helper systems were able to handle it. These helpers also did not require the data to be typed, which wasn’t completed when I started the port. When the initial release came out and there was a flurry of bug reports, it was pretty easy to fix them, because they mostly all fell under already-documented bug classes, and things only needed a slight tweak here and there. So it was about a five-day sprint after I went fully public and shipped a binary to get the port into a pretty solid state. I worked harder at this point than any other point in development, because I wanted to prove that I didn’t have tech debt, and the port wasn’t a LLM mess, and I could actually fix the bugs being reported.

From then on after the rendering issues I missed were patched; it was mostly patching a different class of bugs that impacted stability, mostly coming from the pointer token system. Pointers in the original game are 4 bytes and thus incompatible on LP64. [7] So, pointers are replaced at runtime with a u32 token. Failures with the token system will cause standard C memory issues like use after free. There is also the issue of pointers in display lists. If a display list pointer is passed to LUS instead of being handled, then LUS dereferences memory not allocated to the port and causes a segfault.

The only thing that I didn’t anticipate and was tough to fix, was Linux. The Linux version had much rougher stability problems than the other platforms because of the way that glibc does it’s heap allocation. There is no room for sloppy code on Linux. A bad pointer will cause a segfault, and use after free will cause heap corruption. I was also mostly doing development on my Mac, so I could be around the kids downstairs and still make progress.

Broken vertices in opening room segment Broken vertices on something in the opening room segment.

To get the Linux issues ironed out, I used Asan, which is an address sanitizer debug configuration that bounds allocated memory with red zones. If a bad pointer is dereferenced, ASan catches the dereference in the red zone and can report the exact offending function. Debugging was mostly a process of me adding logging instrumentation or using a specialized debug build, reproducing the bug, and then making a targeted patch. Because ASan is so sensitive, I ended up spending some time just playing through Classic Mode multiple times in a row to catch memory-related bugs which were non-deterministic. I had Claude set on a monitor for an ASan halt, I played through the game, ASan would halt, Claude would detect the halt, read the ASan output, patch the function, then I would rebuild and start playing again. After a few days and multiple sessions the port didn’t halt again, and a lot of stability for Linux was gained.

Something that has generated some heat in the community is regarding the development of the project using AI-assisted tools. What’s your take on this?

Everyone is free to have their own perspective on AI. I believe that software should be free, open-source, and abundant. If something doesn’t exist and I want it to exist, then I’ll make it and use any tools available to me to do so. I think that there are very valid concerns about AI-coded projects and certainly valid concerns of AI-generated shovelware being sold for a price. For this project, it is free, open-source, and I believe the code speaks for itself on its quality at this point. It is also very important that licenses and attribution are respected as a matter of legality and principle for sustainable open-source development. AI does not change that. It makes me sad to see some people being arrogant with licenses, or worse: claiming a clean room when 30 seconds of looking at their repository reveals contamination. But, it’s important to mention that this is the responsibility of the user. Under current law, they are legally entitled to the copyright of what their agent produces as well as legally liable if their agent violates a license or copyright. When you use another project for reference material or to borrow code, it’s your job to follow the terms of the license, attribute accordingly, and ensure that your project’s license is not incompatible with others, AI or not.

I think another source of concern with AI-produced content come from the fact that people can always discern a lack of effort. Nobody wants to see an incorrectly-scoped and misleading project or PR that someone made in one prompt and claims perfect functionality without testing. What we’re in now is a transition period as people learn how to use these tools. At some point, things will revert back to the mean and quality stuff will be able to speak for itself. For BattleShip specifically, a port of Smash 64 from a decomp had never been done before. All the architecture I had to make with data loading and processing had to be made from first principles, iterating for hours a day over the course of three months. The architecture is sound, the codebase is organized, there is no spaghetti code, and it was designed and bifurcated among modules to make it readable for other contributors. I mentioned this in the README, but it is important to mention again that BattleShip stands on years of work on Libultraship, Torch, and the matching decompilation. The project is a connection of those modules and my code and contribution is a comparably small, but extremely precise portion of the whole.

Versing Master Hand

What I’ve discussed above is all important, but the big one that people are afraid of with a project like this is the inability to make mods or improvements. I know this game now like the back of my hand, and I’ve added real widescreen support, three new VS mode levels, new in-game menus, co-op Classic Mode, texture pack support, and lots of other smaller enhancements. I know that people were concerned that because I used AI, I had no idea how the port actually worked and new enhancements or features would be impossible. But that’s just not the case and I’ve proved that.

Since it’s initial 0.2 beta release, how has the overall reception been to BattleShip?

I think the reception has been great and that’s made me very happy to see. It was a little rough at the start, but it was accurately described as work in progress and a beta. I think after I started knocking out the GitHub issues shortly after release and began to add new features like widescreen, people who had dismissed it initially came back to try it out again. It’s important to remember that no matter how a port is made, it’s hard! It takes a lot of effort and play testing to get it stable, especially if you’re targeting multiple platforms. There are a handful of people who are big in the Smash community who are very happy with the port as of today, whose opinions I value a lot, since they like this game a lot more than I do.

What are some of your favorite games, and why?

I’m a big fan of horror and RPGs. My favorite game is Silent Hill 2 and some other games I really love are Final Fantasy VI, Chrono Trigger, and The Witcher 3. I’m also a big fan of the Yakuza and Resident Evil series. Single-player-focused experiences are what I like most; I’m not really into multiplayer and unfortunately a lot of what comes out today is multiplayer-focused.

I’m a huge fan of Silent Hill 2 for a lot of reasons. Compared to other horror games, Silent Hill 2 is fresh and unique even today. I don’t want to compare it too heavily to other horror games, but where it’s different is where its strongest, and why it’s worth playing even today. It takes place in a contemporary, quiet American town, inverting normal locations like an apartment building or hospital into terrifying levels. The music is dark and brooding at times in typical horror fashion, but the most memorable tracks dip into the surreal and psychological.

On the topic of psychology, Silent Hill 2 has a large focus on its characters and their mental states. Artwork in it was heavily inspired by paintings of Francis Bacon, and the story is similar to Dostoevsky’s Crime and Punishment. Where other horror games rely on jump scares and shocking the player, Silent Hill 2 keeps the player nervous and on edge. It takes locations and places that seem normal and corrupts them with grime, dirt, rusty pipes and metal. It’s Japanese heritage really shines with this theme, that cleanliness and order in setting is a reflection of spiritual purity.

Silent Hill 2 remake - screenshot of parking lot

It feels like a bad dream in the best way. Characters move and look like people, but their dialogue is dreamlike and strange. Silent Hill is a liminal place; you feel familiarity to the characters and setting, but can’t shake the feeling that something is very off in a way you just can’t pin down.

For the other games I like, I love grand stories with interesting characters. Final Fantasy VI shines for me over other entries for how large its cast is, I think its 23 playable characters, each has a great arc and story.

I love Yakuza as a series because it oscillates perfectly between being a serious crime drama with themes of honor and duty, to an arcade beat ’em up, to a life simulator, to going completely over the top with some of the most entertaining and wacky side missions. There are tons of games in this series and all live up to exceptional quality. Even the ones that aren’t the best are still fantastic games.

What are some features we can look forward to with BattleShip?

There’s a really nice source-modding PR by Micklemoose in the Discord that added source code mods. I enhanced it slightly to add support for all three PC platforms. What you can do with it is write your own C code and drop it in as a mod; the port at runtime will interpret and replace its source code with your mod. This allows for things like custom items, etc. Super cool stuff. I’ll be merging it in soon. [Edit: this has already been merged since v1.4.]

Knocking Kirbys out in Dreamland

The other big one is rollback netcode. This is being worked on by TechnicallyComputers and he’s making excellent progress on it. Netcode is not my domain and I’m doing my best to ensure compatibility on the port layer and engine side and with some of the new features. After all this is done, I think the port might be complete.

Anything else you want to share with us?

I love games and I’m really happy that today we have more ways to play than ever. It’s a great thing to see user friendly distros like Pop!_OS and Linux Mint bring over gamers who want to get off Windows. Not that I hate Windows or anything, but the competition kicked off by Valve with Proton and the Steam Deck has made everything much better, including Windows. We’re seeing more of this every month, with Windows expanding WSL into WSL 2, adding coreutils, removing bloatware, and reversing some of their worst design decisions.

BattleShip on Steam Deck

The Steam Deck is especially important because it’s created so much demand for Linux native ports and projects. Developers put the time and effort into their Linux versions knowing that Steam Deck owners will play and enjoy their work.

It’s a good time to be a Linux fan.

That’ll wrap this interview up! Check out the BattleShip GitHub if you’d like to give this PC port a shot! Special thanks to Jack for taking the opportunity for me to interview him, and for sending his photos and prototype screenshots of BattleShip.

Terms Explained

  1. Static recompilation is the process of translating machine code to human readable C, which can then be compiled for a different architecture, in most cases for PC. It’s another way to get native PC executables for retro games without going through matching decompilation and recompilation from there.
  2. The agbcc compiler is a modified version of GCC meant to mimic the exact behavior of the C compiler that developers used for the GBA. It was first created by Pret to decompile the Pokémon GBA games.
  3. M2C is an acronym for MIPS to C. IPS is the type of machine code used for the Nintendo 64’s CPU. So it was originally designed to emit reference C code for a disassembled N64 ROM.
  4. Ghidra is an open source tool made by the National Security Agency to disassemble and decompile binaries. It was originally classified but was open-sourced in 2019.
  5. ARM/Thumb are the types of instructions the GBA can use. For example, X86 on PC has a different instruction set than MIPS, or ARM. Even though the GBA CPU is ARM-based, it can use special Thumb instructions which are smaller and easier to fit in memory than ARM. So Thumb instructions are more commonly used for game code and ARM code is used for powerful libraries.
  6. TMEM is the dedicated texture memory used by the Reality Display Processor on the N64. It is very small at just 4 KB and split into eight banks. So textures on a N64 ROM need special decoding to look right on PC.
  7. Pointers in C are references to a specific value in memory. Smash Bros. has pointers inside its game data as well as its game code. These pointers are 4 bytes and thus reference what is in memory on a 4-byte memory address. On a 64-bit PC, pointers are 8 bytes. So if we try to use the game code as it is without intercepting these pointers, we would overrun into an adjacent field and corrupt what the pointer was meant to reference.