OFF-TOPIC: MLBPA Baseball Sega Genesis Hacking

Recommended Posts

This is the thread where we can discuss hacking MLBPA Baseball for the Sega Genesis, in any kind of form. Anyone can post at anytime if they have remarks or findings, but just make sure everything listed is as clear as possible.

First, it would be interesting to find out what the format is for the organ ditties. Organ ditties are played any time a player from the home team comes up to bat.

An index is stored in RAM address $FFE842, from $01-$18, and the starting ROM address is put in RAM address $FFE802. Each organ ditty is terminated with an $FF, and they run from $1A8DD0 to $1B4C27 in ROM (a total of $BE58 or 48,728 bytes).

It seems that each note takes four bytes, because, for example, you might see something like 45 50 05 00 4A 50 04 00 42 50 03 01 3E 50 03 0E (this can be found in the ROM at $1AA235). The first byte seems to represent the note, the fourth byte seems to represent the note length. And there is some kind of header that might look like C1 09 00 B1 01 1E 00 91 (this can be found at $1AA245).

This game will be interesting to hack! I'll come up with more data later.

Link to post
Share on other sites

Here is how the graphics are loaded:

At $000724 in the ROM, you will find:

jsr $000724

move.w $7414(a5),-(a7)

move.w #$FFFF,$7414(a5)

movem.l #$FFFE,-(a7)

Then, it will convert the 16-bit address in a1 to a VDP command like this:

move.w a1,d0

and.l #$FFFF,d0

asl.l #2,d0

lsr.w #2,d0

or.w #$4000,d0

swap d0

move.l d0,($C00004)

lea ($C00000),a1

Then, it goes:

lea ($FF6A9A),a4

move.w #0,d1

move.l (a3)+,d2

lea ($FF744E),a2

move.l a2,a0

Then, a loop, which sets $1000 bytes each to $20:

move.l #$20202020,d3

move.w #$3FF,d0

move.l d3,(a0)+

dbra d0,#$FFFC

And here's the main loop:

move.w #$FEE,d7

moveq #0,d3

moveq #0,d6


dbra d3,#$0006 ; DBRAs to $000784

move.b (a3)+,d6

moveq #7,d3


lsr.b #1,d6

bcc #$002A ; branches to $0007B2

move.b (a3)+,d0

move.b d0,0(d1.w,a4)

add.w #1,d1

and.w #3,d1

bne #$0004 ; branches to $00079E

move.l (a4),(a1)


subq.l #1,d2

beq #$005A ; branches to $0007FC

move.b d0,0(d7.w,a2)

addq.w #1,d7

and.w #$FFF,d7

bra #$FFCC ; branches to $00077C


moveq #0,d4

move.b (a3)+,d4

move.b (a3)+,d0

move.b d0,d5

and.w #$00F0,d0

asl.w #4,d0

or.w d0,d4

and.w #$000F,d5

addq.w #2,d5


move.b 0,(d4.w,a2),d0

addq.w #1,d4

and.w #$FFF,d4

move.b d0,0(d1.w,a4)

add.w #1,d1

and.w #3,d1

bne #$0004 ; branches to $0007E4

move.l (a4),(a1)


subq.l #1,d2

beq #$0014 ; branches to $0007FC

move.b d0,0(d7.w,a2)

addq.w #1,d7

and.w #$FFF,d7

dbra d5,#$FFD2 ; DBRAs to $0007C8

bra #$FF82 ; branches to $00077C


tst.w d1

beq #$0004 ; branches to $000804

move.l (a4),(a1)


movem.l (a7)+,#$7FFF

move.w (a7)+,$7414(a5)

rts ; We're all done!

It appears to be LZSS format, where the length/distance pairs are 12 bytes for distance and 4 for length, and strings can be copied for 3-18 bytes.

I hope this is a starter for everyone. I'll be updating this as I understand more.

Edited by walker7
Link to post
Share on other sites

If anyone wants to try to understand this kind of stuff, you can learn a bit about it in TonyH's tutorial (which is how I learned how to fix the weight bug..)

And to understand the code instructions:

Link to post
Share on other sites

