Skip to content
Index / $13

Magneto From XvSF: Costing an Import Before Building It

Magneto already flickers through Marvel vs. Capcom as a random Special Partner striker, so the tempting story is that half the work is done. It isn't. This is the honest feasibility plan for importing full Magneto from X-Men vs. Street Fighter: a measured 15,304-tile appetite against a stock free pool of 5,649 split across four non-fungible banks, a striker 'seed' that turns out to be a mirage, an extraction blocker that was actually ROM corruption and not cryptography, and the exact price of making him fit -- evict Hulk's family into one bank, or take the 64MB expansion and lose netplay.

Date
Jul 22, 2026
Runtime
13 min · 2,842 words
Tags
cps2, reverse-engineering, xmvsf
Slot
$13
Contents
tip // Evidence Strip

Goal: Decide, with numbers, whether full Magneto -- not the striker cameo, the actual playable fighter -- can be imported from X-Men vs. Street Fighter into Marvel vs. Capcom, and if so at what price. This is a costed plan, not a build. Nothing Magneto-related runs today.

Constraints: No source. Base ROMs untouched; everything would be a build-script artifact, the same discipline that carries the native secret characters. The binding resource is graphics: a fighter can only address one 64K-tile GFX bank at a time, and MvC's free space is nearly gone.

Approach: Measure Magneto's real tile appetite by walking his XvSF animation tree; measure MvC's free space per bank; test the folk-wisdom "seed" (his frames are already in the ROM as a striker) against what the fighter engine can actually reach; confirm the XvSF data is extractable at all; then lay out the eviction-vs-expansion decision and a four-phase plan with honest effort ranges.

Result: Magneto needs 15,304 tiles (MEASURED). Stock MvC has 5,649 free, and the largest single bank has only 2,542 -- he is 6x over the bank that matters. He fits stock only by evicting Hulk's whole family (two roster slots) to open bank 2, or by taking the 64MB expansion that breaks Fightcade netplay. The extraction blocker recorded in prior notes was refuted: it was a corrupted ROM dump, not encrypted data. The "already in the ROM as a striker" head start is real trivia and a useless budget lever.

Proof / Validation: Tile appetite from an animation-tree walk that self-validates by packing flush against the next character's tree; per-bank free counts independently re-measured; XvSF master tables located by code-homology against the MSHvSF port we shipped; striker "reuse" refuted by rendering the matched tile clusters and finding shared FX, not Magneto.

Primary docs (in-repo): analysis/xvsf_budget/ANSWER.md, analysis/eviction_budget/ANSWER_HULK_CC.md, analysis/eviction_budget/bankmap/eviction_scenario.txt.

The Seductive Version of This Story

Here is the pitch that makes Magneto sound easy. In Marvel vs. Capcom's Special Partner system -- the random striker who flies in, does one thing, and leaves -- Magneto is one of the faces in the rotation. So some of his sprites are already sitting in the MvC ROM. Same engine family as the game he comes from. Adjacent hardware. Move the rest of the data and you're most of the way there.

That framing is wrong in the specific way these ports are always wrong, and the interesting part of this post is measuring exactly how wrong, because the number tells you what the real project is.

I did confirm the striker system exists and can be captured. MvC1 indexes its Special Partners through a small table -- a read-tap on $0E4084 through $0E40B5 catches the RNG selecting one of ~25 partner slots -- and a MAME harness (tomichin_capture_partner.lua) drops the chosen partner's OBJ list and palette to disk on a fixed frame. Magneto is a documented entry in that rotation. So the trivia is true: pixels that draw Magneto do live in the ROM.

The problem is what a striker is. A Special Partner is a handful of frames -- a fly-in, one attack pose, a fly-out. A playable fighter is idle, walk, eight-way dash, every normal, every special startup/active/recovery, every super, every hit and block and knockdown reaction. And two hard facts kill the reuse idea outright:

  • The fighter engine cannot reach striker art. A full-ROM scan found exactly one animation-tree pointer table -- the 23-entry fighter table at $0E676C. Strikers are drawn by a separate subsystem; none of their tiles are addressable through the fighter VM that a playable Magneto would run on. Even if the frames are perfect, the fighter can't point at them.
  • The overlap is FX, not Magneto. When XvSF characters' tiles were content-matched against all 262,144 MvC tiles, the "already present" hits rendered as hatching textures and lightning fragments -- shared effect art owned by existing fighters -- not character bodies. Net-new tiles come out at ~99% of the full set for every X-Man measured.

So the seed is a nice palette reference and a fun screenshot. It removes zero tiles from the bill. Keep it in the "narrative" column and out of the "budget" column.

Loading diagram...

What Magneto Actually Costs

I walked Magneto's animation tree in XvSF the same way the shipped Shuma-Gorath port walked his -- expanding each multi-tile sprite segment by the CPS-2 OBJ rule and summing unique tiles. The walk self-validates: each character's tree packs flush against the next character's tree start, so an off-by-anything shows up as overrun. The number:

Magneto's appetite, measured
15,304
tiles Magneto needs
1,958,912 bytes of GFX
slot 17
XvSF roster index (id $22)
resolved through the master tables
5,649
total free tiles in stock MvC
723,072 bytes -- 2.2% of the GFX ROM
2,542
largest single free bank
the number that actually gates a fighter
6.0x
Magneto vs. the biggest free bank
not close, not a compression problem

Magneto is not a small import. Among the X-Men in XvSF he sits near the top -- heavier than Storm (12,377), Cyclops (13,364), Wolverine (13,417) and Rogue (14,359), just under Gambit (15,541), with only Juggernaut (21,219) clearly above him. Set every candidate against the stock free pool and the wall is obvious:

Loading diagram...

The leftmost bar is everything MvC has free. Every other bar is one character. There is no arrangement of cleverness inside the stock address space that turns 5,649 into 15,304 -- and as the next section shows, even the raw pool total is a fiction, because the fighter can only ever see one quarter of it.

The Bank Wall: Why 5,649 Is Really 2,542

CPS-2's sprite word carries a 16-bit tile code, which addresses 65,536 tiles. MvC's GFX region is 262,144 tiles -- four such banks. The two high bits that pick which bank come from object field $47, and that field is written once, at fighter init, from the bank table at $E67C8. Nothing during a match ever changes it. So every frame a character will ever draw -- idle, specials, supers, hit sparks he owns -- must live inside a single 64K window.

That turns "you have 5,649 free tiles" into a statement about the ROM, not about capacity. The free space is four non-fungible pools:

BankTile rangeStock freeLargest run
0$00000–$0FFFF1,8411,840
1$10000–$1FFFF2,542905
2$20000–$2FFFF609608
3$30000–$3FFFF657656

The relevant comparison for a fighter is 15,304 against the biggest single number in that table, 2,542 -- a 6x shortfall. The 1,841 tiles in bank 0 and 2,542 in bank 1 can't be pooled with anything; they're stranded for this purpose because no fighter's whole set fits in them. Full Magneto does not fit stock. That is settled arithmetic, not an opinion.

Making Room: Eviction vs. Expansion

Two roads open a bank wide enough for Magneto.

Road 1 -- eviction. Delete existing characters to free a bank. The measured yields:

  • Deleting the Hulk family frees 16,427 tiles in bank 2. It has to be the whole family: $06 Hulk and $26 Orange Hulk are a palette pair sharing 100% of the same tiles, so removing Hulk alone frees literally zero -- Orange Hulk still references every tile. That's a two roster slots cost for one bank.
  • Deleting Captain Commando ($14) frees 13,496 tiles in bank 3.

Set Magneto's 15,304 against each: bank 2 (post-Hulk-family) holds ~17,037 tiles, so he fits with roughly 1,700 tiles of slack. Bank 3 (post-Captain-Commando) holds ~14,154 -- short by ~1,150. So the single clean stock plan is exact and unforgiving: evict Hulk plus Orange Hulk, seat Magneto in bank 2. No other single eviction opens a bank he fits in.

Loading diagram...

That diagram is the entire deal on one screen: two deleted characters flowing into one bank, almost all of it consumed by Magneto, a sliver left over for rectangle-packing waste and later fixes. It is a tight fit that leaves no room for a second import in that bank ever.

Road 2 -- the 64MB expansion. The custom FBNeo core that seats the native secret characters adds four GFX banks. Magneto drops into the expansion band with room to spare and no roster deletion. The cost is the one this series keeps paying: the expanded ROM layout breaks Fightcade netplay, because it no longer matches the standard set every other player runs. It's an offline/local build.

There is a real precedent worth stating plainly: Shuma-Gorath, at ~11,587 tiles, already failed to fit in stock space and had to go into the expansion band. Magneto is 32% larger than Shuma. The project has run this experiment with a smaller character and the stock answer was no; eviction is the only thing that changes that answer, and eviction is a capability this project has never exercised -- every removal risk below is an unknown, not a solved step.

Can We Even Get the Data Out?

An older project note flagged the XvSF dump as "opcode-only, data ciphertext" -- a hard extraction blocker. That note is refuted, and the correction matters because it moves Magneto from "maybe impossible" to "extractable today."

Two things were conflated. CPS-2 encryption covers opcode fetches only; data fetches return raw ROM bytes, so the stored ROM already is a plaintext data view with no key required. The actual problem was mundane: the xmvsfu.zip dump on hand is corrupted -- two members measure maximum entropy and differ from canonical by ~522KB above the crypto range, which decryption can't explain. The intact xmvsfj.zip carries the MAME-canonical CRCs. The working configuration is:

  • OPCODE view = xmvsfu_plaintext.bin
  • DATA view = byteswapped xmvsfj.zip (the Japanese set; character data is region-invariant)

Through those views, Magneto's per-character tables resolve cleanly, at the identical stride layout MSHvSF used -- the game we already ported Shuma from:

TableAddressNotes
Animation tree$08A94619 entries, indexed by id×2
Bank$08A992which GFX bank the character reads
Boxshape$08A9B8
Hitbox$08AA04
Move-attr$08AA50
Palette$11E83C

Magneto is slot 17. Because XvSF and MSHvSF share this engine family and layout, frame/animation/hitbox data likely carries over the way it did for MSHvSF -- that's the working expectation the Shuma port earned, stated as expectation and not yet proven for Magneto specifically.

The Part the Space Budget Hides

Fitting is necessary, not sufficient, and this project has the receipts to prove it. Cite our own record before treating "it fits" as "it's done":

Shuma-Gorath had all the space he needed -- via the 64MB expansion, no bank pressure at all -- and after many sessions of native-port work he still lacks supers, native physics, and his own sound, running on Ryu's physics rows at ~22 dispatch sites. Space was never his constraint.

Two structural hazards apply directly to Magneto:

  1. The master defect. A fighter's field $52 is char_index × 2, and every per-character table in MvC has exactly 23 entries ($00..$2C). Add a new id and you're reading past the end of tables unless every access is clamped or redirected -- the root of nearly every bug in the secret-character work (damage ×5.94, stun corruption, a one-byte knockdown crash). Magneto's bring-up inherits all 203 catalogued read-sites. Fixes are reader-side clamps; you cannot widen the tables without corrupting the whole roster, which are packed with zero slack.
  2. Eviction breaks id-indexed systems. Deleting Hulk's family leaves two holes the select cursor can land on, plus id-indexed VS portraits, name tiles, ending scripts, the AI table at $1A430, and secret-code handlers -- every one a separate task, none ever done in this project.

And two resources are only barely in the picture: program space is not the wall (244,654 bytes free easily holds one character; Magneto's exact program cost is unmeasured but bounds to his peers' ~88–99KB), while QSound is a live risk -- only ~66KB is genuinely free, ~99% full, so his voice and SFX must reuse existing MvC samples or reclaim a deleted character's audio, and no per-character sample partition has been located to make reclaim safe.

The Plan, Four Phases

Loading diagram...
  • Phase 0 -- Extract (low risk, days). The blocker is gone; this is bounded. Confirm the xmvsfj data view, walk slot 17, re-census the 15,304 tiles independently, and render-gate an idle frame (helmet, cape, the purple ramp) to prove the extraction is Magneto and not a mislabeled slot.
  • Phase 1 -- Place (the irreversible decision). Choose eviction or expansion. Eviction is one shot into bank 2 via the Hulk family with ~1,700 tiles of slack and a two-slot roster loss; expansion is roomy but offline-only. Whichever is chosen, Magneto's entire set must land in one bank.
  • Phase 2 -- Seat and boot (weeks). Relocate his code block and hook dispatch the way the native $30 Shuma relocation does; poison-test every candidate tile before seating art ("all-FF is not sufficient to seat a tile" -- a lesson already paid for); add reader-side clamps for the past-the-end table reads; get him to load and reach fight phase on his own tree.
  • Phase 3 -- Bring-up (the long pole, months). Physics rows, specials (EM Disruptor projectile, Hyper Grav), the flight state that has no clean MvC analogue, supers (Magnetic Tempest / Shockwave), SFX, an assist move MvC needs but XvSF never had, and intro/win/KO plumbing. This is exactly where Shuma still sits, unfinished, with all the space in the world.

Honest Verdict

Full Magneto from XvSF is feasible and costed, not close to built. The GFX arithmetic is the whole story: 15,304 tiles against a bank that holds 2,542, closeable only by evicting Hulk and Orange Hulk into bank 2 with a razor-thin ~1,700-tile margin and a two-character roster loss -- an operation this project has never performed and whose id-indexed fallout is a list of unknowns -- or by the 64MB expansion that trades Fightcade netplay for headroom. Extraction is clear, the tables are located, the engine is the same family we already ported once, and the striker "seed" that makes the pitch sound easy contributes nothing to the budget.

If I were to spend the effort, the shape is: expansion band for a single-player build where space stops being the enemy, or -- if netplay is non-negotiable -- Hulk-family eviction and a very tight bank 2, with eyes open that the removal itself is net-new engineering risk. Either way, Phase 3 is the project, and Shuma-Gorath is the honest yardstick for how long that takes.

warning // What's measured vs. what's promised

Measured, with in-repo receipts: Magneto's 15,304-tile appetite, the 5,649 free pool and its per-bank split, the Hulk-family and Captain Commando eviction yields, the single-bank rule, and the XvSF master-table addresses. Refuted with receipts: the "data ciphertext" extraction blocker (it was ROM corruption) and the striker-reuse head start (the matched tiles render as shared FX). Promised, and only promised: everything downstream of Phase 0. Nothing Magneto-related runs today -- this is a plan you can hold me to, not a build I'm claiming.

EOF · $13 · 2,842 words · Daniel Plas Rivera
Share[X][LinkedIn]