Goal: Import MSHvSF's two-tier New York street -- the one where the ground gives way and the fight drops into the subway -- into MvC1 as a playable stage, on the same custom-ROM lineage that carries the native secret characters.
Constraints: No source. Base ROMs untouched; everything is a build-script artifact. MvC's scroll-GFX space is nearly full -- the stage's art appetite versus MvC's free space is the central conflict of this post.
Approach: Live RAM archaeology in MSHvSF to prove what the tier flip actually is (it is not what any of us guessed); a donor-stage + 64MB-expansion strategy for the art budget; differential and poison-tile testing before seating any graphics.
Result: The tier-flip mechanism is fully RE'd and was live-verified in MSHvSF on 2026-07-02 (counter $FFFF30, gate $06A70A, a +$200 scroll shift, 51/64 palette pages). The police van -- the stage's signature prop -- renders and animates live in MvC, camera-tracked, bounce frames cycling. The stage as a whole is not yet playable in MvC -- forcing it hangs at load. That open defect is described honestly below.
Proof / Validation: Live-verified tier flip in the source game; pixel-level differential runs against pristine stock for every merge; a GFX poison test that caught art being seated on cells the attract mode secretly used.
See also: the Saturn MSHvSF recompile -- a plaintext, byte-identical mirror of the same character data -- and the 64MB ROM expansion the art budget leans on.
Everyone Wants This Stage
If you ask MvC1 players what the game is missing, the answers cluster fast: more characters (we're working on it), and that stage. Marvel Super Heroes vs. Street Fighter's New York street is the most theatrical backdrop in the whole Capcom Versus line: you fight on the pavement, someone gets bounced off a parked police van a few too many times, and the street collapses -- a scripted camera plunge into a subway tunnel where the rest of the match plays out underground, emergency lightbars strobing above.
MvC1 shipped one year later on the same CPS-2 hardware, same engine family, and has nothing like it. So the port question looks simple: same hardware, adjacent engine, move the data. That framing survived about one afternoon of actual reverse engineering.
This post is the story of what the stage turned out to be, why the real wall was never the code, and the first piece of it now rendering live in the wrong game.
What the Underground Actually Is
Before touching MvC, I needed ground truth from the source game. There were three plausible theories for how the two-tier gimmick works, and the community holds all three:


- Two stages -- the collapse triggers a stage load, underground is a separate stage id.
- Object scenery -- the underground is drawn by the OBJ (sprite) system over a static backdrop, like Onslaught's transformation set-pieces.
- One tall tilemap -- both tiers live in a single oversized scroll map, and the "collapse" is a camera trick.
Theory 3 is the truth, and it's the most elegant of the three. The underground is the same stage id $06, and the flip is nothing more than a +512-pixel (+$200) shift of the scroll base offset into the same tall tilemap. There is no second stage. There is no load. The subway was under the street the whole time, in the most literal sense a tile engine allows: the tilemap is simply twice as tall as what the camera shows, and the trigger slides the window down.
The trigger chain is small enough to state exactly, and every piece of it was live-verified in MSHvSF on 2026-07-02. The receipts are inline on the state machine below:
This finding matters for the port in a very practical way. If the underground had been a second stage, the port doubles. If it had been OBJ scenery, it lands in a completely different subsystem with its own budget. Because it's one tall tilemap plus a scroll delta and a palette swap, the mechanism ports almost for free -- the flip logic is a counter, a compare, and an add. The mechanism was never going to be the problem.
- $06
- MSHvSF stage id -- both tiers
- +$200
- scroll base shift on collapse
- $FFFF30
- van-bounce counter address
- $06A70A
- the trigger gate
- 51/64
- palette pages swapped
- 2026-07-02
- live-verified in MSHvSF
How the Stage Is Wired
A CPS-2 stage is not one image. It is three independent scroll layers composited with the OBJ (sprite) layer, all read through a camera window, and the NYC stage uses every one of them. SCROLL3 is the far parallax background, SCROLL2 carries the bulk of the street-and-tunnel tiles (this is the tall tilemap that holds both tiers), SCROLL1 is the near text/detail layer, and the police van lives entirely in the OBJ layer as a bounce prop. The tier flip acts on exactly two things in this picture: the camera window's vertical offset and 51 of the 64 palette pages the layers index into.
The Real Wall Is the Art Budget
Here's the number that reframed the whole project. The NYC stage's scroll art -- both tiers of that tall tilemap, the props, the animation cells -- needs roughly 400KB of scroll-GFX space. I mapped MvC's scroll graphics region for free space, and the largest contiguous free run is about 51KB.
Not 400 versus 300. Not "compress harder and squeak in." An 8-to-1 shortfall against the largest hole in the map. No amount of cleverness inside the stock address space closes that; the tile data for MvC's own stages is packed nearly wall to wall.
Two moves together make the budget real:
- Donate a stage. One of MvC's existing stages gives up its scroll allocation; NYC takes over the donor's space and stage slot. (In the current build lineage the target is stage slot
$0D.) - The custom 64MB GFX expansion. The same expanded FBNeo core that carries the native characters' tiles -- extra graphics chips plus a mapper above the stock 32MB ceiling -- absorbs what the donor slot alone can't. The standing caveat applies here too: the 64MB core is an offline build and breaks Fightcade netplay compatibility.
This is the same shape of solution as the character work, and that's not a coincidence: on CPS-2, code is almost never the scarce resource. Space is.
A Police Van, Rendering in the Wrong Game
The stage's soul is the police van -- it's the trigger object, the thing players remember, and mechanically it's an OBJ-system prop with its own bounce animation frames rather than part of the scroll tilemap. So it made the right first milestone: small enough to seat honestly, load-bearing enough to prove the pipeline.


That milestone is shipped: the van renders and animates live in MvC. Bounce frames cycle, and it tracks the camera correctly -- which sounds cosmetic but is the actual test, because camera-relative OBJ placement is where a half-ported prop falls apart first.
Two bugs from this phase are worth writing down, because both are the kind that silently eat weeks.
The silent canvas trim. For several builds, the underground tier came out of the pipeline with garbled yellow blocks across the top of the tunnel. The art source was provably right; the seated bytes were provably wrong; everything in between claimed success. The culprit was an image-processing step that silently trimmed the working canvas to 1024 pixels -- and since the underground lives in the bottom half of a taller-than-1024 canvas, the trim quietly dropped the tunnel's top rows and shifted everything above them into garbage. v26 of the stage build fixed it. The lesson generalizes: any pipeline stage that can resize without erroring is a pipeline stage that will eventually lie to you.
The attract-mode font. An early merge of the stage's first scroll layer corrupted MvC's attract mode -- four of the GFX cells I'd seated art into were doing double duty as glyphs in an attract-screen font. Those cells read as free by every static test I'd run: nothing in the stage tables referenced them, and they were full of $FF. The fix is deployed and the attract screen is now pixel-identical to stock, but the cautionary tale is the point: all-$FF is not sufficient evidence that a tile is unowned. The rule that came out of it is the GFX poison test, now standard for every seating operation: fill the candidate cells with a loud sentinel pattern, sweep attract mode, the select screen, and full matches, and prove the sentinel renders nowhere before a single byte of real art goes in. Prove cells unreferenced by observation, not by absence of evidence.
Where It Stands: The Load Hang
Honesty section, and it's a real one. The stage work has been merged onto the current native-character build lineage, and the character regression suite passes -- Dark Sakura and Shuma-Gorath are unharmed by the merge. But forcing a match onto stage $0D hangs at load. The diagnosis so far points at a relocated-pointer integration bug -- some pointer in the stage-load path still aims at where data lived before the donor-slot relocation -- but I have not root-caused it, and I won't pretend otherwise. The NYC stage is not playable in the currently deployed ROM. The van milestone is real; the stage milestone is not yet.
Also still open on the art side: eight more OBJ props are extracted but not seated (cops, medics, the dog, civilians), and the flashing emergency lightbars turn out to be the most interesting remaining piece -- they are not OBJ sprites at all but scroll-tilemap animation driven by a small VM in the stage script, a mechanism MvC's stages use differently. That's a genuine porting sub-project, not a copy job.
Open Items
Stated plainly, because the project rule is no false success claims:
- The load hang. Stage
$0Dforced-load hangs in the merged build; suspected relocated-pointer bug; not root-caused. The NYC stage is not playable in the deployed ROM. - Eight OBJ props (cops, medics, dog, civilians) extracted but not seated.
- The lightbar VM. The flashing emergency lights are scroll-tilemap animation driven by a small VM, not sprites -- not yet ported, and genuinely nontrivial.
- The 64MB expansion the art budget depends on remains an offline-only core -- it breaks Fightcade netplay compatibility.
Proven, with receipts: the tier-flip mechanism (live-verified in MSHvSF), the van rendering and animating in MvC, and the attract-mode fix (pixel-identical to stock). Promised, and only promised: the stage playable in MvC. When the load hang falls, that's a follow-up post -- and if it turns out my donor-slot relocation design was itself the mistake, that will be in the post too.
The other half of this investigation -- what MSHvSF's own Sega Saturn port turned out to be, and whether MvC content could go the other direction onto Saturn hardware -- got long enough to earn its own writeup: Byte-Identical on a CD: What the Saturn MSHvSF Port Actually Is.