Creating a Settings file For Monkey Ball

February 12th 2022, 8:26 am

The Naomi Settings Patcher I wrote about recently is pretty cool, but it is ultimately useless without settings definition files. I designed the format to be human-readable and easy to create but somebody still has to go about creating the files themselves! When I created the settings definition file for Monkey Ball I took notes so that I could write up a blog post on my methods for figuring out various settings in an EEPROM image. Note that you can see the finished settings definition file for Monkey Ball here: https://github.com/DragonMinded/netboot/blob/trunk/naomi/settings/definitions/BDF0.settings. The tools I refer to across this blog post are available here: https://github.com/DragonMinded/netboot/. With all that that out of the way, lets get started figuring out the settings for Monkey Ball!

First, I made sure my BIOS, region and controls were all correct in demul. I also deleted the dummy.sram and dummy.eeprom files in the nvram folder just in case. This meant that I would be starting off completely fresh. Next, I loaded up the net boot ROM for Monkey Ball using the "Naomi/Naomi2 Boot" option in demul and waited for the game to finish loading completely. Once it showed the attract screen I completely closed demul (it doesn't seem to write the eeprom files until its closed) and then I took the "dummy.eeprom" file out of the nvram folder and ran it through eeprominfo to get this output:

$ ./eeprominfo dummy.eeprom
Serial: BDF0
Game Settings Hex: 00 03 00 00 00 00 00 00 00 00 00 00 00 ff 00 00 00 80 00 00 00 00 00 00 00 ff 00 00 00 80 00 00

Okay, so the game serial is BDF0 and the length of the game settings is 32 bytes. That's enough to start a settings file. I created a new file using eeprominfo named "BDF0.settings" with the following command:

$ ./eeprominfo --generate-default-settings-file dummy.eeprom
Serial: BDF0
Game Settings Hex: 00 03 00 00 00 00 00 00 00 00 00 00 00 ff 00 00 00 80 00 00 00 00 00 00 00 ff 00 00 00 80 00 00
Settings file BDF0.settings created with defaults from EEPROM!

Then I opened it up to look at what was generated:

$ vim naomi/settings/definitions/BDF0.settings

The eeprominfo utility generated a read-only setting for each byte in the EEPROM that it found:

Setting00: byte, read-only, default is 00
Setting01: byte, read-only, default is 03
Setting02: byte, read-only, default is 00
Setting03: byte, read-only, default is 00
Setting04: byte, read-only, default is 00
Setting05: byte, read-only, default is 00
Setting06: byte, read-only, default is 00
Setting07: byte, read-only, default is 00
Setting08: byte, read-only, default is 00
Setting09: byte, read-only, default is 00
Setting10: byte, read-only, default is 00
Setting11: byte, read-only, default is 00
Setting12: byte, read-only, default is 00
Setting13: byte, read-only, default is ff
Setting14: byte, read-only, default is 00
Setting15: byte, read-only, default is 00
Setting16: byte, read-only, default is 00
Setting17: byte, read-only, default is 80
Setting18: byte, read-only, default is 00
Setting19: byte, read-only, default is 00
Setting20: byte, read-only, default is 00
Setting21: byte, read-only, default is 00
Setting22: byte, read-only, default is 00
Setting23: byte, read-only, default is 00
Setting24: byte, read-only, default is 00
Setting25: byte, read-only, default is ff
Setting26: byte, read-only, default is 00
Setting27: byte, read-only, default is 00
Setting28: byte, read-only, default is 00
Setting29: byte, read-only, default is 80
Setting30: byte, read-only, default is 00
Setting31: byte, read-only, default is 00

If you compare the bytes, you can see that all it did was make a single-byte setting for each byte in the eeprom and write down the defaults. It also set them all to read-only since I didn't know what any of them did yet. To test that I got the defaults right, I ran the following:

./edit_settings mbdefault.eeprom --serial BDF0

Its important to note that the "mbdefault.eeprom" file did not exist when I ran this command, which is why I gave it the "--serial BDF0" argument. I made no changes and exited out, saying yes to write the EEPROM image and then I compared the newly written "mbdefault.eeprom" against "dummy.eeprom". They were exactly the same so I knew that edit_settings created the file properly.

Now it was time to start changing settings and seeing what happened to the EEPROM file. I could try to reverse-engineer the test code for Monkey Ball, but that would take a long time and its not something that very many people can do. I booted up demul again, immediately going into the test menu right when I saw the Naomi splash screen and headed to game test mode. There's three sections that looked like they were persistent: game assignments which is probably stored in the eeprom, joystick calibration which is also probably stored in the eeprom, and bookkeeping which might be stored in the eeprom or sram. I didn't really care about how the bookkeeping was stored, so I made a note to myself to just ignore it. I headed to game assignments first and looked at what was available:

Then I started messing with one of the settings. Just looking at the eeprom data, I was already betting that the second byte "03" was the number of monkeys since it matched the number on the screen. So I changed that one first. Cycling through it, I saw that it could be set to the values 2 through 5. So I set the number of monkeys to 5, exited back to system test so that it would write the EEPROM, exited demul and ran eeprominfo again:

$ ./eeprominfo dummy.eeprom
Serial: BDF0
Game Settings Hex: 00 05 00 00 00 00 00 00 00 00 00 00 00 ff 00 00 00 80 00 00 00 00 00 00 00 ff 00 00 00 80 00 00

As expected, the second byte changed to 05 and the rest were the same as before. So that's for sure the "Number of Monkeys" setting. I updated "Setting1" to this instead:

Number of Monkeys: byte, default is 03, values are 2 to 5

Then I tested that it was right by doing the following:

$ ./eeprominfo dummy.eeprom --display-parsed-settings
Serial: BDF0
Game Settings Hex: 00 05 00 00 00 00 00 00 00 00 00 00 00 ff 00 00 00 80 00 00 00 00 00 00 00 ff 00 00 00 80 00 00
Parsed Game Settings:
Number of Monkeys: 5

It looked good to me, so I tackled the other two settings by doing the exact same thing, narrowing down the byte that each setting used and updating the definitions file accordingly when I figured each one out. Here's what I came up with:

Game Difficulty: byte, default is 00, 0 - Normal, 1 - Hard
Number of Monkeys: byte, default is 03, values are 2 to 5
Ball Velocity Boost: byte, default is 00, 0 - Off, 1 - On
Setting03: byte, read-only, default is 00
Setting04: byte, read-only, default is 00
Setting05: byte, read-only, default is 00
Setting06: byte, read-only, default is 00
Setting07: byte, read-only, default is 00
Setting08: byte, read-only, default is 00
Setting09: byte, read-only, default is 00
Setting10: byte, read-only, default is 00
Setting11: byte, read-only, default is 00
Setting12: byte, read-only, default is 00
Setting13: byte, read-only, default is ff
Setting14: byte, read-only, default is 00
Setting15: byte, read-only, default is 00
Setting16: byte, read-only, default is 00
Setting17: byte, read-only, default is 80
Setting18: byte, read-only, default is 00
Setting19: byte, read-only, default is 00
Setting20: byte, read-only, default is 00
Setting21: byte, read-only, default is 00
Setting22: byte, read-only, default is 00
Setting23: byte, read-only, default is 00
Setting24: byte, read-only, default is 00
Setting25: byte, read-only, default is ff
Setting26: byte, read-only, default is 00
Setting27: byte, read-only, default is 00
Setting28: byte, read-only, default is 00
Setting29: byte, read-only, default is 80
Setting30: byte, read-only, default is 00
Setting31: byte, read-only, default is 00

Now it was on to the calibration screen. I did the same thing on that screen as I did for game assignments: took a screenshot of the defaults then saved them and exited demul. This is what I got when I ran the eeprominfo utility:

$ ./eeprominfo dummy.eeprom
Serial: BDF0
Game Settings Hex: 01 05 01 00 00 00 00 00 00 60 00 00 00 a0 00 00 80 7f 00 00 00 60 00 00 00 a0 00 00 80 7f 00 00

And here's what the settings looked like before I saved:

I could see the 60 and a0 values that were displayed on the screen in a few places of the eeprom so I was willing to bet those were the calibration options. At this point I decided to try something a little bit different from the first section to see if I could narrow each setting down faster. I added the settings to the settings definition file "BDF0.settings", set them to four different unique values using edit_settings and then copied "dummy.eeprom" back into the demul nvram folder. What I was hoping would happen is that the values I set would show up on the screen, allowing me to correlate the settings.

Here's how I set the settings file to do this:

Game Difficulty: byte, default is 00, 0 - Normal, 1 - Hard
Number of Monkeys: byte, default is 03, values are 2 to 5
Ball Velocity Boost: byte, default is 00, 0 - Off, 1 - On
Setting03: byte, read-only, default is 00
Setting04: byte, read-only, default is 00
Setting05: byte, read-only, default is 00
Setting06: byte, read-only, default is 00
Setting07: byte, read-only, default is 00
Setting08: byte, read-only, default is 00
Setting09: byte, default is 60, values are 00 to ff in hex
Setting10: byte, read-only, default is 00
Setting11: byte, read-only, default is 00
Setting12: byte, read-only, default is 00
Setting13: byte, default is a0, values are 00 to ff in hex
Setting14: byte, read-only, default is 00
Setting15: byte, read-only, default is 00
Setting16: byte, read-only, default is 00
Setting17: byte, read-only, default is 80
Setting18: byte, read-only, default is 00
Setting19: byte, read-only, default is 00
Setting20: byte, read-only, default is 00
Setting21: byte, default is 60, values are 00 to ff in hex
Setting22: byte, read-only, default is 00
Setting23: byte, read-only, default is 00
Setting24: byte, read-only, default is 00
Setting25: byte, default is a0, values are 00 to ff in hex
Setting26: byte, read-only, default is 00
Setting27: byte, read-only, default is 00
Setting28: byte, read-only, default is 00
Setting29: byte, read-only, default is 80
Setting30: byte, read-only, default is 00
Setting31: byte, read-only, default is 00

Then I ran:

./edit_settings dummy.eeprom

And after setting the values I copied the eeprom back to demul and re-started it. When I loaded game settings, nothing was changed though... Hmmmm. Maybe I was missing something? But wait, when I went into joystick calibration, changed nothing and chose the "exit with save" option, it didn't just change the 4 bytes that I messed with. It also messed with several other bytes as well. And when the game wrote defaults way back at the top, it didn't write 60 and a0 for the spots I thought were calibration, it wrote 00 and ff. I figured those other bytes that changed were related as well. So I changed the definition file to this:

Game Difficulty: byte, default is 00, 0 - Normal, 1 - Hard
Number of Monkeys: byte, default is 03, values are 2 to 5
Ball Velocity Boost: byte, default is 00, 0 - Off, 1 - On
Setting03: byte, read-only, default is 00
Setting04: byte, read-only, default is 00
Setting05: byte, read-only, default is 00
Setting06: byte, read-only, default is 00
Setting07: byte, read-only, default is 00
Setting08: byte, read-only, default is 00
Setting09: byte, default is 60, values are 00 to ff in hex
Setting10: byte, read-only, default is 00
Setting11: byte, read-only, default is 00
Setting12: byte, read-only, default is 00
Setting13: byte, default is a0, values are 00 to ff in hex
Setting14: byte, read-only, default is 00
Setting15: byte, read-only, default is 00
Setting16: byte, read-only, default is 80
Setting17: byte, read-only, default is 7f
Setting18: byte, read-only, default is 00
Setting19: byte, read-only, default is 00
Setting20: byte, read-only, default is 00
Setting21: byte, default is 60, values are 00 to ff in hex
Setting22: byte, read-only, default is 00
Setting23: byte, read-only, default is 00
Setting24: byte, read-only, default is 00
Setting25: byte, default is a0, values are 00 to ff in hex
Setting26: byte, read-only, default is 00
Setting27: byte, read-only, default is 00
Setting28: byte, read-only, default is 80
Setting29: byte, read-only, default is 7f
Setting30: byte, read-only, default is 00
Setting31: byte, read-only, default is 00

Still no dice. The calibration screen only showed the defaults. That's a bummer. At this point I decided to just configure some values on the configuration screen in demul and then print out what the eeprom looked like after calibrating:

$ ./eeprominfo dummy.eeprom --display
Serial: BDF0
Game Settings Hex: 00 03 00 00 00 00 00 00 39 39 00 00 ff fe 00 00 80 7f 00 00 00 60 00 00 ff fe 00 00 80 7f 00 00
Parsed Game Settings:
Game Difficulty: Normal
Number of Monkeys: 3
Ball Velocity Boost: Off
Setting09: 39
Setting13: fe
Setting21: 60
Setting25: fe

So It looked like my guesses were sorta right. I went back in with a fresh EEPROM, ran the calibration one more time and set some unique values for each setting.

After saving that exact calibration, I printed out the eeprom to see what values were there. It looked like I was actually right about the calibration values, but there was more going on:

$ ./eeprominfo dummy.eeprom --display
Serial: BDF0
Game Settings Hex: 00 03 00 00 00 00 00 00 26 26 00 00 e6 e5 00 00 80 7f 00 00 59 59 00 00 b9 b8 00 00 80 7f 00 00
Parsed Game Settings:
Game Difficulty: Normal
Number of Monkeys: 3
Ball Velocity Boost: Off
Setting09: 26
Setting13: e5
Setting21: 59
Setting25: b8

It was then that I realized the 7f values were pretty suspicious. They were the same as our Now H/Now V values on the calibration screen. I bet those were the joystick center values. For some reason, the game was storing the low values twice, the center values twice (with the first value equal to the second value plus 1), and the high values twice (with the first value equal to the second value plus 1). I can work with that.

I started with the following settings modifications:

Game Difficulty: byte, default is 00, 0 - Normal, 1 - Hard
Number of Monkeys: byte, default is 03, values are 2 to 5
Ball Velocity Boost: byte, default is 00, 0 - Off, 1 - On
Setting03: byte, read-only, default is 00
Setting04: byte, read-only, default is 00
Setting05: byte, read-only, default is 00
Setting06: byte, read-only, default is 00
Setting07: byte, read-only, default is 00
Setting08: byte, read-only, default is 00
Left: byte, default is 60, values are 00 to ff in hex
Setting10: byte, read-only, default is 00
Setting11: byte, read-only, default is 00
Setting12: byte, read-only, default is 00
Right: byte, default is a0, values are 00 to ff in hex
Setting14: byte, read-only, default is 00
Setting15: byte, read-only, default is 00
Setting16: byte, read-only, default is 80
Horizontal Center (Now H): byte, default is 7f, values are 00 to ff in hex
Setting18: byte, read-only, default is 00
Setting19: byte, read-only, default is 00
Setting20: byte, read-only, default is 00
Push: byte, default is 60, values are 00 to ff in hex
Setting22: byte, read-only, default is 00
Setting23: byte, read-only, default is 00
Setting24: byte, read-only, default is 00
Pull: byte, default is a0, values are 00 to ff in hex
Setting26: byte, read-only, default is 00
Setting27: byte, read-only, default is 00
Setting28: byte, read-only, default is 80
Vertical Center (Now V): byte, default is 7f, values are 00 to ff in hex
Setting30: byte, read-only, default is 00
Setting31: byte, read-only, default is 00

Printing out the eeprom I had gave me this:

$ ./eeprominfo dummy.eeprom --display
Serial: BDF0
Game Settings Hex: 00 03 00 00 00 00 00 00 26 26 00 00 e6 e5 00 00 80 7f 00 00 59 59 00 00 b9 b8 00 00 80 7f 00 00
Parsed Game Settings:
Game Difficulty: Normal
Number of Monkeys: 3
Ball Velocity Boost: Off
Left: 26
Right: e5
Horizontal Center (Now H): 7f
Push: 59
Pull: b8
Vertical Center (Now V): 7f

Okay, so I knew that these were the right settings but I still had to handle the other bytes. In situations like this, you can do a fancy trick in "BDF0.settings" where you state that a setting default is dependent on another setting's value. Here's what my settings definition looked like after making that change:

Game Difficulty: byte, default is 00, 0 - Normal, 1 - Hard
Number of Monkeys: byte, default is 03, values are 2 to 5
Ball Velocity Boost: byte, default is 00, 0 - Off, 1 - On
Setting03: byte, read-only, default is 00
Setting04: byte, read-only, default is 00
Setting05: byte, read-only, default is 00
Setting06: byte, read-only, default is 00
Setting07: byte, read-only, default is 00
LeftUnknown: byte, read-only, default is value of Left
Left: byte, default is 60, values are 00 to ff in hex
Setting10: byte, read-only, default is 00
Setting11: byte, read-only, default is 00
RightUnknown: byte, read-only, default is value of Right + 1
Right: byte, default is a0, values are 00 to ff in hex
Setting14: byte, read-only, default is 00
Setting15: byte, read-only, default is 00
HCenterUnknown: byte, read-only, default is value of Horizontal Center (Now H) + 1
Horizontal Center (Now H): byte, default is 7f, values are 00 to ff in hex
Setting18: byte, read-only, default is 00
Setting19: byte, read-only, default is 00
PushUnknown: byte, read-only, default is value of Push
Push: byte, default is 60, values are 00 to ff in hex
Setting22: byte, read-only, default is 00
Setting23: byte, read-only, default is 00
PullUnknown: byte, read-only, default is value of Pull + 1
Pull: byte, default is a0, values are 00 to ff in hex
Setting26: byte, read-only, default is 00
Setting27: byte, read-only, default is 00
VCenterUnknown: byte, read-only, default is value of Vertical Center (Now V) + 1
Vertical Center (Now V): byte, default is 7f, values are 00 to ff in hex
Setting30: byte, read-only, default is 00
Setting31: byte, read-only, default is 00

In the process of figuring all this out I also realized that the game does not display the current calibration on the screen. It always resets back to 60/a0 for both left/right and push/pull if you exit the calibration and re-enter it. So my strategy of setting values and seeing what happened would never have worked for Monkey Ball. I figured that out by running the calibration, saving and exiting and immediately re-entering the screen at which point the calibration values were back to their defaults again. However, it lead me down the path of figuring out that there were other settings bytes that mattered. Now that I had this all figured out, I tested it by going into demul, setting the values for the calibration to some random values, then making a copy of the eeprom. I edited the copy and changed some of the calibrations, and then looked at the output of eeprominfo:

$ ./eeprominfo dummy.eeprom --display
Serial: BDF0
Game Settings Hex: 00 03 00 00 00 00 00 00 39 39 00 00 ff fe 00 00 80 7f 00 00 00 00 00 00 ff fe 00 00 80 7f 00 00
Parsed Game Settings:
Game Difficulty: Normal
Number of Monkeys: 3
Ball Velocity Boost: Off
Left: 39
Right: fe
Horizontal Center (Now H): 7f
Push: 00
Pull: fe
Vertical Center (Now V): 7f

Cool, its adjusting those other bytes the way it should! Finally, I set the values back to what they were before using edit_settings and then compared it to the copy of the EEPROM file that I made above. Everything matched byte-for-byte which meant the settings definition was adjusting the correct bytes in the correct manner!

And that's it! After going through all that, I had a settings editor for Monkey Ball:

Keep in mind that Monkey Ball ended up being a bit difficult to figure out due to the way the calibration screen worked. When I did Marvel Vs. Capcom 2, Crazy Taxi and Jambo Safari it was much more straightforward as they used a much more simple layout for their EEPROM settings. It should be pretty easy to figure out settings for other games if you are motivated to change settings for your favorite game. If you come up with any new EEPROM settings files, feel free to send them to me to be included in the github repo!