Another thing that I might want to add is the "Hello from (wherever). I'm John Shrader welcoming you to today's game..." text that appears right before the game starts. In ROM, the text starts at $16A374, and there is an instruction that points to it at $16A23A (a MOVE.L). But, it seems like, if you change the pointer, the game will crash at the time when the text would be loaded. It seems like that one of the RTS's will cause it to return back to address $000000, which is obviously not part of the game code. Can anyone find a way to relocate this text without any crashing? It would be nice if anyone can figure out a way to do so.

Link to post
Share on other sites

Another thing is that it seems that the subroutine at $16D118 is the one that calculates the pointer for the music.

Here is the subroutine:


movem.l #$7860,-(a7)

lea ($FFE93A),a1

move.w #3,d2

cmp.l #$FFFFFFFF,(a1)

beq $0050 ; branches to $16D17E

move.l (a1),a0

move.l a0,a2

clr.l d3

move.b (a0)+,d3

lsl.w #8,d3

move.b (a0)+,d3

move.l d3,d4

lsl.w #2,d4

add.l d4,a2

add.l #2,a2


cmp.b (a0),d0

bne #$18 ; branches to $16D164

cmp.b 1(a0),d1

bne #$12 ; branches to $16D164

move.b 2(a0),d0

lsl.w #8,d0

move.b 3(a0),d0

move.l a2,a0

and.b #$FE,d1 ? ; comes out as ANDI.B #$FE,#$2C on Gens Tracer

bra #$2C ; branches to $16D190


clr.l d4

move.b 2(a0),d4

lsl.w #8,d4

move.b 3(a0),d4

add.l d4,a2

add.l #4,a0

sub.w #1,d3

bne #$CA ; branches to $16D148


add.l #4,a1

dbra d2, #$FFA0 ; branches to ?

move.w #3,d0

or.b #1,d0 ? ; comes out wrong on Gens Tracer, see above


move.l (a7)+,#$061E


Following the code is a BCS, so I think this subroutine leaves some output in the Carry flag.

Now execute this piece of code with the registers set up such:

















In that case, you should end up with $1AA22A, which is the address of one of the organ ditties. I think that the input is in d1, and the output is in a0 and the Carry flag.

Here is an interesting Game Genie code: To make an organ ditty play regardless of whether the home team is at bat or not, change the 6700 at 16C1BA to 6002, for AMAV-NA74.

Edited by walker7
Link to post
Share on other sites

The teams are formatted like such:

There is a pointer table for the teams that starts at $1B5074. There are 28 pointers, one for each team, but seemingly in no particular order.

For example, let's take the Chicago A team. It starts at $1B740C and appears to look like this:

It has the text "Chicago A" in ASCII format, followed by a bunch of $00 bytes, then a set of bytes that reads 00 64 00 64, then a pointer that reads $001B73CC, then 00 00, "CH A" in ASCII format (this is the team abbreviation that appears on the scoreboard after a side is retired), then a pointer that reads $001B740C (this is the pointer to the team data), then 00 00 00 01, then a bunch more $00 bytes. Then following it are 25 32-bit pointers, one for each player.

The first pointer points to Jack McDowell. The data there looks like this: The player's last name, followed by a comma, and then their first name. (If the combined length of their first and last names is too long to fit on the player info box whenever a player comes up to bat, only the initial letter of their first name and their full last name is displayed.) So it appears as "McDowell,Jack", then a bunch of $00 bytes, followed by 40 00 00 00 00 00 06 04 06 68 40 08 00 1D 00 00 00 00 00 03 00 25 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 FF FF. (The non-$00 bytes are bolded). The FF FF is presumably the end token. Obviously, their jersey number, at-bats, batting average, and other statistics that are displayed on the info box are there.

The teams are stored one right after another, and so are the players. But notice that each player uses up 80 ($50) bytes in ROM, and each team info data block is 170 ($AA) bytes in ROM, so this section shouldn't be too hard to edit.

Edited by walker7
Link to post
Share on other sites
  • 2 weeks later...

At $16C322 is a table, probably used to create the music pointers. It consists of 32-bit values (possibly pointers) increasing from $00000000-$00000014, then skips to $00000020 and continues through $00000032. These are then followed by an $FFFF, which should mean the end of the table.

At $16C314 is the following code:

lea ($16C322),a0

bsr $02B8 ; BSRs to $16C5D4

bra $0BB8 ; branches to $16D1F2

At $16EEFE is a table of 16-bit values. Maybe that is where the music pointers are created.

