Cite as
metroidret/mf
Original
https://github.com/metroidret/mf
Pinned
metroidret/mf @ a6d61875ca5ce39dcf52a0092d19df58c684d06b
Accessed
2026-10-22
Licence
MIT (the repo's LICENSE file, "Copyright 2025 YohannDR", which GitHub's API also reports). The README says building needs a baserom; the game code it rebuilds is Nintendo's.
Credit
The metroidret community's C decompilation of Metroid Fusion. GitHub lists 9 contributors (2026-10-22), led in commit count by biosp4rk, SpineSh4rk, and YohannDR. Function, variable, and constant names and the comments quoted in mf claims are theirs, not Nintendo's.
Notes
At the pinned commit the README counts 3231 of 3607 functions decompiled (89.57%); the rest sit in asm/disasm_*.s files, so the C files hold decompiled functions only, and the Makefile's `check` target compares the build with mf_us.sha1. The README warns the decomp "is not shiftable". Its only supported build is mf_us.gba, the North American release, with SHA-1 ca33f4348c2c05dd330d37b97e2c5a69531dfe87, the SHA-1 of the No-Intro file "Metroid Fusion (USA).gba" (hashed 2026-10-22); the Makefile defaults to REGION us and defines REGION_US. Samus's physics are src/samus.c with constants in include/constants/samus.h; tank pickups are src/bg_clip.c; X parasites are src/x_parasite_util.c and src/sprite_util.c.

Cited on

Claims (10)

