+  RHDN Forum Archive
|-+  Romhacking
| |-+  ROM Hacking Discussion
| | |-+  Finding Data in MMX3
Pages: [1]
Author Topic: Finding Data in MMX3  (Read 2 times)
elixirnova
Guest
« on: July 24, 2008, 01:16:38 am »

Ok so, I have tried just searching for data and trying to figure it out. So far I am stuck!

I found this block of data that obviously changes the room order or which rooms go where on the stage map or something like that. There is even a pointer table that points to the data sets. So I know it must be a block of some sort of data!

Is there any techniques to tracing how blocks of data are used? Like looking at the assembly? I have snes9x debugger but am pretty new to it still.

There must be a more effective way of finding and UNDERSTANDING data that I want to edit...

I'm thinking that I need to read through the assembly of the stage loading and see what I can find? Since ultimately stage data is what I want to be editable!

On a side note I noticed parasytes sources code for Syndrome (MM7 editor) has lots of data similar to megaman X3 so far. I don' really understand what parasyte means by structures and blocks and rooms and such. Parasyte also has stage header data being read in the Syndrome editor. I'm guessing MMX3 has stage headers as well. Any special way of finding them?

Any help is appreciated. I am going to try reading through the assembly to figure out what is happening, but just wondering if there are any easier methods that anyone knows about!
Ryusui
Guest
« Reply #1 on: July 24, 2008, 02:16:02 am »

It might be time-consuming, but it sounds like you're on the right track.

Set a read breakpoint for the data and watch what the game does with it.
kuja killer
Guest
« Reply #2 on: July 24, 2008, 11:40:34 am »

I hope I am not hijacking the thread or anything. But I was just screwing around for a little while on X3 this morning, and somehow i managed to find what seems like a wall detection routine that stops you from proceeding forward when you walk up to a solid wall (i was doing it on the left side of the screen with the door) ..and i saw this LDA #11, and then later STA $05,X ..so i messed with the 11 for a bit, and it actually let me walk back more. Smiley but if i were to go under 10, then i end up way on the right side of the screen inside of the door. :p

http://www.a3share.com/members/1119/walldetect.PNG

And it also made volt catfish just instantly disappear off the screen when he was jumping around Tongue

I do not hack SNES games, or have any 65816 knowledge, I'm profficent in just the NES, but this was an interesting find though Tongue
elixirnova
Guest
« Reply #3 on: July 24, 2008, 12:42:46 pm »

Quote from: Ryusui on July 24, 2008, 02:16:02 am
It might be time-consuming, but it sounds like you're on the right track.

Set a read breakpoint for the data and watch what the game does with it.

How do I set a breakpoint for data being read? I know how to set a breakpoint when a RAM address is read/written/accessed by just checking the breakpoint feature in SNES9x debug. I tried setting it to break when whatever the LOROM address was accessed/read/written to, but that was useless I guess I'll have to play with SNES9x debug a bit more to find out how to break when a block of data is read...

Edit:
Also, in case anyone is interested the specificc data I'm looking at begins at 0x1AF886 in the ROM and is for the Bee level or whatever the top left boss' name is. Sometimes if I increase a byte by one it will shift a row of rooms to the left, but scrolling/enemies/etc is still the same. Also there was once I increased a byte by one and it shifted a row of rooms to the right one. The starting location stays the same relative to the enemies and scrolling, but if the row of rooms is shifted left one you will start in the room to the right of the usual starting room if that makes sense. Also I have figure out that in this block of data that starts up a bit higher than the address I mentioned each level's block of this data ends with these two bytes[00, FF] and all blocks are even numbers so I'm guessing each data comes in pairs. The blocks can either affect the background of a stage's rooms or the actual foreground rooms.
0x1AF800 - 0x1AFFFF is the entire block

I have yet to figure out how to trace a block of data using SNES9X btw.
« Last Edit: July 24, 2008, 07:57:22 pm by elixirnova »
Ryusui
Guest
« Reply #4 on: July 24, 2008, 10:37:00 pm »

Quote from: elixirnova on July 24, 2008, 12:42:46 pm
I tried setting it to break when whatever the LOROM address was accessed/read/written to, but that was useless I guess I'll have to play with SNES9x debug a bit more to find out how to break when a block of data is read...

Um? If it's a ROM address of any sort, there are no writes. That's why it's called read-only memory. That said, do you have Lunar Address? Because it's useful for converting file addresses into SNES addresses. (And make sure Megaman X3 is actually a LoROM game before you base all your calculations on that assumption.)

Oh, and depending on which side of the Pacific you're on, he's either Blast Hornet or Explose Horneck.
elixirnova
Guest
« Reply #5 on: July 24, 2008, 11:21:05 pm »

Well I got the breakpoint set and logged the CPU. So I'm commenting through the code to understand it! So far so good! Thanks for all the help so far! I'll post my progress after I get through it since I'm sure I'll have some questions as I have already had.....

