News: 11 March 2016 - Forum Rules

Author Topic: mmx 1-3  (Read 1960 times)

RedGuy

  • Jr. Member
  • **
  • Posts: 89
    • View Profile
mmx 1-3
« on: February 23, 2016, 09:02:18 pm »
I didn't see a recent thread on mmx (megaman X) 1-3 hacking so I figured I start a new one up.

I've been trying to work out how the object (mainly enemy) properties are stored.  I figured it would be useful to be able to modify them in a gui MMX editor.  There's another post about where active objects are stored in RAM so I tracked back to how they are setup.  Looks like it's a series of jump tables (switch statements?) indexed by Id as well as state to say if the object is already active.  Unfortunately, it's not a simple table reference as things like HP and damage modifier are loaded as constants into A and stored to the correct offset into RAM.  I've made a real basic hack to following the jump table and string match for the LDA and STA operations.  Any better ideas on how to approach this?

The RAM stores what looks like 64B entries with things like xpos, ypos, current hp, damage modifier, sprite frame info, and a lot of other information.  Some of them come from constants.  Some of them look like preprocessed state of other values in the entry to speed up execution.  Has anyone worked through what all of these mean?

justin3009

  • Hero Member
  • *****
  • Posts: 1666
  • Welp
    • View Profile
Re: mmx 1-3
« Reply #1 on: February 24, 2016, 04:07:53 am »
I have a slight bit more detail on that but I can't get them at the moment until I'm off work later today. At least for X2 and X3 anyway. I don't do any X1 hacking so I can't help much there but more than likely it's about the same per game.

Edit:

+40 per enemy

7E0D18 - Start of enemy list
7E10D8 - End of enemy list (Missile List starts here)


7E0D18 - Set to 01 for enemy to be initialized
7E0D19 - What event enemy is on
7E0D1A - What attack event to use
7E0D1D - X coordinate (Low)   Enemy 1
7E0D1E - X coordinate (High)  Enemy 1
7E0D20 - Y coordinate (Low)   Enemy 1
7E0D21 - Y coordinate (High)  Enemy 1
7E0D22 - Enemy to load/event #
7E0D29 - Palette of Enemy 1
7E0D2A - Layer of enemy.  02 = In Front, 04 = Behind
7E0D2C \ Pointer to sprites?
7E0D2D /
7E0D2E - Sprite Assembly of Enemy 1
7E0D2F - Current Frame of animation on Enemy 1
7E0D3F - Current enemy life

That's about all I have listed for it.  I haven't actually checked the ASM to see how it gets all the values.
« Last Edit: February 24, 2016, 12:59:58 pm by justin3009 »
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

RedGuy

  • Jr. Member
  • **
  • Posts: 89
    • View Profile
Re: mmx 1-3
« Reply #2 on: February 24, 2016, 03:32:33 pm »
When l get home I'll add an example from x1 to show where the hp (life) and other things come from. Several fields are constants inlined within the code.  And each enemy can have a unique function. The x3 table in your post looks very similar to the x1 table. Only difference is starting offset. I have working code that walks through the jump tables and tries to find the Hp and damage modifer by decoding instructions. The boss code is long enough where my code gives up before finding the values.

How does sprite assembly work?  I would prefer displaying a sprite of the enemy when showing the events instead of just a red rectangle.

justin3009

  • Hero Member
  • *****
  • Posts: 1666
  • Welp
    • View Profile
Re: mmx 1-3
« Reply #3 on: February 24, 2016, 04:17:31 pm »
Sprite assembly works based off of what's stored in VRAM, so in order to properly display the enemy sprite, you'd have to actually have their VRAM pointers and stuff located as well (Which is a bit annoying but it works).  VRAM pointers tend to have a pointer to the graphics and then how much data to transfer.  I believe the max each sprite can have is THREE sets of data so it can get rather confusing and annoying.

X/Zero sprites are the worst in this case since they're dynamic.  Enemy sprites, however, are just flat out loading a sheet (Which basically since most are compressed, you're good to go with loading the graphics and then loading the sprite assembly)

