Mario Tennis GBC: the level-up system, decoded
Reverse engineered from a ROM dumped from my own cartridge · May 2026
The four RPG characters (Alex, Harry, Nina, Kate) each have 11 substats shown on a 1-10 scale. On level-up you pick a category (Spin, Power, Control, Speed) to invest in. Stats are not stored directly; they are recomputed from your category investments and each character's hidden threshold table every time the game recalculates. The "stat decay" community players observe is a natural consequence of this formula, not a separate mechanic.
How it was done
Three days, seven working sessions, alternating between reading the game's code and watching it run.
Tools
- Ghidra with the GhidraBoy extension, for disassembly and decompilation of the Game Boy Color's SM83 CPU.
- GhidraMCP connected to Claude Code, so the AI could decompile functions, follow cross-references and rename symbols in Ghidra directly. GhidraMCP is LaurieWired's bridge; I set it up by hand from its 1.4 release, before it shipped as part of a ready-made reverse-engineering bundle.
- BGB, a high-accuracy emulator, for memory searches and write watchpoints on the running game.
The loop
The AI walked the code statically and flagged the exact bytes or memory addresses that needed checking at runtime. I checked them in the emulator and reported back, and the analysis continued from confirmed ground truth.
Milestones
- Mapped the engine and decoded its cross-bank call trampoline, which every function in the level-up system goes through.
- Found the 11 substats in memory with emulator searches, plus a second block holding the up/down arrows on the level-up screen. Whatever wrote those arrows had to be the stat algorithm.
- Traced the level-up screen's call flow back from those addresses.
- Found the function that recomputes every stat from scratch, and with it the formula and the equipment system.
- Read all four characters' threshold tables (44 arrays) straight out of the ROM file.
- Resolved a call the decompiler couldn't follow by reading its two hidden inline bytes from the ROM. It led to the arrow preview, which simulates the real spend on a copy of the character and then rolls everything back.
- Matched each character to their internal type from their starting stats on fresh saves. The first guess had two of them swapped.
Finally, the formula was checked against the running game, which caught an off-by-one in the first version.
What came out of it
- An exact model of every displayed stat, for every character, at every point distribution, including equipment.
- "Stat decay" explained: there is no decay routine. Every level adds a penalty to the categories you didn't invest in.
- Each character's hidden affinities, measured. For example, Harry needs 17 straight points in Speed to max it, the hardest grind in the game; no other character needs more than 13 anywhere.
| Category | Substat | Value |
|---|
Objective
Best builds at max level (99) for every character, searched across all 21 equipment combinations (7 rackets × 3 shoes). Max Total Stats shows the build that maximises the sum of all 11 displayed values. Max Weakest Stat shows the build that maximises the lowest displayed stat — the most balanced option available. Both total and weakest values are shown for every build.