Here is some of the Assembly routine for decoding it, it is indeed compressed somewhat. It has a byte to tell if the following byte should be copied into memory so many times. In the end it looks like lots of 00 & 01 values are stored to memory. I tried changing them and nothing seems to change in the level... Hmm. Surely this isn't useless data. I'll have to look at it more. I'm pretty excited though because this is the first assembly routine I have actually read through and sort of understood!

Code:
X is used to keep track of how many times the byte is copied
Y is used to keep track of ???.........
Z & N flags are used
First 3 bytes are stored to RAM
4th Byte can tell how many times the 5th Byte will be repeated if Z flag is reset at that time

$00/BE3F B7 10       LDA [$10],y[$35:F800]   A:D014 X:0000 Y:0000 P:envMxdIZc
$00/BE41 8F 00 F0 7E STA $7EF000[$7E:F000]   A:D01C X:0000 Y:0000 P:envMxdIzc // $7E:F000 = #$1C
$00/BE45 C8          INY                     A:D01C X:0000 Y:0000 P:envMxdIzc
$00/BE46 B7 10       LDA [$10],y[$35:F801]   A:D01C X:0000 Y:0001 P:envMxdIzc
$00/BE48 8F 01 F0 7E STA $7EF001[$7E:F001]   A:D008 X:0000 Y:0001 P:envMxdIzc // $7E:F001 = #$08
$00/BE4C C8          INY                     A:D008 X:0000 Y:0001 P:envMxdIzc
$00/BE4D B7 10       LDA [$10],y[$35:F802]   A:D008 X:0000 Y:0002 P:envMxdIzc
$00/BE4F 8F 02 F0 7E STA $7EF002[$7E:F002]   A:D024 X:0000 Y:0002 P:envMxdIzc // $7E:F002 = #$24
$00/BE53 C8          INY                     A:D024 X:0000 Y:0002 P:envMxdIzc
$00/BE54 B7 10       LDA [$10],y[$35:F803]   A:D024 X:0000 Y:0003 P:envMxdIzc // 4th value is loaded to accumulator
$00/BE56 C9 FF       CMP #$FF                A:D09A X:0000 Y:0003 P:eNvMxdIzc // If the value is not #$FF then run routine
$00/BE58 F0 1A       BEQ $1A    [$BE74]      A:D09A X:0000 Y:0003 P:eNvMxdIzc // Do not branch since Z is reset
$00/BE5A 85 01       STA $01    [$00:0001]   A:D09A X:0000 Y:0003 P:eNvMxdIzc // $00:0001 = #$9A (4th value)
$00/BE5C 29 7F       AND #$7F                A:D09A X:0000 Y:0003 P:eNvMxdIzc // #$7F AND #$9A = #$1A, N flag is reset
$00/BE5E 85 00       STA $00    [$00:0000]   A:D01A X:0000 Y:0003 P:envMxdIzc // $00:0000 = #$1A
$00/BE60 C8          INY                     A:D01A X:0000 Y:0003 P:envMxdIzc
$00/BE61 B7 10       LDA [$10],y[$35:F804]   A:D01A X:0000 Y:0004 P:envMxdIzc // Read 5th value
$00/BE63 C8          INY                     A:D000 X:0000 Y:0004 P:envMxdIZc
$00/BE64 9F 03 F0 7E STA $7EF003,x[$7E:F003] A:D000 X:0000 Y:0005 P:envMxdIzc // $7E:F003 = $00
$00/BE68 24 01       BIT $01    [$00:0001]   A:D000 X:0000 Y:0005 P:envMxdIzc // [#$9A AND #$00]-> N & Z flag are set
$00/BE6A 30 01       BMI $01    [$BE6D]      A:D000 X:0000 Y:0005 P:eNvMxdIZc // Skip next operation since N flag is set

$00/BE6D E8          INX                     A:D000 X:0000 Y:0005 P:eNvMxdIZc // Bit 7 of #$01 is not set so N is turned off
$00/BE6E C6 00       DEC $00    [$00:0000]   A:D000 X:0001 Y:0005 P:envMxdIzc // DEC $00:0000 = #$1A - #$01 = #$19, Z/N flags are off
$00/BE70 D0 F2       BNE $F2    [$BE64]      A:D000 X:0001 Y:0005 P:envMxdIzc // Branch back to BE64 since Z flag is reset

$00/BE64 9F 03 F0 7E STA $7EF003,x[$7E:F004] A:D000 X:0001 Y:0005 P:envMxdIzc // $7E:F004 = #$00
$00/BE68 24 01       BIT $01    [$00:0001]   A:D000 X:0001 Y:0005 P:envMxdIzc // [#$9A AND #$00]-> N & Z flags are set
$00/BE6A 30 01       BMI $01    [$BE6D]      A:D000 X:0001 Y:0005 P:eNvMxdIZc // Skip next op since N flag is set
$00/BE6D E8          INX                     A:D000 X:0001 Y:0005 P:eNvMxdIZc // X = 2, N flag is reset since bit 7 of #$02 is reset
$00/BE6E C6 00       DEC $00    [$00:0000]   A:D000 X:0002 Y:0005 P:envMxdIzc // DEC $00:0000 = #$18, N & Z stay reset
$00/BE70 D0 F2       BNE $F2    [$BE64]      A:D000 X:0002 Y:0005 P:envMxdIzc // Branch since Z is reset