Sprite Assembly is set per frame.  The first byte it uses is the total amount of pieces there are and what direction the sprite will face (+20 to make it use 16x16 tiles, +40 to dictate flipping).  The following pieces are: X coordinate, Y coordinate and graphic to use from VRAM.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

RedGuy

  • Jr. Member
  • **
  • Posts: 89
    • View Profile
Re: mmx 1-3
« Reply #4 on: February 24, 2016, 09:03:22 pm »
Thanks for the sprite assembly info.  I'll take a look at it some examples.

Here's the setup for some of the active enemy state from X1 highway stage.  First enemy encountered.  Lots of inline constant LDAs.

Code: [Select]
$80/D271 20 00 D5    JSR $D500  [$80:D500]   A:1928 X:0000 Y:0093 P:envMXdiZC


$80/D500 C2 20       REP #$20                A:1928 X:0000 Y:0093 P:envMXdiZC
$80/D502 A9 68 0E    LDA #$0E68              A:1928 X:0000 Y:0093 P:envmXdiZC
$80/D505 5B          TCD                     A:0E68 X:0000 Y:0093 P:envmXdizC # setup direct offset register with first active table entry (0x0e68)
$80/D506 E2 30       SEP #$30                A:0E68 X:0000 Y:0093 P:envmXdizC
$80/D508 A5 00       LDA $00    [$00:0E68]   A:0E68 X:0000 Y:0093 P:envMXdizC
$80/D50A F0 03       BEQ $03    [$D50F]      A:0E01 X:0000 Y:0093 P:envMXdizC
$80/D50C 20 46 D5    JSR $D546  [$80:D546]   A:0E01 X:0000 Y:0093 P:envMXdizC


$80/D546 C2 20       REP #$20                A:0E01 X:0000 Y:0093 P:envMXdizC
$80/D548 A5 05       LDA $05    [$00:0E6D]   A:0E01 X:0000 Y:0093 P:envmXdizC
$80/D54A 85 22       STA $22    [$00:0E8A]   A:0270 X:0000 Y:0093 P:envmXdizC
$80/D54C A5 08       LDA $08    [$00:0E70]   A:0270 X:0000 Y:0093 P:envmXdizC
$80/D54E 85 24       STA $24    [$00:0E8C]   A:0170 X:0000 Y:0093 P:envmXdizC
$80/D550 E2 20       SEP #$20                A:0170 X:0000 Y:0093 P:envmXdizC
$80/D552 A9 80       LDA #$80                A:0170 X:0000 Y:0093 P:envMXdizC
$80/D554 14 0E       TRB $0E    [$00:0E76]   A:0180 X:0000 Y:0093 P:eNvMXdizC
$80/D556 A5 0A       LDA $0A    [$00:0E72]   A:0180 X:0000 Y:0093 P:eNvMXdiZC # load enemyId (0x15 == spikey)
$80/D558 0A          ASL A                   A:0115 X:0000 Y:0093 P:envMXdizC # 2*Id
$80/D559 AA          TAX                     A:012A X:0000 Y:0093 P:envMXdizc
$80/D55A 7C F3 F8    JMP ($F8F3,x)[$80:FA30] A:012A X:002A Y:0093 P:envMXdizc # indirect jump to jump table with spikey index
$80/FA30 22 CB 9B 82 JSL $829BCB[$82:9BCB]   A:012A X:002A Y:0093 P:envMXdizc # take jump in table to function (index 0 has RTS right back)


$82/9BCB A6 01       LDX $01    [$00:0E69]   A:012A X:002A Y:0093 P:envMXdizc # get active? variable
$82/9BCD FC 63 9C    JSR ($9C63,x)[$82:9C69] A:012A X:0000 Y:0093 P:envMXdiZc # not-active -> jump to state setup


$82/9C69 64 3D       STZ $3D    [$00:0EA5]   A:012A X:0000 Y:0093 P:envMXdiZc
$82/9C6B 22 7D 82 82 JSL $82827D[$82:827D]   A:012A X:0000 Y:0093 P:envMXdiZc # jump to function to load some common state


$82/827D A9 02       LDA #$02                A:012A X:0000 Y:0093 P:envMXdiZc
$82/827F 85 01       STA $01    [$00:0E69]   A:0102 X:0000 Y:0093 P:envMXdizc
$82/8281 A9 03       LDA #$03                A:0102 X:0000 Y:0093 P:envMXdizc
$82/8283 85 28       STA $28    [$00:0E90]   A:0103 X:0000 Y:0093 P:envMXdizc # damage modifier = 0x3
$82/8285 A5 0A       LDA $0A    [$00:0E72]   A:0103 X:0000 Y:0093 P:envMXdizc
$82/8287 3A          DEC A                   A:0115 X:0000 Y:0093 P:envMXdizc
$82/8288 0A          ASL A                   A:0114 X:0000 Y:0093 P:envMXdizc
$82/8289 AA          TAX                     A:0128 X:0000 Y:0093 P:envMXdizc
$82/828A BD E4 A5    LDA $A5E4,x[$86:A60C]   A:0128 X:0028 Y:0093 P:envMXdizc
$82/828D 85 16       STA $16    [$00:0E7E]   A:0122 X:0028 Y:0093 P:envMXdizc
$82/828F BD E5 A5    LDA $A5E5,x[$86:A60D]   A:0122 X:0028 Y:0093 P:envMXdizc
$82/8292 AA          TAX                     A:011F X:0028 Y:0093 P:envMXdizc
$82/8293 BF 00 82 7F LDA $7F8200,x[$7F:821F] A:011F X:001F Y:0093 P:envMXdizc
$82/8297 85 18       STA $18    [$00:0E80]   A:0100 X:001F Y:0093 P:envMXdiZc
$82/8299 BF 00 83 7F LDA $7F8300,x[$7F:831F] A:0100 X:001F Y:0093 P:envMXdiZc
$82/829D 85 11       STA $11    [$00:0E79]   A:0129 X:001F Y:0093 P:envMXdizc
$82/829F 64 30       STZ $30    [$00:0E98]   A:0129 X:001F Y:0093 P:envMXdizc
$82/82A1 C2 20       REP #$20                A:0129 X:001F Y:0093 P:envMXdizc
$82/82A3 64 1A       STZ $1A    [$00:0E82]   A:0129 X:001F Y:0093 P:envmXdizc
$82/82A5 64 1C       STZ $1C    [$00:0E84]   A:0129 X:001F Y:0093 P:envmXdizc
$82/82A7 64 1E       STZ $1E    [$00:0E86]   A:0129 X:001F Y:0093 P:envmXdizc
$82/82A9 E2 20       SEP #$20                A:0129 X:001F Y:0093 P:envmXdizc
$82/82AB 6B          RTL                     A:0129 X:001F Y:0093 P:envMXdizc # return from loading common state


$82/9C6F A5 11       LDA $11    [$00:0E79]   A:0129 X:001F Y:0093 P:envMXdizc
$82/9C71 29 0E       AND #$0E                A:0129 X:001F Y:0093 P:envMXdizc
$82/9C73 85 33       STA $33    [$00:0E9B]   A:0108 X:001F Y:0093 P:envMXdizc
$82/9C75 A9 02       LDA #$02                A:0108 X:001F Y:0093 P:envMXdizc
$82/9C77 85 27       STA $27    [$00:0E8F]   A:0102 X:001F Y:0093 P:envMXdizc # hp = 0x2
$82/9C79 A9 03       LDA #$03                A:0102 X:001F Y:0093 P:envMXdizc
$82/9C7B 85 28       STA $28    [$00:0E90]   A:0103 X:001F Y:0093 P:envMXdizc # overwrite damage modifier (enemy specific value) = 0x3

...

« Last Edit: March 01, 2016, 10:31:06 am by RedGuy »