The mf decompilation's README names mf_us.gba, the North American release, as its default and only supported build and gives its SHA-1 as ca33f4348c2c05dd330d37b97e2c5a69531dfe87, which is the SHA-1 of the No-Intro file Metroid Fusion (USA).gba. The README counts 376 functions not yet decompiled. The atlas hasn't built it.README.md L5README.md L13–17README.md L26mf_us.sha1 L1Makefile L4–11Code
When SamusInit runs with no file loading (gIsLoadingFile clear) and an unnamed flag, gUnk_3000be3, clear, it copies sEquipment_Empty into gEquipment: 99 energy of 99, 10 missiles of 10, 10 power bombs of 10, and no weapon flags (MBF_NONE). The atlas reads this as a new game's start. Zero Mission starts with the same 99 energy, but with every ammunition count at 0.src/samus.c L7523–7526src/data/samus/samus_animation_pointers.c L47–55include/constants/samus.h L236–239Code
An energy tank adds 100 to Samus's maximum energy and sets her energy to the new maximum, unless the new maximum would pass MAX_ENERGY_AMOUNT, 20 tanks plus the starting 99, or 2099. The tank code reads no difficulty. Zero Mission's tank also adds 100 and refills, or 50 on Hard, and stops at 12 tanks: 1299 on Easy and Normal and 699 on Hard (computed).src/bg_clip.c L267–274include/constants/samus.h L241–247Code
Samus has one missile count and one power bomb count, each with a maximum. A missile tank adds 5 to both the missile count and its maximum, unless the maximum would pass 255; a power bomb tank adds 2 to both, up to 254. The missile types the downloads add (super, ice, and diffusion missiles, flags in weaponsStatus) draw on that one count. Zero Mission keeps separate counts for missiles, super missiles, and power bombs, and its missile tank also adds 5, or 2 on Hard.src/bg_clip.c L258–282include/constants/samus.h L241–251include/structs/samus.h L42–50include/constants/samus.h L273–280Code
A jump sets Samus's upward yVelocity to 170 (SAMUS_LOW_JUMP_VELOCITY), or 220 with the High Jump, with no separate suitless speed. The velocity counts eighths of a subpixel and a pixel is 4 subpixels, so these are 5.3125 and 6.875 px/frame (computed). Movement caps the velocity at 128 (16 subpixels, 4 px), so a jump's first 8 frames each rise 4 px, and a High Jump's first 16 (computed). Zero Mission's jump takes off at 192, or 232 with the High Jump, under a cap of 192: 6 px/frame from the first frame.src/samus.c L4784–4793src/samus.c L4929–4942include/constants/samus.h L321–327include/macros.h L192–193include/types.h L43–59src/samus.c L5526–5538Code
Out of liquid, SamusUpdatePhysics sets the vertical acceleration to 6 and the vertical speed cap to 128, and SamusUpdateVelocityPosition takes 6 from yVelocity on every frame of the airborne poses while the velocity is above -220, whether A is held or not: 0.1875 px/frame², with rises and falls both capped at 4 px/frame (computed). In water, lava, or acid without the Gravity Suit or the flag the decompilers name SMF_SA_X_SUIT, the acceleration drops to 4 and the cap to 48, 0.125 px/frame² and 1.5 px/frame. Zero Mission's gravity is 10, 0.3125 px/frame², with the same 4 px/frame fall cap (computed).include/constants/samus.h L326–335src/samus.c L137–175src/samus.c L5526–5538Code
Stepping the code's arithmetic with A held, out of liquid, a jump from the ground peaks about 71 px up (283 subpixels) on its 28th frame, and a High Jump 104 px (416 subpixels) on its 36th (computed: each frame moves yVelocity capped at 128 and shifted right 3, then takes 6 from it). The same stepping gives Zero Mission about 59 px on the 19th frame and 83 px on the 23rd (mzm/jump-height), so Fusion's jump is higher and slower.include/constants/samus.h L321–327src/samus.c L5526–5538Code
On any frame Samus rises (yVelocity above 0) without A held, the mid-air handlers set yVelocity to 0, at any height: SamusMidAir, SamusTurningAroundMidAir, SamusSpinning (which runs the spin jump, the Space Jump, and the Screw Attack), and SamusWallJumping, which also drops a wall jump into a spin. The test is each handler's last step but the wall jump's, so a frame whose earlier branch returns skips it. Zero Mission's first three handlers end with the same test.src/samus.c L2124–2130src/samus.c L2195–2196src/samus.c L2596–2597src/samus.c L3025–3032src/data/samus_data.c L162–189Code
Touching an absorbable X parasite runs SamusAbsorbX, which refills by its color: a red X (SSC_RED_X_PARASITE) 500 energy, 100 missiles, and 10 power bombs; a green X 2 missiles; any other (yellow) X 10 energy. SpriteUtilRefillSamus adds missiles only once a missile flag is set and power bombs only once the power bomb flag is, and stops each at its maximum.src/x_parasite_util.c L482–497src/x_parasite_util.c L433–470src/sprite_util.c L2686–2707Code
When a dying sprite's countdown ends, SpriteDying sets its pose to 0x5B (the decompilers' SPRITE_POSE_TURNING_INTO_X) unless it is a secondary sprite, and an enemy's AI (Choot's, for one) runs XParasiteInit in that pose. The X it becomes takes its color from a number from 1 to 1024, made from the low 2 bits of gSpriteRandomNumber and the 8-bit frame counter, against three weights in that sprite's row of sPrimarySpriteStats: the top red-weight values give red and the next green-weight values green, each only when its weight is above 0, and everything left below the green bound gives yellow, whatever the yellow weight is, unless it is 0, which deletes the X instead. A would-be green X turns yellow when missiles are full and energy isn't, or Samus has no missiles yet; a would-be yellow X turns green when energy is full and missiles aren't. An X from a core X is green when gSpriteRandomNumber is below 5 or that energy test holds, and otherwise yellow; an X placed in a room is yellow. All of this applies only to an X whose sprite property is SSP_X_ABSORBABLE_BY_SAMUS: one marked SSP_X_UNABSORBABLE_BY_SAMUS, or the unnamed SSP_UNKNOWN_40, is always yellow, and any other property deletes the X.src/x_parasite_util.c L561–572src/x_parasite_util.c L574–655src/x_parasite_util.c L657–669src/x_parasite_util.c L509–530src/sprites_AI/choot.c L328–342include/constants/sprite.h L477src/sprite_util.c L2746–2770src/x_parasite_util.c L697–737Code