$00/BE64 9F 03 F0 7E STA $7EF003,x[$7E:F005] A:D000 X:0002 Y:0005 P:envMxdIzc
$00/BE68 24 01       BIT $01    [$00:0001]   A:D000 X:0002 Y:0005 P:envMxdIzc
$00/BE6A 30 01       BMI $01    [$BE6D]      A:D000 X:0002 Y:0005 P:eNvMxdIZc
$00/BE6D E8          INX                     A:D000 X:0002 Y:0005 P:eNvMxdIZc
$00/BE6E C6 00       DEC $00    [$00:0000]   A:D000 X:0003 Y:0005 P:envMxdIzc // #$00 is copied to memory many times!

$00/BE64 9F 03 F0 7E STA $7EF003,x[$7E:F01C] A:D000 X:0019 Y:0005 P:envMxdIzc
$00/BE68 24 01       BIT $01    [$00:0001]   A:D000 X:0019 Y:0005 P:envMxdIzc
$00/BE6A 30 01       BMI $01    [$BE6D]      A:D000 X:0019 Y:0005 P:eNvMxdIZc
$00/BE6D E8          INX                     A:D000 X:0019 Y:0005 P:eNvMxdIZc
$00/BE6E C6 00       DEC $00    [$00:0000]   A:D000 X:001A Y:0005 P:envMxdIzc // Z flag is set so byte copying is done
$00/BE70 D0 F2       BNE $F2    [$BE64]      A:D000 X:001A Y:0005 P:envMxdIZc
$00/BE72 80 E0       BRA $E0    [$BE54]      A:D000 X:001A Y:0005 P:envMxdIZc //******* branch back to origional routine

I suppose the next step is to figure out what is going on with this data. It has something to do with room placement on the stage map...
« Last Edit: July 25, 2008, 02:02:36 am by elixirnova »
Ryusui
Guest
« Reply #6 on: July 25, 2008, 02:00:12 am »

Good work. Congratulations. ^_^

Quote
It has a byte to tell if the following byte should be copied into memory so many times.

Just so you know, that's called RLE, or Run-Length Encoding.
elixirnova
Guest
« Reply #7 on: July 26, 2008, 12:47:24 am »

Well thus far I have found quite a few pointer tables!
0x309B3 -- Pointers to Stage Maps
0x30A22 -- Pointers to Room Data (Stage tile arrangements)
0x30A91 -- Pointers to mini-tile data (Arrangement of mini-tiles to create Stage Tiles) (possibly the beginning?)
0x30B00 -- Pointers to 4bpp block data ( Arrangement of 4bpp tiles to make mini-Tiles)
0x30B6F -- Pointers to structure data (collision of X with tiles)
0x30BDE -- Pointers to stage maps for Vile Stages? Maybe other Vile stage stuff
0x30c4d -- Pointers to BG Stage Tiles (Room Data)
0x30cbc -- Pointers to BG mini-tile arrangements
0x30d2b -- Pointers to BG 4bpp block data


I have an understanding of the "Room Data", "Mini-Tile data", probably the 4bpp block data is simple, and all the BG data.

The only thing I'm unsure about now is the Stage Maps and structure data(havn't even looked at yet). The stage map data however I believe is similar to the MM7 data as it gives a possible width and height that seem to be logital to each level and the 3rd bit seems to be a length of how many uncompressed bytes of data their are for each stage. I'm not so sure what the uncompressed bytes represent yet, but I suppose some more tinkering could give the answer!

In fact I just tinkered and figure out that the first value is the width of the ucnompressed data and second is height of uncompressed data. Then the data is loaded by row and each data value represents the Room number that is placed in the respective stage map square.


Well now if I can figure out how the 4bpp block data is connected to the mini-tiles and how the actual decompressed graphics are connected to the 4bpp blocks I'll be able to display a stage in an editor! Roll Eyes .... Sans objects/enemies bah... :banghead:

Anyone have any idea what a stage header might contain? MM7 editor Syndrome reads some sort of stage header... I've also seen it used in Lunar Magic I believe. I'm thinking it would tell which sprite set to use and which fg/bg graphics set to load and music selection maybe and I guess some other stuff. If anyone has an example of what one might look like maybe that would help me to understand how to find it?

EDIT:
I may have found the Stage headers! I have also found all pointer tables I need to load the Stage. I have however not found or searched too much for Sprite (enemies and items and such) pointer tables or data.. I'm sure it won't be too hard! Assembly tracing really helps find lots of stuff apparently!
« Last Edit: July 27, 2008, 02:34:17 pm by elixirnova »
Pages: [1]  


Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC