Goal: Map MvC1's character select screen entity system: cursor navigation, character ID assignment, and secret character table formats -- all from the compiled binary.
Constraints: No source code or debug symbols. Hardware-encrypted program code (mitigated via Phoenix Edition). Multiple data formats for the same conceptual operation (secret character pairs).
Approach: MAME debugger memory watches + breakpoints during character select. Ghidra static analysis for cross-references. Pattern matching for character ID byte pairs across ROM.
Result: Character data table located at $065CCA (32 bytes/entry). Player structure mapped: char ID at +$53, data ptr at +$54, health at +$60. Unlock flags at $FF803C-$FF804C. 3 distinct secret table types documented. 18 grid positions + 5 secret positions mapped. Hardcoded position checks found for positions 1, 6, 11, 12, 13 only (position 5 missing = blocker).
Proof / Validation: ULTRA SETTINGS screen verifies: NORMAL IDS: 16, SECRET IDS: 05, palettes OK, all 4 secret load functions verified. Cursor position variables confirmed via MAME memory watch at $FF2000/$FF2002.
Repo / Artifacts: CHARACTER_SELECT/docs/02_CHARACTER_ID_MAP.md, DECOMP_MVC/include/memory_map.h, DECOMP_MVC/include/character_ids.h.
The table forensics and memory maps below stand as documented. The plan for the $2E slot has changed: the Armored Spider-Man / Iron Spider line was retired, and the slot's character work pivoted to a Dark Sakura port from MSHvSF (char-id $2A in that game) -- a same-generation port whose animation/frame tables carry over byte-identical to MvC1, so the work is table porting plus tile bank remapping rather than new art.
When you only have a compiled binary, how do you understand its UI system? MvC1's character select screen uses cursor navigation tables, multiple secret character table formats, and entity ID mappings across different ROM sections. This guide documents the forensic techniques used to identify all of them.
Character Select Screen Layout
Note: Secret characters are accessed via directional input codes starting from Zangief's portrait, except where noted.
Secret Character Pairs Found in ROM
Analysis Results (mvc.05a)
| Secret Character | Base → Secret | ROM Location | Occurrences |
|---|---|---|---|
| Shadow Lady | 0x16 → 0x2A | 0x014D6E | 1 |
| Lilith | 0x1E → 0x2C | 0x04A3F2 | 1 |
| Orange Hulk | 0x06 → 0x26 | 0x024D3A | 1 |
| Gold War Machine | 0x02 → 0x28 | 0x03EDD4 | 2 |
| Red Venom | 0x0C → 0x24 | 0x07249E | 1 |
| Roll | Special | N/A | Via code |
Secret Character Table Types
Secret Box Entry Structure
Shadow Lady Entry (0x014D6E)
Context at 0x014D60:
014D60: 40 A0 00 40 00 00 49 00 00 00 06 00 2B 00 16 2A
^^ ^^
Chun-Li → Shadow LadyStructure (16 bytes):
| Byte | Value | Description |
|---|---|---|
| 0-1 | 40 A0 | Unknown - flags? |
| 2-3 | 00 40 | Position/coordinate? |
| 4-5 | 00 00 | Padding? |
| 6 | 49 | Unknown - box type? |
| 7 | 00 | Padding? |
| 8-9 | 00 00 | Unknown |
| 10 | 06 | Unknown - count? |
| 11 | 00 | Padding? |
| 12-13 | 2B 00 | Pointer/offset? |
| 14 | 16 | BASE CHARACTER ID - Chun-Li |
| 15 | 2A | SECRET CHARACTER ID - Shadow Lady |
Lilith Entry (0x04A3F2)
Context at 0x04A3F2:
04A3F2: 1E 2C 62 2C 86 2C 1A 2D 8E 2D 02 2E 76 2E CA 2E
^^ ^^
Morrigan → LilithDifferent structure! This appears to be in a different table with different format.
Orange Hulk Entry (0x024D3A)
Context at 0x024D3A:
024D3A: 06 26 1A 26 1A 26 00 00 00 26 74 26 28 27 3C 28
^^ ^^
Hulk → Orange HulkAlso different structure! Followed by more data.
Key Findings
1. Multiple Table Types
Secret characters are NOT in a single unified table. They appear in at least 3 different table structures:
- Type A (0x014D6E): 16-byte structured entries (Shadow Lady)
- Type B (0x04A3F2): Sequence/list format (Lilith)
- Type C (0x024D3A): Packed format (Orange Hulk)
2. Location Patterns
| Secret | ROM Location | Table Type | Section |
|---|---|---|---|
| Shadow Lady | 0x014D6E | Type A | Character select |
| Lilith | 0x04A3F2 | Type B | Animation/graphics |
| Orange Hulk | 0x024D3A | Type C | Palette/graphics |
| Gold War Machine | 0x03EDD4 | Type B | Animation/graphics |
| Red Venom | 0x07249E | Type C | Late section |
3. Character Data Structure (from Decompilation)
The character table at $065CCA uses 32-byte entries. Each character's runtime data is stored in the player structure at $FF3000 (P1) and $FF3100 (P2):
| Offset | Size | Purpose | Example |
|---|---|---|---|
| 0x10 | word | Player state | Animation state machine |
| 0x20 | word | X position | Screen coordinates |
| 0x24 | word | Y position | Screen coordinates |
| 0x53 | byte | Character ID | 0x0E = Spider-Man |
| 0x54 | long | Character data pointer | Points to ROM table entry |
| 0x60 | word | Health | Remaining HP |
The unlock flags are stored relative to a base address (A5 = $FF8000):
| Offset | Character |
|---|---|
+$3C | Red Venom |
+$40 | Orange Hulk |
+$44 | Gold War Machine |
+$48 | Shadow Lady |
+$4C | Lilith |
4. Secret Load Function Patterns
From decompilation of all 4 secret character load functions:
| Function | Address | Size | Key Operation |
|---|---|---|---|
load_red_venom | $022B2E | 66 bytes | move.w #$24, d0 + bsr.w $22CF2 |
load_orange_hulk | $05D044 | 60 bytes | move.w #$24, d0 + property writes |
load_gold_war_machine | $07EF90 | 12 bytes | move.w #$24, d0 + movep.l d0, $3141(a0) |
load_shadow_lady | $0A26C8 | 20 bytes | move.b #$24, d0 + flag setup |
All functions follow a pattern: set a value in D0, then write character properties to the player structure via indirect addressing through A0 or A6. Gold War Machine is the simplest (12 bytes), suggesting it was either the first implemented or the most straightforward.
5. Hardcoded Position Checks
The assembly code that controls secret box visibility has hardcoded character positions:
; Only these positions trigger a secret box check:
Positions: 1 (Morrigan), 6 (Hulk), 11 (Venom), 12 (War Machine), 13 (Chun-Li)Position 5 (Wolverine) is NOT in the list. This is why data-only patches fail -- the code never even reads the table for Wolverine's position. Fixing this requires patching the assembly to add a position 5 check.
6. CPS-2 Encryption Note
Only program code is encrypted in CPS-2 ROMs. Data sections (character tables, palettes, graphics pointers) are unencrypted. This is why palette patches always work. Using the Phoenix Edition (mvscud) with decrypted code eliminates the encryption complication entirely.
Cursor Navigation System
Grid Positions (from Decompilation)
Position: 0 1 2 3 4 5
Row 0: [Zan] [Mor] [Cap] [Meg] [Str] [Wol]
Position: 6 7 8 9 10 11
Row 1: [Hul] [Gam] [Ryu] [Jin] [CCo] [Ven]
Position: 12 13 14 15 16 17
Row 2: [W.M] [Chu] [Rol] [Spi] [?] [?]
Secret positions (virtual row below visible grid):
Below Gambit → Shadow Lady (Chun-Li unlock code)
Below War Mach → Lilith (Morrigan unlock code)
Right of Megaman→ Roll (Zangief code)
Above Zangief → Gold War Machine (Zangief code)
Above Ryu → Orange Hulk (Chun-Li code)
Above Venom → Red Venom (Chun-Li code)
Below Wolverine → Armored Spidey (TARGET - position 5)Cursor position tracked at: P1 = $FF2000, P2 = $FF2002
Character ID written to: P1 = $FF3053, P2 = $FF3153
Down Navigation
When pressing Down on certain characters:
- Chun-Li (pos 13) → Secret box appears (Shadow Lady)
- Morrigan (pos 1) → Secret box appears (Lilith)
- Hulk (pos 6) → Secret box appears (Orange Hulk)
- War Machine (pos 12) → Secret box appears (Gold War Machine)
- Venom (pos 11) → Secret box appears (Red Venom)
Target: Wolverine (pos 5) → Secret box (Armored Spider-Man)
ROM Patching Strategy
Required ROM Patches
To add Armored Spider-Man below Wolverine, we need to patch:
1. Character Pair Entry (Type A - 0x014D6E style)
Location: Find or create entry near 0x014D6E
Pattern:
40 A0 00 40 00 00 49 00 00 00 06 00 2B 00 08 0E
^^ ^^
Wolverine → Armored Spider-ManStatus: ⚠️ Added at 0x014D70 but doesn't work alone
2. Animation/Graphics Entry (Type B - 0x04A3F2 style)
Location: Find similar table and add entry
Pattern: TBD (needs more analysis)
3. Palette/Graphics Entry (Type C - 0x024D3A style)
Location: Find similar table and add entry
Pattern: TBD (needs more analysis)
4. Cursor Navigation Table
Location: TBD (needs MAME debugger)
Modification: Make Down on Wolverine (pos 5) go to secret box position
ROM Table Locations
Analysis TODO
Immediate Research Needed
- Find cursor navigation table (where Down destinations are defined)
- Understand Type B table structure (Lilith/Gold WM)
- Understand Type C table structure (Orange Hulk/Red Venom)
- Find secret box graphics data
- Find secret box positioning data
Tools Needed
- MAME debugger to trace character select code
- Memory watch to find cursor position variable
- Breakpoint on Down input during character select
- Disassembly of character select routine
Hypothesis: Why Only One Type A Entry?
Observation: Only Shadow Lady has a Type A entry at 0x014D6E.
Possible reasons:
- Shadow Lady was added last / is special case
- Other secrets use older/different system
- Type A is newer format, others use legacy format
- Each secret type has unique implementation
Implication: We may need to add Wolverine entry to MULTIPLE tables, not just one.
Next Steps
Step 1: Find Cursor Navigation Table
Use MAME debugger:
1. Set breakpoint on character select screen
2. Watch memory when pressing Down on Chun-Li
3. Find variable that changes (cursor position)
4. Find code that reads this variable
5. Find table that defines Down destinationsStep 2: Add All Required Entries
Once we understand all table types:
1. Add Type A entry (done at 0x014D70)
2. Add Type B entry (location TBD)
3. Add Type C entry (location TBD)
4. Patch cursor navigationStep 3: Test Incrementally
1. Test after each patch
2. Document which patch enables the box
3. Refine as neededCurrent Status
| Component | Status | Notes |
|---|---|---|
| Secret character pairs | ✅ Complete | All 6 located in ROM |
| Multiple table types | ✅ Identified | 3 types: structured, sequence, packed |
| Entry structures | ✅ Documented | Shadow Lady (Type A) fully mapped |
| ROM expansion | ✅ Complete | 128MB GFX + 16MB Audio (CPS-2 max) |
| In-game verification | ✅ Complete | ULTRA SETTINGS screen in F2 menu |
| Palette locations | ✅ Verified | P palette at $0C8642, K palette at $0C86A2 |
| Secret load functions | ✅ Verified | All 4 entry points contain valid code |
| Character ID 0x2E | ✅ Found | 85 code references, present in roster scan |
| Cursor navigation table | In Progress | Traced via MAME debugger |
| New character injection | In Progress | Infrastructure built, wiring remaining |
Key Discovery: False Positive IDs
During analysis, IDs 0x30 and 0x32 initially appeared to have 80+ ROM references. Deeper investigation revealed these were false positives: the 68000 MOVE.W #imm,D0 instruction encodes as 0x303C, which pattern-matched against ID 0x30 searches. The actual animation marker count for both IDs is zero -- they are completely empty slots available for new characters.
References
- PalMod: Shows Lilith/Shadow Lady have separate palette entries
- ROM Analysis: Multiple table types found across mvc.05a
- MAME Debugger: Instruction tracing and memory watches
- Ghidra: Static analysis via GhidraMCP plugin
- Community: Secret character codes documented by MvC1 modding community