Link to post
Share on other sites

The player stars are stored to VRAM by way of a DMA operation. Therefore, these graphics are uncompressed. Each star takes up 6 tiles in VRAM, and are stored in sprite tile order (top to bottom, then left to right). However, each star graphic is preceded by a $0006, which presumably represents the number of tiles to decompress.

Each star has two possible states, the "highlight" state (this is when the person you are currently controlling is in possession of the ball; it looks akin to a dithered translucent shading inside the star), and the "outline" state (this is when the currently controlled player is not in possession of the ball, and it is just an outline). Each star can be one of four colors, based on which controller you use: Player 1 is yellow, player 2 is blue, player 3 is red, and player 4 is orange. During the game, palette 3 has these colors, in that order, from colors $3B-$3E. So, you can choose the order of the colors just by changing the order of the $B's, $C's, $D's, and $E's. And of course, they don't have to be stars. You can make them any shape you want. The example on the NHL '94 site changed the stars to circles. They can be anything, such as circles, rectangles, triangles, etc.

Here is are the data locations. Each star is 6 tiles, plus a $0006 at the beginning, for a grand total of 194 ($C2) bytes.

$0C84DE: Player 1, highlight state

$0C85A0: Player 1, outline state

$0C8662: Player 2, highlight state

$0C8724: Player 2, outline state

$0C87E6: Player 3, highlight state

$0C88A8: Player 3, outline state

$0C896A: Player 4, highlight state

$0C8A2C: Player 4, outline state

The dots and crosses that represent each player's position on the field in the diagram are probably done the same way as well, but require 1 tile, not 6.

Edited by walker7
Link to post
Share on other sites
  • 2 weeks later...
  • 4 weeks later...

Here are the addresses of each organ ditty, according to their ID. The IDs are stored in $FFE842 in RAM, and the address is stored in $FFE802. Address $FFE824 is the offset that the song is currently at. In the game, in the place where the organ ditty list is stored, 00 means an unused slot, and anything from 01-18 is an organ ditty. To tell which organ ditty goes with which ID, you can use the patch code 16C006:00xx, where xx is the organ ditty ID, and listen when the game is turned on (or after a Reset). Using 00 plays an organ ditty that isn't used in the game--it is in fact heard on the SNES version of this game. As always, organ ditties are played any time when a player from the home team comes up to bat, but with the Game Genie code AMAV-CA74 (equivalent to patch code 16C1BA:6002), organ ditties will play any time a player comes up to bat, whether it is from the home team or the visiting team. 33 is the theme song and 34 is the music played in the Options menu (when you pause the game). The addresses for the organ ditties are:

00 - 1A8DD1

01 - 1A901D

02 - 1A9049

03 - 1A923D

04 - 1A96BD

05 - 1A99FF

06 - 1A9DDD

07 - 1AA1EE

08 - 1AA22A

09 - 1AA53E

0A - 1AA704

0B - 1AAC7E


0D - 1AB526

0E - 1ABB8A

0F - 1AC205

10 - 1AC738

11 - 1ACB28

12 - 1AD374

13 - 1AD978

14 - 1ADE9C

15 - 1AE7B4

16 - 1AEA6E

17 - 1AF0BC

18 - 1AF11C

33 - 1AF89E (Title Screen)

34 - 1B1E91 (Options Menu)

Edited by walker7
Link to post
Share on other sites
  • 9 months later...

Just to clarify, this is the game I am talking about:

The music pointer table can actually be found at offset $16EFF0 in ROM. Each entry has 4 bytes:

Byte #1: Always $03

Byte #2: This byte starts at $00 for the first entry, $01 for the second, etc. up to $19, then skipping $1A-$1F and then going from $20-$35. This is the ID for each song/sound effect. ($00-$19 are organ ditties, $20-$32 and $35 are sound effects, $33 is the main theme, and $34 is the options theme.)

Bytes #3-#4: A 16-byte value that tells the length of each song, in bytes.

Now, here's an example of an organ ditty:

At song ID $08, or offset $1AA22A, this is the "Charge!" theme. It all begins with the header:

00 00 00

C0 08 00

B0 01 1E 00

The "C0 08" is the organ instrument. I am not sure of what the "B0 01 1E" does.

If a byte is in the range of $90-$9F, then what follows is a series of notes; the lower nybble tells what instrument to use. It begins:

45 50 05 00 | 4A 50 04 00 | 42 50 03 01 | 3E 50 03 0E

This is the first note. Each entry has 4 bytes:

Byte #1: Note

Byte #2: I am not sure, though it always seems to be somewhere around $50

Byte #3: Length of note

Byte #4: Amount of time to wait before next entry

Now, here is the list of notes, $24 is Middle C. The theme song and options theme use this setup, but for the organ ditties, the key is transposed somewhat:

$00 = C-1

$01 = C#-1 / Db-1

$02 = D-1

$03 = D#-1 / Eb-1

$04 = E-1

$05 = F-1

$06 = F#-1 / Gb-1

$07 = G-1

$08 = G#-1 / Ab-1

$09 = A-1

$0A = A#-1 / Bb-1

$0B = B-1

$0C = C-2

$0D = C#-2 / Db-2

$0E = D-2

$0F = D#-2 / Eb-2

$10 = E-2

$11 = F-2

$12 = F#-2 / Gb-2

$13 = G-2

$14 = G#-2 / Ab-2

$15 = A-2

$16 = A#-2 / Bb-2

$17 = B-2

$18 = C-3

$19 = C#-3 / Db-3

$1A = D-3

$1B = D#-3 / Eb-3

$1C = E-3

$1D = F-3

$1E = F#-3 / Gb-3

$1F = G-3

$20 = G#-3 / Ab-3

$21 = A-3

$22 = A#-3 / Bb-3

$23 = B-3

$24 = C-4 (This is Middle C)

$25 = C#-4 / Db-4

$26 = D-4

$27 = D#-4 / Eb-4

$28 = E-4

$29 = F-4

$2A = F#-4 / Gb-4

$2B = G-4

$2C = G#-4 / Ab-4

$2D = A-4

$2E = A#-4 / Bb-4

$2F = B-4

$30 = C-5

$31 = C#-5 / Db-5

$32 = D-5

$33 = D#-5 / Eb-5

$34 = E-5

$35 = F-5

$36 = F#-5 / Gb-5

$37 = G-5

$38 = G#-5 / Ab-5

$39 = A-5

$3A = A#-5 / Bb-5

$3B = B-5

$3C = C-6

$3D = C#-6 / Db-6

$3E = D-6

$3F = D#-6 / Eb-6

$40 = E-6

$41 = F-6

$42 = F#-6 / Gb-6

$43 = G-6

$44 = G#-6 / Ab-6

$45 = A-6

$46 = A#-6 / Bb-6

$47 = B-6

$48 = C-7

$49 = C#-7 / Db-7

$4A = D-7

$4B = D#-7 / Eb-7

$4C = E-7

$4D = F-7

$4E = F#-7 / Gb-7

$4F = G-7

$50 = G#-7 / Ab-7

$51 = A-7

$52 = A#-7 / Bb-7

$53 = B-7

$54 = C-8

$55 = C#-8 / Db-8

$56 = D-8

$57 = D#-8 / Eb-8

$58 = E-8

$59 = F-8

$5A = F#-8 / Gb-8

$5B = G-8

$5C = G#-8 / Ab-8

$5D = A-8

$5E = A#-8 / Bb-8

$5F = B-8

That means notes $45, $4A, $42, and $3E play all at once; if it were in the key of C, this is an A, D, F#, and D one octave lower all at once, making a chord.

A byte of $FF signifies the end of the song.

Here are the ID's for the sound effects:

19 - Menu Move SFX (a "ding" sound)

20 - Hit the Ball

21 - Hit the Ball 2

22 - "Foul!"

23 - "Foul Ball!"

24 - Hit the Ball 3

25 - Hit the Ball 4

26 - Hit the Ball 5

27 - Bump

28 - "Out!"

29 - "Safe!!!!!"

2A - "Safe!"

2B - "Strike Three!"

2C - "Stee-rike!"

2D - "Strike!"

2E - "Take Your Base!"

2F - "You're Out!"

30 - "You're Outta There!" (this is when you get three outs to retire the side)

31 - Big Cheer

32 - Cheer

35 - Slide

Edited by walker7
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Who's Online   0 Members, 0 Anonymous, 13 Guests (See full list)

    There are no registered users currently online